1. はじめに
この記事は、前回公開した 「【第1回】ミニPCにKubernetes環境を構築するまで ~概要編~」 の続編です。
前回の記事では、Kubernetesの主要な機能やコンポーネントについて整理しました。
今回はそれを踏まえ、実際にミニPCに Kubernetes クラスターを構築していきます。
📘 まだご覧になっていない方は、こちらから:
👉 【第1回】ミニPCにKubernetes環境を構築するまで ~概要編~
2. 構成概要・事前準備
この章では、今回構築する Kubernetes クラスターの構成イメージと、事前に行っておくべき準備について紹介します。
🔧 2.1 構築する環境の概要
今回構築する Kubernetes クラスターは、以下のようなミニマルな構成を採用しています。
項目 | 内容 |
---|---|
ノード数 | 1台構成(単一のミニPCでコントロールプレーン兼ワーカー) |
OS | Ubuntu 22.04 LTS |
Kubernetesのインストール方法 | kubeadm |
CNIプラグイン | Calico |
コンテナランタイム | containerd |
1台構成の Kubernetes クラスターのイメージ図は以下になります。
この図では、各コンポーネントを役割ごとに色分けしています。
- 🟨 黄色:コントロールプレーン(制御プレーン)に属するコンポーネント
- 🟥 赤色:全ノード共通のコンポーネント
- 🟦 青色:CNI プラグイン(Calico)
本来、コントロールプレーンとワーカーノードは複数のマシンに分かれて構成されるのが一般的ですが、今回は学習目的のため、1 台のミニPCに両方の役割を担わせています。
このような最小構成でも Kubernetes の仕組みを十分に体験・学習することができます。
まずはこの構成で動作を確認し、慣れてきたら複数ノード構成への拡張を検討するのも良いかと思います!
🖥 2.2 使用するミニPCについて
構築に使用するのは、以下のようなスペックのミニPCです(筆者環境)。
- 製品名: Beelink MINI-S12 Pro
- CPU: 4コア
- メモリ: 16GB
- ストレージ: 512GB SSD
- OS: Ubuntu 22.04 LTS
このようなスペックがあれば、Kubernetes のシングルノード構築や簡単なアプリケーションのデプロイにも十分対応可能です。
📥 2.3 事前に行った準備(Ubuntu インストール)
OSとして使用する Ubuntu 22.04 LTS は、あらかじめミニPCにインストールしておきました。
インストール手順や初期設定(SSH 有効化など)については、以下の記事で詳しく紹介しています。
💻 Ubuntuインストール手順はこちら
👉 ミニPCにUbuntu 22.04をインストール
まだ OS の準備ができていない方は、先に上記記事をご参照ください。
📦 2.4 今回使用するソフトウェアとバージョン
ソフトウェア | バージョン | 備考 |
---|---|---|
Ubuntu | 22.04 LTS | 事前にミニPCにインストールしておく |
Kubernetes | 1.30.11 | kubeadm で構築。最新の安定版を使用(執筆時点) |
containerd | 1.7.27 | Kubernetes のコンテナランタイム |
kubeadm / kubelet / kubectl | 1.30.11 | Kubernetes コンポーネント |
Calico (CNI Plugin) | 3.27.0 | Pod 間通信のための CNI プラグインとして使用 |
バージョンは執筆時点のものですので、今後の変更に合わせて適宜読み替えてください。
🔑 2.5 作業前の前提
このあと構築作業に入りますが、以下の前提条件を満たしていることを確認してください。
- Ubuntu がインストールされ、SSH 接続が可能である
- sudo 権限のあるユーザーで作業する
- インターネットに接続できる状態である
次章では、いよいよ Kubernetes のインストールに取りかかっていきます!
3. Kubernetes インストール手順
3.1 Ubuntu のパッケージを最新化
まずは、システムのパッケージを最新の状態にしておきます。
古いパッケージはセキュリティ面での脆弱性がある可能性があるため、パッケージを最新化することは大切です。
sudo apt update && sudo apt upgrade -y
3.2 SWAP無効化
下記の Kubernetes 公式ドキュメントにも記載されている通り、SWAP が有効化されていると kubelet が正常に動作しない可能性があります。
👉 https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
そのため、Kubernetes を構築する際は SWAP を必ず無効化する必要があります。
また、SWAP 領域はディスク上に存在するため、物理メモリに比べて非常に低速です。
SWAP が使用されるとディスク I/O が増加し、システム全体のパフォーマンス低下の原因となる可能性もあります。
以下のコマンドで SWAP を無効化できます。
-
swapoff -a
コマンドで SWAP 領域を無効化します -
/etc/fstab
に定義された SWAP の自動マウント設定をコメントアウトし、再起動後も有効化されないようにします
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
3.3 カーネル設定
Kubernetes ではネットワーク通信を正しく行うために、以下のカーネルモジュールやネットワーク設定が必要です。
特に、br_netfilter
モジュールとカーネルパラメーターの設定により、ブリッジ接続されたインターフェース間の通信(Pod 間の通信など)に対しても iptables
のルールが適用されるようになります。
Kubernetes はネットワーク制御に iptables
を活用しているため、これらの設定が欠けていると、Pod 間通信が正しく機能しなくなる可能性があります。
3.3.1 必要なカーネルモジュールのロード
以下のコマンドで、overlay
および br_netfilter
モジュールを読み込みます。
sudo modprobe overlay
sudo modprobe br_netfilter
起動時に自動でロードされるよう、設定ファイルを作成します。
sudo tee /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF
3.3.2 カーネルパラメーターの設定
次の設定を行うことで、ブリッジ接続を経由するトラフィックにも iptables
のルールが適用され、また IP 転送(ルーティング)も有効になります。
sudo tee /etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
設定を反映します。
sudo sysctl --system
3.4 containerd インストール
次に、コンテナランタイムである containerd のインストールを行います。
3.4.1 依存パッケージのインストール
以下のコマンドを実行し、containerd のインストールに必要なパッケージを準備します。
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates
3.4.2 Docker リポジトリの登録
containerd は Docker の APT リポジトリで提供されています。
- Ubuntu 22.04(コードネーム: jammy)の containerd.io パッケージは以下に存在します。
https://download.docker.com/linux/ubuntu/dists/jammy/pool/stable/amd64/
以下のコマンドを実行し、Docker のリポジトリを登録します。
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
3.4.3 containerd のインストール
パッケージリストを更新し、containerd パッケージをインストールします。
sudo apt update
sudo apt install -y containerd.io
3.4.4 containerd の設定変更
Kubernetes では、CPU・メモリなどのリソース制御に Linux の cgroup
を使用します。
Ubuntu のように init システムが systemd
の場合は、cgroup
の制御方式(cgroup
ドライバー)にも systemd
を使うことが推奨されています。
そのため、containerd 側でも以下のように SystemdCgroup = true
に設定変更を行います。
containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml
containerd デーモンを再起動し、設定変更を反映します。
また、containerd デーモンを自動起動する設定を行います。
sudo systemctl restart containerd
sudo systemctl enable containerd
cgroup とは
cgroup
(Control Group) は、プロセス単位で CPU・メモリなどのリソースを制御する Linux の機能です。
Kubernetes のノードでは、以下2種類の cgroup
ドライバーのどちらかを使ってリソース管理を行います。
cgroupfs
systemd
Ubuntu などの systemd
ベースのシステムでは、systemd
が cgroup
マネージャーとして動作します。
この環境において、cgroupfs
を使うと、2つの cgroup
マネージャーが動作することになり、これがノードを動かすうえでよろしくない場合があります。
例えば、kubelet
やコンテナランタイムで cgroupfs
を、残りのプロセスに systemd
を使用するようにノードが設定されていると、高負荷時に不安定になることがあります。
Kubernetes 公式ドキュメントでも、systemd
が init システムとして動作している場合は SystemdCgroup = true
に設定することが推奨されています。
参考:
https://kubernetes.io/ja/docs/setup/production-environment/container-runtimes/#containerd-systemd
3.5 Kubernetes APT リポジトリの追加
Ubuntu 22.04 には、デフォルトで Kubernetes 関連の APT パッケージ(kubeadm
・kubelet
・kubectl
など)を提供するリポジトリが登録されていません。
そのため、以下のコマンドを実行して Kubernetes 公式の APT リポジトリを追加します。
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
補足:リポジトリの仕様変更について
以前は apt.kubernetes.io
から配布されていましたが、2024年3月以降は 新しいリポジトリ pkgs.k8s.io
に移行されています。
3.6 kubelet、kubectl、kubeadm のインストール
先ほど追加した APT リポジトリを使って、以下の Kubernetes パッケージをインストールします。
-
kubelet
: Kubernetes クラスターのコンポーネントの 1 つで、各ノードで Pod の起動・管理を行うエージェント -
kubeadm
: クラスターの構築・初期化・アップグレードなどを行うツール -
kubectl
: Kubernetes を操作するための CLI
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
# 自動アップグレードされないようにバージョンを固定
sudo apt-mark hold kubelet kubeadm kubectl
補足:kubeadm とは?
kubeadm
は Kubernetes クラスターの構築や初期化、アップグレードを簡単に行うための公式ツールです。
個別にコンポーネントを設定・起動するよりもはるかに手軽に、標準的なクラスター構成を立ち上げることができます。
補足:kubectl とは?
kubectl
は Kubernetes クラスターと対話するためのコマンドラインツールです。
Pod の作成・削除・ログ取得・設定変更など、あらゆる操作を Kubernetes API 経由で行うことができます。
3.7 Kubernetes の初期化
これまでの作業を経て、Kubernetes を構築する準備ができました。
kubeadm
コマンドを使って、Kubernetes クラスターの初期化を行います。
これにより、下図の赤枠部分が構築されます。

