🐮

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を作成する予定はないですが、一応入れておきます。
https://metallb.universe.tf/installation/

と、思いましたがCiliumにはMetalLBと同じ機能を持ったものが存在するようです。
https://sreake.com/blog/learn-about-cilium-l2-announcement/

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の置き換えが楽というのが一番です。一応比較などはあるようです。
https://www.pomerium.com/blog/best-ingress-controllers-for-kubernetes
helmを使用します。
https://doc.traefik.io/traefik/getting-started/install-traefik/

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管理します。
https://zenn.dev/pkkudo/articles/gitops-secret-enc-using-sops

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