【おうち k8s クラスタ】 Kubernetes クラスタ構築編 (containerd + flannel)

「Kubernetes」をUbuntu上にセットアップしました。
物理サーバー2台を用意して、マスターノード1台とワーカーノード1台の構成です。それぞれのサーバーには Ubuntu Server をインストールしました。

CRI (Container Runtime Interface) としては Containerd (※) を採用しました。
また、CNI (Container Networking Interface) として flannel を採用しました。
※CRIとしての Docker は、Kubernetes 1.20 から非奨励となっています。そこで「containerd」か「CRI-O」で迷いましたが、文献が多そうな「containerd」を選択しました。

目次

構築環境

サーバーとして物理サーバー2台を用意して、Ubuntu Server 20.04 をセットアップしています。
Kubernetes のインストール作業は、Kubernetes 公式ページの手順に従って行いました。

Kubernetes クラスター構築にあたって使用した各コンポーネントのバージョンは以下の通りです。

OS / パッケージバージョン役割
Ubuntu20.04.3OS
Kubernetes1.22.4Kubernetes (kubeadm / kubectl / kubelet …)
containerd1.4.12CRI
flannel0.15.1CNI
etcd3.5.0Key-Value ストア
各コンポーネントのバージョン情報

Ubuntu のインストール方法は以下の記事に記載しています。

Kubernetes 公式サイトにより詳細で様々な環境に適用できるインストール手順が記載されています。

前準備

マスター ワーカー の両方で実施

Kubernetes を構築する前の準備として、以下の設定を行ってください。

Swap 機能を OFF にする

Kubernetes のシステム要件として、「Swap 機能が オフ であること。」と書いてあります。

Swapがオフであること。kubeletが正常に動作するためにはswapは必ずオフでなければなりません。

https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

これに従って、Swap を利用しないように設定します。

swapoff -a

top コマンドで、Swap領域の容量が 0 になっていることを確認します。

top
top - 07:31:50 up 3 days, 12:31,  1 user,  load average: 3.54, 4.90, 6.14
Tasks: 304 total,   2 running, 301 sleeping,   0 stopped,   1 zombie
%Cpu(s): 35.1 us,  5.7 sy,  0.0 ni, 54.9 id,  1.6 wa,  0.0 hi,  2.7 si,  0.0 st
MiB Mem :   7840.5 total,    455.5 free,   3843.9 used,   3541.1 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.   3664.8 avail Mem

さらに、サーバー再起動をするとSwap領域が復活してしまうので、 /etc/fstabのSwap領域の確保に関する行をコメントアウトします。

vi /etc/fstab
# /swap.img     none    swap    sw      0       0

ホスト名で名前解決できるようにする

ノード間で通信できるように、ホスト名で名前解決できるようにしておく必要があります。内部DNSサーバにレコードを追加することでも対応できますが、ここでは /etc/hostsで設定することにします。

vi /etc/hosts

末尾2行を追加しました。

127.0.0.1 localhost
127.0.1.1 4mo-sv10

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

# Settings for Kubernetes
192.168.180.10 4mo-sv10
192.168.180.30 4mo-sv30

CRI (Containerd) のインストール

マスター ワーカー の両方で実施

公式サイトに記載の手順に従って、 Containerd をインストールしていきます。

Containerd に必要な設定の追加

カーネルモジュール overlay br_netfilterを読み込むように設定します。この設定は再起動後も永続化されます。

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

カーネルモジュール overlay br_netfilterを読み込みます。

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 のインストール

(公式サイトの手順をそのまま抜粋)

# (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

Containerd の起動確認

