
EKSのHybrid Nodesを、Calicoを利用したPodネットワークを構成してみました。
EKSのハイブリッド構成を試す際に、Pod ネットワークとして Calico を導入してみました。Calico は VXLAN を利用して Pod 間の通信を行うため、EC2 ノード同士のルーティングさえ正しく設定されていれば、VPC をまたいだ環境でもシームレスに Pod 間通信を行えます。(Pod用のルーティング設定が不要です)

今回、簡単に試せる環境として、上図の構成を作ってみました。2 つの VPC(左側がメインの EKS VPC、右側が「オンプレミス環境を模した」VPC)を用意し、それぞれの VPC に EKS ノードを配置しています。EKS はマネージドノードグループで構築し、Calico の CNI プラグインを導入することで、同一の Pod CIDRを両方の VPC 上のノードで共有しています。
コード
IaCのコードはこちらにあります。DevContainerを構成しているので、この記事の作業では、DevContainer上で作業を進めていきます。
github.comAWS環境のデプロイ方法
設定ファイルの準備
まずは以下のように2つの設定ファイルを用意します。
- vars/env.tfvars.sample を参考にしてvars/env.tfvars ファイルを作成してください。
- vars/backend.tfvars.sample を参考にしてvars/backend.tfvars ファイルを作成してください。
Terraformの実行
以下のコマンドでTerraformで図の環境がデプロイ可能です。
$ make tf-apply-aws
EKS Hybrid NodeはEC2のuserdataを設定する以下の部分でインストールして、EKSに参加しています。
user_data = <<EOF
省略
--==BOUNDARY==
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
#cloud-config
write_files:
- path: /etc/nodeadm/nodeConfig.yaml
owner: root:root
permissions: '0644'
content: |
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
cluster:
name: eks-hybrid
region: ap-northeast-1
hybrid:
ssm:
activationCode: ${aws_ssm_activation.this.activation_code}
activationId: ${aws_ssm_activation.this.id}
runcmd:
- curl -OL 'https://hybrid-assets.eks.amazonaws.com/releases/latest/bin/linux/arm64/nodeadm'
- mv nodeadm /usr/bin/nodeadm
- chmod +x /usr/bin/nodeadm
- nodeadm install ${local.cluster_version} --credential-provider ssm
- nodeadm init -c file:///etc/nodeadm/nodeConfig.yaml
- nodeadm debug -c file:///etc/nodeadm/nodeConfig.yaml
--==BOUNDARY==--
EOFEKSへのアクセス確認
awsコマンドでkubeconfigを更新します。
$ aws eks update-kubeconfig --profile your_profile --name eks-hybrid Updated context arn:aws:eks:ap-northeast-1:012345678901:cluster/eks-hybrid in /home/vscode/.kube/config
以下がこの時点でのk9sの画面ですが、「ip-」 始まりがEKSのManaged Node Groupで起動されたEC2インスタンスです。
「mi-」始まりのものがUserdataの処理を利用して、Hybrid NodeとしてEKSに参加したNodeとなります。こちらはEKSからはEC2として認識されていないため、VPC CNIが適用されおらずNotReadyとなります。

Calicoの導入
CNI PluginとしてCalicoを適用します。手順はこちらの公式ドキュメントを参考にしています。
# AWS VPC CNIを削除します $ kubectl delete daemonset -n kube-system aws-node # Calicoをインストールします $ kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.2/manifests/calico-vxlan.yaml $ kubectl -n kube-system set env daemonset/calico-node FELIX_AWSSRCDSTCHECK=DoNothing
Calicoインストール後、既存のManaged Node Groupとして起動していたEC2は削除します。

これで新しいインスタンスがCalico CNIを利用して起動してきます。

