Skip to content

emmaylots/microk8s-platform-bootstrap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MicroK8s Bootstrap Scripts

License: MIT-0 OS: Ubuntu 24.04 LTS Kubernetes MicroK8s Rancher

This repository packages the automation and documentation for a MicroK8s homelab or production edge build. It covers both a simple single-node deployment and a three-node replicated-storage deployment.

This directory contains two supported deployment paths:

  • single-node MicroK8s with local hostpath-storage
  • three-node MicroK8s with OpenEBS Mayastor replicated storage

Both paths include:

  • MicroK8s
  • CoreDNS
  • RBAC
  • ingress
  • MetalLB
  • cert-manager
  • Rancher

Use the single-node path when you want a simple lab or edge setup with local, non-replicated storage. That path now supports either the default node-backed microk8s-hostpath storage or a dedicated physical disk mounted and used as the hostpath backing directory. Use the three-node path when you want shared replicated block storage through Mayastor, optionally with a dedicated second NIC or storage VLAN for node-to-node and Mayastor traffic.

Why This Project Exists

I started this project for two practical reasons.

First, I wanted a simple, repeatable, easy-to-use deployment script for MicroK8s. MicroK8s is a strong fit for a homelab or Datacenter deployment, but the path from a clean Ubuntu install to a working cluster with ingress, load balancing, storage, and Rancher still involves enough moving parts that it is easy to drift, forget a step, or lose time rebuilding the same setup.

Second, I wanted a cleaner foundation for expanding my home lab AI stack. Most of my existing AI workloads were running directly on Docker. That worked, but it made growth, ingress management, storage behavior, and multi-service operations harder to standardize. Moving to MicroK8s provided a better platform for experimenting with self-hosted AI services, management tooling, and future cluster growth while still staying light enough for a home environment.

This repository is the result of turning that work into something reusable, documented, and easier to share, especially as a small personal way to mark 12 years of Kubernetes.

Lab Environment

The work in this repository was developed and tested in a home lab environment based on:

  • Ubuntu 24.04 LTS guest nodes
  • VMware Workstation 7 as the local virtualization platform used for this lab
  • a gaming PC host with an AMD Ryzen 5 5500
  • 32 GB RAM on the host
  • a Docker-based AI stack as the starting point before moving services toward MicroK8s

You do not need identical hardware to use the repository, but the scripts and documentation were shaped around that kind of practical homelab setup.

Requirements

Software

  • Ubuntu 24.04 LTS on the target node or nodes
  • latest Ubuntu package updates applied before bootstrap, ideally:
sudo apt update
sudo apt upgrade -y
  • SSH server enabled on each node
  • an SSH user with passwordless sudo
  • outbound internet access from the nodes for package and snap downloads
  • a working LAN segment for node-to-node communication

Hardware

  • one machine for the single-node path, or three machines/VMs for the three-node path
  • enough CPU and RAM to run MicroK8s, ingress, MetalLB, cert-manager, and Rancher
  • for the three-node path, one additional unused block device per node for Mayastor when using disk-only mode
  • for the single-node path, enough local disk space for microk8s-hostpath, or one dedicated local block device if you want the physical-disk-backed option

Networking

  • static IP addresses or stable DHCP reservations
  • a reserved MetalLB IP range on the same LAN as the cluster nodes
  • DNS or /etc/hosts control for names such as rancher.example.local
  • ideally two NICs or two network paths if you want cleaner separation between management traffic and lab/service traffic

Two NICs are not a hard requirement for the scripts to work, but they are a sensible design choice for a more serious home lab, especially if you want to separate administrative access from workload exposure.

Three-node path note:

  • If you provide primary_storage_ip, node2_storage_ip, and node3_storage_ip, the three-node bootstrap will configure MicroK8s kubelet --node-ip on those addresses. That means Kubernetes node-to-node traffic and Mayastor traffic will prefer the storage network.
  • This is not a Mayastor-only binding. It is a cluster-internal node IP change for the three-node deployment.

