目的
K8s cluster構築には kubeadm を用いるが、以下要件がある。
- 次のいずれかが動作しているマシンが必要です
- Ubuntu 16.04+
- Debian 9+
- CentOS 7
- Red Hat Enterprise Linux (RHEL) 7
- Fedora 25+
- HypriotOS v1.0.1+
- Container Linux (tested with 1800.6.0)
- 1台あたり2GB以上のメモリ(2GBの場合、アプリ用のスペースはほとんどありません)
- 2コア以上のCPU
- クラスター内のすべてのマシン間で通信可能なネットワーク(パブリックネットワークでもプライベートネットワークでも構いません)
- ユニークなhostname、MACアドレス、とproduct_uuidが各ノードに必要です。詳細はここを参照してください。
- マシン内の特定のポートが開いていること。詳細はここを参照してください。
- Swapがオフであること。kubeletが正常に動作するためにはswapは必ずオフでなければなりません。
CentOS 後継の RockyLinux は 8以上からがリリースされており、且つ PowerPC系(ここではPower9(ppc64le)を対象とする)のサポートは RockyLinux 9 以上が必要。
kubeadm標準ではサポート対象外だが、導入した際の手順・注意事項などをここに記す。
事前準備
RockyLinux 9特有のことは無い。
swap off
一時的には以下のようにする。
$ sudo swapoff -a
恒久的には /etc/fstab 上の swap マウント箇所をコメントアウトすればよい。
$ vi /etc/fstab
# xxxxx none swap defaults 0 0
swap off になっているかは以下で確認できる。
$ cat /proc/swaps
空っぽなら swap off 状態になっている。
port有効化
以下のポートを有効にしておく必要がある。
https://kubernetes.io/ja/docs/reference/networking/ports-and-protocols/
- コントロールプレーン
プロトコル | 通信の向き | ポート範囲 | 目的 | 使用者 |
---|---|---|---|---|
TCP | Inbound | 6443 | Kubernetes | API |
TCP | Inbound | 2379-2380 | etcd | server |
TCP | Inbound | 10250 | Kubelet | API |
TCP | Inbound | 10259 | kube-scheduler | 自身 |
TCP | Inbound | 10257 | kube-controller-manager | 自身 |
- ワーカーノード
プロトコル | 通信の向き | ポート範囲 | 目的 | 使用者 |
---|---|---|---|---|
TCP | Inbound | 10250 | Kubelet API | 自身, コントロールプレーン |
TCP | Inbound | 30000-32767 | NodePort Services† | 全て |
control-plane にする場合は以下でポートを有効にする。
$ sudo firewall-cmd --zone=public --add-port 6443/tcp --add-port 2379-2380/tcp --add-port 10250/tcp --add-port 10259/tcp --add-port 10257/tcp --add-port 30000-32767/tcp --permanent
$ sudo firewall-cmd --reload
Installing a container runtime
Enable IPv4 packet forwarding
# sysctl params required by setup, params persist across reboots
$ cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF
# Apply sysctl params without reboot
$ sudo sysctl --system
Disable IPv6
$ cat <<EOF | sudo tee /etc/sysctl.d/disable_ipv6.conf
net.ipv4.ip_forward = 1
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
EOF
# Apply sysctl params without reboot
$ sudo sysctl --system
build and install cri-dockerd
docker を使うため、cri-dockerd をインストールする。
https://github.com/Mirantis/cri-dockerd/releases
に対応するパッケージがあるが、PowerPC用のものが提供されてないのでビルドするしかない。
$ git clone https://github.com/Mirantis/cri-dockerd
$ cd cri-dockerd
$ git checkout v0.3.13
$ make cri-dockerd
https://mirantis.github.io/cri-dockerd/usage/install-manually/
に従ってcri-dockerd サービスを設定する。
$ sudo install -o root -g root -m 0755 cri-dockerd /usr/local/bin/cri-dockerd
$ sudo install packaging/systemd/* /etc/systemd/system
$ sudo sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.service
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now cri-docker.socket
$ sudo systemctl start cri-docker.socket
install kubeadm, kubelet, kubectl
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
に従って行う。
add kubernatis yum repository
# This overwrites any existing configuration in /etc/yum.repos.d/kubernetes.repo
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.30/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.30/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF
install kubelet, kubeadm and kubectl
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
(Optional) Enable the kubelet service before running kubeadm:
sudo systemctl enable --now kubelet
Configuring a cgroup driver
https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/
によれば 'systemd' driver を推奨するとあり、かつ 1.22 以降では 'systemd' driverがデフォルトになっているとあるため、何もしない。
Creating a cluster
Network setup
各ノードに以下要件を満たしていること。
- default route が設定されていること
- ノード間で唯一のIPで通信しあえること
Initializing control-plane node
initialize control-plane single node
kubeadm で初期化実行。
- control-plane-endpoint に DNSラウンドロビンアドレスを指定 (→ k8s-cluster とする)
- cri-socket には cri-docker を指定
- pod-network-cidr は 10.244.0.0/16 とする
- service-cluster-ip-range のデフォルトが 10.96.0.0/12 のためoverlapしないようにする
- network add-in に flannel を選択したが、そのデフォルト値が 10.244.0.0/16 となっており、変更しても何故か反映されない(多分、flannel のバグ)ため、デフォルト値に従う。
- HA availability のために upload-certs を指定
$ sudo -E kubeadm init \
--control-plane-endpoint k8s-cluster \
--cri-socket unix:///var/run/cri-dockerd.sock \
--pod-network-cidr 10.244.0.0/16 \
--upload-certs
以下のようなメッセージが出ればクラスタ構築成功。
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
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
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/
失敗した場合、いくつかのコンテナが動作した状態になっているので、'kubeadm reset' を実行して一旦リセットする。
cri-socket の指定も忘れずに。
$ sudo -E kubeadm reset --cri-socket unix:///var/run/cri-dockerd.sock
add control-plane node
`kubeadm init --upload-certs' とした場合、以下のようなメッセージが出る。
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join k8s-cluster:6443 --token XXXXXXXXXXXXXXXXXXX \
--discovery-token-ca-cert-hash sha256:YYYYYYYYYYYYYYYYYYYYYY \
--control-plane --certificate-key ZZZZZZZZZZZZZZZZZZ
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 k8s-cluster:6443 --token XXXXXXXXXXXXXXXXXXXX \
--discovery-token-ca-cert-hash sha256:YYYYYYYYYYYYYYYYYYYYYY
要するに、認証鍵が 2h間有効になっているため、その間に control-plane node を kubeadm join で追加せよ、といこと。
2h 過ぎた場合は、鍵を再生成するよう kubeadm init phase upload-certs --upload-certs
を実行すればよい。
$ sudo kubeadm init phase upload-certs --upload-certs
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
ZZZZZZZZZZZZZZZZZZZZ
ノード追加用トークンの再生成は以下。
$ kubeadm token create --print-join-command
kubeadm join k8s-cluster:6443 --token XXXXXXXXXXXXXXXX --discovery-token-ca-cert-hash sha256:YYYYYYYYYYYYYYYYYYYYYY
追加ノードを control-plane にしたい場合は鍵再生成結果を --certificate-key に指定する。
cri-docker 指定も忘れずに。
$ sudo kubeadm join k8s-cluster:6443 \
--token XXXXXXXXXXXXXXXXX --discovery-token-ca-cert-hash sha256:YYYYYYYYYYYYYYYYYYYY \
--certificate-key ZZZZZZZZZZZZZZZZZZZZZ \
--cri-socket unix:///var/run/cri-dockerd.sock \
--control-plane
add worker node to cluster
control-plane でないworkerノードを追加する場合は --control-plane
の部分を抜けばよい。
$ sudo kubeadm join k8s-cluster:6443 \
--token XXXXXXXXXXXXXXXXX --discovery-token-ca-cert-hash sha256:YYYYYYYYYYYYYYYYYYYY \
--certificate-key ZZZZZZZZZZZZZZZZZZZZZ \
--cri-socket unix:///var/run/cri-dockerd.sock
delete node
ノードの削除方法は以下のように drain して関連daemonsets を消してから delete node する。
$ kubectl drain [node-name] --ignore-daemonsets --delete-emptydir-data
$ kubectl delete node [node-name]
docker credential情報を使用する
docker loginしたときの認証情報をk8sにも適用したいとき。
$ kubectl create secret generic regcred \
--from-file=.dockerconfigjson=$HOME/.docker/config.json \
--type=kubernetes.io/dockerconfigjson
匿名で使う場合は pull 回数に制限があるため、認証することで回避
Installing a Pod network add-on
k8s pod 内のネットワークをどのように管理するかのポリシー的なアルゴリズムを入れる必要がある。
から選べるとあるが、PowerPCの場合は Flannel 一択。
Flannel
マニフェストを適用すればインストールできる。
$ kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
flannelのデフォルト設定では CIDR 割当範囲が 10.244.0.0/16 となっているが、変更するには yaml ファイルをダウンロードしてから編集して適用する
$ wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
$ vi kube-flannel.yml
...
net-conf.json: |
{
"Network": "192.168.49.0/24",
"Backend": {
"Type": "vxlan"
}
}
...
## 編集したflannelを適用。
$ kubectl apply -f kube-flannel.yml
firewall configuration
flannel はバックエンドとして VXLAN を用いるが、特定の UDPポートをノード間の通信に使用する。
https://github.com/flannel-io/flannel/blob/master/Documentation/backends.md
Linuxの場合は 8472/UDP を用いるため、各ノードで許可しておく。
$ sudo firewall-cmd --permanent --zone=public --add-port=8472/udp
$ sudo firewall-cmd --reload
Calico
一般的には Calico の利用率が高いらしいが、残念ながら PowerPC 系には対応していない。
具体的には calico/node-driver-registrarというコンテナ が platform linux/ppc64le を提供しているにも関わらず "exec format error" で動かない。
なんじゃそりゃー (ノ`Д´)ノ彡┻━┻
(後日談)
どうやら PowerPC 未対応なのは release-3.27 以前の模様。
現在 3.29 までがリリースされているが、3.28 以降であれば exec format error にならないため動きそう。
が、今更に移行する気は無いので保留。
local-path dynamic volume provisioner
local path はdynamic provisioning に対応していないため、都度割り当てる必要がある。
Local volumes do not support dynamic provisioning in Kubernetes 1.30; however a StorageClass should still be created to delay volume binding until a Pod is actually scheduled to the appropriate node. This is specified by the WaitForFirstConsumer volume binding mode.
local path の dynamic provisioning の対応例に以下のものがある。
https://github.com/rancher/local-path-provisioner
だが、残念ながら PowerPC系には対応していない。
PowerPCを除外して適用するには以下のようにする。
$ wget https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.26/deploy/local-path-storage.yaml
$ vi local-path-storage.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: local-path-provisioner
namespace: local-path-storage
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "kubernetes.io/arch"
operator: In
values: ["amd64", "arm64"]
...
firewall backend の変更
istioやflannelではPod間の通信制御に iptables を使用するが、RHEL9 では iptables が deprecated になり nftables に移行した。
ipset and iptables-nft have been deprecated
The ipset and iptables-nft packages have been deprecated in RHEL. The iptables-nft package contains different tools such as iptables, ip6tables, ebtables and arptables. These tools will no longer receive new features and using them for new deployments is not recommended. As a replacement, prefer using the nft command-line tool provided by the nftables package. Existing setups should migrate to nft if possible.
この仕様変更により、RockyLinux 9 では pod間の通信ができなくなってしまっている。
本来なら K8s がiptablesでなく nftables に対応してほしいところだが、従来の iptables で制御することを許可すれば当座はしのげる。
バックエンドを iptables に変更
/etc/firewalld/firewalld.conf
:
#FirewallBackend=nftables
FirewallBackend=iptables
以下で適用。
$ sudo systemctl restart firewalld
$ sudo firewall-cmd --reload
iptables rule順序変更
backend を iptables に変更しても、iptables チェインが以下のようになる場合がある。
$ sudo iptables -L FORWARD --line-number
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
1 KUBE-PROXY-FIREWALL all -- anywhere anywhere ctstate NEW /* kubernetes load balancer firewall */
2 KUBE-FORWARD all -- anywhere anywhere /* kubernetes forwarding rules */
3 KUBE-SERVICES all -- anywhere anywhere ctstate NEW /* kubernetes service portals */
...
17 FORWARD_direct all -- anywhere anywhere
18 FORWARD_ZONES all -- anywhere anywhere
19 DROP all -- anywhere anywhere ctstate INVALID
20 REJECT all -- anywhere anywhere reject-with icmp-host-prohibited
21 FLANNEL-FWD all -- anywhere anywhere /* flanneld forward */
21番目にある FLANNEL-FWD ルールが REJECT より後にあるため、当該ノードへの通信が遮断されてしまう。
このルールを上に上げる必要があるが、FORWARD_ZONES内の FWD_public ルール内でREJECTしているため、それより上にする必要がある。
$ sudo iptables -L FORWARD_ZONES --line-number
# Warning: iptables-legacy tables present, use iptables-legacy to see them
Chain FORWARD_ZONES (1 references)
num target prot opt source destination
1 FWD_docker all -- anywhere anywhere [goto]
2 FWD_docker all -- anywhere anywhere [goto]
3 FWD_public all -- anywhere anywhere [goto]
4 FWD_public all -- anywhere anywhere [goto]
5 FWD_public all -- anywhere anywhere [goto]
6 FWD_public all -- anywhere anywhere [goto]
$ sudo iptables -L FWD_public --line-number
# Warning: iptables-legacy tables present, use iptables-legacy to see them
Chain FWD_public (4 references)
num target prot opt source destination
1 FORWARD_POLICIES_pre all -- anywhere anywhere
2 FWD_public_pre all -- anywhere anywhere
3 FWD_public_log all -- anywhere anywhere
4 FWD_public_deny all -- anywhere anywhere
5 FWD_public_allow all -- anywhere anywhere
6 FWD_public_post all -- anywhere anywhere
7 FORWARD_POLICIES_post all -- anywhere anywhere
8 REJECT all -- anywhere anywhere reject-with icmp-port-unreachable
上記例では FORWARD チェイン内 18番目に FORWARD_ZONES があるため、FLANNEL-FWD ルールをそれより上になるようにすればよい。
### FLANNEL-FWD ルール を No.18 に挿入
$ sudo iptables -I FORWARD 18 -j FLANNEL-FWD
当然ながら、iptables ルールが更新されるとルールも刷新されるため、この対処は "都度" 必要になる。
### iptables が更新される
$ sudo firewall-cmd --reload
そもそも RHEL9 では前述のとおり iptables による制御は deprecated のため暫定的であるべきである。