Vagrant と kubeadm で Kubernetes クラスターをつくる

勉強用の Kubernetes クラスターを kubeadm でつくりました。ローカル PC 上に Vagrant で仮想マシンを起動して、ノードとして利用します。

単にコンテナーのデプロイを試したいだけであれば、Docker DesktopKind を利用するのが早いと思いますが、Kubernetes コンポーネントの設定もふくめて色々触りながら勉強したかったので、VM を用意してクラスターをつくることにしました。

環境

  • macOS Monterey version 12.2.1

Vagrant で Ubuntu の VM を起動する

Vagrant は Homebrew を使ってインストールできます。

brew install vagrant

Vagrantfile を記述していきます。

Ubuntu 20.04 の Box を利用して、まずは 2 ノード分の VM 定義を用意しました。

プロビジョニング用のシェル スクリプトを使って Swap を無効化しています。

Vagrant.configure("2") do |config|
  config.vm.box = "generic/ubuntu2004"

  config.vm.define "node01" do |server|
    server.vm.hostname = "node01"
    server.vm.network "private_network", ip: "192.168.56.10"
  end

  config.vm.define "node02" do |server|
    server.vm.hostname = "node02"
    server.vm.network "private_network", ip: "192.168.56.11"
  end

  config.vm.provision "shell", inline: <<-SHELL
    # Disable swap
    swapoff -a
    sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
    sed -i '/ swap / s/^\\(.*\\)$/#\\1/g' /etc/fstab
  SHELL
end

あとは vagrant up コマンドを実行するだけ。 vagrant ssh で各 VM に SSH できる。 これで VM の用意は完了。

vagrant up
vagrant ssh node01
vagrant ssh node02

kubeadm のインストール

VM が用意できたら Kubernetes ドキュメントに従って kubeadm やクラスター コンポーネントのインストールをすすめていきます。 用意した各 VM に対してインストールします。

kubeadmのインストール | Kubernetes

このページではkubeadmコマンドをインストールする方法を示します。このインストール処理実行後にkubeadmを使用してクラスターを作成する方法については、kubeadmを使用したシングルマスタークラスターの作成を参照してください。 始める前に 次のいずれかが動作しているマシンが必要です Ubuntu 16.04+ Debian 9+ CentOS 7 Red Hat Enterprise Linux (RHEL) 7 Fedora 25+ HypriotOS v1.0.1+ Container Linux (tested with 1800.6.0) 1台あたり2GB以上のメモリ(2GBの場合、アプリ用のスペースはほとんどありません) 2コア以上のCPU クラスター内のすべてのマシン間で通信可能なネットワーク(パブリックネットワークでもプライベートネットワークでも構いません) ユニークなhostname、MACアドレス、とproduct_uuidが各ノードに必要です。詳細はここを参照してください。 マシン内の特定のポートが開いていること。詳細はここを参照してください。 Swapがオフであること。kubeletが正常に動作するためにはswapは必ずオフでなければなりません。 MACアドレスとproduct_uuidが全てのノードでユニークであることの検証 ネットワークインターフェースのMACアドレスはip linkもしくはifconfig -aコマンドで取得できます。 product_uuidはsudo cat /sys/class/dmi/id/product_uuidコマンドで確認できます。 ハードウェアデバイスではユニークなアドレスが割り当てられる可能性が非常に高いですが、VMでは同じになることがあります。Kubernetesはこれらの値を使用して、クラスター内のノードを一意に識別します。これらの値が各ノードに固有ではない場合、インストール処理が失敗することもあります。 ネットワークアダプタの確認 複数のネットワークアダプターがあり、Kubernetesコンポーネントにデフォルトで到達できない場合、IPルートを追加して、Kubernetesクラスターのアドレスが適切なアダプターを経由するように設定することをお勧めします。 iptablesがブリッジを通過するトラフィックを処理できるようにする Linuxノードのiptablesがブリッジを通過するトラフィックを正確に処理する要件として、net.bridge.bridge-nf-call-iptablesをsysctlの設定ファイルで1に設定してください。例えば以下のようにします。 cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl --system この手順の前にbr_netfilterモジュールがロードされていることを確認してください。lsmod | grep br_netfilterを実行することで確認できます。明示的にロードするにはmodprobe br_netfilterを実行してください。 詳細はネットワークプラグインの要件を参照してください。 iptablesがnftablesバックエンドを使用しないようにする Linuxでは、カーネルのiptablesサブシステムの最新の代替品としてnftablesが利用できます。iptablesツールは互換性レイヤーとして機能し、iptablesのように動作しますが、実際にはnftablesを設定します。このnftablesバックエンドは現在のkubeadmパッケージと互換性がありません。(ファイアウォールルールが重複し、kube-proxyを破壊するためです。)

iptablesがブリッジを通過するトラフィックを処理できるようにする

sudo su -

cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

iptablesがnftablesバックエンドを使用しないようにする

# レガシーバイナリがインストールされていることを確認してください
sudo apt-get install -y iptables arptables ebtables

# レガシーバージョンに切り替えてください。
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo update-alternatives --set arptables /usr/sbin/arptables-legacy
sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy

ランタイムのインストール

ここでは containerd を利用します。

必要な設定の追加

sudo su -

cat > /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF

modprobe overlay
modprobe br_netfilter

# 必要なカーネルパラメータの設定をします。これらの設定値は再起動後も永続化されます。
cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sysctl --system

containerdのインストール

sudo su -

# (containerdのインストール)
## リポジトリの設定
### HTTPS越しのリポジトリの使用をaptに許可するために、パッケージをインストール
apt-get update && apt-get install -y apt-transport-https ca-certificates curl software-properties-common

## Docker公式のGPG鍵を追加
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -

## Dockerのaptリポジトリの追加
add-apt-repository \
    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) \
    stable"