Storage Notes

  • Single-node deployments can use the default microk8s-hostpath storage class or a dedicated physical disk mounted as the backing directory for a custom hostpath storage class.
  • Three-node deployments support Mayastor sparse mode and disk-only mode.
  • For disk-only, the chosen devices must be real block devices, must not be mounted, and must not hold data you care about.
  • In disk-only, the final intended state is disk-backed Mayastor pools only, but the bootstrap may briefly create default sparse pools first and then remove them.

Repository Layout

  • scripts/enable-microk8s-single-node.sh End-to-end single-node bootstrap. It installs MicroK8s on one node, enables the required addons, configures either default hostpath storage or a dedicated physical-disk-backed hostpath storage class, exposes ingress through MetalLB, and installs Rancher.
  • examples/single-node-answers.example.yaml Example flat YAML answers file for repeatable single-node runs.
  • scripts/enable-microk8s-three-node.sh End-to-end three-node bootstrap. It prepares nodes, installs MicroK8s, joins the cluster, enables addons, deploys Mayastor, and installs Rancher.
  • examples/cluster-answers.example.yaml Example flat YAML answers file for repeatable three-node runs.
  • scripts/prepare-node-for-mayastor.sh Standalone Mayastor host preparation script for the three-node path.
  • scripts/remove-mayastor-sparse-pools.sh Helper script to detect and optionally remove sparse Mayastor DiskPool resources.
  • scripts/health-status.sh Health summary script for single-node and three-node deployments. It checks SSH access, MicroK8s state, nodes, problem pods, ingress exposure, storage classes, Mayastor state when present, and Rancher pods.
  • docs/troubleshooting.md Troubleshooting notes, diagnostic commands, and fixes for issues already encountered.
  • CONTRIBUTING.md Contribution guidelines for keeping the automation, documentation, and behavior consistent.
  • LICENSE MIT-0 license for unrestricted reuse.
  • archive/README.md Notes about the archived legacy scripts.
  • backups/ Local timestamped backups created before edits. This is intended for local safety, not for source control history.

Quick Start

Single node:

chmod +x scripts/enable-microk8s-single-node.sh
cp examples/single-node-answers.example.yaml single-node-answers.yaml
./scripts/enable-microk8s-single-node.sh --answers single-node-answers.yaml
./scripts/health-status.sh --answers single-node-answers.yaml

Three nodes:

chmod +x scripts/enable-microk8s-three-node.sh scripts/prepare-node-for-mayastor.sh
cp examples/cluster-answers.example.yaml cluster-answers.yaml
./scripts/enable-microk8s-three-node.sh --answers cluster-answers.yaml
./scripts/health-status.sh --answers cluster-answers.yaml

Architecture

Single Node

                            +----------------------+
                            |   Admin Workstation  |
                            | SSH + local kubeconfig|
                            +----------+-----------+
                                       |
                                       | SSH / kubectl
                                       |
                    ------------------------------------------------
                                       |
                         Management / LAN (example 192.168.1.0/24)
                                       |
                               +-------+--------+
                               | kubenode01     |
                               | MicroK8s       |
                               | Control/worker |
                               | CoreDNS        |
                               | RBAC           |
                               | ingress        |
                               | MetalLB        |
                               | cert-manager   |
                               | Rancher        |
                               | hostpath       |
                               +-------+--------+
                                       |
                        +--------------+--------------+
                        |                             |
              +---------+---------+         +---------+---------+
              | MetalLB ingress IP|         | Local storage     |
              | example: .50      |         | hostpath or disk  |
              +---------+---------+         +-------------------+
                        |
              +---------+---------+
              | Host-based ingress|
              | rancher.lab.local |
              +-------------------+

Three Nodes

                                   +----------------------+
                                   |   Admin Workstation  |
                                   | SSH + local kubeconfig|
                                   +----------+-----------+
                                              |
                                              | SSH / kubectl
                                              |
                   ---------------------------------------------------------
                                              |
                    Management / Cluster Network (example 192.168.1.0/24)
                                              |
        ---------------------------------------------------------------------------------
        |                                   |                                   |