PodネットワークでL3ルーティングを確認
L3ルーティングを確認するために、上図の赤枠のPodをデプロイします。
$ kubectl apply -f manifest/nw-check.yaml namespace/nw-check created deployment.apps/nw-check-managed created deployment.apps/nw-check-hybrid created
Managed NodeとHybrid Nodeの両方にPodが配置されました。
$ kubectl get pod -n nw-check -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nw-check-hybrid-5854bbd794-tndpr 1/1 Running 0 39s 192.168.35.7 mi-06d5ac211e74887c1 <none> <none> nw-check-managed-c7cd75cc6-bvf8x 1/1 Running 0 39s 192.168.231.3 ip-10-10-2-193.ap-northeast-1.compute.internal <none> <none>
Managed Node <-> Hybrid Node相互のPINGができることが確認できます。
# それぞれのNodeに配置されたPodが確認できます。 $ kubectl get pod -n nw-check -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nw-check-hybrid-5854bbd794-tndpr 1/1 Running 0 10m 192.168.35.7 mi-06d5ac211e74887c1 <none> <none> nw-check-managed-c7cd75cc6-bvf8x 1/1 Running 0 10m 192.168.231.3 ip-10-10-2-193.ap-northeast-1.compute.internal <none> <none> # Hybrid -> Managed $ kubectl exec -n nw-check nw-check-hybrid-5854bbd794-tndpr -- ping -c3 192.168.231.3 PING 192.168.231.3 (192.168.231.3) 56(84) bytes of data. 64 bytes from 192.168.231.3: icmp_seq=1 ttl=125 time=1.87 ms 64 bytes from 192.168.231.3: icmp_seq=2 ttl=125 time=1.83 ms 64 bytes from 192.168.231.3: icmp_seq=3 ttl=125 time=1.81 ms --- 192.168.231.3 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2004ms rtt min/avg/max/mdev = 1.813/1.839/1.872/0.024 ms # Managed -> Hybrid $ kubectl exec -n nw-check nw-check-managed-c7cd75cc6-bvf8x -- ping -c3 192.168.35.7 PING 192.168.35.7 (192.168.35.7) 56(84) bytes of data. 64 bytes from 192.168.35.7: icmp_seq=1 ttl=62 time=1.84 ms 64 bytes from 192.168.35.7: icmp_seq=2 ttl=62 time=1.81 ms 64 bytes from 192.168.35.7: icmp_seq=3 ttl=62 time=1.81 ms --- 192.168.35.7 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 1.807/1.819/1.843/0.016 ms
当然、ここではPod NetworkのCIDRはAWSのルートテーブルには出てきていません。

Session ManagerでManaged Nodeに入ってコマンドで確認してみると、以下のようにHybrid Nodeへの通信はCalicoが構築してくれたVXLANで通信されていることがわかります。
$ ip route default via 10.10.2.1 dev eth0 10.10.2.0/24 dev eth0 proto kernel scope link src 10.10.2.193 169.254.169.254 dev eth0 169.254.170.23 dev pod-id-link0 192.168.35.0/26 via 192.168.35.0 dev vxlan.calico onlink blackhole 192.168.231.0/26 proto 80 192.168.231.3 dev cali9ce7ff61306 scope link
ALBを通して(オンプレを模した)VPCのPodにアクセス
最後にALBを通したHybrid Node上のPodへの通信を確認したいと思います。
$ kubectl apply -f manifest/sample.yaml
まずは、Podを通してService Networkを通した通信を確認してみます。
# sample-appがHybrid Nodeに配置されていることがわかります $ kubectl get po -n sample -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES sample-app-7d5b76dcff-qjdmh 1/1 Running 0 3h9m 192.168.35.5 mi-06d5ac211e74887c1 <none> <none> # 以下のようにNodePortとして登録されています $ kubectl get svc -n sample NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE sample-svc NodePort 172.16.58.99 <none> 80:30080/TCP 3h5m # Managed Node側からService Network経由で通信確認 $ kubectl exec -n nw-check nw-check-managed-c7cd75cc6-dlv6r -- curl -s 172.16.58.99:80 "Hello from Pod [sample-app-7d5b76dcff-qjdmh] !" $ kubectl exec -n nw-check nw-check-managed-c7cd75cc6-dlv6r -- curl -s sample-svc.sample.svc.cluster.local "Hello from Pod [sample-app-7d5b76dcff-qjdmh] !"
次にNodePortを通した通信確認もしてみます。
$ kubectl exec -n nw-check nw-check-managed-c7cd75cc6-dlv6r -- curl -s 10.10.1.14:30080 "Hello from Pod [sample-app-7d5b76dcff-qjdmh] !" $ kubectl exec -n nw-check nw-check-managed-c7cd75cc6-dlv6r -- curl -s 10.90.1.182:30080 "Hello from Pod [sample-app-7d5b76dcff-qjdmh] !"
ALBに登録していきます。最初のTerraformでALBは登録済みなので、「eks-hybrid-alb」という名前のTarget Groupを探します。

Manged Node、Hybrid NodeそれぞれのEC2のIPを調べて登録します。

後はALBのURLに対してアクセスしてみると、Hybrid Nodeで動いているsample-appのPod名が返ってくることが確認できます。
$ curl eks-hybrid-alb-xxxxxx.ap-northeast-1.elb.amazonaws.com "Hello from Pod [sample-app-7d5b76dcff-qjdmh] !"
片付け
最後に以下のコマンドでTerraformで作成したリソースを全て削除します。
$ make tf-destroy-aws
タイトルの構成を作成するIaCと手順の話でした。もし理解が薄い場合も環境さえ構築できれば、その中で試したり調査してみることができると思います。
最後に今回の範囲だと以下のような情報が大変参考になりましたので紹介させていただきます。