本記事は個人の意見であり、所属する組織の見解とは関係ありません。
こちらはAmazon EKS Advent Calendar 2019の18日目の記事です。現在の時刻は、12/18 190時ぐらいでしょうか
re:Inventでの EKS on Fargete 発表もあり、改めてEKSに注目されている方も多くいらっしゃると思います。re:Inventで発表された内容そのものではありませんが、今回はVPC内部の通信のみでEKSを利用できるかを手順のウォークスルーを通じて確認していきます。
確認結果
12月24日現在の動作として次の様な挙動をします。
- Worker Node としてEC2 インスタンスを利用している場合、 VPC 内部通信のみで利用可能
- AWWS Fargete を利用している場合、インターネット通信が必要である。
結果としては、EKS を VPC 内部通信のみで利用する事が可能です。もちろん、利用している add on 等のツールがインターネット通信を必要とするケースもあると思います。実際の利用においては、手持ちの環境で事前検証をする事をおすすめします。 Fargateを利用する場合は、現時点ではインターネット通信が必要ですが、これは実際の動作から確認したものであるという点にご留意ください。
検証の流れ
インターネット通信を遮断した状況でのセットアップは地味に手間がかかりますね。今回は Cloud9 + VPC Peering を利用してみました。EKS 用のVPCに作成されたリソースからは直接のインターネットアクセスは出来ません。作業用となるCloud9 インスタンス からはインターネットにアクセス出来ます。
EKS clusterを作成する VPC には4つの Subnet があり、そのうち3つは Worker Node を作成する Subnet として利用します。残りの1つは、予備として作成しておきます。これはあとで、インターネット通信が必要になった場合に、NATGW を作成する為の Subnet として利用します。(結果的にこのsubnetを利用する事になりました。)
VPC内部通信に制限する為に、VPC endpoint 活用していきます。利用するサービス、環境に応じて、適宜アレンジしてみてください。ユースケースを妄想しながら、この辺りは使うかな?と以下の様な環境で構成してみました。
- Amazon ECR VPCエンドポイント(ecr.apiとecr.dkrの2種類)
- Amazon S3 VPCエンドポイント
- Amazon EC2 VPCエンドポイント
- Amazon Cloudwatch logs VPCエンドポイント
現時点では、EKS のAPI は VPC endpoint をサポートしていませんので、EKS 自身の管理は public な endpoint 経由で実施する必要があります。
環境セットアップ
Cloud9 インスタンスで必要なツール類(aws cli、kubectl、eksctl)のセットアップ、EC2 インスタンスへのIAM ロール設定を済ませたらいざセットアップの開始です。
(Cloud9を利用する場合のセットアップ内容は eks workshopの手順が参考になります。)
まず最初にEKS clusterを作成する際に利用するIAM認証情報を確認しておきます。ここが想定と異なる場合、設定を見直しましょう
$ aws sts get-caller-identity
{
"Account": "123456789012",
"UserId": "AROA5O666JYXWZ5UOGYY7:i-xxxxxxxxxxxxxxxxx",
"Arn": "arn:aws:sts::123456789012:assumed-role/eks-admin/i-xxxxxxxxxxxxxxxxx"
}
続いてeksctlで既存VPC上に EKS cluster を作成します。
$ cat eks-cluster.yml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: eks-cluster-private
region: us-east-2
vpc:
clusterEndpoints:
publicAccess: false
privateAccess: true
id: vpc-038949360da1e5281
cidr: 172.16.0.0/16
subnets:
private:
us-east-2a: { id: subnet-0b369e89278e184bc }
us-east-2b: { id: subnet-0566c87640b758942 }
us-east-2c: { id: subnet-0c7c9a28ec7c595bd }
nodeGroups:
- name: private-standard-group
instanceType: t3.medium
desiredCapacity: 3
maxSize: 3
minSize: 3
privateNetworking: true
cloudWatch:
clusterLogging:
enableTypes:
- api
- audit
- authenticator
- controllerManager
- scheduler
$ eksctl create cluster -f eks-cluster.yml [ℹ] eksctl version 0.11.1
[ℹ] using region us-east-2
[✖] warning, having public access disallowed will subsequently interfere with some features of eksctl. This will require running subsequent eksctl (and Kubernetes) commands/API calls from within the VPC. Running these in the VPC requires making updates to some AWS resources. See: https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html#private-access for more details
いきなりつまづきました。eksctl で cluster を作成する場合に、public access
をdisable
とした場合は、clusterの作成が行えない様です。aws cli での作成に切り替えます。
$ aws eks --region us-east-2 create-cluster --name privateEKS \
--kubernetes-version 1.14 \
--role-arn arn:aws:iam::123456789012:role/eksServiceRole \
--resources-vpc-config subnetIds=subnet-0b369e89278e184bc,\
subnet-0566c87640b758942,subnet-0c7c9a28ec7c595bd,\
securityGroupIds=sg-0b6ecda1c7a802b79,\
endpointPublicAccess=false,endpointPrivateAccess=true
Clusterの作成が完了するまで少し時間がかかりますので、その間に ECR repository の作成と、適当な Docker イメージを push しておきます。
$ aws ecr --region us-east-2 create-repository --repository-name private4eks
$ $(aws ecr get-login --no-include-email --regio us-east-2)
$ docker tag private4eks:01 123456789012.dkr.ecr.us-east-2.amazonaws.com/private4eks:01
$ docker push 123456789012.dkr.ecr.us-east-2.amazonaws.com/private4eks:01
Worker Node にEC2 インスタンスを利用する場合
最初に Managed Node Group を作成して、Worker Node のセットアップを行います。 Managed Node Group は、11月にリリースされたアップデートで、こちらを使うと Worker Node をいい感じに構成できます。なお、 Worker Node で利用するIAM ロールを指定していますが、これは事前に作成しておく必要があります。
aws eks create-nodegroup --cluster-name privateEKS \
--nodegroup-name privateGroup \
--subnets subnet-0b369e89278e184bc,subnet-0566c87640b758942,subnet-0c7c9a28ec7c595bd \
--node-role arn:aws:iam::123456789012:role/eks-nodegroup-ng-NodeInstanceRole \
--region us-east-2
Worker Node が構成され、cluster に Join している事を確認します。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
ip-172-16-4-166.us-east-2.compute.internal Ready <none> 2m25s v1.14.7-eks-1861c5
ip-172-16-40-206.us-east-2.compute.internal Ready <none> 2m41s v1.14.7-eks-1861c5
これで準備が整いました。先ほど push した docker イメージを利用して pod を作成してみます。
$ kubectl create deployment ec2-app --image 123456789012.dkr.ecr.us-east-2.amazonaws.com/private4eks:01
deployment.apps/ec2-app created
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
ec2-app 1/1 1 1 51s
Fargate での動作を確認する前に、kube-system で動いている CoreDNS の状況を確認しておきます。Managed Workger Group 経由で起動したEC2 インスタンス上で起動されていることがわかります。
$ kubectl get po,node -o wide --namespace kube-system
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/aws-node-v9w2h 1/1 Running 0 36m 172.16.4.166 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
pod/aws-node-x72b7 1/1 Running 0 36m 172.16.40.206 ip-172-16-40-206.us-east-2.compute.internal <none> <none>
pod/coredns-6ffc87dccf-6nf22 1/1 Running 0 44m 172.16.7.56 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
pod/coredns-6ffc87dccf-hr8hp 1/1 Running 0 44m 172.16.5.204 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
pod/kube-proxy-2z775 1/1 Running 0 36m 172.16.40.206 ip-172-16-40-206.us-east-2.compute.internal <none> <none>
pod/kube-proxy-hrd9c 1/1 Running 0 36m 172.16.4.166 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node/ip-172-16-4-166.us-east-2.compute.internal Ready <none> 36m v1.14.7-eks-1861c5 172.16.4.166 52.15.125.83 Amazon Linux 2 4.14.146-119.123.amzn2.x86_64 docker://18.6.1
node/ip-172-16-40-206.us-east-2.compute.internal Ready <none> 36m v1.14.7-eks-1861c5 172.16.40.206 3.14.3.148 Amazon Linux 2 4.14.146-119.123.amzn2.x86_64 docker://18.6.1
Fargateを利用する場合
Fargate を利用する場合には、Worker Node 向けの設定として profile を作成します。 profile の作成はEKSの機能ですので、aws cli での作成です。 今回は、namespaceにfargate
が指定された場合に、Pod が Fargate 上で起動します。
aws eks create-fargate-profile --fargate-profile-name private-fargate --cluster-name privateEKS --region us-east-2 --pod-execution-role-arn arn:aws:iam::123456789012:role/AmazonEKSFargatePodExecutionRole --subnets subnet-0b369e89278e184bc subnet-0566c87640b758942 subnet-0c7c9a28ec7c595bd --selectors namespace=fargate
EC2インスタンスを利用した時と同様にPodを起動します。今回はnamespaceとしてfargateを指定しています。
$ kubectl create namespace fargate
$ kubectl create deployment fargate-app --image 123456789012.dkr.ecr.us-east-2.amazonaws.com/private4eks:01 --namespace fargate
$ kubectl get po,node -o wide --namespace fargate
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/fargate-app-7fcb75bf84-ghfql 0/1 Pending 0 5m47s <none> <none> 6686814949-d8df61853ca64096aabccc25785772b9 <none>
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node/ip-172-16-4-166.us-east-2.compute.internal Ready <none> 42m v1.14.7-eks-1861c5 172.16.4.166 52.15.125.83 Amazon Linux 2 4.14.146-119.123.amzn2.x86_64 docker://18.6.1
node/ip-172-16-40-206.us-east-2.compute.internal Ready <none> 42m v1.14.7-eks-1861c5 172.16.40.206 3.14.3.148 Amazon Linux 2 4.14.146-119.123.amzn2.x86_64 docker://18.6.1
残念。PodのステータスがPendingのままです。どうやらこの環境ではFargate上でPodが起動しません。ここで Fargate 向けに指定した Subnet に適用している Route Table を変更して NATGW 経由でインターネット通信が行える様にすると、以下の様になります。無事起動しました。
$ kubectl get po,node -o wide --namespace fargate
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/fargate-app-7fcb75bf84-ghfql 0/1 ContainerCreating 0 8m29s <none> fargate-ip-172-16-35-143.us-east-2.compute.internal <none> <none>
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node/fargate-ip-172-16-35-143.us-east-2.compute.internal Ready <none> 18s v1.14.8-eks 172.16.35.143 <none> Amazon Linux 2 4.14.152-127.182.amzn2.x86_64 containerd://1.3.0
node/ip-172-16-4-166.us-east-2.compute.internal Ready <none> 45m v1.14.7-eks-1861c5 172.16.4.166 52.15.125.83 Amazon Linux 2 4.14.146-119.123.amzn2.x86_64 docker://18.6.1
node/ip-172-16-40-206.us-east-2.compute.internal Ready <none> 45m v1.14.7-eks-1861c5 172.16.40.206 3.14.3.148 Amazon Linux 2 4.14.146-119.123.amzn2.x86_64 docker://18.6.1
EC2 インスタンスを利用した時と同じ様に CoreDNS が動いている場所を確認してみます。
$ kubectl get po,node -o wide --namespace kube-system
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/aws-node-v9w2h 1/1 Running 0 49m 172.16.4.166 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
pod/aws-node-x72b7 1/1 Running 0 49m 172.16.40.206 ip-172-16-40-206.us-east-2.compute.internal <none> <none>
pod/coredns-6ffc87dccf-6nf22 1/1 Running 0 57m 172.16.7.56 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
pod/coredns-6ffc87dccf-hr8hp 1/1 Running 0 57m 172.16.5.204 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
pod/kube-proxy-2z775 1/1 Running 0 49m 172.16.40.206 ip-172-16-40-206.us-east-2.compute.internal <none> <none>
pod/kube-proxy-hrd9c 1/1 Running 0 49m 172.16.4.166 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node/fargate-ip-172-16-35-143.us-east-2.compute.internal Ready <none> 4m52s v1.14.8-eks 172.16.35.143 <none> Amazon Linux 2 4.14.152-127.182.amzn2.x86_64 containerd://1.3.0
node/ip-172-16-4-166.us-east-2.compute.internal Ready <none> 49m v1.14.7-eks-1861c5 172.16.4.166 52.15.125.83 Amazon Linux 2 4.14.146-119.123.amzn2.x86_64 docker://18.6.1
node/ip-172-16-40-206.us-east-2.compute.internal Ready <none> 49m v1.14.7-eks-1861c5 172.16.40.206 3.14.3.148 Amazon Linux 2 4.14.146-119.123.amzn2.x86_64 docker://18.6.1
CoreDNS は標準では EC2 インスタンス上で起動する様になっています。こちらも Fargate 上で動かしたい場合は、追加の設定が必要になります。詳しくはドキュメントを参考にしてみてください。
$ aws eks create-fargate-profile --fargate-profile-name fargate \
--cluster-name privateEKS \
--region us-east-2 \
--pod-execution-role-arn arn:aws:iam::123456789012:role/AmazonEKSFargatePodExecutionRole \
--subnets subnet-0b369e89278e184bc subnet-0566c87640b758942 subnet-0c7c9a28ec7c595bd \
--selectors namespace=kube-system,labels={k8s-app=kube-dns}
$ kubectl get po,node -o wide --namespace kube-systemNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/aws-node-v9w2h 1/1 Running 0 63m 172.16.4.166 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
pod/aws-node-x72b7 1/1 Running 0 63m 172.16.40.206 ip-172-16-40-206.us-east-2.compute.internal <none> <none>
pod/coredns-6d59cf6ccd-592rh 0/1 Running 0 62s 172.16.33.134 fargate-ip-172-16-33-134.us-east-2.compute.internal <none> <none>
pod/coredns-6d59cf6ccd-v7tjz 0/1 Running 0 62s 172.16.26.225 fargate-ip-172-16-26-225.us-east-2.compute.internal <none> <none>
pod/coredns-6ffc87dccf-hr8hp 1/1 Running 0 71m 172.16.5.204 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
pod/kube-proxy-2z775 1/1 Running 0 63m 172.16.40.206 ip-172-16-40-206.us-east-2.compute.internal <none> <none>
pod/kube-proxy-hrd9c 1/1 Running 0 63m 172.16.4.166 ip-172-16-4-166.us-east-2.compute.internal <none> <none>
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node/fargate-ip-172-16-26-225.us-east-2.compute.internal Ready <none> 6s v1.14.8-eks 172.16.26.225 <none> Amazon Linux 2 4.14.152-127.182.amzn2.x86_64 containerd://1.3.0
node/fargate-ip-172-16-33-134.us-east-2.compute.internal Ready <none> 10s v1.14.8-eks 172.16.33.134 <none> Amazon Linux 2 4.14.152-127.182.amzn2.x86_64 containerd://1.3.0
node/fargate-ip-172-16-35-143.us-east-2.compute.internal Ready <none> 18m v1.14.8-eks 172.16.35.143 <none> Amazon Linux 2 4.14.152-127.182.amzn2.x86_64 containerd://1.3.0
node/ip-172-16-4-166.us-east-2.compute.internal Ready <none> 63m v1.14.7-eks-1861c5 172.16.4.166 52.15.125.83 Amazon Linux 2 4.14.146-119.123.amzn2.x86_64 docker://18.6.1
node/ip-172-16-40-206.us-east-2.compute.internal Ready <none> 63m v1.14.7-eks-1861c5 172.16.40.206 3.14.3.148 Amazon Linux 2 4.14.146-119.123.amzn2.x86_64 docker://18.6.1
最後に
今回は手順上、省略していますが、aws cliを利用する場合、EKS が利用する IAM ロールを事前に作成したり、 CoreDNS に対するアップデートを個別に実施しました。このあたり、実は eksctl を利用すると 上記の様な設定を自動的にしてくれます。とても便利です。ぜひ eksctl もお試しください!