+-------+--------+                  +-------+--------+                  +-------+--------+
| kubenode01     |                  | kubenode02     |                  | kubenode03     |
| Primary node   |                  | Cluster node   |                  | Cluster node   |
| MicroK8s       |                  | MicroK8s       |                  | MicroK8s       |
| Control plane  |                  | Control/worker |                  | Control/worker |
| Mayastor pool  |                  | Mayastor pool  |                  | Mayastor pool  |
| /dev/nvme0n1   |                  | /dev/nvme0n1   |                  | /dev/nvme0n1   |
+-------+--------+                  +-------+--------+                  +-------+--------+
        |                                   |                                   |
        ---------------------------------------------------------------------------------
                                              |
                                +-------------+--------------+
                                |     MicroK8s Cluster       |
                                | dns, ingress, helm3,       |
                                | cert-manager, RBAC,        |
                                | MetalLB, Mayastor          |
                                +-------------+--------------+
                                              |
                          +-------------------+-------------------+
                          |                                       |
                +---------+---------+                   +---------+---------+
                |   MetalLB IP(s)   |                   |   Mayastor CSI    |
                | example range:    |                   | replicated volumes |
                | 192.168.1.240-250 |                   | StorageClass:      |
                +---------+---------+                   | mayastor-3         |
                          |                             +-------------------+
                          |
                +---------+---------+
                | Rancher Ingress   |
                | rancher.lab.local |
                +-------------------+

Before You Use The Scripts

Complete these common prerequisites first.

  1. Prepare Ubuntu nodes with fixed IP addresses.
  2. Ensure the nodes can reach each other over the management network.
  3. Ensure you can SSH from the machine running the scripts to the target node or nodes.
  4. Ensure the SSH user has passwordless sudo.
  5. Set Linux hostnames and make sure they match the Kubernetes node names you plan to use.
  6. Reserve an unused MetalLB IP range on your LAN, for example 192.168.1.240-192.168.1.250.
  7. Decide the DNS name for Rancher, for example rancher.lab.local.
  8. Ensure your firewall allows SSH and normal cluster traffic.

Three-node path only:

  1. Identify the block device to use for Mayastor on each node, for example /dev/nvme0n1.
  2. Make sure the selected Mayastor disks are not mounted, are not used by the OS, and do not contain data you need.
  3. Make sure each selected Mayastor disk exists on the target node as a real block device.

Enable Passwordless SSH

Both bootstraps use SSH with BatchMode=yes, so key-based login must work before you run either script.

1. Check whether you already have an SSH key

On the machine where you will run the bootstrap:

ls -la ~/.ssh

If you already have a key pair such as id_ed25519 and id_ed25519.pub, you can reuse it.

2. Create a new SSH key if needed

ssh-keygen -t ed25519 -C "microk8s-bootstrap"

When prompted:

  1. Press Enter to accept the default file path, or choose another path.
  2. Press Enter for no passphrase if you want fully non-interactive automation.

3. Copy your public key to each node

Single-node example:

ssh-copy-id kuser@192.168.1.40

Three-node example:

ssh-copy-id kuser@192.168.1.40
ssh-copy-id kuser@192.168.1.41
ssh-copy-id kuser@192.168.1.42

If your SSH server listens on a non-default port, include -p.

4. If ssh-copy-id is not available, install the key manually

Display your public key:

cat ~/.ssh/id_ed25519.pub

Then on each node:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Paste the public key into ~/.ssh/authorized_keys.

5. Verify non-interactive SSH exactly the way the bootstraps expect

Single-node example:

ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new kuser@192.168.1.40 "echo ok"

Three-node example:

ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new kuser@192.168.1.40 "echo ok"
ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new kuser@192.168.1.41 "echo ok"
ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new kuser@192.168.1.42 "echo ok"

6. Configure passwordless sudo on each node

Check it:

