k3sからkubeadmへの移行
はじめに
自宅サーバーをk3sで運用したのですが、色々設定をいじりたいときに制約が多く、今後拡張していきたいときにデータをdropせずにkubeadmに移行するのが難しくなってくると思うので、早い段階での移行を行います。備忘録です。
構成はMaster Node x 1 + Worker Node x 2 です。
サーバーダウン
今回は自宅サーバーなので移行の間はサーバーを止めることとします。
バックアップ
まずk3sを止めます。
sudo systemctl stop k3s
次にSQLiteのBackUpを取ります。
sudo cp -a /var/lib/rancher/k3s/server/db/state.db "$BACKUP_DIR"/ 2>/dev/null || true
sudo cp -a /var/lib/rancher/k3s/server/cred "$BACKUP_DIR"/ 2>/dev/null || true
sudo cp -a /var/lib/rancher/k3s/server/manifests "$BACKUP_DIR"/ 2>/dev/null || true
sudo cp -a /etc/rancher/k3s "$BACKUP_DIR"/ 2>/dev/null || true
次にlonghornのbackupを取ります。UIのBackupから行います。
一応GitOpsから漏れているmanifestを残しておきます。
kubectl get all,cm,secret,ingress,svc,pv,pvc,crd --all-namespaces -o yaml > ~/backup/k3s-all.yaml
k3sのuninstall
master, workerともに消し去ります。
master
sudo /usr/local/bin/k3s-uninstall.sh
worker
sudo /usr/local/bin/k3s-agent-uninstall.sh
kubeadmのsetup
ここからは一般的なkubeadmセットアップ作業です。
swapの無効化とブリッジ経由のトラフィックも iptables のルールが適用されるようにします。
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
コンテナランタイム
containerdにしました。cri-oと悩みましたが、今後dockerを立てる可能性もないことはないのでcontainerdでいいかと思いました。本質的にはほとんど差がない認識です。
sudo apt install -y containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl enable --now containerd
kubeadm
version 1.34
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/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.34/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
masterを初期化
sudo kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12 \
--control-plane-endpoint=k8s-master \
--upload-certs
ここでcontainerdのversion古かったので上げました。criも有効化しました。
workerをjoin
kubeadm join k8s-master:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
ciliumをinstall
nodeがNotReadyだったので、NotReadyにも降られるようにします。
ciliumがkubeproxyを置き換えてエラーになったので置き換えないようにします。
curl -L https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz -o cilium.tgz
sudo tar xzf cilium.tgz -C /usr/local/bin
cilium install --version v1.18.2 \
--set tolerateUnready=true \
--set nodeinit.enabled=true \
--set kubeProxyReplacement=false \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--set cni.binPath=/opt/cni/bin \
--set cni.confPath=/etc/cni/net.d \
--set cni.exclusive=true
このタイミングでworkerの4244がport開けていなかったため開けた
sudo ufw allow proto tcp from 10.0.0.0/8 to any port 4244
❯ kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 18h v1.34.1
newpi1 Ready <none> 9h v1.34.1
newpi2 Ready <none> 9h v1.34.1
❯ cilium status
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Envoy DaemonSet: OK
\__/¯¯\__/ Hubble Relay: OK
\__/ ClusterMesh: disabled
DaemonSet cilium Desired: 3, Ready: 3/3, Available: 3/3
DaemonSet cilium-envoy Desired: 3, Ready: 3/3, Available: 3/3
Deployment cilium-operator Desired: 1, Ready: 1/1, Available: 1/1
Deployment hubble-relay Desired: 1, Ready: 1/1, Available: 1/1
Deployment hubble-ui Desired: 1, Ready: 1/1, Available: 1/1
Containers: cilium Running: 3
cilium-envoy Running: 3
cilium-operator Running: 1
clustermesh-apiserver
hubble-relay Running: 1
hubble-ui Running: 1
Cluster Pods: 4/4 managed by Cilium
その後kubeproxyをclium管理にする。k8sServiceHost, k8sServicePortを明示化しておきます。
cilium upgrade --version v1.18.2 \
--set kubeProxyReplacement=true \
--set socketLB.enabled=true \
--set bpf.masquerade=true \
--set k8sServiceHost={{.IP}} \
--set k8sServicePort=6443
疎通テストをしておきます
cilium connectivity test
/healthで4240をworker, master側で開けてなくて落ちたので開けた。
sudo ufw allow from 10.0.0.0/8 to any port 4240 proto tcp
MetalLB
MetalLBを入れます。基本的にCloudflared(Cloudflare Tunnel)+ Traefik で TLS 終端するので、type: LoadBalancerを作成する予定はないですが、一応入れておきます。
と、思いましたがCiliumにはMetalLBと同じ機能を持ったものが存在するようです。
Cilium L2 Announcement
l2announcementsを有効化します。
cilium upgrade \
--version 1.18.2 \
--set l2announcements.enabled=true \
--set kubeProxyReplacement=true \
--set k8sClientRateLimit.qps=20 \
--set k8sClientRateLimit.burst=40
apiVersion: cilium.io/v2alpha1
kind: CiliumL2AnnouncementPolicy
metadata:
name: l2-announce-home
spec:
serviceSelector:
matchLabels:
expose: "lb"
nodeSelector:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: DoesNotExist
interfaces:
- ^eth[0-9]+$
- ^en[a-z0-9]+$
loadBalancerIPs: true
externalIPs: false
apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
name: "ip-pool"
spec:
blocks:
- start: "192.168.1.170"
stop: "192.168.1.255"
Traefik
Traefikの選定理由ですがk3sが標準で使用したいたので、ingressの置き換えが楽というのが一番です。一応比較などはあるようです。 helmを使用します。
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm upgrade --install traefik traefik/traefik -n traefik -f values.yaml
cloudflared
すでにあるtunnnelからtokenを引っ張ってきてsecretに詰めます。sopsで暗号化してGit管理します。
sops -e -i cloudflared/secret.yaml
あとは既存のconfig, deploymentをapplyします。
argo cd
作成済みのhelmを使用します。
k3sだとtraefikがkube-systemのnamaspaceに作られるために前のcloudflaredのconfigだとうまくいきませんでした。
http://traefik.kube-system.svc.cluster.local:80
↓
http://traefik.traefik.svc.cluster.local:80
無事に疎通しました。めでたし。

longhorn
前のhelmを使います。k3sの時と同じback up targetを使用します。
helm upgrade --install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace -f=values.yaml
Discussion