概要
Canned-Catfood Gamingを提供しているインフラ基盤は基本的にはコンテナベースで稼働しています。以前にも当ブログの記事にてクラスタの構築方法として、kubeadm + containerdによる環境構築方法を紹介していました。
検証用Kubernetesクラスタの作成 – Canned Catfood Gaming
今回開発環境を再構築するにあたり、前回構築時の2022年よりインストール方法に変更点が複数ありましたので改めて記事にしました。
kubeadmおよびcontainerdによるインストール方法については kubeadmを使ってクラスターを構築する | Kubernetes の公式のドキュメントでも記載されています。しかしながら、containerd周りのアップデートなどの影響により dockershimとして利用する際のパラメータ等に細かな修正点があるため、ドキュメントの記載内容を実行するのみでは正常にkube-api, etcd等のコンテナが起動しない状態となっていました。
注意点
- デプロイツールには kubeadm を使用しています。
- CRIにはcontainerdを使用しています。
- サービスメッシュのネットワークアドオンにはciliumを使用しています。
- 使用したkubernetesバージョンはv1.30.3です。
環境情報
各コンポーネントのバージョンは以下の通りです。
ソフトウェア | バージョン |
Ubuntu (server) | 24.04.3 LTS(Noble Numbat) |
Kubernetes (kubeadm, kubelet, kubectl) | v1.30.3 |
Containerd | version 1.7.19 |
Helm | Version: “v3.15.3” |
Cilium | version 1.16.0 |
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo
$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"30", GitVersion:"v1.30.3", GitCommit:"6fc0a69044f1ac4c13841ec4391224a2df241460", GitTreeState:"clean", BuildDate:"2024-07-16T23:53:15Z", GoVersion:"go1.22.5", Compiler:"gc", Platform:"linux/amd64"}
$ helm version
version.BuildInfo{Version:"v3.15.3", GitCommit:"3bb50bbbdd9c946ba9989fbe4fb4104766302a64", GitTreeState:"clean", GoVersion:"go1.22.5"}
$ containerd --version
containerd containerd.io 1.7.19 2bf793ef6dc9a18e00cb12efb64355c2c9d5eb41
またサーバには有効なネットワークアダプタが2つ、うち一つにIPv4アドレスが付与されてインターネットに対して疎通可能な状態、かつデフォルトルートが設定されています。(kubeadmでは特に指定しない場合、デフォルトルートが設定されているインターフェースが使用されます。)
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:15:5d:e6:e9:00 brd ff:ff:ff:ff:ff:ff
inet 192.168.150.1/24 brd 192.168.150.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::215:5dff:fee6:e900/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 00:15:5d:e6:e9:01 brd ff:ff:ff:ff:ff:ff
$ ip route
default via 192.168.150.254 dev eth0 proto static
構築手順
nftablesからレガシーiptablesへのモード切替え
前回から引き続いて、Linuxカーネルのiptablesサブシステムは、最近のバージョンではnftablesへの置換えが進んでいます。Ubuntuでも他のディストリと同様に、19.04以降ではnftablesが使用されています。nftablesはkubeadmと現状で非互換であるため、正常に動作させる為にレガシーなiptablesへ切り換えておきます。
切り替えに必要なパッケージを下記でインストールします。
$ sudo apt install -y iptables arptables ebtables
update-alternativesを利用して、各機能をlegacy iptablesに実際に切り替えていきます。
$ sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives: using /usr/sbin/iptables-legacy to provide /usr/sbin/iptables (iptables) in manual mode
$ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives: using /usr/sbin/ip6tables-legacy to provide /usr/sbin/ip6tables (ip6tables) in manual mode
$ sudo update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives: using /usr/sbin/arptables-legacy to provide /usr/sbin/arptables (arptables) in manual mode
$ sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy
update-alternatives: using /usr/sbin/ebtables-legacy to provide /usr/sbin/ebtables (ebtables) in manual mode
kernelパラメータの調整
使用するkernelモジュールのうち、一部(overlayおよびbr_netfilter)デフォルトで読み込まれていないものがあるので事前に有効化しておきます。
$ echo -e "overlay\nbr_netfilter" | sudo tee /etc/modules-load.d/containerd.conf
$ sudo modprobe overlay
$ sudo modprobe br_netfilter
iptablesがブリッジインターフェースを通過するパケットを、正常にフォワーディングできるようにkernelパラメータを調整します。
$ echo -e "net.bridge.bridge-nf-call-ip6tables = 1\nnet.bridge.bridge-nf-call-iptables = 1\nnet.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/kubernetes.conf
$ sudo sysctl --system
swapの無効化(有効化されている場合のみ)
kubeletの実行時にswapが有効化されていると、メモリ使用が逼迫した場合にMemory Evictationを招くため、無効化することが推奨されています。(kubernetes 1.22以降ではWorker nodeでのswap利用がサポートされています。)
既にswapが有効化/利用されている環境では、swapoffを実行してswap利用を止めます。fstabに起動時のswapのマウントについて設定が記述されているので削除(またはコメントアウト)しておきましょう。
$ sudo swapoff -a
/etc/fstab の記載内容(swap.imgファイルを再起動後にマウントしないため、コメントアウトにて対応します。)
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/sda2 during curtin installation
/dev/disk/by-uuid/58dc637c-9e1f-45e1-9543-d1dd29c96122 / ext4 defaults 0 1
# /boot/efi was on /dev/sda1 during curtin installation
/dev/disk/by-uuid/D128-E041 /boot/efi vfat defaults 0 1
# /swap.img none swap sw 0 0
CRI(container runtime interface)の導入
前回導入次点と同様に、Containerd をCRIとして導入していきます。containerdのパッケージはUbuntuレポジトリでも提供されていますが、新しいパッケージについてはdockerのレポジトリより利用可能です。
まずはDockerのubuntuレポジトリを追加するために、必要なパッケージを導入していきます。(Ubuntuをminimalでセットアップしていない限り、下記パッケージは既に導入されています。)
$ sudo apt-get update
$ sudo apt-get install ca-certificates curl
Dockerレポジトリ追加の為に公式のGPGキーを追加します。
$ sudo install -m 0755 -d /etc/apt/keyrings
$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
$ sudo chmod a+r /etc/apt/keyrings/docker.asc
aptレポジトリを追加、セットアップします。Docker Engineのインストール手順として、公式のドキュメントにて提示されている手順通りに実行します。
$ echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
apt パッケージリストを更新して、パッケージをインストールします。
$ sudo apt update && sudo apt install -y containerd.io
containerdデフォルトの設定では、criプラグインが無効化されているので予め有効化しておきます。また末尾にruncのoptionとして、systemdのcgroupドライバを使用するように明示的に指定します。
(参考)containerd/docs/cri/config.md at main · containerd/containerd · GitHub
更に一部の kubeletによって起動されるコンテナ(kube-api, etcd)がCrashLoopBackoff にて再起動を繰り返すためcontainerdで使用する sandbox containerを明示的に指定します。
(参考)Container Runtimes | Kubernetes
/etc/containerd/config.toml
# disabled_plugins = ["cri"]
version = 2
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.k8s.io/pause:3.9"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
config.toml上の該当行をコメントアウト後、および必要な記述を追記後にcontainerdを再起動します。
$ sudo systemctl restart containerd
(補遺)nerdctlの導入
今回のセットアップではDocker Engine自体を導入していないため、各コンテナをデバッグするにはインターフェースを追加で導入する必要があります。containerdにはcliとしてnerdctlが提供されているので、今回はこちらを利用していきましょう。
パッケージとして提供されてはいないので、GitHubからバイナリをダウンロードして適切なディレクトリに配置していきます。提供されている最新のバージョンについては Releases · containerd/nerdctl より確認できます。
$ curl -LO https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-1.7.6-linux-amd64.tar.gz
$ tar zxvf nerdctl-1.7.6-linux-amd64.tar.gz
$ sudo cp nerdctl /usr/local/bin/
k8sでデプロイされた各コンテナを参照する際には、–namespace=k8s.ioをオプション付与して利用します。
$ sudo nerdctl --namespace=k8s.io ps
[[CONTAINER ID IMAGE
COMMAND CREATED STATUS PORTS NAMES
16dd5316a7b3 registry.k8s.io/coredns/coredns:v1.11.1
"/coredns -conf /etc…" About an hour ago Up k8s://kube-system/coredns-7db6d8ff4d-qlfwb/coredns
1a90962165df registry.k8s.io/coredns/coredns:v1.11.1
"/coredns -conf /etc…" About an hour ago Up k8s://kube-system/coredns-7db6d8ff4d-dcz2x/coredns
1c2709d17a4d registry.k8s.io/pause:3.9
"/pause" 13 hours ago Up k8s://kube-system/kube-controller-manager-ubuntusrv-stg01
kubeadm, kubelet, kubectl の導入
CRIが準備できたので、実際にkubernetesのレポジトリ追加、パッケージ導入を作業していきます。レポジトリ追加作業前に必要となるパッケージについて導入しておきましょう。
$ sudo apt-get update
$ sudo apt-get install -y apt-transport-https ca-certificates curl gpg
先ほどDockerレポジトリを追加したのと同様の手順で、kubernetesのレポジトリを追加していきます。まずはGPGキーのインポートとレポジトリ情報をapt上へ登録します。Kubernetesのレポジトリ構造が変更されたため、major + minorバージョンで個別にキーファイルをインストール、レポジトリを追加する必要があります。
$ curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
$ 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
パッケージリストを更新し、kubeadm, kubelet, kubectlの必要パッケージをインストールします。
$ sudo apt update && sudo apt install -y kubelet kubeadm kubectl
(補遺)各パッケージのhold
kubernetes以外のパッケージを更新する際に、合わせてkubernetes関連のパッケージが更新されてしまうことを避けるため、kubelet, kubeadm, kubectlの各パッケージについてholdします。
$ sudo apt-mark hold kubelet kubeadm kubectl
kubernetes クラスタのセットアップ(kubeadm init)
kubeadmを利用してクラスターをセットアップしていきます。今回はネットワークアドオンとしてciliumを使用するので、podのアドレス範囲が他のネットワークと衝突しないように引数を追加しています。
$ sudo kubeadm init --pod-network-cidr="10.244.0.0/16"
問題無くクラスターが作成されると、下記のメッセージが表示されます。
Your Kubernetes control-plane has initialized successfully!
現在使用している一般ユーザでkubectl経由でクラスターを利用できるように、configを~/.kubeディレクトリに配置していきます。
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
この時点ではまだネットワークアドオンが展開されていないため、control-planeノードのstatusはNotReadyとなっています。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ubuntusrv-stg01 NotReady control-plane 1h v1.30.3
ネットワークアドオンのインストール
今回は eBPFを利用しservice meshやVXLANの実装、また各パケットの動作についてトレース可能な可観測性を高めた cilium を利用します。cilium は cilium cliまたは kubernetes向けの構成管理ソフトウェア Helm からインストールすることができます。前者の手順は Cilium Quick Installation — Cilium 1.16.0 documentation から参照可能です。
今回のインストールではインストール後の構成管理の側面や、設定投入(cilium-cliからのインストールの場合、設定変更に必要なリファレンスがすべて公開されていない)の側面から Helm よりインストールします。
Helmインストール手順
ubuntuの場合、パッケージマネージャ snap より最新の Helm をインストールできます。下記コマンドを実行して最新のHelmを導入してください。
$ sudo snap install helm --classic
Ciliumインストール手順
インストールしたHelmを利用して、Ciliumを導入します。ubuntu server 24.04.3 のsnap(2.63+24.04ubuntu0.1) より導入する場合は、–classic オプションを付与してインストールする必要があります。
またインストール先のnamespaceを –namespaceオプションにて指定してインストールします。通常は kube-systemにリソースをデプロイしますが、個別にテナントを分離する必要がある場合は別namespaceに導入しましょう。
$ helm install cilium cilium/cilium --version 1.16.0 --namespace kube-system
Helm経由でのciliumのデプロイ後、すべてのリソースが正常に展開されているかどうか確認します。kube-system namespaceに展開されているpodを一覧で参照します。一部、cilium-operator podがシングルノードクラスタの場合に1nodeに複数展開できないため、Pendingにて保留されます。
$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
cilium-envoy-rfp4q 1/1 Running 0 151m
cilium-nntbn 1/1 Running 0 151m
cilium-operator-7ddc48bb97-cqjs6 1/1 Running 0 151m
cilium-operator-7ddc48bb97-xt6hf 0/1 Pending 0 151m
coredns-7db6d8ff4d-dcz2x 1/1 Running 0 14h
coredns-7db6d8ff4d-qlfwb 1/1 Running 0 14h
etcd-ubuntusrv-stg01 1/1 Running 101 14h
kube-apiserver-ubuntusrv-stg01 1/1 Running 96 14h
kube-controller-manager-ubuntusrv-stg01 1/1 Running 97 14h
kube-proxy-qjbt9 1/1 Running 0 14h
kube-scheduler-ubuntusrv-stg01 1/1 Running 103 14h
このままシングルノードクラスタにて使用する場合は、kube-system namespaceのcilium-operator deploymentを編集して、replicasを2から1へ変更します。
$ kubectl edit deployments.apps -n kube-system cilium-operator
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
io.cilium/app: operator
name: cilium-operator
レプリカ数が2から1に変更され、不要となったcilium operator podがスケジュールされなくなります。
$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
cilium-envoy-rfp4q 1/1 Running 0 155m
cilium-nntbn 1/1 Running 0 155m
cilium-operator-7ddc48bb97-cqjs6 1/1 Running 0 155m
coredns-7db6d8ff4d-dcz2x 1/1 Running 0 14h
coredns-7db6d8ff4d-qlfwb 1/1 Running 0 14h
etcd-ubuntusrv-stg01 1/1 Running 101 14h
kube-apiserver-ubuntusrv-stg01 1/1 Running 96 14h
kube-controller-manager-ubuntusrv-stg01 1/1 Running 97 14h
kube-proxy-qjbt9 1/1 Running 0 14h
kube-scheduler-ubuntusrv-stg01 1/1 Running 103 14h
また、CNIプラグインがインストールされたことにより coredns podが正常にデプロイされ、nodeのSTATUSがReadyとなりリソースがデプロイ可能となります。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ubuntusrv-stg01 Ready control-plane 14h v1.30.3
シングルノードクラスターとして利用する準備
以前のバージョンの kubernetesのcontrol-planeには原則としてpodがscheduleされないように設定されています。(control-planeに過剰にpodがscheduleされ、リソースが逼迫するのを防ぐ為にこのような措置が取られています。)podのscheule可否はtaintで制御されていますでの、設定されたtaintを変更しましょう。
$ kubectl taint node ubuntusrv-stg01 node-role.kubernetes.io/control-plane:NoSchedule-
node/k8s-develop1 untainted
(補遺)auto-completion 入力補完の設定
kubectlの使用時に入力補完を利用可能にするためには、下記を実行してbash_completion.dに適切なファイルを配置します。
$ kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null