ssh kuser@192.168.1.40 "sudo -n true && echo sudo-ok"

If this fails, add a sudoers rule on the node with visudo:

sudo visudo

Add a line like this, replacing kuser with your SSH user:

kuser ALL=(ALL) NOPASSWD:ALL

Recommended Prechecks

Three-node path only:

chmod +x scripts/prepare-node-for-mayastor.sh scripts/enable-microk8s-three-node.sh
./scripts/prepare-node-for-mayastor.sh --check-only
./scripts/prepare-node-for-mayastor.sh --device /dev/nvme0n1 --check-only

If you want to validate or stage a node ahead of the full bootstrap:

./scripts/prepare-node-for-mayastor.sh --device /dev/nvme0n1

Automated Setup

Single Node

chmod +x scripts/enable-microk8s-single-node.sh
./scripts/enable-microk8s-single-node.sh

To use a saved YAML answers file:

cp examples/single-node-answers.example.yaml single-node-answers.yaml
./scripts/enable-microk8s-single-node.sh --answers single-node-answers.yaml

The single-node answers file supports:

  • channel
  • ssh_user
  • ssh_port
  • node_name
  • node_host
  • storage_mode
  • storage_class_name
  • storage_disk_device
  • storage_disk_mountpoint
  • storage_disk_allow_format
  • metallb_range
  • rancher_hostname
  • rancher_bootstrap_password
  • ingress_loadbalancer_ip
  • ingress_address_pool
  • proceed

Single-node storage mode rules:

  • if storage_mode: hostpath, use storage_class_name: microk8s-hostpath and do not set storage_disk_device
  • if storage_mode: disk, set a dedicated storage_class_name such as microk8s-hostpath-disk, plus storage_disk_device and storage_disk_mountpoint

Three Nodes

chmod +x scripts/enable-microk8s-three-node.sh scripts/prepare-node-for-mayastor.sh
./scripts/enable-microk8s-three-node.sh

To use a saved YAML answers file:

cp examples/cluster-answers.example.yaml cluster-answers.yaml
./scripts/enable-microk8s-three-node.sh --answers cluster-answers.yaml

The three-node answers file supports:

  • channel
  • ssh_user
  • ssh_port
  • join_mode
  • primary_name, primary_host, primary_disk
  • primary_storage_ip
  • node2_name, node2_host, node2_disk
  • node2_storage_ip
  • node3_name, node3_host, node3_disk
  • node3_storage_ip
  • metallb_range
  • rancher_hostname
  • rancher_bootstrap_password
  • mayastor_storageclass
  • mayastor_mode
  • mayastor_pool_size
  • ingress_loadbalancer_ip
  • ingress_address_pool
  • proceed

Health Checks

Use the health script after deployment, after upgrades, or during troubleshooting.

Single node:

./scripts/health-status.sh --answers single-node-answers.yaml

Three nodes:

./scripts/health-status.sh --answers cluster-answers.yaml

Ad hoc single-node check without an answers file:

./scripts/health-status.sh --host 192.168.1.40 --user kuser

The script exits with a non-zero status if it detects warnings such as failed SSH access, unhealthy pods, missing ingress exposure, or missing MicroK8s components.

Example NGINX Deployments

These examples are intentionally simple and are useful as quick smoke tests after the cluster is up.

Deploy NGINX from Helm

microk8s helm3 repo add bitnami https://charts.bitnami.com/bitnami
microk8s helm3 repo update
microk8s helm3 upgrade --install nginx bitnami/nginx
microk8s kubectl get pods,svc

Deploy NGINX from Docker Hub

This uses the standard nginx image from Docker Hub and creates a Deployment plus a Service:

microk8s kubectl create deployment nginx --image=nginx:stable
microk8s kubectl expose deployment nginx --port=80 --target-port=80 --type=ClusterIP
microk8s kubectl get pods,svc

Expose NGINX through an ingress hostname

After deploying NGINX, create an Ingress resource:

microk8s kubectl apply -f - <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx
spec:
  ingressClassName: public
  rules:
    - host: nginx.example.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx
                port:
                  number: 80
