手元に使えるRasPi3があったのでクラスタを組んでみました。そのメモです。
- RasPi 3B+
- Kubernetes v1.18.2
- kubeadmを使用
- 7台 (LB, controller x 3, worker x 3)
- Pod network add-on として Flannel
ちなみに練習としてこの前にKubernetes the Hard Wayとそのon Vagrant版をやっています。
前回: https://qiita.com/amedama/items/4bd9cf067c456bd59ead
環境のメモ
$ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 10 (buster)"
NAME="Raspbian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
$ cat /proc/cpuinfo
processor : 0
model name : ARMv7 Processor rev 4 (v7l)
BogoMIPS : 38.40
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xd03
CPU revision : 4
processor : 1
model name : ARMv7 Processor rev 4 (v7l)
BogoMIPS : 38.40
...
Hardware : BCM2835
Revision : a020d3
Serial : 000000005b98c9fa
Model : Raspberry Pi 3 Model B Plus Rev 1.3
ARMv7というのがあかんですが、本記事の範囲ではこのままでやってます。
今回確認したかった焦点
- 実ハードウェアを動員した時に変わる視点はどこか
-
kubeadm
は何を管理してくれて何を自前で管理する必要があるか。何が追加で問題になるか。何が楽になるか
ここではやったことを一つ一つ説明するのではなく他の資料を見ながら「違うな」と思った点などをかいつまんで書いておきます。
準備
Raspbian (Buster) が元々入っていたのでそのまま使います。後で気づきましたが 64bits モードで起動するのを忘れていてCPUが ARMv7 と認識されていました。
こうなると Pod network add-on として選択できるのはガチで Flannel だけなのですが、これはこれで現状(2020-05-06)ちょっと怪しい記述があってドキドキします。
Remove flannel from the list of CNIs in the kubeadm "create cluster"
page. The reason for that is that Cluster Lifecycle have been
getting a number of issues related to flannel (either in kubeadm or
kops tickets) and we don't have good answers for the users as the
project is not actively maintained.
気づかずにCalicoを使ってみたら、add-onをインストール (yamlをapply) した後にいつまで経ってもDockerイメージをとってきてくれず、調べてみたらarchに対応するイメージがない、という話でした。なんと凡庸なミス。
ARM 64bits ならCalicoとか、もっと人が集まってそうなものを使えそうな気がしますが、ここでは上記のドキドキものりこえてFlannelを使います。結論から言えば「運用時にどうなるかは知らんが今回のチュートリアルではまだ問題ない」という状況です。
また、CPU温度とか色々調べたかったのもあってZabbixをLB相当のマシンに入れました。これはRasPi 3Bの方の学びを得るためとか、ついでにコロナ禍でおうちネットワークが断続的に落ちるので外部にpingしておいてネットワークダウンを計測したいとか、色々と今回の記事と関係ない需要にも対応しています。
予習
kubeadm絡みの公式の資料は相当充実しているので一周読んでおきます
- Installing kubeadm
-
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
(https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/) - Creating a single control-plane cluster with kubeadm
- [https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/]
- Options for Highly Available topology
- https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/ha-topology/
- Creating Highly Available clusters with kubeadm
- https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/
今回の構成では Controll Plane 側のホストが3台あり、いわゆる高可用クラスタに属することになります。これは Kubernetes the Hard Way も同じです。
これ以外にRasPiベースの他の記事を読んでおきます。ちなみに大抵は何某か事情が古い部分があったり前提が異なっているため、そのままやるとハマることもあります。
ネットワーク構成
- LB
- lb-0 = 192.168.7.140
- Zabbixマシンも兼用。
- lb-0 = 192.168.7.140
- Controll Plane (etcd同居を想定)
- controller-0 ... 192.168.7.201
- controller-1 ... 192.168.7.202
- controller-2 ... 192.168.7.203
- Application Plane (Worker)
- worker-0 ... 192.168.7.204
- worker-1 ... 192.168.7.205
- worker-2 ... 192.168.7.206
配線が面倒なのですべて宅内のWi-Fiで済ませています。これで「高可用クラスタ」とか言われても
※ 外に出ないネットワークとしてハブで有線化する構成も考えたんですが、運悪く8ポートのハブが壊れしまい、余っているのが5ポートで足りないというね……
かいつまんでポイント
cgroup
今回のBuster版のRaspbianではcgroup周りの設定をいじる必要はありませんでした
$ cat /proc/cgroups
# subsys_name hierarchy num_cgroups enabled
cpuset 9 1 1
cpu 3 1 1
cpuacct 3 1 1
blkio 4 1 1
memory 7 76 1
devices 6 33 1
freezer 5 1 1
net_cls 2 1 1
pids 8 39 1
swap
swapは無効化します。最近のKubeletでは起動しない、という話らしいので。
$ swapon --show
NAME TYPE SIZE USED PRIO
/var/swap file 100M 0B -2
Rapsbianでは以前からSwapファイルの管理には dphys-swapfile
というものを使っているようです。Buster版ではこれがsystemd配下にありますので、disableします。
$ sudo systemctl disable dphys-swapfile
Synchronizing state of dphys-swapfile.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable dphys-swapfile
Removed /etc/systemd/system/multi-user.target.wants/dphys-swapfile.service.
MACアドレスとproduct_uuidが全てのノードでユニークであることの検証
kubeadmを利用する際の確認事項なのですが、RasPiでは product_uuid
は得られません。いきなりなんだってー
/sys/class/dmi/id/product_uuid: The main board product UUID, as set by the board manufacturer and encoded in the BIOS DMI information. It may be used to identify a mainboard and only the mainboard. It changes when the user replaces the main board. Also, often enough BIOS manufacturers write bogus serials into it. In addition, it is x86-specific. Access for unprivileged
http://0pointer.de/blog/projects/ids.html
この点は今回は無視します。幸いこの問題についてはwarningも何も出ませんでした。
MACアドレスがユニークかどうか、といった点はクリアしています。この「検証」の背景は、おそらくVMをコピーするとこのあたりの値が完全一致してしまうケースが出てしまうので調べておこう、ということでしょう。素直なハードウェアで被るような話ではないように思えます。
iptablesがnftablesバックエンドを使用しないようにする
もしあなたのシステムのiptablesツールがnftablesバックエンドを使用している場合、これらの問題を避けるためにiptablesツールをレガシーモードに切り替える必要があります。これは、少なくともDebian 10(Buster)、Ubuntu 19.04、Fedora 29、およびこれらのディストリビューションの新しいリリースでのデフォルトです。
これには引っかかります、ので対応します。
$ 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
Dockerインストール
kubeadmの資料をそのままやるとこれにハマります
https://github.com/docker/for-linux/issues/709
以下の方法を取りました。
$ sudo su
# curl https://get.docker.com | sh
...
# sudo usermod -aG docker pi
kubeadmが警告を出すので native.cgroupdriver=systemd
の指定もしておきます。
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
Kubernetes周りのツールインストール
$ 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
地味なのですが apt-mark
あたりは学びです。単純な apt-get upgrade
でKubernetesのツールが更新されて破壊される、といったことを防ぐわけですが、手でインストールしてないとしばしば忘れて、後で「アッー」ってなるやつです。お遊びだと忘れがちですねぇ……
LBの設定
aptでHAProxyを入れます。 net.ipv4.ip_nonlocal_bind=1
も追加しておきます
$ sudo su
# grep -q -F 'net.ipv4.ip_nonlocal_bind=1' /etc/sysctl.conf || echo 'net.ipv4.ip_nonlocal_bind=1' >> /etc/sysctl.conf
(戻る)
$ sudo apt-get install haproxy
HAProxyの設定を変更します。素のインストールだとHTTPのロードバランサ的な設定が入っているので mode tcp
にしたりk8s用の設定を足したりします。
$ cat /etc/haproxy/haproxy.cfg
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
# stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
ssl-default-bind-options no-sslv3
defaults
log global
# mode http
mode tcp
# option httplog
option tcplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend k8s
bind 192.168.7.140:6443
default_backend k8s_backend
backend k8s_backend
balance roundrobin
mode tcp
server controller-0 192.168.7.201:6443 check inter 1000
server controller-1 192.168.7.202:6443 check inter 1000
server controller-2 192.168.7.203:6443 check inter 1000
controllerが用意されてなくても反応はします。
$ nc -v 192.168.7.140 6443
Connection to 192.168.7.140 port 6443 [tcp/sun-sr-https] succeeded!
1台目のcontrollerのセットアップ
kubeadmを練習に使う際のちょっとしたつまづきポイントとして「先に決めておかないと後の祭り」がそれなりにあるってことですかね。ARMv7も、まぁ、それなんですけど。
FlannelをPodネットワークのadd-onに使うと決めた場合、 kubeadm init
の段階で --pod-network-cidr=10.244.0.0/16
を指定しておく必要があります。いやま、後から手で設定を書き換えて回るのは出来ると思いますが面倒ですしミスも増えるので、最初にやっておく。
LBのエンドポイント、つまりクラスタの外から kubectl
経由などでKube API Serverにアクセスする際のクチも指定します。あと、今回は「高可用」構成とするため、 --upload-certs
も指定します
When
--upload-certs
is used withkubeadm init
, the certificates of the primary control plane are encrypted and uploaded in thekubeadm-certs
Secret.
$ sudo kubeadm init --control-plane-endpoint "192.168.7.140:6443" --upload-certs --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:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join 192.168.7.140:6443 --token 3c2iy2.jkx1zkmj54ak4pez \
--discovery-token-ca-cert-hash sha256:964e73...56d6c65 \
--control-plane --certificate-key 1221d937fc...c9cc2dca049
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.7.140:6443 --token 3c2i...pez \
--discovery-token-ca-cert-hash sha256:964e7...033fffdca56d6c65
Kubernetes the Hard Way で苦行だった証明書周りもダブついた作業も全部ケアされてるー。すごーい(と、素直に感動しました)
ちなみにこの1台目のmasterには、インストール後、次のような感じで証明書や設定が保存されます。
$ tree /etc/kubernetes
/etc/kubernetes
├── admin.conf
├── controller-manager.conf
├── kubelet.conf
├── manifests
│ ├── etcd.yaml
│ ├── kube-apiserver.yaml
│ ├── kube-controller-manager.yaml
│ └── kube-scheduler.yaml
├── pki
│ ├── apiserver.crt
│ ├── apiserver-etcd-client.crt
│ ├── apiserver-etcd-client.key
│ ├── apiserver.key
│ ├── apiserver-kubelet-client.crt
│ ├── apiserver-kubelet-client.key
│ ├── ca.crt
│ ├── ca.key
│ ├── etcd
│ │ ├── ca.crt
│ │ ├── ca.key
│ │ ├── healthcheck-client.crt
│ │ ├── healthcheck-client.key
│ │ ├── peer.crt
│ │ ├── peer.key
│ │ ├── server.crt
│ │ └── server.key
│ ├── front-proxy-ca.crt
│ ├── front-proxy-ca.key
│ ├── front-proxy-client.crt
│ ├── front-proxy-client.key
│ ├── sa.key
│ └── sa.pub
└── scheduler.conf
3 directories, 30 files
これ、感動ポイントです。 こちらやったときのディレクトリをlsするとこんなですから
(これは Kubernetes the Hard Way on Vagrant の最終状態。ぱっぱらぱなし)
$ ls -1
activate.zsh
admin.csr
admin-csr.json
admin-key.pem
admin.kubeconfig
admin.kubeconfig.bak
admin.pem
bin
ca-config.json
ca.csr
ca-csr.json
ca-key.pem
ca.pem
coredns.yaml
encryption-config.yaml
kube-controller-manager.csr
kube-controller-manager-csr.json
kube-controller-manager-key.pem
kube-controller-manager.kubeconfig
kube-controller-manager.pem
kube-proxy.csr
kube-proxy-csr.json
kube-proxy-key.pem
kube-proxy.kubeconfig
kube-proxy.pem
kubernetes.csr
kubernetes-csr.json
kubernetes-key.pem
kubernetes.pem
kube-scheduler.csr
kube-scheduler-csr.json
kube-scheduler-key.pem
kube-scheduler.kubeconfig
kube-scheduler.pem
README.md
service-account.csr
service-account-csr.json
service-account-key.pem
service-account.pem
setup.sh
Vagrantfile
worker-0.csr
worker-0-csr.json
worker-0-key.pem
worker-0.kubeconfig
worker-0.pem
worker-1.csr
worker-1-csr.json
worker-1-key.pem
worker-1.kubeconfig
worker-1.pem
worker-2.csr
worker-2-csr.json
worker-2-key.pem
worker-2.kubeconfig
worker-2.pem
docker ps
の結果も見ておきます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
59cda3239ab4 0919cc09383b "/usr/local/bin/kube…" 10 seconds ago Up 9 seconds k8s_kube-proxy_kube-proxy-wnprf_kube-system_9d231a62-7b1c-47a0-b243-5abd4b62c580_0
aff39cd3448e k8s.gcr.io/pause:3.2 "/pause" 11 seconds ago Up 10 seconds k8s_POD_kube-proxy-wnprf_kube-system_9d231a62-7b1c-47a0-b243-5abd4b62c580_0
9ca88ca88e8e 8de7dc8a661a "kube-controller-man…" About a minute ago Up About a minute k8s_kube-controller-manager_kube-controller-manager-hrus-001_kube-system_807045fe48b23a157f7fe1ef20001ba0_0
6053f549b283 19a741f6ffe7 "etcd --advertise-cl…" About a minute ago Up About a minute k8s_etcd_etcd-hrus-001_kube-system_93e2c1d4e818f05306ffdc2d9bb5e740_0
2801e67594aa 916fa374fc34 "kube-apiserver --ad…" About a minute ago Up About a minute k8s_kube-apiserver_kube-apiserver-hrus-001_kube-system_39a390fdc92ee1594bd13b2888fd71ac_0
074bdfe01c3a 8d8286f173d9 "kube-scheduler --au…" About a minute ago Up About a minute k8s_kube-scheduler_kube-scheduler-hrus-001_kube-system_155707e0c19147c8dc5e997f089c0ad1_0
f4bfbf691696 k8s.gcr.io/pause:3.2 "/pause" About a minute ago Up About a minute k8s_POD_etcd-hrus-001_kube-system_93e2c1d4e818f05306ffdc2d9bb5e740_0
a2b49cc1bbdb k8s.gcr.io/pause:3.2 "/pause" About a minute ago Up About a minute k8s_POD_kube-scheduler-hrus-001_kube-system_155707e0c19147c8dc5e997f089c0ad1_0
d294f70f0161 k8s.gcr.io/pause:3.2 "/pause" About a minute ago Up About a minute k8s_POD_kube-controller-manager-hrus-001_kube-system_807045fe48b23a157f7fe1ef20001ba0_0
dd27bec6d6c7 k8s.gcr.io/pause:3.2 "/pause" About a minute ago Up About a minute k8s_POD_kube-apiserver-hrus-001_kube-system_39a390fdc92ee1594bd13b2888fd71ac_0
これらは kubelet
が管理するもののようです。systemdの管理下にあるので、controllerの再起動とかしたいならsystemctl経由でやる、ということのようです。
※ なぜ書いたかというと実際トラブってそこまでやる必要があったためです。
PodネットワークAdd-onのインストール
今回はFlannel v0.12.0 の設定を利用します。
$ echo "net.bridge.bridge-nf-call-iptables=1" | sudo tee -a /etc/sysctl.conf
$ sudo sysctl -p
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.12.0/Documentation/kube-flannel.yml
※ あーうん、 net.bridge.bridge-nf-call-iptables=1
がすでに設定されていないかを確認するひつようあるね
上記の実行直後だとそのためのPodが準備されていないので
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-66bff467f8-d4fh5 0/1 Pending 0 2m57s
kube-system coredns-66bff467f8-lqqfz 0/1 Pending 0 2m57s
kube-system etcd-hrus-001 1/1 Running 0 3m5s
kube-system kube-apiserver-hrus-001 1/1 Running 0 3m5s
kube-system kube-controller-manager-hrus-001 1/1 Running 0 3m5s
kube-system kube-flannel-ds-arm-w4r96 0/1 Init:0/1 0 29s
kube-system kube-proxy-wnprf 1/1 Running 0 2m56s
kube-system kube-scheduler-hrus-001 1/1 Running 0 3m5s
少し待ちますと、Podが全部Runningな状態になります。
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-66bff467f8-d4fh5 1/1 Running 0 4m34s
kube-system coredns-66bff467f8-lqqfz 1/1 Running 0 4m34s
kube-system etcd-hrus-001 1/1 Running 0 4m42s
kube-system kube-apiserver-hrus-001 1/1 Running 0 4m42s
kube-system kube-controller-manager-hrus-001 1/1 Running 0 4m42s
kube-system kube-flannel-ds-arm-w4r96 1/1 Running 0 2m6s
kube-system kube-proxy-wnprf 1/1 Running 0 4m33s
kube-system kube-scheduler-hrus-001 1/1 Running 0 4m42s
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
hrus-001 Ready master 5m5s v1.18.2
最終的にSTATUSがReadyになっていれば大丈夫そうです。
controllerとworkerの追加
1台目のcontrollerで kubeadm init
したときに出てきたコマンドをrootで実行すれば良いです。楽ですね。
軽く動作確認
Kubernetes the Hard Wayのスモークテストを一部実行します(暗号化部分の確認はちょっとハードルが高いので kubeadm
を信頼してパスw)
$ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
$ kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-f89759699-j5wpp 1/1 Running 0 2m14s
$ POD_NAME=$(kubectl get pods -l app=nginx -o jsonpath="{.items[0].metadata.name}")
$ echo $POD_NAME
nginx-f89759699-j5wpp
$ kubectl port-forward $POD_NAME 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080
(ホスト内の他のターミナルで)
$ curl --head http://127.0.0.1:8080
HTTP/1.1 200 OK
Server: nginx/1.17.10
Date: Wed, 06 May 2020 10:17:54 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT
Connection: keep-alive
ETag: "5e95c66e-264"
Accept-Ranges: bytes
$ kubectl logs $POD_NAME
127.0.0.1 - - [06/May/2020:10:17:54 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.64.0" "-"
$ kubectl exec -ti $POD_NAME -- nginx -v
nginx version: nginx/1.17.10
チュートリアルおわり。
(参考) kubeadm reset による各環境のリセット
kubeadmではkubeadm init
なりkubeadm join
なりをした後に環境を「ベストエフォートで」元に戻すkubeadm reset
コマンドまで用意されています。すごいね
とはいえ全部やってくれるわけではなく、一部のファイルは残ったりしますので、一応いくらか手を動かす必要はあります。
$ sudo kubeadm reset
[reset] Reading configuration from the cluster...
[reset] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[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] Removing info for node "hrus-002" from the ConfigMap "kubeadm-config" in the "kube-system" Namespace
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
[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]
[reset] Deleting contents of stateful directories: [/var/lib/etcd /var/lib/kubelet /var/lib/dockershim /var/run/kubernetes /var/lib/cni]
The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d
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 by using the "iptables" command.
If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar)
to reset your system's IPVS tables.
The reset process does not clean your kubeconfig files and you must remove them manually.
Please, check the contents of the $HOME/.kube/config file.
$ rm $HOME/.kube/config
$ sudo rm /etc/cni/net.d
$ sudo su
# iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
学び
GCPでのKubernetes the Hard Way, on Vagrant, kubeadm + RasPi3B と3段階で構築を遊んでみました。なんとなく雑感を書いておきます
ホスト構築の面倒臭さは、当たり前ですが GCP << Vagrant << RasPi3B となります。RasPi3Bについては思い立ってから必要な物理的な部品を準備するのも含めてVagrantのさらに倍以上かかっている感じ。調べたり試行錯誤を含めて、GCP版が2〜3時間、on Vagrant版が割り込み等ありつつ1日、RasPi3Bがほぼ2日でした。これらに今後の「運用」の観点はないですが、ハードのトラブル考えるとこれ以上にRasPi3B(もしくはオンプレ構成)は大変でしょうねぇ。
※ ちなみにある種の「心理的安全性」だと Vagrant > RasPi3B >>> GCP です。LBはGCP任せとして、ほとんど空のインスタンスを6台ぶちかますのはホビーとしてはドキドキします。ちなみに200円くらいで済んだようで、「ちゃんと管理さえできれば」単なる杞憂なんですけど。
とはいうものの今回コロナ禍におけるGWに3構成全部試せるくらいの時間しかかかっていない、と考えると、全体としては十分「短い」時間でチュートリアルは終わっています。これは「設計思想とかを把握していればKubernetes自体は単発のインストールに対してとてもシンプル」ということの裏返しかと思います。
今回は「高可用な構成にしてみたかった」というだけでControl Plane 3台ありますが、LBが明らかに脆弱で、クラスタ的には明らかに価値がないです。実践でこうする意味はほとんどないと思います。kubeadm
的には実行するコマンドとケアするポイントが少し変わるので、練習としてはありだとは思いますが……。
当然、Control Plane 1台から3台へ行く時に当然激しい物理構成上のジャンプがあると思います。落ちてもいいよね、っていうサービスならControl Planeは信頼の置けるハードウェア上に1台としておく方がトラブルは少ないでしょうねぇ
遊ぶにしてももう少しやりようはありそうですが、一旦はハードウェア・構成面は以上です。後はソフト面です。
kubadmは「これは自動化できるよなぁ」とthe Hard Wayで思っていた部分を自動化してくれるのがよく分かります。数台規模の小規模構成であれば kubeadm
をつきつめても別に問題ない気がします。
フルスクラッチの場合、自分で規約を決めないと作業過程や中間ファイルが整理されずに乱雑に散らばる、ということになりがちですが、 kubeadm
を介すると概ねそのあたりはケアしてくれるので、他者にとっても見通しの良いインストール構成になるのかなと思います。 kubectl
でクラスタの構成を把握しつつIP割当の台帳とか見つつ後はローカルの設定ファイルをKubernetes及び kubeadm
の流儀で見ていけば概ね状況把握できる印象(セキュリティ的な観点はまた別にあると思いますが、Nodeのホスト類に普通の人が出入りすべきでないのはおそらく普通なので、大丈夫な気もする)
ただ、背後で何が起こるのか、については、the Hard Wayのように手でやるのと比べると格段に複雑になります。特に自動でホストやインターフェースの一意性を判定する、みたいな処理が入るときにMACアドレスの一意性だの product_uuid
の一意性だの、手で心をこめてやるのとは違う制約が導入される感じ。当たり前ですけど
この点は「抽象化レイヤを入れるほどその抽象化レイヤにハマる」ということでもあるのかなと思われました。管理を容易にしようとミドルウェアを入れると、そのミドルウェアが判断に必要なポイント(あるいは故障点)を増やしてハマりポイントが増える。the Hard Wayだと判断ポイントもなにも、基本的には「配線する」レベル感で手で設定するだけなので、PKIとかそういう部分が理解できていればそこまで難しくない。
※ 例外がCNIかなぁ、という印象。CNIは今回のkubeadmでもハマりましたが、the Hard Wayでもそこまで丁寧に説明されておらず手を動かすだけになっていた印象。Pod単位でIP振られるという時点でかなり高度な暗黙の前提(設計)をKubernetesが設定レイヤに要求しているので、ここだけ高度に「物理配線」的でない印象を受けています。私が勉強したら、この問題は改善するかもしれません。
今回、個人的に特に困ったのは以下の点です。
-
product_uuid
がないことをはじめ、それぞれの制約や注意事項の濃淡、つまり「kubeadm
が動作するのか否か」の判断に使える情報が十分でない。 - 暗黙にAMD64アーキテクチャで構築する想定でドキュメントが書かれていて、他のアーキテクチャ、特に今回は事故的にARMv7 (32bits)でどうなるか、というのはcaveatも含めて基本なにも書かれていない
- Podネットワークadd-onの話が途中から登場するのだけど、結構前の段階で意思決定しないとハマる類の選択である。まぁ今回は全部ARMv7のせいかもしれないけど
上記に kubedam reset
の項目があるのは実際にやったからです。とはいえ、kubeadm
はここでもよく出来ていたのでとても良い感じでした。分別がよくついていて、ツールでやるべきこととやるべきでないことをはっきり区別しつつ、出力にそれを書いてくれるのは圧倒的にユーザフレンドリです。
クラスタを構築したとはいえ、これが正しく動作しているのか、自分の意図したとおりに動いているのか、長期間稼働させる際にどこが問題になるのか、といった側面はこれだけではあんまり学べないなぁ、という印象。
ちなみに v1.18.2 の現時点で、例えばReplicaSetで5台nginxを走らせて、その上でそのPodが乗っているWorker Nodeを物理的に電プチしたとします。すると、
$ k get pods
NAME READY STATUS RESTARTS AGE
replicaset-exp-6lb48 1/1 Terminating 0 114m
replicaset-exp-gw4w4 1/1 Running 0 106m
replicaset-exp-hvtsz 1/1 Terminating 0 114m
replicaset-exp-qtvqq 1/1 Running 0 114m
replicaset-exp-w26rf 1/1 Running 0 106m
replicaset-exp-xfsrz 1/1 Running 0 106m
replicaset-exp-zksq6 1/1 Running 0 114m
いつまでたっても Terminating
が消えないんですねぇ。消えないんだ、これ。まぁ、消えないか(他の資料だと Unknown
だったりするんですが、現状のレベルだと違いがわからず)
そもそも電プチ後、Nodeが NotReady
になるまで素朴な期待よりはるかに時間がかかるんですよね。これはデフォルト設定のタイムアウトが結構長いからだそうです。
現状ではクラスタ運用云々だけでなくそもそもGKE等でKubernetesを使い倒したと言えるレベル感でもなくて、ここから先をこの段階で突きつめるのはどうなんかな、と思う状態。一旦ここでやめておきます。
VM系と比較した場合の良い点として(当たり前ですが)ハードの制約に引きづられるのを体感出来るのは、まぁ、良いポイントですかね。RasPi3Bなんだから、64bitsで起動できるよね……なんでこんなままなの。