はじめに (対象読者・この記事でわかること)

この記事は、ローカル開発環境に Vagrant を導入し、Linux 上でマルチノードの Kubernetes クラスターを構築したいエンジニア・DevOps 初心者を対象としています。
- Vagrant の基本的な使い方と Vagrantfile の書き方が分かっている前提です。
- この記事を読むことで、以下が実現できるようになります。
1. Vagrant と VirtualBox(または libvirt)で 3 台以上の Linux VM を起動する方法。
2. kubeadm を用いたマスターノードとワーカーノードのセットアップ手順。
3. 「kubelet が起動しない」や「cgroup driver の不一致」など、典型的なエラーの原因と対処法。

本稿は、実務や学習で「ローカルで手軽に K8s を試したい」場面に直面した際に、時間を無駄にしないための実践ガイドです。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。
- Linux の基本操作(bash、ssh、root権限の取得)
- Vagrant のインストールと vagrant up/vagrant ssh が使えること
- Docker の基本概念と、docker run が動く環境が整っていること
- kubeadm/kubectl の概要と、Kubernetes の概念(Pod、Service、Control Plane)

背景と概要:Vagrant でマルチノード K8s を構築したい理由

Kubernetes は本番環境だけでなく、学習や CI のテスト環境でも広く利用されています。
しかし、クラウド上に環境を構築するとコストやネットワーク遅延が発生しやすく、ローカルで軽量に試す手段として Vagrant + VirtualBox (または libvirt) が人気です。

マルチノード構成をローカルで作る主な目的は次の通りです。

目的 具体的なメリット
1. 複数ノード間のネットワークや Service の動作確認 NodePort、LoadBalancer、Ingress の挙動をローカルで検証できる
2. RBAC や Namespace のテスト 本番と同等の権限設定をローカルで試せる
3. CI 用の自動テスト基盤構築 GitHub Actions などで Vagrant を立ち上げ、テストを自動化できる

ただし、Vagrant 環境はリソースが限られ、cgroup の設定や swap の有無 など、Kubernetes が要求する前提条件が満たされていないケースが多く、エラーに直面しやすい点が課題です。本セクションでは、代表的なエラー要因とその根本的な対策を概観します。

具体的な手順と実装方法

以下では、Ubuntu 22.04 ベースの 3 台構成(1 マスタ + 2 ワーカー)を例に、Vagrantfile の作成 → VM 起動 → kubeadm でクラスター構築 → エラー対策 の流れを詳しく解説します。

ステップ 1:Vagrantfile の作成

Ruby
# Vagrantfile VAGRANT_DEFAULT_PROVIDER = "virtualbox" VMS = { "master" => { :ip => "192.168.56.10", :cpu => 2, :mem => 2048 }, "worker1" => { :ip => "192.168.56.11", :cpu => 2, :mem => 2048 }, "worker2" => { :ip => "192.168.56.12", :cpu => 2, :mem => 2048 } } VMS.each do |name, cfg| config.vm.define name do |node| node.vm.box = "ubuntu/jammy64" node.vm.hostname = name node.vm.network "private_network", ip: cfg[:ip] node.vm.provider "virtualbox" do |vb| vb.name = "k8s-#{name}" vb.cpus = cfg[:cpu] vb.memory = cfg[:mem] end # 共有スクリプトで共通設定を実行 node.vm.provision "shell", path: "provision/common.sh" # マスタ用だけ追加プロビジョニング if name == "master" node.vm.provision "shell", path: "provision/master.sh" else node.vm.provision "shell", path: "provision/worker.sh" end end end

ポイント:
- private_network に固定 IP を割り当て、ノード間通信をシンプルに。
- CPU/Memory は最低 2 コア・2GB を確保。
- common.sh で Docker、swap 無効化、必要なカーネルモジュールをインストール。
- master.shworker.sh はそれぞれ kubeadm init/join 用のスクリプトを保持。

common.sh(抜粋)

Bash
#!/usr/bin/env bash set -e # 必要パッケージ apt-get update && apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release # Docker CE のインストール curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" apt-get update && apt-get install -y docker-ce docker-ce-cli containerd.io # Docker の cgroup driver を systemd に設定 cat > /etc/docker/daemon.json <<EOF { "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": {"max-size": "100m"}, "storage-driver": "overlay2" } EOF systemctl restart docker # swap 無効化(K8s の必須要件) swapoff -a sed -i '/ swap / s/^/#/' /etc/fstab # 必要なカーネルモジュール modprobe overlay modprobe br_netfilter cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-ip6tables = 1 EOF sysctl --system