EOF

Verify:

microk8s kubectl get ingress nginx
microk8s kubectl get svc -n ingress ingress

Then point the hostname to your MetalLB ingress IP, for example:

192.168.1.50 nginx.example.local

Test it:

curl -I -H 'Host: nginx.example.local' http://192.168.1.50

What Each Bootstrap Does

Single-node bootstrap

When you run scripts/enable-microk8s-single-node.sh, it will:

  1. Validate SSH access, sudo, and MetalLB input.
  2. Install MicroK8s if it is not already present.
  3. Enable dns, helm3, ingress, metallb, cert-manager, rbac, and hostpath-storage.
  4. Create a MetalLB-backed LoadBalancer service in the ingress namespace when the MicroK8s NGINX ingress controller is present.
  5. In hostpath mode, make microk8s-hostpath the default StorageClass.
  6. In disk mode, validate the target block device, optionally format it if explicitly allowed, mount it, and create a physical-disk-backed hostpath StorageClass.
  7. Install or upgrade Rancher with Helm.

Three-node bootstrap

When you run scripts/enable-microk8s-three-node.sh, it will:

  1. Validate SSH access, sudo, node uniqueness, and MetalLB input.
  2. Validate the Mayastor block devices when you use disk-only mode.
  3. Validate optional dedicated storage-network IPs when you provide them.
  4. Apply the Mayastor host prerequisites on all 3 nodes.
  5. Install MicroK8s on nodes that do not already have it.
  6. If storage-network IPs are provided, configure kubelet --node-ip on those addresses and restart MicroK8s.
  7. Join node 2 and node 3 only if they are not already part of the cluster.
  8. Wait for 3 visible Kubernetes nodes, then wait for the 3-node cluster to become ready.
  9. Enable dns, helm3, ingress, metallb, cert-manager, and rbac only if they are not already enabled.
  10. Create a MetalLB-backed LoadBalancer service in the ingress namespace when the MicroK8s NGINX ingress controller is present.
  11. Enable Mayastor.
  12. In sparse mode, keep the addon-created default sparse pools.
  13. In disk-only mode, Mayastor may briefly create default sparse pools during bootstrap; the script then removes them and replaces them with block-device-backed pools on the 3 nodes.
  14. Create or reconcile the default replicated Mayastor StorageClass.
  15. Install or upgrade Rancher with Helm.

Rerun Behavior

Both bootstraps are resumable. Rerunning them will skip work that is already complete where possible.

Single-node reruns will:

  • skip MicroK8s installation if it is already installed
  • skip addons that are already enabled
  • preserve the existing ingress LoadBalancer service
  • re-assert the selected single-node default storage class
  • run Rancher with helm upgrade --install

Logging

The deployment scripts now write a local timestamped log file by default. This makes it much easier to review failures, long-running steps, and remote command output after a run.

Default behavior:

You can override the path with --log-file:

./scripts/enable-microk8s-three-node.sh --answers cluster-answers.yaml --log-file /tmp/microk8s-three-node.log
./scripts/enable-microk8s-single-node.sh --answers single-node-answers.yaml --log-file /tmp/microk8s-single-node.log
./scripts/prepare-node-for-mayastor.sh --device /dev/nvme0n1 --log-file /tmp/mayastor-prep.log

For the two bootstrap scripts, you can also set log_file: in the answers YAML.

Three-node reruns will:

  • skip MicroK8s installation on nodes where it is already installed
  • skip cluster join for nodes already present in the cluster
  • skip addons that are already enabled
  • preserve existing explicit-disk Mayastor pools
  • keep existing sparse pools when you use sparse mode
  • remove only default sparse Mayastor pools when you use disk-only mode, after the initial Mayastor bootstrap if they were created
  • re-apply the Mayastor StorageClass
  • run Rancher with helm upgrade --install

After The Bootstrap

After either deployment completes:

  1. Verify Rancher and ingress resources:
