KubernetesをDual Stackで動かす

Posted on
1215 words, 6 minutes to read
この記事は、最終更新日から 5 年以上経過しています。 情報が古い可能性があります。

KubernetesのIPv4, IPv6共存(いわゆるDual Stack)は、1.16でalphaバージョン(デフォルト無効)としてリリースされており、 1.18でbeta(デフォルト有効)となる見込みです。

また、CNIのCalicoが3.11からDual Stackに対応しています。

そこで、今回はこの構成でDual Stackを構築してみます。

手順、設定の詳細は、巻末の参照ドキュメントも参照ください。

構成

  • masterノード1台、workerノード2台
  • IPv4, IPv6のIPアドレスが各ノードにアサインされている
  • IPv4, IPv6で名前解決ができる

SWバージョン

  • CentOS 7.7.1908
  • Docker 19.03.5
  • Kubernetes 1.17.2
  • Calico 3.11

Docker 設定

Dockerをインストールし、設定していきます。

/etc/docker/daemon.json を修正する際、IPv6に対応する設定を入れておく必要があります。

{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"ipv6": true,
"fixed-cidr-v6": "fd00:1::/64"
}

fixed-cidr-v6 はkubernetes上では使用されないので、書かなくても大丈夫かもしれません。(ちゃんと確認してない、おい)

Kubernetes デプロイ

kubeadmでデプロイしていきます。kubeadmはこちらに沿ってインストールしておきます。 systemctl enable --now kubelet を実行しているところがありますが、この時点では kubelet はまだ起動できないので、 systemctl enable kubelet がよいです。

kubeadm init の引数に、--config <config file> を指定し、クラスターをデプロイします。 ネットワークが不安定な環境の場合、 kubeadm init の実行前に kubeadm config images pull を実行しておくと、予めデプロイに必要なイメージをpullできます。 kubeadm init の実行後は、 network plugin is not ready: cni config uninitialized でnodeは NotReady となるので、次のCalicoのインストールを継続してきます。

以下がコンフィグファイルのサンプルです。ポイントは、

  • ClusterConfigurationfeatureGatesIPv6DualStack を有効化する
  • ClusterConfigurationnetworking.podSubnet でIPv4、IPv6双方のサブネットを記載する
  • ClusterConfigurationnetworking.serviceSubnet でIPv4、IPv6双方のサブネットを記載する
  • KubeProxyConfigurationipvs モードで起動する (kube-proxyをipvsモードで動かすための準備はこちら)
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: <master node ipv4 address>
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: <master node hostname>
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
featureGates:
IPv6DualStack: true
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: v1.17.2
networking:
dnsDomain: cluster.local
podSubnet: "10.244.0.0/16,fd00:2::/48"
serviceSubnet: "10.96.0.0/16,fd00:3::/112"
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs

こちらに書かれている設定の仕方とわりと違うような気がしたのがもやっとポイントでした。 ↑のコンフィグはこちらから拝借しています。

Calico インストール

Calicoのマニュフェストをダウンロードし、IPv6に対応するよう修正し、クラスターに適用します

  • ConfigMapの calico-configipam で、IPv4, IPv6を有効化する
"ipam": {
"type": "calico-ipam",
"assign_ipv4": "true",
"assign_ipv6": "true"
},
  • DaemonSetの calico-node のコンテナの環境変数で以下のように設定する
# Auto-detect the BGP IP address.
- name: IP
value: "autodetect"
- name: IP6
value: "autodetect"
# The default IPv4 pool to create on startup if none exists. Pod IPs will be
# chosen from this range. Changing this value after installation will have
# no effect. This should fall within `--cluster-cidr`.
- name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/16"
- name: CALICO_IPV6POOL_CIDR
value: "fd00:2::/48"
# Enable IPv6 on Kubernetes.
- name: FELIX_IPV6SUPPORT
value: "true"

動作確認

Validate IPv4/IPv6 dual-stack に沿って確認をしていくと、 .status.addresses だけ、IPv4のアドレスしか付きませんでした。

最終的に、起動したクラスターで、nginxのアプリケーションを起動した様子です。 (officialのnginxのイメージはIPv6をListenしていなかったので、Listenするイメージを準備しました。。)

[root@k8s-master01 ~]# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/my-nginx-94c87cdcd-88hzq 1/1 Running 0 60m
pod/my-nginx-94c87cdcd-c6np8 1/1 Running 0 60m
pod/my-nginx-94c87cdcd-xlqfd 1/1 Running 0 60m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 149m
service/my-nginx-svc-ipv4 ClusterIP 10.96.48.15 192.168.200.145 80/TCP 60m
service/my-nginx-svc-ipv6 ClusterIP fd00:3::5068 2000:db1::120 80/TCP 60m
service/my-nginx-svc-ipv6-local LoadBalancer fd00:3::1ff3 2000:db1::121 80:32405/TCP 58m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/my-nginx 3/3 3 3 60m
NAME DESIRED CURRENT READY AGE
replicaset.apps/my-nginx-94c87cdcd 3 3 3 60m

service/my-nginx-svc-ipv4, service/my-nginx-svc-ipv6ExternalIP でIPを割り当てています。 service/my-nginx-svc-ipv6-localMetalLB を使っています。 MetalLBで .spec.isFamily によって IPv4 か IPv6 かを割り当ててほしかったのですが、それはできなそうでした。

ノード上で ipvsadm -ln を実行すると、ipvsモードでのルーティングの状況が確認できます。(ipvsadmコマンドはパッケージマネージャでインストールしておいてください)

デフォルトでは、外部からのアクセスはNATされますが、 Service を作成する際、 externalTrafficPolicy: Local を指定したりなどすると、 外部のIPを維持できます。

その他

参照

このBlogの内容は個人の意見に基づくものであり、 所属組織団体の公式見解とは異なる場合があります点、ご了承ください。