この記事は デジタル創作サークル UniProject Advent Calendar 2025 および Kubernetes Advent Calendar 2025 18 日目の記事です。
はじめに
つい先日、Cilium に大きな新機能が登場しました。
まさかの、IPv6 外部広告が NDP に対応したのです。
弊サークルに限らず、IPv6 で外部に広告できることを望んでいた方はとても多かったはずです。
しかし、従来は BGP+ を使う他なく、それに対応した機器となると、とても高価で我々のようなサークルには手が出せませんでした。
今回 L2 に対応したということで、早速試していきたいと思います。
この記事では、Cilium の Preview 版を使用します。
前提
この環境は、以下のような構成で構築されています。
- Ubuntu 24
- CRI-O 1.34.3
- Kubeadm で構築した K8s v1.34.3
- IPv6 DualStack の構成は K8s のドキュメント通り行っているものとします
準備
まずは、IPv6 を広告するにあたって、パケット転送などを有効化します。
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv6.conf.default.forwarding = 1
net.ipv6.conf.all.forwarding = 1
設定を反映します。
sudo sysctl -p
kube-proxy を消し去る
Cilium で外部 IP を広告する場合、kube-proxy を置き換える必要があります。
まずは、DaemonSet を削除します。
kubectl -n kube-system delete ds kube-proxy
# Delete the configmap as well to avoid kube-proxy being reinstalled during a Kubeadm upgrade
kubectl -n kube-system delete cm kube-proxy
また、すべてのノードで下記コマンドを実行して、iptables に残ったデータを抹消します。
# Run on each node with root permissions:
iptables-save | grep -v KUBE | iptables-restore
この段階で、すべてのノードが NotReady になりますが、この後の Cilium のインストールで Ready に戻るので問題ありません。
Cilium のインストール
Cilium は helm でインストールしていきます。
まず、helm repo の追加をしましょう。
helm repo add cilium https://helm.cilium.io/
helm で使用する values.yaml は以下の通りに記述しましょう。
cluster:
name: kubernetes
externalIPs:
enabled: true
# Kube API サーバーの IP を指定する
# 今回は HA 構成なので、ロードバランサーの IP を指定した
k8sServiceHost: 172.16.110.100
k8sServicePort: 6443
kubeProxyReplacement: true
l2announcements:
enabled: true
operator:
replicas: 1
routingMode: tunnel
tunnelProtocol: vxlan
ipv6:
enabled: true
l2NeighDiscovery:
enabled: true
さて、インストールしていきましょう。
まだ Preview 版でのみ配信されている機能なので、1.19.0-pre.3 を指定します。
sudo helm upgrade --install cilium cilium/cilium \
-n kube-system -f values.yaml \
--version 1.19.0-pre.3
確認してみる
Cilium CLI を使って確認しましょう。
Cilium CLI のインストールはこちらを確認してください。
この記事では割愛します。
cilium status --wait
以下のように、Cilium: OKなどとなっていれば OK です。
/¯¯\
/¯¯\__/¯¯\ 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: 35/35 managed by Cilium
Helm chart version: 1.19.0-pre.3
Image versions cilium quay.io/cilium/cilium:v1.19.0-pre.3@sha256:9ba932dcafcb30f44ae4835edb83081423ae4139b2a8e8b8c7245f47a60de925: 3
cilium-envoy quay.io/cilium/cilium-envoy:v1.35.3-1764238404-a890eb288598920fc146308ef4b05004f2ee7bcf@sha256:5a5403c2847af60352f2ae0c69642b0484b741a8ca5c15b34737e10553c64e08: 3
cilium-operator quay.io/cilium/operator-generic:v1.19.0-pre.3@sha256:c2796566b40cfdc4b59cc1d460d91b86436ded0b447ef82d4e3663f745db6671: 1
hubble-relay quay.io/cilium/hubble-relay:v1.19.0-pre.3@sha256:6771ceb69dbe96e91950c474b146e3e9dc74c64340b6a87dea28be20ed6566fc: 1
hubble-ui quay.io/cilium/hubble-ui-backend:v0.13.3@sha256:db1454e45dc39ca41fbf7cad31eec95d99e5b9949c39daaad0fa81ef29d56953: 1
hubble-ui quay.io/cilium/hubble-ui:v0.13.3@sha256:661d5de7050182d495c6497ff0b007a7a1e379648e60830dd68c4d78ae21761d: 1
L2 Announce Policy を追加する
これは、Cilium がどのインターフェースを使って広告するかを設定するものです。
今回は以下のように設定しました。
コントロールプレーン外から広告したい場合は、nodeSelector を変更してください。
また、interfaces も、eth から始まっている場合などがあると思います。
適宜変更してください。
apiVersion: "cilium.io/v2alpha1"
kind: CiliumL2AnnouncementPolicy
metadata:
name: policy1
spec:
nodeSelector:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: Exists
interfaces:
- ^ens[0-9]+
externalIPs: true
loadBalancerIPs: true
kubectl apply policy.yaml
LB IPAM を作成する
これは、Cilium にどの範囲の IP を広告できるかを示すものです。
今回は以下のように設定しました。
(IPv6 は伏せています)
apiVersion: "cilium.io/v2"
kind: CiliumLoadBalancerIPPool
metadata:
name: "default"
spec:
# 0と225を指定したくない場合はNoにする
allowFirstLastIPs: "No"
blocks:
- cidr: "172.16.152.0/24"
- cidr: "24xx:xxxx:xxxx:xxxx:xxxx::/80"
kubectl apply ip-pool.yaml
Nginx をおいて確認してみる
下記マニュフェストファイルをデプロイしてみましょう。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
namespace: default
spec:
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
run: my-nginx
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: my-nginx
ports:
- containerPort: 80
protocol: TCP
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
run: my-nginx
name: my-nginx
namespace: default
spec:
ipFamilies:
- IPv4
- IPv6
ipFamilyPolicy: PreferDualStack
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: my-nginx
sessionAffinity: None
type: LoadBalancer
確認してみると、External IP が割り振られていることがわかります。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.223.0.1 <none> 443/TCP 2d13h
my-nginx LoadBalancer 10.223.245.118 172.16.152.1,xxx:xxxx:xxxx:xxxx::xxxx 80:30684/TCP 2d13h
実際にアクセスして確かめてみてください!
トラブルシューティング
今回私が遭遇したトラブルとして...
NDP は通っていて、SYN も通るのに応答が返ってこない現象が発生しました。
原因はよくわかりませんが、ノード自体を再起動することで解決しました。
もし IPv4 通るのに IPv6 通らないよ!という方がいれば試してみるといいかもしれません。
最後に
今回は、Cilium の最新機能を使って L2 で IPv6 を広告する方法を実践してみました。
お読みいただきありがとうございました!
いいね等々お願いします!
また、当サークルでは ProxmoxVE や Kubernetes を運用しています。
もし興味がありましたら、下記 URL へ飛んでいただければと思います!
⭐︎ 公式 HP ↓
⭐︎ Discord ↓