Raspberry Pi 4×4台でKubernetesクラスタを構成するためにしたこと(Kubernetes v1.20 with kubeadm)
概要
Raspberry Pi 4台でkubeadmを使用したシングルコントロールプレーンクラスターの作成を参考にKubernetesクラスタを構成する際に躓いたところを中心に記録した記事です。(2021年1月3日時点)
構成
- Raspberry Pi 4 ModelB 8GB:4台(Master 1台、Worker3台)
- SDカード:32GB
- kubeadm v1.20(GitVersion:v1.20.1)
- コンテナランタイム:containerd(1.4.3)
- ネットワークアドオン:Flannel
Raspberry Piの設定
以下、Kubernetesクラスタ構成時特有の設定ではないが、計4つのRaspberry Piに行います。
- OS書き込み
- www.raspberrypi.org からインストールできるRaspberry Pi Imagerを使い、Raspberry Pi OS Lite(32-bit)をSDカードに書き込み。
- ホスト名変更
- ディスプレイ、キーボードを接続するなどしてログインし、raspi-configからホスト名を変更(System Optionsより)
- SSH設定
- raspi-configから設定。(Interface Optionsより)
- kubeletのためにswapをオフにする
$ sudo dphys-swapfile swapoff $ sudo systemctl stop dphys-swapfile $ sudo systemctl disable dphys-swapfile
- cgroupを有効にするため、
/boot/cmdline.txt
を次のようにする(cgroup_enable以降を加筆。改行せず、1行に記載する)
console=serial0,115200 console=tty1 root=PARTUUID=eec83cbb-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
kubeadmインストール
kubernetes.io より、 Rasberry Pi OSはDebian(Buster)系のため、iptables設定として
net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1
となるようにし、加えてnftablesバックエンドを使わないように切り替えました。
また、 /sys/class/dmi/id/product_uuid
が存在しなかったため、ユニーク性の検証は省略しています。
containerdインストール
Kubernetes v1.20から、採用するコンテナランタイムの選択肢としてのDockerが非推奨となったため、今回はcontainerdを選択しました。 kubernetes.io
kubernetes.io より、Ubuntu 16.04の手順に倣ってインストールします。
ただし、Raspberry Piではadd-apt-repositoryの実行時に
aptsources.distro.NoDistroTemplateException: Error: could not find a distribution template for Raspbian/buster
のようなエラーが出ること、CPUアーキテクチャが異なること、ubuntuではなくdebianを指定するため、以下のように一部手順を変更しました。
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - # GPG鍵追加 # add-apt-repository \ # "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ # $(lsb_release -cs) \ # stable" echo "deb [arch=armhf] https://download.docker.com/linux/debian\ $(lsb_release -cs) \ stable" > /etc/apt/sources.list.d/docker.list #リポジトリ設定追加
cgroupドライバーの設定
cgroupドライバーをcgroupfsではなくsystemdに変更します。 必須の項目ではないですが、
systemdと一緒に cgroupfs を使用するということは、2つの異なるcgroupマネージャーがあることを意味します。 コントロールグループはプロセスに割り当てられるリソースを制御するために使用されます。 単一のcgroupマネージャーは、割り当てられているリソースのビューを単純化し、 デフォルトでは使用可能なリソースと使用中のリソースについてより一貫性のあるビューになります。
ということを踏まえて、systemdへ統一します。
ここで、containerdがsystemdのcgroupドライバを使う方法について、
systemdのcgroupドライバーを使うには、/etc/containerd/config.toml内でplugins.cri.systemd_cgroup = trueを設定してください。
について具体的にどの項目を指すかというところに躓きました。
containerd config default > /etc/containerd/config.toml
で得られた設定ファイルについて、systemd_cgroupという項目があるため、当初はtrueに変更すればよいように思われたのですが、実際はdeprecatedになっていました。
[plugins."io.containerd.grpc.v1.cri"] disable_tcp_service = true stream_server_address = "127.0.0.1" stream_server_port = "0" stream_idle_timeout = "4h0m0s" enable_selinux = false selinux_category_range = 1024 sandbox_image = "k8s.gcr.io/pause:3.2" stats_collect_period = 10 systemd_cgroup = false # ここかと思いきやここではない
runtiime_type= io.containerd.runc.v2
の場合は次のように設定します。
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes] [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] runtime_type = "io.containerd.runc.v2" runtime_engine = "" runtime_root = "" privileged_without_host_devices = false base_runtime_spec = "" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true # 追加
加えて、kubeletからもsystemdを使用するよう、 /etc/default/kubelet
を作成し、
KUBELET_EXTRA_ARGS="--cgroup-driver=systemd"
を記載しました。この作業は計4台全ノードで必要なものです。
クラスタ作成
マスタノードでクラスタを作成し、残りのノードで作成したクラスタに参加します。
まず、マスタノードで kubeadm init
としてクラスタを作成します。
Flannelを使うために、kubeadm init
時に --pod-network-cidr=10.244.0.0/16
を渡す必要がありますが、設定項目を保存するため、あらかじめ kubeadm config init-defaults > ~/kubeadm_config.yaml
としてから kubeadm init --config kubeadm_config.yaml
とすることとしました。デフォルト設定との差分は以下のとおりです。
< advertiseAddress: 1.2.3.4 --- > advertiseAddress: <IP address> # masterノードのIPアドレス。worker側でkubeadm joinする際にアクセスするためのものも兼ねる < criSocket: /var/run/dockershim.sock --- > criSocket: "unix:///run/containerd/containerd.sock"
また、pod-network-cidrは以下の箇所で指定しました。
networking: dnsDomain: cluster.local serviceSubnet: 10.96.0.0/12 podSubnet: 10.244.0.0/16 # 追加
最後に、 kubeadm init --config kubeadm_config.yaml
でクラスタ作成を試みると、以下のエラーで失敗しました。
[ERROR Mem]: the system RAM (1 MB) is less than the minimum 1700 MB
これはkubeadmのメモリ容量計算式のバグで、Raspberry Pi 4 8GBのような32bitシステムかつ4GB以上のメモリを持つシステムでのみ起きる(メモリサイズを誤判定する)挙動のようです。
そこで、(上記GitHub Issueでも示されているように)
kubeadm init --config kubeadm_config.yaml --ignore-preflight-errors=Mem
とすることで作成できました。
※ Issueに対応するPull Requestがマージ済みのため、後のkubeadmでは --ignore-preflight-errors=Mem
は不要になる
最後に、クラスタ作成時に表示された kubeadm join
コマンド(トークンを含む)を他の3ノードでも実行して完了です。
結果
kubectl get pod -n kube-system
としてapiserverなどの各種コンポーネントが確認でき、実際に kubectl run
としてPodが動作したため、ひとまず構築できたようです。
Raspberry Piなのでやはり kubectl get pod
のようなリクエストでも重く、時間がかかるようですが、Kubernetesの実験のために使っていきたいところです。