## containerdのインストール
apt-get update && apt-get install -y containerd.io

# containerdの設定
mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

# containerdの再起動
systemctl restart containerd

kubeadm、kubelet、kubectlのインストール

sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s 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

コントロールプレーンノードのkubeletによって使用されるcgroupドライバーの設定

ワーカーノードの IP アドレスの指定を KUBELET_EXTRA_ARGS であわせて行います。 参考: Playing with kubeadm in Vagrant Machines, Part 2

cat << EOF | sudo tee /etc/default/kubelet
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd --node-ip=<worker IP address (ex: 192.168.56.10)>
EOF

sudo systemctl daemon-reload
sudo systemctl restart kubelet

コントロール プレーン ノードのセットアップ

node01 VM をコントローラー ノードとして、シングル コントロール プレーンのクラスターをセットアップします。

コントロールプレーンノードの初期化

kubeadm init コマンドを実行するだけで非常にかんたん。

sudo su -
kubeadm init \
  --pod-network-cidr 10.244.0.0/16 \
  --apiserver-advertise-address 192.168.56.10

初期化が完了したら kubeconfig ファイルをホーム ディレクトリ配下にコピーしておきます。

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

これで kubectl コマンドでクラスター操作ができるようになります。 この時点では、ネットワーク プラグインが未インストールのため、ノードは NotReady ステータスです。

% kubectl get nodes
NAME     STATUS     ROLES                  AGE   VERSION
node01   NotReady   control-plane,master   71s   v1.23.3

% kubectl describe node node01
  ...
Conditions:
  ...
  Ready            False   Mon, 07 Feb 2022 20:35:14 +0000   Mon, 07 Feb 2022 20:34:56 +0000   KubeletNotReady              container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized

Podネットワークアドオンのインストール

ここでは flannel をインストールしました。 https://github.com/flannel-io/flannel#getting-started-on-kubernetes

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

flannel のマニフェストの apply 後、ノードが Ready ステータスに変わることを確認します。

% kubectl get pods -A
NAMESPACE     NAME                             READY   STATUS    RESTARTS   AGE
kube-system   coredns-64897985d-4g6dm          1/1     Running   0          7m57s
kube-system   coredns-64897985d-c579n          1/1     Running   0          7m57s
kube-system   etcd-node01                      1/1     Running   1          8m5s
kube-system   kube-apiserver-node01            1/1     Running   1          8m5s
kube-system   kube-controller-manager-node01   1/1     Running   1          8m5s
kube-system   kube-flannel-ds-76tbb            1/1     Running   0          39s
kube-system   kube-proxy-nfk6r                 1/1     Running   0          7m57s
kube-system   kube-scheduler-node01            1/1     Running   1          8m5s

% kubectl get nodes
NAME     STATUS   ROLES                  AGE     VERSION
node01   Ready    control-plane,master   8m16s   v1.23.3

ノードの追加

2 ノード目以降では、kubeadm join コマンドを実行してクラスターにノードが追加できる。 kubeadm init の実行結果にトークンを含むコマンド例が表示されるので、そのコマンドをそのまま実行すればよい。

sudo su -
kubeadm join 192.168.56.10:6443 --token 1ubbqx.mad3qulm6jk77dvc \
  --discovery-token-ca-cert-hash sha256:a347de9fa17bc6cda79ff3fdcf9804fb6862fe14ad8a711fdb53cf16c6be6373

node02 が追加された。

% kubectl get nodes
NAME     STATUS   ROLES                  AGE   VERSION
node01   Ready    control-plane,master   15m   v1.23.3
node02   Ready    <none>                 49s   v1.23.3

kubeadm init の実行結果を控えておらず、kubeadm join に渡すトークンがわからないときにはどうすればよいか?

--token オプションに渡すトークンは、kubeadm token list コマンドで確認ができる。

% kubeadm token list
TOKEN                     TTL         EXPIRES                USAGES                   DESCRIPTION                                                EXTRA GROUPS
1ubbqx.mad3qulm6jk77dvc   23h         2022-02-08T20:35:01Z   authentication,signing   The default bootstrap token generated by 'kubeadm init'.   system:bootstrappers:kubeadm:default-node-token

トークンの有効期限が切れていて利用できない場合には、kubeadm token create コマンドで新しいトークンが作成できる。

% kubeadm token create
pl1f37.3rrw0sl7x5jk2kug

% kubeadm token list
TOKEN                     TTL         EXPIRES                USAGES                   DESCRIPTION                                                EXTRA GROUPS
1ubbqx.mad3qulm6jk77dvc   23h         2022-02-08T20:35:01Z   authentication,signing   The default bootstrap token generated by 'kubeadm init'.   system:bootstrappers:kubeadm:default-node-token
pl1f37.3rrw0sl7x5jk2kug   23h         2022-02-08T20:55:58Z   authentication,signing   <none>                                                     system:bootstrappers:kubeadm:default-node-token

--discovery-token-ca-cert-hash オプションの値は、以下コマンドで確認できる。

% openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
   openssl dgst -sha256 -hex | sed 's/^.* //'
a347de9fa17bc6cda79ff3fdcf9804fb6862fe14ad8a711fdb53cf16c6be6373

あとは kubeadm join コマンドに対して、コントロール プレーンのエンドポイントと一緒にトークンを渡せば、ノードの追加ができる。 --discovery-token-ca-cert-hash オプションの値には、先頭に sha256: をつける。

% kubeadm join 192.168.56.10:6443 \
  --token pl1f37.3rrw0sl7x5jk2kug \
  --discovery-token-ca-cert-hash sha256:a347de9fa17bc6cda79ff3fdcf9804fb6862fe14ad8a711fdb53cf16c6be6373

comments powered by Disqus