kubectl --kubeconfig ~/.kube/config get pods -n cattle-system
kubectl --kubeconfig ~/.kube/config get ingress -A
kubectl --kubeconfig ~/.kube/config get svc -A
kubectl --kubeconfig ~/.kube/config get svc -n ingress ingress
  1. Note the EXTERNAL-IP of svc/ingress in the ingress namespace.
  2. Add a DNS entry or a /etc/hosts entry for your Rancher hostname.

Example:

192.168.1.50 rancher.example.local
  1. Open Rancher in your browser using the hostname:
https://rancher.example.local
  1. Log in as admin using the bootstrap password you provided.
  2. If https://<node-ip> returns 404, that is expected. Rancher is exposed through a host-based ingress rule and should be accessed by hostname, not raw IP.

Ingress LoadBalancer recovery

If your cluster does not automatically create svc/ingress in the ingress namespace, apply this service manually:

apiVersion: v1
kind: Service
metadata:
  name: ingress
  namespace: ingress
spec:
  selector:
    name: nginx-ingress-microk8s
  type: LoadBalancer
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
    - name: https
      protocol: TCP
      port: 443
      targetPort: 443

Apply it with:

ssh kuser@192.168.1.40 "sudo microk8s kubectl apply -f -" <<'EOF'
apiVersion: v1
kind: Service
metadata:
  name: ingress
  namespace: ingress
spec:
  selector:
    name: nginx-ingress-microk8s
  type: LoadBalancer
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
    - name: https
      protocol: TCP
      port: 443
      targetPort: 443
EOF

Then verify:

ssh kuser@192.168.1.40 "sudo microk8s kubectl get svc -n ingress ingress"

Remove Sparse Mayastor Pools

Three-node path only. Use this only if you want to move away from the addon-created sparse Mayastor pools.

Scripted method

Dry-run first:

./scripts/remove-mayastor-sparse-pools.sh --ssh kuser@192.168.1.40

Delete the detected sparse pools:

./scripts/remove-mayastor-sparse-pools.sh --ssh kuser@192.168.1.40 --apply

If you already have microk8s kubectl access locally, you can also run:

./scripts/remove-mayastor-sparse-pools.sh
./scripts/remove-mayastor-sparse-pools.sh --apply

Notes

  • The standalone Mayastor prep script is only needed for the three-node path.
  • The kubeconfig written by the bootstraps is stored in ~/.kube/config on the machine where you run the script.
  • The single-node path uses local storage only. It is not replicated and it lives on that one node.
  • In hostpath mode, the single-node path uses the default microk8s-hostpath storage class.
  • In disk mode, the single-node path mounts a dedicated local disk and creates a hostpath storage class backed by that mountpoint.
  • In disk mode, the script only formats the selected disk if you explicitly set storage_disk_allow_format: true.
  • The three-node path supports sparse and disk-only Mayastor modes.
  • In disk-only mode, Mayastor may create temporary sparse pools during bootstrap, but the script is designed to remove them and leave disk-backed pools as the final state.
  • If your Linux hostnames do not match the node names you provide, Mayastor pool creation will fail later in the three-node path.
  • If you provide *_storage_ip values in the three-node path, those IPs must already exist on the nodes on a reachable second NIC or VLAN.
  • The three-node storage-network option changes kubelet node IPs. It is intended to steer cluster-internal and Mayastor traffic to the dedicated network, not just Mayastor alone.
  • In the preferred setup, Rancher and other ingress apps should be reached through the MetalLB floating IP assigned to svc/ingress, together with the configured hostname.
  • If svc/ingress is missing, use the ingress LoadBalancer recovery command above.
  • For prior failure modes and the exact recovery commands, use docs/troubleshooting.md.

About

Automated MicroK8s platform deployment for single-node and HA clusters with Mayastor storage, MetalLB, NGINX Ingress, Cert-Manager, Rancher, RBAC, troubleshooting tools, and ready-to-use Kubernetes platform using simple answer files and repeatable automation

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages