KubernetesをDual Stackで動かす
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 設定
/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のインストールを継続してきます。
以下がコンフィグファイルのサンプルです。ポイントは、
ClusterConfigurationのfeatureGatesでIPv6DualStackを有効化するClusterConfigurationのnetworking.podSubnetでIPv4、IPv6双方のサブネットを記載するClusterConfigurationのnetworking.serviceSubnetでIPv4、IPv6双方のサブネットを記載するKubeProxyConfigurationをipvsモードで起動する (kube-proxyをipvsモードで動かすための準備はこちら)
apiVersion: kubeadm.k8s.io/v1beta2bootstrapTokens: - groups: - system:bootstrappers:kubeadm:default-node-token token: abcdef.0123456789abcdef ttl: 24h0m0s usages: - signing - authenticationkind: InitConfigurationlocalAPIEndpoint: advertiseAddress: <master node ipv4 address> bindPort: 6443nodeRegistration: criSocket: /var/run/dockershim.sock name: <master node hostname> taints: - effect: NoSchedule key: node-role.kubernetes.io/master---apiServer: timeoutForControlPlane: 4m0sapiVersion: kubeadm.k8s.io/v1beta2certificatesDir: /etc/kubernetes/pkiclusterName: kubernetescontrollerManager: {}dns: type: CoreDNSetcd: local: dataDir: /var/lib/etcdfeatureGates: IPv6DualStack: trueimageRepository: k8s.gcr.iokind: ClusterConfigurationkubernetesVersion: v1.17.2networking: 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/v1alpha1kind: KubeProxyConfigurationmode: ipvsこちらに書かれている設定の仕方とわりと違うような気がしたのがもやっとポイントでした。 ↑のコンフィグはこちらから拝借しています。
Calico インストール
Calicoのマニュフェストをダウンロードし、IPv6に対応するよう修正し、クラスターに適用します
- ConfigMapの
calico-configのipamで、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 allNAME READY STATUS RESTARTS AGEpod/my-nginx-94c87cdcd-88hzq 1/1 Running 0 60mpod/my-nginx-94c87cdcd-c6np8 1/1 Running 0 60mpod/my-nginx-94c87cdcd-xlqfd 1/1 Running 0 60m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEservice/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 149mservice/my-nginx-svc-ipv4 ClusterIP 10.96.48.15 192.168.200.145 80/TCP 60mservice/my-nginx-svc-ipv6 ClusterIP fd00:3::5068 2000:db1::120 80/TCP 60mservice/my-nginx-svc-ipv6-local LoadBalancer fd00:3::1ff3 2000:db1::121 80:32405/TCP 58m
NAME READY UP-TO-DATE AVAILABLE AGEdeployment.apps/my-nginx 3/3 3 3 60m
NAME DESIRED CURRENT READY AGEreplicaset.apps/my-nginx-94c87cdcd 3 3 3 60mservice/my-nginx-svc-ipv4, service/my-nginx-svc-ipv6 は ExternalIP でIPを割り当てています。
service/my-nginx-svc-ipv6-local は MetalLB を使っています。
MetalLBで .spec.isFamily によって IPv4 か IPv6 かを割り当ててほしかったのですが、それはできなそうでした。
ノード上で ipvsadm -ln を実行すると、ipvsモードでのルーティングの状況が確認できます。(ipvsadmコマンドはパッケージマネージャでインストールしておいてください)
デフォルトでは、外部からのアクセスはNATされますが、 Service を作成する際、 externalTrafficPolicy: Local を指定したりなどすると、
外部のIPを維持できます。
その他
- 既存のIPv4 Onlyのクラスターを設定変更して、Dual Stack対応にするのは現状できないようです。(できるようにするためのエンハンスメントリクエストが出ているようです)
- IPv6 Only/Dual Stack 環境のサポートは 1.18 で alpha(デフォルト無効) から beta(デフォルト有効) となる見込みです。
参照
- CRIのインストール
- IPv6 with Docker
- kubeadmのインストール
- kubeadmを使用したシングルマスタークラスターの作成
- Run kube-proxy in IPVS mode
- IPVSプロキシーモード
- Enable dual stack
- IPv4/IPv6 dual-stack
- Validate IPv4/IPv6 dual-stack
- IPVS-Based In-Cluster Load Balancing Deep Dive
- RFE: kubeadm operator
- MetalLB
- IPv6 support added
- Add IPv4/IPv6 dual-stack support