🍣

IPv4/IPv6 Dual stack な Kubernetes 1.26 クラスターを kubeadm で作った

2023/01/06に公開

kubeadm で Kubernetes クラスターを作るための下準備を Ansible でまとめてみた の続きです。

kubeadm のコンフィグを用意する

Dual-stack support with kubeadm のドキュメントの流れに従ってシンプルにやってみました。

kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
networking:
  podSubnet: 172.24.0.0/16,fd8e:a2c3:ca45::/64
  serviceSubnet: 172.25.0.0/16,fd8e:a2c3:ca45:feed::/112

IPv6 のアドレス空間は ULA Prefix を IPv6のUnique Local Addressを生成する のページの手順に従って実際のネットワークインターフェースの MAC アドレスから生成したものを使っています。
serviceSubnet の CIDR はホストアドレス部が 20 bit が上限になるので注意して下さい。(コンフィグ例だと IPv4 も IPv6 もどっちも 16 bit になるように揃えています)

また IPv6 Only stack だと API Endpoint も IPv6 に揃えたりしてますが、Dual stack で既存のツール群が IPv4 前提だったりするものが多いので、いったんはデフォルトの IPv4 アドレスを使い回しするような感じにしてます。

kubeadm init でコントロールプレーンを起動する

先ほど作製したコンフィグファイルを元に kubeadm でクラスターを初期化します。

$ sudo kubeadm init --config kubeadm-config.yaml

クラスターの初期化が終わったら表示されるメッセージに従って .kube/config を設定しておきます。

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

Calico をデプロイする

CNI として Calico をデプロイします。Flannel 等もありますが、自分が慣れているので。。。

まずは Calico の Manifest をダウンロードしてきます。

$ curl -O  https://raw.githubusercontent.com/projectcalico/calico/v3.24.5/manifests/calico.yaml

次に Dual stack にするために IPv6 関連の設定を追記しています。
ref. Configure dual stack or IPv6 only

--- calico.yaml.orig    2023-01-05 08:32:04.773243390 +0000
+++ calico.yaml 2023-01-05 11:02:01.860067201 +0000
@@ -62,7 +62,9 @@
           "nodename": "__KUBERNETES_NODE_NAME__",
           "mtu": __CNI_MTU__,
           "ipam": {
-              "type": "calico-ipam"
+              "type": "calico-ipam",
+              "assign_ipv4": "true",
+              "assign_ipv6": "true"
           },
           "policy": {
               "type": "k8s"
@@ -4518,6 +4520,14 @@
             # Auto-detect the BGP IP address.
             - name: IP
               value: "autodetect"
+            - name: IP_AUTODETECTION_METHOD
+              value: "cidr=192.168.XXX.0/24"
+            - name: IP6
+              value: "autodetect"
+            - name: IP6_AUTODETECTION_METHOD
+              value: "cidr=XXXX:XXX:XXXX:XXXX::/64"
+            - name: CALICO_IPV6POOL_NAT_OUTGOING
+              value: "true"
             # Enable IPIP
             - name: CALICO_IPV4POOL_IPIP
               value: "Always"
@@ -4558,7 +4568,7 @@
               value: "ACCEPT"
             # Disable IPv6 on Kubernetes.
             - name: FELIX_IPV6SUPPORT
-              value: "false"
+              value: "true"
             - name: FELIX_HEALTHENABLED
               value: "true"
           securityContext:

重要なのは CALICO_IPV6POOL_NAT_OUTGOING = true です。この設定がないと Pod が持っている IPv6 アドレスのまま外向き通信 (Egress) が流れてしまって BGP でルーティング可能でないネットワークの場合は通信に失敗します。そのため、この NAT 設定をすることでホストが持っている IPv6 アドレスでクラスターの外に出て行くようになります。

ファイルを保存したあとに kubectl で Calico をデプロイしていきます。

$ kubectl apply -f calico.yaml

ワーカーノードを参加させる

ワーカーノードの参加用コマンドは kubeadm コマンドの実行後のメッセージも表示されていますが時間が経ったりしたときは以下のようにして再表示することが出来ます。

$ kubeadm token create --print-join-command

Pod に IPv4 だけでなく IPv6 のアドレスが付いたことを確認する

試しに Ubuntu コンテナを作ってみます。

ubuntu.yml
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
    - name: ubuntu
      image: ubuntu
      command: [ 'sleep', 'infinity' ]
$ kubectl apply -f ubuntu.yml

$ kubectl get pod -o wide
NAME     READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
ubuntu   1/1     Running   0          60m   172.24.2.130   dsk8snode1   <none>           <none>

$ kubectl get pod ubuntu -o json | jq .status.podIPs
[
  {
    "ip": "172.24.2.130"
  },
  {
    "ip": "fd8e:a2c3:ca45:0:f4ee:f9a1:1545:9a41"
  }
]

ちゃんと IPv4 + IPv6 のアドレスが付与されています。

試しに Pod の中に入って外向き通信をテストしてみます。

$ kubectl exec -it ubuntu -- bash
root@ubuntu:/# curl -4 ifconfig.io
XX.XX.93.205
root@ubuntu:/# curl -6 ifconfig.io
XXXX:XXX:XXXX:XXXX:215:5dff:fe01:ed05

ちゃんと Internet と IPv4 + IPv6 で通信できています。ヽ(^。^)丿

Discussion