こちらはAWS Containers Advent Calendar 2020の20日目の記事です。
本記事は個人の意見であり、所属する組織の見解とは関係ありません。
1年半程前、私もラズパイでKubernetesクラスタを作成しました。
使用したのは3台のRaspberry Pi 3 Model B+で、その頃のKubernetesのバージョンは1.13でした。このラズパイクラスタはその後ほとんど活用されていないので、今回はこのラズパイクラスタでEKS Distroを動かしてみたいと思います。
EKS Distroとは何か、についてはFAQがわかりやすいです。日本語です。
方針
公式ドキュメントにはkopsを使ったデプロイ手順があります。パートナーがそれぞれのサービスのKubernetesクラスターでEKS Distroを使う方法を用意しています。例えば、CanonicalのSnapパッケージを使うと簡単にラズパイでもEKS Distroが動くようです。これはMicroK8sのKubernetes部分をEKS Distroに置き換えているようです。
Snapではなくkubeadmを使った手順を探していたところ、同僚に以下のブログ記事を教えてもらいました。
今回はこのブログ記事を参考にして、ラズパイに「kubeadm」で「EKS Distro」をデプロイし、「ラズパイEKSクラスタ」を作成したいと思います。ブログ記事ではコントロールプレーンを冗長化していますが、私はシングルコントロールプレーンのクラスターを作成します。
ラズパイクラスタの準備
実は最初、以前作成したラズパイクラスタを流用し、一度Dockerやらkubeadmやらを削除してきれいにした上で、EKS Distroをデプロイしようとしました。しかし私のラズパイは32bitのarmv7互換のOSで動いており、一方、EKS Distroのバイナリやイメージはarm64版しか提供されていないため失敗しました。
頑張れば自分でarmv7版のバイナリとイメージをビルドすることも可能かもしれませんが、OSを64bit版に入れ替える方が簡単そうなので、OSを入れ替えました。しかし、64bit OSはメモリー消費量が多いのか、あるいは以前よりKubernetesのバージョンが上がってメモリー消費量が多くなったのか、メモリーが1GBしかないRaspberry Pi 3 Model B+ではkubeadm init
を実行するとハングしてしまうという自体に陥りました。
結局、Raspberry Pi 4 Model B (4GB RAM)を追加で購入し、Masterノードとして利用することにしました。
したがって、新しいラズパイ4Bと既存のラズパイ3B+に64bit版のOSを入れるところからはじめます。RaspbianはRaspberry Pi OSに名前が変わったのですね。64bit版はまだbetaテスト版で、以下にイメージがあります。
Ubuntuも64bit版があるようです。
今回はRaspberry Pi OSの64bit版を使うことにします。イメージをSDカードに焼くツールは、今回はRaspberry Pi Imagerを使いました。とても簡単です。
ラズパイクラスタの基本的なセットアップについては、以下の以前の記事を参照下さい。
こちらの記事にしたがって、SSHログインができるところまで進めて下さい。
なお、以前の記事ではクラスターの上部に配置した小型のWiFiルーターを使って上流のWiFiネットワークに接続する構成で、ラズパイのIPアドレスは192.11.13.101
〜192.11.13.103
でした。しかしこの構成だと小型のWiFiルーターの速度が遅いので、今回は家庭内LANに有線で直接繋がるようにしています。ラズパイのIPアドレスは192.11.11.101
〜192.11.11.104
です。
ホスト名 | IPアドレス | 役割 | ハードウェア | メモリー |
---|---|---|---|---|
k8s-master | 192.168.11.101 | Master | Raspberry Pi 4 Model B | 4GB |
k8s-node1 | 192.168.11.102 | Worker | Raspberry Pi 3 Model B+ | 1GB |
k8s-node2 | 192.168.11.103 | Worker | Raspberry Pi 3 Model B+ | 1GB |
k8s-node3 | 192.168.11.104 | Worker | Raspberry Pi 3 Model B+ | 1GB |
手順
では、ここからクラスターの作成に取りかかります。
cgroupの有効化
起動する前にSDカードの中のcmdline.txt
を編集しなかった場合は、/boot/cmdline.txt
を編集して行の末尾にcgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1
を追加して再起動します。
console=serial0,115200 console=tty1 root=PARTUUID=af570baa-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1
/proc/cgroups
を確認してenabledの列が1になっていればOKです。
pi@k8s-master:~ $ cat /proc/cgroups
#subsys_name hierarchy num_cgroups enabled
cpuset 6 1 1
cpu 7 1 1
cpuacct 7 1 1
blkio 2 1 1
memory 9 92 1
devices 4 77 1
freezer 8 1 1
net_cls 3 1 1
perf_event 5 1 1
net_prio 3 1 1
pids 10 85 1
スワップの無効化
スワップを無効化しておきます。
sudo dphys-swapfile swapoff
sudo systemctl stop dphys-swapfile
sudo systemctl disable dphys-swapfile
free
コマンドでスワップが使われていないことを確認します。
pi@k8s-master:~ $ free
total used free shared buff/cache available
Mem: 934532 248860 265572 7636 420100 615608
Swap: 0 0 0
Dockerのインストール
convenience scriptを使ってインストールします。
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
pi@k8s-master:~ $ sudo sh get-docker.sh
# Executing docker install script, commit: 3d8fe77c2c46c5b7571f94b42793905e5b3e42e4
+ sh -c apt-get update -qq >/dev/null
+ sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq apt-transport-https ca-certificates curl >/dev/null
+ sh -c curl -fsSL "https://download.docker.com/linux/debian/gpg" | apt-key add -qq - >/dev/null
Warning: apt-key output should not be parsed (stdout is not a terminal)
+ sh -c echo "deb [arch=arm64] https://download.docker.com/linux/debian buster stable" > /etc/apt/sources.list.d/docker.list
+ sh -c apt-get update -qq >/dev/null
+ [ -n ]
+ sh -c apt-get install -y -qq --no-install-recommends docker-ce >/dev/null
+ sh -c docker version
Client: Docker Engine - Community
Version: 20.10.1
API version: 1.41
Go version: go1.13.15
Git commit: 831ebea
Built: Tue Dec 15 04:35:39 2020
OS/Arch: linux/arm64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.1
API version: 1.41 (minimum version 1.12)
Go version: go1.13.15
Git commit: f001486
Built: Tue Dec 15 04:33:40 2020
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: 1.4.3
GitCommit: 269548fa27e0089a8b8278fc4fc781d7f65a939b
runc:
Version: 1.0.0-rc92
GitCommit: ff819c7e9184c13b7c2607fe6c30ae19403a7aff
docker-init:
Version: 0.19.0
GitCommit: de40ad0
If you would like to use Docker as a non-root user, you should now consider
adding your user to the "docker" group with something like:
sudo usermod -aG docker your-user
Remember that you will have to log out and back in for this to take effect!
WARNING: Adding a user to the "docker" group will grant the ability to run
containers which can be used to obtain root privileges on the
docker host.
Refer to https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface
for more information.
20.10
はまだKubernetesではサポートされていないバージョンであるため、19.03
にダウングレードします。
まず利用可能なバージョンを確認します。
pi@k8s-master:~ $ apt-cache madison docker-ce
docker-ce | 5:20.10.1~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:20.10.0~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.14~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.13~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.12~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.11~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.10~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.9~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.8~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.7~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.6~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.5~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.4~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.3~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.2~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.1~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:19.03.0~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:18.09.9~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:18.09.8~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:18.09.7~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:18.09.6~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:18.09.5~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:18.09.4~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:18.09.3~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:18.09.2~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:18.09.1~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 5:18.09.0~3-0~debian-buster | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 18.06.3~ce~3-0~debian | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 18.06.2~ce~3-0~debian | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 18.06.1~ce~3-0~debian | https://download.docker.com/linux/debian buster/stable arm64 Packages
docker-ce | 18.06.0~ce~3-0~debian | https://download.docker.com/linux/debian buster/stable arm64 Packages
ダウングレードします。
sudo apt-get install -y --allow-downgrades --no-install-recommends \
docker-ce=5:19.03.14~3-0~debian-buster \
docker-ce-cli=5:19.03.14~3-0~debian-buster
バージョンは固定しておきます。
sudo apt-mark hold docker-ce docker-ce-cli
pi
ユーザーでもdocker
コマンドを実行できるようにしておきます。
sudo usermod -aG docker pi
ここからはroot
ユーザーで作業します。
sudo -i
Dockerのcgroupドライバーを確認します。
root@k8s-master:~# docker info | grep -i cgroup
Cgroup Driver: cgroupfs
WARNING: No swap limit support
WARNING: No blkio weight support
WARNING: No blkio weight_device support
Kubernetesのドキュメントにしたがって、Dockerのcgroupドライバーをsystemd
に変更します。log-driverとstorage-driverは既にこの指定の通りになっていますが、明示的に指定しておきます。
cat <<EOF > /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
Dockerを再起動します。
systemctl daemon-reload
systemctl restart docker
Dockerのcgroupドライバーがsystemd
になったことを確認します。
root@k8s-master:~# docker info | grep -i cgroup
Cgroup Driver: systemd
WARNING: No swap limit support
kubeadm(EKS Distro版)のインストール
root
ユーザーで作業します。
kubeadmはapt-getではなくバイナリを直接ダウンロードします。まず以下のリンクに記載のkubeadmの前提条件を確認します。
iptablesがブリッジを通過するトラフィックを処理できるようにするため、net.bridge.bridge-nf-call-iptables
を1
に設定します。この時点で既に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
iptablesがnftablesをバックエンドに使用しないようにします。レガシーバージョンをインストールします。
apt-get install -y iptables arptables ebtables
レガシーバージョンに切り替えます。
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives --set ebtables /usr/sbin/ebtables-legacy
変更を反映するため、念のためここでラズパイを再起動します。
reboot
EKS DistroのリポジトリからCNIプラグインをダウンロードしてインストールします。
mkdir -p /opt/cni/bin
wget https://distro.eks.amazonaws.com/kubernetes-1-18/releases/1/artifacts/plugins/v0.8.7/cni-plugins-linux-arm64-v0.8.7.tar.gz
tar zxf cni-plugins-linux-arm64-v0.8.7.tar.gz -C /opt/cni/bin/
EKS Distroのリポジトリからkubeadm、kubelet、kubectlをダウンロードしてインストールします。
wget https://distro.eks.amazonaws.com/kubernetes-1-18/releases/1/artifacts/kubernetes/v1.18.9/bin/linux/arm64/kubeadm
wget https://distro.eks.amazonaws.com/kubernetes-1-18/releases/1/artifacts/kubernetes/v1.18.9/bin/linux/arm64/kubelet
wget https://distro.eks.amazonaws.com/kubernetes-1-18/releases/1/artifacts/kubernetes/v1.18.9/bin/linux/arm64/kubectl
mv kubeadm kubelet kubectl /usr/bin/
chmod +x /usr/bin/kubeadm /usr/bin/kubelet /usr/bin/kubectl
kubeletが必要とするパッケージをインストールします。
apt-get install -y conntrack ebtables socat
kubeletに引数を渡して、cgroupドライバーをsystemd
に変更します。Dockerが使用するcgroupドライバーと一致する必要があります。参考にしているブログはCentOSなので、Debian(Raspberry Pi OS)とはファイルの配置場所が違うところに注意が必要です。
cat <<EOF > /etc/default/kubelet
KUBELET_EXTRA_ARGS='--cgroup-driver=systemd'
EOF
kubeadmとkubeletが使用するディレクトリを作成します。
mkdir -p /etc/kubernetes/manifests
mkdir -p /etc/systemd/system/kubelet.service.d
ブログ記事と以下のリンクも参考にしながら、kubeadmの設定ファイルとkubeletのユニット定義ファイルを作成します。
cat <<EOF > /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
# Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
# the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/default/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet \$KUBELET_KUBECONFIG_ARGS \$KUBELET_CONFIG_ARGS \$KUBELET_KUBEADM_ARGS \$KUBELET_EXTRA_ARGS
EOF
cat <<EOF > /lib/systemd/system/kubelet.service
[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=https://kubernetes.io/docs/
Wants=network-online.target
After=network-online.target
[Service]
ExecStart=/usr/bin/kubelet
Restart=always
StartLimitInterval=0
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
システム起動時にkubeletが起動するようにします。
systemctl enable kubelet
Kubernetesコンポーネント(EKS Distro版)のダウンロード
コントロールプレーンに必要なDockerイメージをAmazon ECR Publicからpullします。
docker pull public.ecr.aws/eks-distro/etcd-io/etcd:v3.4.14-eks-1-18-1
docker pull public.ecr.aws/eks-distro/kubernetes/pause:v1.18.9-eks-1-18-1
docker pull public.ecr.aws/eks-distro/kubernetes/kube-scheduler:v1.18.9-eks-1-18-1
docker pull public.ecr.aws/eks-distro/kubernetes/kube-proxy:v1.18.9-eks-1-18-1
docker pull public.ecr.aws/eks-distro/kubernetes/kube-apiserver:v1.18.9-eks-1-18-1
docker pull public.ecr.aws/eks-distro/kubernetes/kube-controller-manager:v1.18.9-eks-1-18-1
docker pull public.ecr.aws/eks-distro/coredns/coredns:v1.7.0-eks-1-18-1
kubeadmにハードコードされた値に合わせる必要があるため、イメージに追加のタグを付与します。
docker tag public.ecr.aws/eks-distro/kubernetes/pause:v1.18.9-eks-1-18-1 public.ecr.aws/eks-distro/kubernetes/pause:3.2
docker tag public.ecr.aws/eks-distro/coredns/coredns:v1.7.0-eks-1-18-1 public.ecr.aws/eks-distro/kubernetes/coredns:1.6.7
イメージを確認します。
root@k8s-master:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
public.ecr.aws/eks-distro/kubernetes/pause 3.2 430398c8f74c 2 weeks ago 630kB
public.ecr.aws/eks-distro/kubernetes/pause v1.18.9-eks-1-18-1 430398c8f74c 2 weeks ago 630kB
public.ecr.aws/eks-distro/kubernetes/kube-proxy v1.18.9-eks-1-18-1 0ff76167f898 2 weeks ago 579MB
public.ecr.aws/eks-distro/kubernetes/kube-scheduler v1.18.9-eks-1-18-1 2f471234bdca 2 weeks ago 479MB
public.ecr.aws/eks-distro/kubernetes/kube-controller-manager v1.18.9-eks-1-18-1 2c01694a0619 2 weeks ago 543MB
public.ecr.aws/eks-distro/kubernetes/kube-apiserver v1.18.9-eks-1-18-1 94f388827354 2 weeks ago 553MB
public.ecr.aws/eks-distro/etcd-io/etcd v3.4.14-eks-1-18-1 61b76a81855c 2 weeks ago 473MB
public.ecr.aws/eks-distro/coredns/coredns v1.7.0-eks-1-18-1 c04916f93277 2 weeks ago 44.4MB
public.ecr.aws/eks-distro/kubernetes/coredns 1.6.7 c04916f93277 2 weeks ago 44.4MB
etcdのイメージはこのIssueと同じエラーで起動しないため、ETCD_UNSUPPORTED_ARCH=arm64
という環境変数を渡す必要があります。kubeadmの設定オプションで環境変数を渡すことができなそうだったため、環境変数を追加したイメージをビルドします。
Dockerfileを作成します。
cat <<EOF > Dockerfile
FROM public.ecr.aws/eks-distro/etcd-io/etcd:v3.4.14-eks-1-18-1
ENV ETCD_UNSUPPORTED_ARCH=arm64
EOF
イメージをビルドします。
docker build -t public.ecr.aws/eks-distro/etcd-io/etcd:v3.4.14-eks-1-18-1 .
イメージを確認します。
oot@k8s-master:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
public.ecr.aws/eks-distro/etcd-io/etcd v3.4.14-eks-1-18-1 bcc9e6b4e4d4 4 seconds ago 473MB
public.ecr.aws/eks-distro/kubernetes/pause 3.2 430398c8f74c 2 weeks ago 630kB
public.ecr.aws/eks-distro/kubernetes/pause v1.18.9-eks-1-18-1 430398c8f74c 2 weeks ago 630kB
public.ecr.aws/eks-distro/kubernetes/kube-proxy v1.18.9-eks-1-18-1 0ff76167f898 2 weeks ago 579MB
public.ecr.aws/eks-distro/kubernetes/kube-scheduler v1.18.9-eks-1-18-1 2f471234bdca 2 weeks ago 479MB
public.ecr.aws/eks-distro/kubernetes/kube-controller-manager v1.18.9-eks-1-18-1 2c01694a0619 2 weeks ago 543MB
public.ecr.aws/eks-distro/kubernetes/kube-apiserver v1.18.9-eks-1-18-1 94f388827354 2 weeks ago 553MB
public.ecr.aws/eks-distro/etcd-io/etcd <none> 61b76a81855c 2 weeks ago 473MB
public.ecr.aws/eks-distro/kubernetes/coredns 1.6.7 c04916f93277 2 weeks ago 44.4MB
public.ecr.aws/eks-distro/coredns/coredns v1.7.0-eks-1-18-1 c04916f93277 2 weeks ago 44.4MB
ここまでの操作は全てのラズパイに対して行います。
Masterノードの初期化
以下のリンクにしたがってクラスターを作成します。
Masterノード上でkubeadmの構成ファイルを作成します。Kubernetesの各コンポーネントの取得元のイメージリポジトリとして、EKS Distroのリポジトリを指定しています。PodネットワークアドオンはFlannelを使う想定でPodネットワークのCIDRを指定しています。Calicoだと我が家のLANのCIDRと被ってしまうためFlannelを選択しています。
cat <<EOF > kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
networking:
podSubnet: "10.244.0.0/16"
etcd:
local:
imageRepository: public.ecr.aws/eks-distro/etcd-io
imageTag: v3.4.14-eks-1-18-1
extraArgs:
listen-peer-urls: "https://0.0.0.0:2380"
listen-client-urls: "https://0.0.0.0:2379"
imageRepository: public.ecr.aws/eks-distro/kubernetes
kubernetesVersion: v1.18.9-eks-1-18-1
EOF
このファイルを指定してkubeadm init
を実行します。
kubeadm init --config kubeadm-config.yaml
root@k8s-master:~# kubeadm init --config kubeadm-config.yaml
W1219 02:15:50.059301 1349 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
[init] Using Kubernetes version: v1.18.9-eks-1-18-1
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [k8s-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.11.101]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [k8s-master localhost] and IPs [192.168.11.101 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [k8s-master localhost] and IPs [192.168.11.101 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
W1219 02:16:09.651280 1349 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
[control-plane] Creating static Pod manifest for "kube-scheduler"
W1219 02:16:09.655043 1349 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 39.519892 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.18" in namespace kube-system with the configuration for the kubelets in the cluster
[kubelet-check] Initial timeout of 40s passed.
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node k8s-master as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node k8s-master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: v4aezo.0qqsig2csphtm5dj
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
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:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.11.101:6443 --token v4aezo.0qqsig2csphtm5dj \
--discovery-token-ca-cert-hash sha256:04da2245c17641aec3cec1edc74e0ae88c7411573cc287a920c42ebba9a5c4e8
出力の最後にあるkubeadm join
コマンドを後で使います。
一般ユーザーに戻って、kubeconfigを設定します。
exit
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
ですが、VERSION
はEKSっぽいバージョンになっていますね!
pi@k8s-master:~ $ kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master NotReady master 2m3s v1.18.9-eks-1-18-1
Podネットワークアドオンのインストール
PodネットワークアドオンとしてFlannelをインストールします。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml
しばらくするとノードがReady
になります。
pi@k8s-master:~ $ kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 4m27s v1.18.9-eks-1-18-1
コマンドの補完とk
のエイリアスを有効にしておきます(オプション)。
sudo apt-get install -y bash-completion
cat <<EOT >> ~/.bashrc
alias k="kubectl"
source <(kubectl completion bash)
complete -o default -F __start_kubectl k
EOT
source ~/.bashrc
Workerノードの追加
全てのWorkerノード上で、先ほどMasterノードでkubeadm init
を実行した際に出力されていたkubeadm join
コマンドをroot
ユーザーで実行します。
root@k8s-node3:~# kubeadm join 192.168.11.101:6443 --token v4aezo.0qqsig2csphtm5dj \
> --discovery-token-ca-cert-hash sha256:04da2245c17641aec3cec1edc74e0ae88c7411573cc287a920c42ebba9a5c4e8
W1219 02:22:56.373017 2477 join.go:346] [preflight] WARNING: JoinControlPane.controlPlane settings will be ignored when control-plane flag is not set.
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.18" ConfigMap in the kube-system namespace
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
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.
Masterノード上で、ノードが追加されReady
となっていることを確認します。
pi@k8s-master:~ $ kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master Ready master 7m33s v1.18.9-eks-1-18-1 192.168.11.101 <none> Debian GNU/Linux 10 (buster) 5.4.79-v8+ docker://19.3.14
k8s-node1 Ready <none> 66s v1.18.9-eks-1-18-1 192.168.11.102 <none> Debian GNU/Linux 10 (buster) 5.4.79-v8+ docker://19.3.14
k8s-node2 Ready <none> 60s v1.18.9-eks-1-18-1 192.168.11.103 <none> Debian GNU/Linux 10 (buster) 5.4.79-v8+ docker://19.3.14
k8s-node3 Ready <none> 55s v1.18.9-eks-1-18-1 192.168.11.104 <none> Debian GNU/Linux 10 (buster) 5.4.79-v8+ docker://19.3.14
全てのPodがRunning
であることを確認します。
pi@k8s-master:~ $ kubectl get pod -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system coredns-8f7b4cf65-f4dhv 1/1 Running 0 7m40s 10.244.0.2 k8s-master <none> <none>
kube-system coredns-8f7b4cf65-lgg6d 1/1 Running 0 7m40s 10.244.0.3 k8s-master <none> <none>
kube-system etcd-k8s-master 1/1 Running 0 7m46s 192.168.11.101 k8s-master <none> <none>
kube-system kube-apiserver-k8s-master 1/1 Running 0 7m46s 192.168.11.101 k8s-master <none> <none>
kube-system kube-controller-manager-k8s-master 1/1 Running 0 7m46s 192.168.11.101 k8s-master <none> <none>
kube-system kube-flannel-ds-arm64-cfdxg 1/1 Running 0 87s 192.168.11.103 k8s-node2 <none> <none>
kube-system kube-flannel-ds-arm64-d7hgj 1/1 Running 0 93s 192.168.11.102 k8s-node1 <none> <none>
kube-system kube-flannel-ds-arm64-frcl2 1/1 Running 0 82s 192.168.11.104 k8s-node3 <none> <none>
kube-system kube-flannel-ds-arm64-md7gh 1/1 Running 0 3m44s 192.168.11.101 k8s-master <none> <none>
kube-system kube-proxy-fcbm2 1/1 Running 0 93s 192.168.11.102 k8s-node1 <none> <none>
kube-system kube-proxy-lgvw2 1/1 Running 0 87s 192.168.11.103 k8s-node2 <none> <none>
kube-system kube-proxy-sbh7v 1/1 Running 0 7m40s 192.168.11.101 k8s-master <none> <none>
kube-system kube-proxy-vpgkg 1/1 Running 0 82s 192.168.11.104 k8s-node3 <none> <none>
kube-system kube-scheduler-k8s-master 1/1 Running 0 7m46s 192.168.11.101 k8s-master <none> <none>
稼働確認
NginxをデプロイしてNodePortで公開し、クラスターが機能していることを確認しましょう。
NginxのDeploymentを作成します。
pi@k8s-master:~ $ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
DeploymentをNodePortタイプのServiceとして公開します。
pi@k8s-master:~ $ kubectl expose deployment nginx --type NodePort --port 80
service/nginx exposed
ServiceのNodePortを確認します。
pi@k8s-master:~ $ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10m
nginx NodePort 10.105.150.24 <none> 80:31972/TCP 6s
ラズパイではなく手元のマシンから、いずれかのノードのIPアドレス(192.168.11.101
〜192.168.11.104
)のNodePort(上記出力の31972
ポート)にアクセスして確認しましょう。
$ curl 192.168.11.103:31972
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
無事にNginxにアクセスできました。以上でラズパイEKSクラスタは完成です!
補足
クラスターの作成に失敗したり上手く動かない場合に、やり直すときは以下の手順で行います。
Masterノードでノードを削除します。
kubectl delete node k8s-node1
kubectl delete node k8s-node2
kubectl delete node k8s-node3
kubeconfigを削除します。
rm -rf $HOME/.kube
全てのノード上で、root
ユーザーでkubeadm reset
コマンドを実行します。
kubeadm reset -f
全てのノードを再起動します。再起動しないと、iptablesのルールや、CNIプラグインが作成したネットワークインターフェースが残っていて、クラスターを再作成した際にハマります。再起動後、以下のコマンドで不要なiptablesルールや、flannel.1
やcni0
といったネットワークインターフェースが残っていないことを確認して下さい。
ip a
iptables -L
CNIプラグインをCalicoからFlannelに変更した場合など、以下のディレクトリ配下に設定ファイルが残っていてハマることがあるので、不要なファイルは削除して下さい。
rm -rf /etc/cni/net.d/*