systemctl status containerd
● containerd.service - containerd container runtime
     Loaded: loaded (/lib/systemd/system/containerd.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2021-12-07 19:02:15 UTC; 4 days ago
       Docs: https://containerd.io
   Main PID: 782 (containerd)
      Tasks: 1482
     Memory: 5.4G
     CGroup: /system.slice/containerd.service
             ├─    782 /usr/bin/containerd

Kubernetes のインストール

マスター ワーカー の両方で実施

公式サイトに記載の手順に従って、 kubeadm / kubelet / kubectl をインストールします。

Kubernetes インストールで必要なパッケージのインストールを行います。

apt-get update && apt-get install -y apt-transport-https curl

GoogleのGPGキーを取得して、登録します。

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -

Kubernetes のリポジトリを追加します。

cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF

Kubernetesのパッケージkubelet kubeadm kubectl をインストールします。

apt-get update && apt-get install -y kubelet kubeadm kubectl

Kubernetes のアップデートには特別な手順が必要となります。
アップグレード (apt upgrade) によって意図せず Kubernetes パッケージが更新されてしまうことを防ぐため、パッケージの更新対象からKubernetesパッケージを除きます。

sudo apt-mark hold kubelet kubeadm kubectl

マスターノードのセットアップ

マスター のみで実施

公式の手順に従って、マスターノードのセットアップを行います。

マスターノードの初期化

マスターノードの初期化を行います。
マスターノード を初期化するには kubeadm init <args>コマンドを実行します。

公式サイトの以下の注意に従って、オプションを設定することにします。

  1. (推奨)シングルコントロールプレーンのkubeadmクラスターを高可用性クラスターにアップグレードする予定がある場合、--control-plane-endpointを指定して、すべてのコントロールプレーンノードとエンドポイントを共有する必要があります。エンドポイントにはDNSネームやロードバランサーのIPアドレスが使用できます。
  2. Podネットワークアドオンを選んで、kubeadm initに引数を渡す必要があるかどうか確認してください。選んだサードパーティーのプロバイダーによっては、--pod-network-cidrをプロバイダー固有の値に設定する必要がある場合があります。詳しくは、Podネットワークアドオンのインストールを参照してください。
  • --control-plane-endpoint
    将来的にHAクラスター(高可用性クラスター)を構築する可能性に備えてコントロールプレーンのローカルIPを指定します。
  • --pod-network-cidr
    CNI (Podネットワークアドオン) として flannel を採用するため、flannel のデフォルトのCIDRを指定します。
kubeadm init --control-plane-endpoint=192.168.180.1:6443 --pod-network-cidr=10.244.0.0/16

しばらく待っていると以下のインストール完了メッセージが表示されます。

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

You should now deploy a Pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  /docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:

  kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>

この一番最後に表示されている kubeadm join コマンドが重要です。この後の手順でワーカーノード(やコントロールプレーンノード)を追加する際に利用します。

<token>discovery-token-ca-cert-hashを無くしたとしても再発行できますが、どこかに保存しておいたほうが今後の作業がスムーズに進みます。※再発行の手順はトラブルシューティングとして後述します。

Kubernetes操作環境の設定

kubectl (Kubernetesを操作するコマンド)を一般ユーザで実行できるようにするには、対象の一般ユーザーで以下のコマンドを実行します。

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

一般ユーザーではなく管理者ユーザーで kubectl を実行する場合には、以下のコマンドを実行します。

export KUBECONFIG=/etc/kubernetes/admin.conf
source ~/.bashrc

flannel (CNI/Podネットワークアドオン) のインストール

以下のコマンドで最新の flannel をインストールします。

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

セットアップ後の確認

kubectl get nodeコマンドでノードの状態を確認します。

kubectl get node

STATUSが Readyになっていればマスターノードのセットアップに成功しています。

NAME       STATUS   ROLES                  AGE     VERSION
4mo-sv10   Ready    control-plane,master   7d11h   v1.22.4

ワーカーノードのセットアップ

ワーカー のみで実施

続いて、ワーカーノードを追加していきます。

ワーカーノードのセットアップ

マスターノードのセットアップ時に出力された kubeadm joinコマンドを実行します。

kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>

ノード追加完了のメッセージが表示されれば、ワーカーノードのセットアップに成功しています。

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

セットアップの確認

kubectl get nodeコマンドでノードの状態を確認します。

kubectl get node

STATUSが Readyになっていれば正常です。

NAME       STATUS   ROLES                  AGE     VERSION
4mo-sv10    Ready    control-plane,master   7d11h   v1.22.4
4mo-sv30    Ready    <none>                 7d11h   v1.22.4

Pod の状態を kubectl get pod -Aコマンドで確認します。

kubectl get pod -A

namespace: kube-system で以下のPodのSTATUSが Runningとなっていれば正常です。

NAMESPACE          NAME                                                     READY   STATUS      RESTARTS          AGE
kube-system        coredns-78fcd69978-4lcjv                                 1/1     Running     4 (4d1h ago)      7d11h
kube-system        coredns-78fcd69978-q5kfj                                 1/1     Running     4 (4d1h ago)      7d11h
kube-system        etcd-4mo-sv10                                            1/1     Running     20 (4d1h ago)     7d11h
kube-system        kube-apiserver-4mo-sv10                                  1/1     Running     20 (4d1h ago)     7d11h
kube-system        kube-controller-manager-4mo-sv10                         1/1     Running     21 (2d2h ago)     7d11h
kube-system        kube-flannel-ds-pg7qf                                    1/1     Running     5 (4d1h ago)      7d11h
kube-system        kube-flannel-ds-wv9bp                                    1/1     Running     6 (37h ago)       7d11h
kube-system        kube-proxy-8xhhw                                         1/1     Running     6 (37h ago)       7d11h
kube-system        kube-proxy-9w4vc                                         1/1     Running     4 (4d1h ago)      7d11h
kube-system        kube-scheduler-4mo-sv10                                  1/1     Running     21 (2d2h ago)     7d11h

トラブルシューティング

Kubernetes のセットアップを最初からやり直したい

一度Kubernetesクラスターをリセットしてから、もう一度Kubernetesのセットアップを行いたい場合は、ワーカーノードとマスターノードの両方でkubectl resetコマンドを実行します。

kubeadm reset
[reset] WARNING: changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted.
[reset] are you sure you want to proceed? [y/N]: y
[preflight] running pre-flight checks
[reset] no etcd config found. Assuming external etcd
[reset] please manually reset etcd to prevent further issues
[reset] stopping the kubelet service
[reset] unmounting mounted directories in "/var/lib/kubelet"
[reset] deleting contents of stateful directories: [/var/lib/kubelet /etc/cni/net.d /var/lib/dockershim /var/run/kubernetes]
[reset] deleting contents of config directories: [/etc/kubernetes/manifests /etc/kubernetes/pki]
[reset] deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf]

