はじめに (対象読者・この記事でわかること)
この記事は、ローカル開発環境に 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.sh と worker.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
Bashsudo 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 の設定(マスタだけ)
Bashmkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
ステップ 3:ネットワークプラグイン(Flannel)のデプロイ
Bashkubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
この時点で kubectl get nodes が Ready になるまで数十秒待ちます。
ステップ 4:ワーカーノードの参加
ワーカーノードに ssh し、kubeadm join コマンドを実行します(vagrant ssh worker1、vagrant ssh worker2)。例:
Bashsudo 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 -a と sed -i '/ swap / s/^/#/' /etc/fstab を再実行し、再起動後に free -h で swap が 0 であることを確認 |
| Failed to load cgroup driver: cgroupfs | カーネルが cgroupfs をサポートしない古いバージョン |
Ubuntu 22.04 ではデフォルトで systemd が推奨。/etc/default/kubelet に KUBELET_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 を実行 |
エラー解決のベストプラクティス
- ログの取得:
journalctl -u kubelet -fでリアルタイムにエラーログを確認。 - cgroup の統一:Docker と kubelet の cgroup driver を必ず
systemdに揃える。 - swap の永続化無効化:
/etc/fstabでコメントアウトし、再起動後も有効にする。 - ネットワーク設定の再読み込み:
sysctl --systemを忘れずに実行。
まとめ
本記事では、Vagrant 上の Linux VM でマルチノード Kubernetes クラスターを構築する際に遭遇しやすいエラーと、その具体的な対処方法 を解説しました。
- Vagrantfile とプロビジョニングスクリプトで環境を統一し、Docker の cgroup driver を
systemdに設定。 - swap を完全に無効化し、Kubernetes の前提条件を満たす。
- kubeadm init / join 手順を明示し、Flannel によるネットワークプラグイン導入を実演。
- 代表的なエラー(cgroup 不一致、swap 有効、ネットワーク未設定)に対し、ログ確認と設定変更の手順を示した。
これらを踏むことで、ローカル環境でも本番に近いマルチノード K8s クラスターを安定して起動でき、学習・開発・CI の高速なサイクルが実現します。次回は、Ingress コントローラの導入や、Helm を用いたアプリケーションデプロイまでの流れを紹介する予定です。
参考資料
- Kubernetes公式ドキュメント – kubeadmインストールガイド
- Vagrant公式サイト – Getting Started
- Flannel公式リポジトリ – ネットワークプラグイン
- Docker公式 – cgroup driver の設定方法
- 「Kubernetes in Action」 – Marko Luksa (Manning Publications)