ステップ 2:VM の起動と kubeadm のインストール

Bash
# Vagrant 起動 vagrant up # マスタノードにログイン vagrant ssh master # kubeadm、kubelet、kubectl のインストール(マスタ・ワーカー共通) curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl

マスタノードで kubeadm init

Bash
sudo kubeadm init --apiserver-advertise-address=192.168.56.10 \ --pod-network-cidr=10.244.0.0/16 \ --cri-socket /var/run/dockershim.sock
  • --pod-network-cidr は Flannel 用に指定。
  • 成功すれば kubeadm init の出力に kubeadm join コマンドが表示されます。

kubeconfig の設定(マスタだけ)

Bash
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config

ステップ 3:ネットワークプラグイン(Flannel)のデプロイ

Bash
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

この時点で kubectl get nodesReady になるまで数十秒待ちます。

ステップ 4:ワーカーノードの参加

ワーカーノードに ssh し、kubeadm join コマンドを実行します(vagrant ssh worker1vagrant ssh worker2)。例:

Bash
sudo kubeadm join 192.168.56.10:6443 --token <token> \ --discovery-token-ca-cert-hash sha256:<hash>

ハマった点やエラー解決

エラー 発生条件 解決策
**kubelet failed to start: failed to run Kubelet: misconfiguration: kubelet cgroup driver: "cgroupfs" is different from docker cgroup driver: "systemd" Docker の cgroup driver が systemd に設定されているが、kubelet がデフォルトで cgroupfs を使用 sudo sed -i 's/cgroup-driver: .*/cgroup-driver: systemd/' /var/lib/kubelet/config.yaml
その後 systemctl restart kubelet
swap is enabled swapoff -a が実行されていない、または /etc/fstab のエントリが残っている swapoff -ased -i '/ swap / s/^/#/' /etc/fstab を再実行し、再起動後に free -h で swap が 0 であることを確認
Failed to load cgroup driver: cgroupfs カーネルが cgroupfs をサポートしない古いバージョン Ubuntu 22.04 ではデフォルトで systemd が推奨。/etc/default/kubeletKUBELET_EXTRA_ARGS=--cgroup-driver=systemd を追記し、systemctl daemon-reload && systemctl restart kubelet
NodeNotReady: NetworkUnavailable ネットワークプラグイン(Flannel)が正しくデプロイされていない kubectl get pods -n kube-system で flannel の Pod が CrashLoopBackOff でないか確認し、kubectl logs <flannel-pod> でエラーメッセージを見る。/etc/sysctl.d/k8s.conf の設定が反映されていない場合は sysctl --system を再実行
Connection refused when running kubectl get nodes kube-apiserver が起動していない、もしくはファイアウォールがポート 6443 をブロック sudo systemctl status kube-apiserver で状態確認。ufw が有効なら sudo ufw allow 6443/tcp を実行

エラー解決のベストプラクティス

  1. ログの取得journalctl -u kubelet -f でリアルタイムにエラーログを確認。
  2. cgroup の統一:Docker と kubelet の cgroup driver を必ず systemd に揃える。
  3. swap の永続化無効化/etc/fstab でコメントアウトし、再起動後も有効にする。
  4. ネットワーク設定の再読み込みsysctl --system を忘れずに実行。

まとめ

本記事では、Vagrant 上の Linux VM でマルチノード Kubernetes クラスターを構築する際に遭遇しやすいエラーと、その具体的な対処方法 を解説しました。

  • Vagrantfile とプロビジョニングスクリプトで環境を統一し、Docker の cgroup driver を systemd に設定。
  • swap を完全に無効化し、Kubernetes の前提条件を満たす。
  • kubeadm init / join 手順を明示し、Flannel によるネットワークプラグイン導入を実演。
  • 代表的なエラー(cgroup 不一致、swap 有効、ネットワーク未設定)に対し、ログ確認と設定変更の手順を示した。

これらを踏むことで、ローカル環境でも本番に近いマルチノード K8s クラスターを安定して起動でき、学習・開発・CI の高速なサイクルが実現します。次回は、Ingress コントローラの導入や、Helm を用いたアプリケーションデプロイまでの流れを紹介する予定です。

参考資料