The reset process does not reset or clean up iptables rules or IPVS tables.
If you wish to reset iptables, you must do so manually.
For example:
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X

If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar)
to reset your system's IPVS tables.


Kubernetes クラスターのリセットが完了したら、再度 Kubernetes のセットアップ を行います。

ノード追加コマンドの token や discovery-token-ca-cert-hash を忘れた

token の確認

トークンが分からない場合は、コントロールプレーンノードで kubeadm token listコマンドを実行します。

kubeadm token list

発行済のトークンが表示されます。(表示されない場合は次を確認してください。)

TOKEN                     TTL         EXPIRES                USAGES                   DESCRIPTION
                         EXTRA GROUPS
jat85g.mtrah2hjdarj9lrk   23h         2021-12-12T20:52:06Z   authentication,signing   <none>

トークンの有効期限はデフォルトでは24時間です。有効期限が切れた後にクラスターにノードを参加させたい場合は、コントロールプレーンノードでkubeadm token createコマンドを実行してトークンを生成します。

kubeadm token create

トークンが表示されます。

5didvk.d09sbcov8ph2amjw

discovery-token-ca-cert-hash の再生成

--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/^.* //'

ハッシュを取得できます。

8cb2de97839780a412b93877f8507ad6c94f73add17d5d7058e91741c9d5ec78

最後に

これでおうちKubernetesクラスターが完成しましたが、まだ使い勝手の良くありません。

  • 永続化ボリュームが自動で作成されない
  • Service で LoadBalancer が使えない
  • Ingress が使えない

パブリッククラウドであればクラウドが管理してくれて簡単に利用できるストレージがあったり、マネージドサービスのロードバランサーを使えたりしますが、おうち Kubernetes クラスターではそうもいきません。

また、おうち Kubernetes クラスターに限った話ではありませんが、プロダクション環境の運用には監視基盤も欲しいところです。

そこで、次回以降の記事では おうちKubernetes をより便利にするための構築手順を紹介していきます。

この記事が気に入ったら
いいね または フォローしてね!

よかったらシェアしてね!
目次
閉じる