3.7.1 kubeadm による Kubernetes クラスターの初期化
以下のコマンドを実行し、Kubernetes クラスターの初期化を行います。
sudo kubeadm init
以下は上記コマンドの実行ログです。
kube-apiserver
や kube-controller-manager
等のコントロールプレーンのコンポーネントが動く Pod マニフェストが作成されたり、CoreDNS
や kube-proxy
が作成されていることが分かります。
user1@kubenode:~$ sudo kubeadm init
I0418 23:07:58.068217 2397 version.go:256] remote version is much newer: v1.32.3; falling back to: stable-1.30
[init] Using Kubernetes version: v1.30.11
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
W0418 23:07:58.650321 2397 checks.go:844] detected that the sandbox image "registry.k8s.io/pause:3.8" of the container runtime is inconsistent with that used by kubeadm.It is recommended to use "registry.k8s.io/pause:3.9" as the CRI sandbox image.
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubenode kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.3.17]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [kubenode localhost] and IPs [192.168.3.17 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [kubenode localhost] and IPs [192.168.3.17 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "super-admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests"
[kubelet-check] Waiting for a healthy kubelet at http://127.0.0.1:10248/healthz. This can take up to 4m0s
[kubelet-check] The kubelet is healthy after 502.208458ms
[api-check] Waiting for a healthy API server. This can take up to 4m0s
[api-check] The API server is healthy after 6.002051973s
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node kubenode as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node kubenode as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule]
[bootstrap-token] Using token: m3i4yj.yvlwrvpq5o4jpdll
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.3.17:6443 --token m3i4yj.yvlwrvpq5o4jpdll \
--discovery-token-ca-cert-hash sha256:e97391516c8f47e94867cfeee0329f8986a5b03a507cfbd4cf7046f7ef5887be
user1@kubenode:
↑のメッセージにも記載されていますが、初期化完了後、一般ユーザーで以下のコマンドを実行する必要があります。
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl
では、コマンドを実行する際、$HOME/.kube/config
ファイルを参照し、その情報を使って Kubernetes の API サーバーと通信します。
また、管理者権限で実行するのに必要な config ファイルは以下です。
/etc/kubernetes/admin.conf
コントロールプレーンにおいて、現在利用している OS ユーザーで管理者権限で kubectl
を実行できるようにするために、以下のコマンドを実行します。
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubeconfig ファイルとは?
Kubernetes API にアクセスするための認証・接続情報を記述した設定ファイルです。
デフォルトでは $HOME/.kube/config
に配置することで、kubectl
コマンドが自動で使用します。
3.7.2 ノードステータスの確認
Kubernetes クラスター初期化後、以下のコマンドでノードの状態を確認します。
kubectl get nodes
この時点では、ノードのステータスが「NotReady」となっているはずです。
これは、Pod 間通信を担うネットワーク機能(CNI)がまだ有効化されていないためです。
3.8 CNI プラグインのインストール
Kubernetes では、Pod 同士の通信を行うために、CNI(Container Network Interface)プラグインが必要です。
今回は、代表的な CNI プラグインの 1 つである Calico を使用します。
以下のコマンドを実行し、Calico をインストールします。
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml
インストールが完了すると、Calico によって Pod 間のネットワークが構成され、ノードのステータスが「Ready」に変わります。
kubectl get nodes
ノードが「Ready」となっていれば、Kubernetes クラスターの基盤が正常に稼働し始めたことを意味します。
補足:CNI プラグインとは
CNI(Container Network Interface)は、コンテナにネットワーク機能を付与するための仕様です。
Calico の他に Flannel、Cilium など複数の実装がありますが、いずれも Pod に IP アドレスを割り当て、ネットワーク通信を可能にします。
3.9 コントロールプレーンノードの Taints 削除
コントロールプレーンノードは、デフォルトでは Pod(コントロールプレーンのコンポーネントの Pod を除く) をスケジューリングできないようになっています。
これは、コントロールプレーンノードはあくまで Kubernetes クラスター全体を管理する役割を担っており、本来ワークロード Pod を動かすのはワーカーノードの役割だからです。
今回の Kubernetes クラスターは 1 台構成であり、このノードはコントロールプレーン兼ワーカーノードとなり、このノードにワークロード Pod を配置するので、以下のコマンドを実行して、ノードにこれらの Pod を配置できるようにします。
ノードから node-role.kubernetes.io/control-plane
Taints を削除します。
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
補足:Taints/Tolerations とは
Taints (汚染) とは Kubernetes の機能の 1 つであり、特定のノードに特定の Pod を配置できないようにするための仕組みです。
例えば、このノードには本番環境用の Pod 以外は配置しない、といった制御をこの機能で行うことができます。
一方、Tolerations(許容)とは、Pod 側に設定するプロパティで、「この Pod は特定の Taints を持ったノードにもスケジュールされてよい」と明示的に許可するためのものです。
つまり、Taints があるノードに Pod をスケジュールするには、Pod 側に対応する Tolerations が設定されている必要があります。
たとえば、コントロールプレーンノードには node-role.kubernetes.io/control-plane:NoSchedule
という Taints がデフォルトで付与されており、通常の Pod はこれに Tolerations を持たないため、そのノードにスケジュールされません。
これは、重要なコントロールプレーンノードに誤ってワークロードを配置し、リソースを圧迫してしまうことを防ぐために、こうした仕組みを設けていると考えられます。
補足:node-role.kubernetes.io/control-plane とは
kubeadm
がコントロールプレーンノードに適用する Taints で、Pod の配置を制限し、特定の Pod のみにスケジュールを許可します。
この Taints が適用されていることで、コントロールプレーンノードではクリティカルなワークロードの Pod のみがスケジュールされるようになります( kube-apiserver
や kube-scheduler
等の Pod )。
補足:なぜコントロールプレーンノードでは kube-apiserver 等のコントロールプレーンを構成するコンポーネントの Pod を起動できるのか?
コントロールプレーンノードでは、上記の Taints が設定されているため、この Taints に対応する Tolerations を Pod に設定しない限り、このノードでは Pod を起動することはできません。
一方で、コントロールプレーンノードでは kube-apiserver
等のコントロールプレーンを構成するコンポーネントの Pod がいくつか起動しています。
これらの Pod の YAML には Tolerations が設定されておらず、Taints の仕組みだけを考えると、本来は起動できないのでは?と疑問に思う方もいるかもしれません。
これはどういうことかというと、これらの Pod は Static Pod だからです。
Static Pod は、kube-scheduler
を介さず kubelet
が直接管理・起動するため、Kubernetes API によるスケジューリング制御(Taints/Tolerations を含む)を受けない特殊な Pod です。
Taints はあくまでスケジューリング時に考慮されるものであり、Static Pod は kube-scheduler
を経由せず、kubelet
自身が起動するので、Taints/Tolerations の仕組みの影響を受けません。
これらの Pod の YAML は以下のディレクトリに存在しますが、kubelet
ではこのパスにある Pod を Static Pod として起動させます。
/etc/kubernetes/manifests
ちなみに、コントロールプレーンノード上の kubelet
の構成設定ファイルは以下になります。
/var/lib/kubelet/config.yaml
このファイル内の staticPodPath
が Static Pod の YAML 配置先ディレクトリを指しており、コントロールプレーンで起動する kubelet
では /etc/kubernetes/manifests
が指定されています。
この設定により、上記ディレクトリにある Pod はすべて Static Pod として自動的に起動されます。
staticPodPath: /etc/kubernetes/manifests
4. サンプル Pod の起動
Kubernetes の構築はこれで完了です。
試しに、Nginx コンテナを Pod として起動し、クラスターが正しく動作しているか確認してみます。
kubectl run nginx --image=nginx --port=80
Pod が正常に作成されたかどうか、以下のコマンドでステータスを確認します。
kubectl get pods
Pod のステータスが「Running」となっていれば、Kubernetes クラスターは正常に動作しています 🎉
5. おわりに
ミニPCで Kubernetes を構築することで、手元で自由に試せる学習環境が手に入りました。
今後はこの環境を使って、アプリケーションのデプロイや監視、CI/CD の検証などにも挑戦していきます!
参考資料