Incus VMでMicroK8sクラスタを組んでみた (1of2) 構築編
List of documents
Incus VMでMicroK8sクラスタを組んでみた (1of2) 構築編
Incus VMでMicroK8sクラスタを組んでみた (2of2) 検証編
MicroK8sをクラスタ構成で構築してみたメモです。
実際にHA (High Avaiability)がどう機能するかは検証編に続きます。
はじめに
物理マシン1台の上にIncusでVMインスタンスを4台を立てて、各VMインスタンスをMicroK8sのノードとするクラスタを組みました。
物理マシンはほとんどいじっていない素のUbuntuサーバで、自宅ホームネットワークに設置済みです。今回、これをリモートのクライアントPCから操作・管理できるようにしたいと考え、そのためにVPNのTailscaleと、MicroK8sのアドオンのMetalLB (ロードバランサ)も導入しました。
MicroK8sの構築は下記のmicrok8s公式サイトを主に参考にしました。
LXDとIncusの違いはありますが、ほぼほぼ同じ手順で構築できました。
- LXDのVM上にmicrok8sをインストールする手順
- microk8sでクラスタを組む手順
事前に用意するもの
-
適当な物理マシン 1台
Incus MVのホストマシンです。
- OS: Ubuntu 24.04.2
- 自宅ホームネットワーク内からInternet reachable
- openssh-serverインストール済 -
適当なクライアントPC 1台
Incusホストマシンを操作する作業用ノートPCです。
- OS: Ubuntu 24.04.2
- 自宅ホームネットワーク内または宅外ではFree WiFi等からInternet reachable
- SSHクライアント -
論理ネットワーク
- home_private: 192.168.0.0/24
DefaultGW: ホームルータ (192.168.0.1)
- incusbr0_private: 10.57.140.0/24
DefautGW: Incusホストマシンのincusbr0 (10.57.140.1)
1 Incusのインストール
作業対象: Incusホストマシン
Incus公式のインストール手順に沿ってインストールします。
インストールのコマンドだけ抜粋すると以下のとおりです。
## パッケージインストール
$ sudo apt install incus
$ sudo apt install qemu-system
## カレントユーザをincus-adminグループに追加
$ sudo adduser $USER incus-admin
$ newgrp incus-admin
## 初期化
$ incus admin init --minimal
初期化まで実行すると、ip a
コマンドでincusbr0
ブリッジとそのIPアドレス(10.57.140.1/24)を確認できます。
$ ip a show incusbr0
8: incusbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 10.57.140.1/24 scope global incusbr0
(...)
このincusbr0
ブリッジは、Incusのデフォルト設定でVMインスタンスを作成した場合に、VMインスタンスのNICインタフェースが接続されるブリッジです。
incusbr0
ブリッジのデフォルト設定ではDHCPサーバが有効になっており、VMのNICインタフェースに対してIPアドレスを動的に割り当てます。特に何も考えずVMインスタンスを作成しても、MVインスタンスはこのincusbr0
ブリッジ (NAT)を経由してインターネットにアクセスできるため便利なのですが、デフォルト設定ではDHCPで払い出すIPアドレスプールの範囲が無制限となっています。今回、DHCPのIPアドレスプールの範囲を明示的に.199までに狭めることにします。これは、後で設定するmetallbが使用するIPアドレスプールとの重複を避けるためです。
$ incus network set incusbr0 ipv4.dhcp.ranges="10.57.140.2-10.57.140.199"
$ incus network show incusbr0
2 Tailscaleのインストール
作業対象: クライアントPC
Tailscale公式の下記インストール手順に沿ってインストールします。
作業対象: Incusホストマシン
Tailscale公式の下記インストール手順に沿ってサブネットルータとしてインストールします。
Tailscaleインストール後の正常性確認
-
クライアントPCからping疎通することを確認します。
- 確認1: Incusホストマシンのtailnet0のIPv4アドレス
へping
- 確認2: Incusホストマシンのincusbr0のIPv4アドレス(10.57.140.1)
へping -
クライアントPCからIncusホストマシンへSSHログインできることを確認します。
- 確認3: Incusホストマシンのtailnet0のIPアドレス
へssh
3 Incus VMでMicroK8sクラスタを構築
3.1 Incus VMインスタンスの作成
microk8sの仕様上、HA (High Availability)機能を利用するためには複数のVMインスタンス(ノード)が必要となります。
- VMインスタンス(ノード)の必要台数:
- Master node 3台
- Standby node 1台 (任意)
Standby nodeは、いずれか1台のMaster nodeが障害となった際にMaster nodeに昇格するノードで、構築は任意ですが、今回は昇格による障害リカバリの動作を試したいためVMインスタンス 4台をIncusで作成します。
$ incus launch images:ubuntu/noble/desktop k8s0-vm --vm -c limits.cpu=2 -c limits.memory=4GiB
$ incus launch images:ubuntu/noble/desktop k8s1-vm --vm -c limits.cpu=2 -c limits.memory=4GiB
$ incus launch images:ubuntu/noble/desktop k8s2-vm --vm -c limits.cpu=2 -c limits.memory=4GiB
$ incus launch images:ubuntu/noble/desktop k8s3-vm --vm -c limits.cpu=2 -c limits.memory=4GiB
$ incus list
launchはVMインスタンスの作成と起動(start)を兼ねていて、incus list
コマンドにより、MVインスタンス 4台がRUNNINGの状態になっていることが確認できます。
3.2 microk8sのインストール
microk8sのcurrentバージョンを確認します。
(下記は、2025年6月時点のバージョン表示例)
$ incus exec k8s0-vm -- snap info microk8s
(...)
channels:
1.32/stable: v1.32.3 2025-04-22 (8148) 172MB classic
1.32/candidate: v1.32.3 2025-04-22 (8148) 172MB classic
1.32/beta: v1.32.3 2025-04-22 (8148) 172MB classic
1.32/edge: v1.32.6 2025-06-19 (8266) 172MB classic
latest/stable: v1.32.3 2025-04-07 (7964) 172MB classic
latest/candidate: v1.32.3 2025-03-12 (7890) 179MB classic
latest/beta: v1.32.3 2025-03-12 (7890) 179MB classic
latest/edge: v1.33.2 2025-06-19 (8267) 177MB classic
1.33/stable: v1.33.0 2025-04-24 (8205) 177MB classic
1.33/candidate: v1.33.0 2025-04-24 (8205) 177MB classic
1.33/beta: v1.33.0 2025-04-24 (8205) 177MB classic
1.33/edge: v1.33.2 2025-06-18 (8244) 177MB classic
(...)
microk8s公式サイトのインストールガイドを参考に、どのバージョン(チャンネル)をインストールするか決定します。
今回は、current latest/stableより先の1.33/stableをインストールしてみます。
$ incus exec k8s0-vm -- snap install microk8s --classic --channel=1.33/stable
$ incus exec k8s1-vm -- snap install microk8s --classic --channel=1.33/stable
$ incus exec k8s2-vm -- snap install microk8s --classic --channel=1.33/stable
$ incus exec k8s3-vm -- snap install microk8s --classic --channel=1.33/stable
(...)
microk8s (1.33/stable) v1.33.0 from Canonical installed
各VMノードでmicrok8sが起動状態になっていることを確認します。(表示例: microk8s is running)
まだクラスタを組んでいないため、master nodesの表示は自ノードのみです。(表示例: 127.0.0.1)
$ incus exec k8s0-vm -- microk8s status --wait-ready
$ incus exec k8s1-vm -- microk8s status --wait-ready
$ incus exec k8s2-vm -- microk8s status --wait-ready
$ incus exec k8s3-vm -- microk8s status --wait-ready
(...)
microk8s is running
high-availability: no
datastore master nodes: 127.0.0.1:19001
datastore standby nodes: none
addons:
enabled:
dns # (core) CoreDNS
ha-cluster # (core) Configure high availability on the current node
helm # (core) Helm - the package manager for Kubernetes
helm3 # (core) Helm 3 - the package manager for Kubernetes
disabled:
cert-manager # (core) Cloud native certificate management
cis-hardening # (core) Apply CIS K8s hardening
community # (core) The community addons repository
dashboard # (core) The Kubernetes dashboard
gpu # (core) Alias to nvidia add-on
host-access # (core) Allow Pods connecting to Host services smoothly
hostpath-storage # (core) Storage class; allocates storage from host directory
ingress # (core) Ingress controller for external access
kube-ovn # (core) An advanced network fabric for Kubernetes
mayastor # (core) OpenEBS MayaStor
metallb # (core) Loadbalancer for your Kubernetes cluster
metrics-server # (core) K8s Metrics Server for API access to service metrics
minio # (core) MinIO object storage
nvidia # (core) NVIDIA hardware (GPU and network) support
observability # (core) A lightweight observability stack for logs, traces and metrics
prometheus # (core) Prometheus operator for monitoring and logging
rbac # (core) Role-Based Access Control for authorisation
registry # (core) Private image registry exposed on localhost:32000
rook-ceph # (core) Distributed Ceph storage using Rook
storage # (core) Alias to hostpath-storage add-on, deprecated
各VMノードで、どのノードとクラスタを組んでいるか確認します。
まだクラスタを組んでいないため、get nodesの表示は自ノードのみです。(表示例: k8s0-vm)
$ incus exec k8s0-vm -- microk8s kubectl get nodes
$ incus exec k8s1-vm -- microk8s kubectl get nodes
$ incus exec k8s2-vm -- microk8s kubectl get nodes
$ incus exec k8s3-vm -- microk8s kubectl get nodes
(...)
NAME STATUS ROLES AGE VERSION
k8s0-vm Ready <none> 9m18s v1.33.0
3.3 microk8s VMノードのクラスタを組む (add-nodeとjoin)
add-nodeとjoinによりVMノード 4台でクラスタを組みます。
- k8s0-vmのクラスタにadd-nodeするためのトークンをk8s0-vm上で発行します。
- トークンを使って他のVMノードをk8s0-vmのクラスタにjoinさせます。
- トークンはjoin 1回しか使えず、joinごとにトークンを発行します。
- k8s1-vmをjoinさせます。
$ incus exec k8s0-vm -- microk8s add-node
From the node you wish to join to this cluster, run the following:
microk8s join 10.57.140.189:25000/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxx
(...)
$ incus exec k8s1-vm -- microk8s join 10.57.140.189:25000/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxx
Successfully joined the cluster.
- 同様に、k8s2-vmをjoinさせます。
$ incus exec k8s0-vm -- microk8s add-node
From the node you wish to join to this cluster, run the following:
microk8s join 10.57.140.189:25000/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxx
(...)
$ incus exec k8s2-vm -- microk8s join 10.57.140.189:25000/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxx
Successfully joined the cluster.
- 同様に、k8s3-vmをjoinさせます。
$ incus exec k8s0-vm -- microk8s add-node
From the node you wish to join to this cluster, run the following:
microk8s join 10.57.140.189:25000/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxx
$ incus exec k8s3-vm -- microk8s join 10.57.140.189:25000/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxx
Successfully joined the cluster.
クラスタを組み終わったため、get nodesの表示は4台となります。
$ incus exec k8s0-vm -- microk8s kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s0-vm Ready <none> 29m v1.33.0
k8s1-vm Ready <none> 13m v1.33.0
k8s2-vm Ready <none> 12m v1.33.0
k8s3-vm Ready <none> 10m v1.33.0
正常にクラスタを組み終わった状態では、microk8sは以下のステータス表示となります。
- high-availability: yes
- master nodes: k8s0-vm, k8s1-vm, k8s2-vmのIPアドレス(3個)
- standby nodes: 最後にjoinさせたk8s3-vmのIPアドレス(1個)
$ incus exec k8s0-vm -- microk8s status --wait-ready
microk8s is running
high-availability: yes
datastore master nodes: 10.57.140.189:19001 10.57.140.40:19001 10.57.140.98:19001
datastore standby nodes: 10.57.140.147:19001
(...)
$ incus list | grep k8s
| k8s0-vm | RUNNING | 10.57.140.189 (enp5s0) | fdxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx (enp5s0) | VIRTUAL-MACHINE | 0 |
| k8s1-vm | RUNNING | 10.57.140.40 (enp5s0) | fdxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx (enp5s0) | VIRTUAL-MACHINE | 0 |
| k8s2-vm | RUNNING | 10.57.140.98 (enp5s0) | fdxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx (enp5s0) | VIRTUAL-MACHINE | 0 |
| k8s3-vm | RUNNING | 10.57.140.147 (enp5s0) | fdxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx (enp5s0) | VIRTUAL-MACHINE | 0 |
3.4 microkl8sのアドオン追加 (dashboardとmetalld)
dashboardアドオンを有効化します。
$ incus exec k8s0-vm -- microk8s enable dashboard
(...)
NOTES:
*************************************************************************************************
*** PLEASE BE PATIENT: Kubernetes Dashboard may need a few minutes to get up and become ready ***
*************************************************************************************************
Congratulations! You have just installed Kubernetes Dashboard in your cluster.
To access Dashboard run:
kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard-kong-proxy 8443:443
NOTE: In case port-forward command does not work, make sure that kong service name is correct.
Check the services in Kubernetes Dashboard namespace using:
kubectl -n kubernetes-dashboard get svc
Dashboard will be available at:
https://localhost:8443
Applying manifest
secret/microk8s-dashboard-token created
If RBAC is not enabled access the dashboard using the token retrieved with:
microk8s kubectl describe secret -n kube-system microk8s-dashboard-token
Use this token in the https login UI of the kubernetes-dashboard service.
In an RBAC enabled setup (microk8s enable RBAC) you need to create a user with restricted
permissions as shown in:
https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md
有効化すると、RBACを有効化していない場合の、ダッシュボードへのログインに必要なトークンの表示コマンドが表示されます。
今すぐトークンを表示する必要はありませんが、後ほどログインすることになるので、今ここでトークンの表示コマンドを実行してtoken:
の値をメモしておきます。(以下の/////部分)
$ incus exec k8s0-vm -- microk8s kubectl describe secret -n kube-system microk8s-dashboard-token
Name: microk8s-dashboard-token
Namespace: kube-system
Labels: <none>
Annotations: kubernetes.io/service-account.name: default
kubernetes.io/service-account.uid: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1123 bytes
namespace: 11 bytes
token: ////////////////////////////////////////////////////////////////////////////////////////
metallbアドオンを有効化します。
metallb(ロードバランサ)をmicrok8sサービスに紐付けると、外部から該当microk8sサービスにアクセスできるようになります。有効化する際に、引数として、metallbが外部向けのExternal-IP
として用いるIPアドレスプールの範囲を指定します。
$ incus exec k8s0-vm -- microk8s enable metallb:10.57.140.200-10.57.140.219
MetalLB is enabled
3.5 ダッシュボードへのアクセス設定
get all -A
でダッシュボードのネームスペース名とサービス名を特定します。
i.e. 443/TCPポートを持っているサービスを特定します。
特定した結果は、
- ネームスペース名: kubernetes-dashboard
- サービス名: kubernetes-dashboard-kong-proxy
$ incus exec k8s0-vm -- microk8s kubectl get all -A
(...)
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-dashboard service/kubernetes-dashboard-kong-proxy ClusterIP 10.152.183.31 <none> 443/TCP 25m
ダッシュボードのサービス名とネームスペース名を指定して、サービス設定の編集を行います。
edit svc
を実行すると編集画面(vi画面)になるので、そこでtype:
の値をClusterIP
からLoadBalancer
に書き換えて保存します。
$ incus exec k8s0-vm -- microk8s kubectl edit svc kubernetes-dashboard-kong-proxy -n kubernetes-dashboard
(..)
編集前 type: ClusterIP
編集後 type: LoadBalancer
保存してvi画面を抜けると設定変更が即時反映されます。
get all -A
で設定変更が反映されたことを確認できます。
- TYPE: LoadBalancer
- EXTERNAL-IP: metallbが割り当てたIPアドレス (表示例: 10.57.140.200)
$ incus exec k8s0-vm -- microk8s kubectl get all -A
(...)
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-dashboard service/kubernetes-dashboard-kong-proxy LoadBalancer 10.152.183.31 10.57.140.200 443:31034/TCP 31m
設定は以上です。
クライアントPCのWebブラウザからダッシュボードにアクセスしてみましょう。
- アクセスURL:
https://10.57.140.200
下記のようなWarning画面が表示されれば成功です。
Continue to 10.57.140.200 (unsafe)
をクリックして続行します。
ダッシュボードへログインするためのトークンの入力が求められます。
あらかじめメモしておいたトークン値を入力するか、または、今ここでトークン表示コマンドを実行して表示されたトークン値を入力します。
ダッシュボード画面が表示されます。
3.6 microbotへのアクセス設定
お試しサービスとして、microk8sの公式サイト (Installing - MicroK8s in LXD)でも紹介されているmicrobotをインストールしてみます。
まず、microbotをデプロイします。
$ incus exec k8s0-vm -- microk8s kubectl create deployment microbot --image=dontrebootme/microbot:v1
deployment.apps/microbot created
get all
でデプロイできたことを確認します。
$ incus exec k8s0-vm -- microk8s kubectl get all
(...)
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 88m
デプロイした素の状態だと外部からサービスへアクセスできません。外部からロードバランサを介してサービスへアクセスできるようにLoadBalancer
タイプでmicrobotサービスをexposeします。
$ incus exec k8s0-vm -- microk8s kubectl expose deployment microbot --type=LoadBalancer --port=80 --name=microbot-service
service/microbot-service exposed
get all
でmicrobotサービスの状態を確認します。
- TYPE: LoadBalancer
- EXTERNAL-IP: metallbが割り当てたIPアドレス (表示例: 10.57.140.201)
- PORT(S): 内部ポート:外部ポート/TCP (表示例: 80:30740/TCP)
incus exec k8s0-vm -- microk8s kubectl get all
(...)
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/microbot-service LoadBalancer 10.152.183.246 10.57.140.201 80:30740/TCP 15s
設定は以上です。
クライアントPCのWebブラウザからmicrobotにアクセスしてみましょう。
- アクセスURL:
http://10.57.140.201/
以下のような画像とhostnameが表示されれば成功です。
Webブラウザからに限らず、CLIのcurl
コマンドからでもmicrobotにアクセスできます。
$ curl 10.57.140.201:80
<!DOCTYPE html>
<html>
<style type="text/css">
.centered
{
text-align:center;
margin-top:0px;
margin-bottom:0px;
padding:0px;
}
</style>
<body>
<p class="centered"><img src="microbot.png" alt="microbot"/></p>
<p class="centered">Container hostname: microbot-7d987d6fc6-8m2xz</p>
</body>
</html>
なお、microbotサービスが実際にどのVMノード上で動いているかmicrok8sのコマンドで確認することもできます。(表示例: k8s3-vm上で動作している)
incus exec k8s0-vm -- microk8s kubectl describe pod microbot | grep Node:
Node: k8s3-vm/10.57.140.147
構築編は以上です。
The next document:
Incus VMでMicroK8sクラスタを組んでみた (2of2) 検証編
Discussion