EKS on Fargateクラスタ構築メモ
2019年12月にGAを発表したEKS on Fargateを使ってみたので、そのメモを残します。
EKS on Fargateとは
はじめにAWSが提供するコンテナ関連のサービスについておさらいします。 サービスが提供するものは、大きく分けて『コントロールプレーン』と『データプレーン』の2つに分類できます。 よく耳にするECSやEKSは、コンテナを管理するコントロールプレーンを提供するサービスです。 他方、コンテナを動かすデータプレーンを提供するサービスとして、EC2とFargateがあります。 EKS on Fargateは、これまでなかったEKSとFargateの組み合わせです。
コントロールプレーン | データプレーン |
---|---|
ECS(AWS独自/Serverless) | EC2 |
ECS(AWS独自/Serverless) | Fargate(Serverless) |
EKS(Kubernetes/Serverless) | EC2 |
EKS(Kubernetes/Serverless) | Fargate(Serverless) ←New |
EKS on Fargateの利点はサーバ運用無しでk8sを使えることでしょう。
EKS on Fargateの制限事項
サーバ運用から解放される一方で(2019年12月13日現在)いくつかの制限があります。 このため、ログ収集周りの対応に手間がかかります。
- CLB/NLB未対応
- GPU未対応
- Podのリソース上限は4 vCPUと30GBメモリ
- Podのディスク上限は10GB、Volume Mount向けに4GB
- Daemonsets、Privileged Container、HostNetwork、HostPortは利用不可
- 永続ボリュームやファイルシステムで必要とされるステートフルなワークロードは未対応
クラスタの構成
EKS on Fargateが外部からのアクセスを受け付ける公式の手段はALB Ingress Controllerです。 ALB Ingress ControllerはIngressリソースの数だけALBを作成してしまい、その分費用がかかります。 これを回避するため、k8s内部にALBのトラフィックをすべて受け取るTraefikを配置します。 TraefikはIngress Controllerとしてトラフィックを各サービスに振り分けます。
+---------+ +-----------------------------+
| | | |
| ALB | | k8s |
| | | |
| | | +---------+ +---------+ |
| | | | | | | |
| | | | | +-+ Service | |
| | | | | | | | |
| | | | | | +---------+ |
| +-----+ Traefik +-+ |
| | | | | | +---------+ |
| | | | | | | | |
| | | | | +-+ Service | |
| | | | | | | |
| | | +---------+ +---------+ |
| | | |
+---------+ +-----------------------------+
EKS on Fargateクラスタの構築
eksctlというCLIを使用して、k8sクラスタを1コマンドで構築します。 eksctlは内部でCloudFormationを用いて必要なリソースを作成します。
brew tap weaveworks/tap
brew install weaveworks/tap/eksctl
eksctl create cluster --name your-cluster-name --version 1.14 --fargate
既存のSubnetに構築する場合は、オプションに--vpc-private-subnets
と--vpc-public-subnets
を指定します。
ALB Ingress Controllerの構築
EKS on FargateにおけるPodの公開手段はALBのみです。 ALBはALB Ingress Controllerを利用して構築できます。
構築するにあたり、ALB Ingress ControllerにALBを作成する権限を与える必要があります。 言い換えると、Fargate上のPodに権限を与える必要があります。 これはAWSのIAM RoleとService Accountの関連付けを行うことで実現できます。 以降では実際の導入手順を説明します。
注意点として、AWSの公式ドキュメントは執筆時点でFargateに対応しておらず、ワーカーノード(EC2)に対応した手順が公開されています。そのため、公式ドキュメントに従うとFargateでは動作しません。
- 参考(ALB Ingress Controller):https://kubernetes-sigs.github.io/aws-alb-ingress-controller/
- 参考(AWS公式):https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html
Subnetのタグ設定
ALBをどのサブネットに配置すべきかを知らせるため、サブネットにタグを設定します。 プライベートサブネットにはNo.1とNo.2のタグを設定してください。 パブリックサブネットにはNo.1とNo.3のタグを設定してください。
No. | Key | Value |
---|---|---|
1 | kubernetes.io/cluster/${cluster-name} | owned or shared |
2 | kubernetes.io/role/internal-elb | 1 |
3 | kubernetes.io/role/elb | 1 |
Service AccountとIAMの紐付け
ALB Ingress ControllerがALBを作成するためのIAM Policyを作成します。
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.4/docs/examples/iam-policy.json
mv -i iam-policy.json alb-ingress-iam-policy.json
aws iam create-policy \
--policy-name ALBIngressControllerIAMPolicy \
--policy-document file://alb-ingress-iam-policy.json
policy_arn=$(
aws iam list-policies \
| jq -r '.Policies[] | select(.PolicyName == "ALBIngressControllerIAMPolicy") | .Arn'
)
自クラスタでService AccountとIAMを関連付けるためのOIDC Identity Providerを作成します。
eksctl utils associate-iam-oidc-provider \
--region=ap-northeast-1 \
--cluster=your-cluster-name \
--approve
ALB Ingress ControllerのService AccountとRBACを作成します。 マニフェストは公式が公開しているものを使用します。
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.4/docs/examples/rbac-role.yaml
mv -i rbac-role.yaml alb-ingress-rbac-role.yaml
kubectl apply -f alb-ingress-rbac-role.yaml
eksctlを使ってIAMとService Accountの関連付けを行います。 内部で次の処理を行っています。
- CloudFormationを用いて、指定したIAM PolicyをアタッチしたIAM Roleを作成
- 作成したIAM RoleをService Accountに関連付け
eksctl create iamserviceaccount \
--name alb-ingress-controller \
--namespace kube-system \
--cluster your-cluster-name \
--attach-policy-arn ${policy_arn} \
--approve --override-existing-serviceaccounts
kubectl get sa -n kube-system alb-ingress-controller -o jsonpath="{.metadata.annotations['eks\.amazonaws\.com/role-arn']}"
ALB Ingress Controllerのデプロイ
公式のマニフェストをダウンロードします。
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.4/docs/examples/alb-ingress-controller.yaml
alb-ingress-controller.yaml
を編集します。
編集箇所は、ALB Ingress Controllerコンテナの引数であるクラスタ名、VPC ID、およびAWSリージョン名です。
- args:
- --ingress-class=alb
- --cluster-name=devCluster
- --aws-vpc-id=vpc-xxxxxx
- --aws-region=us-west-1
デプロイします。
kubectl apply -f alb-ingress-controller.yaml
kubectl get po -n kube-system -w
ALB Ingress Controllerのデプロイがうまくいかない場合
ログを確認します。
kubectl logs -n kube-system deployment.apps/alb-ingress-controller
Traefik Ingress Controllerの構築
Traefikはシンプルなリバースプロキシです。 k8sのIngress Controllerとしてデプロイします。
Traefikのデプロイ
筆者が用意したマニフェストをダウンロードして、適用します。
git clone https://github.com/twihike/k8s-manifests.git
cd k8s-manifests/eks-on-fargate/traefik
# 不要なコンテナ定義(node-exporter/fluent-bit)を削除してください
# vi deployment.yml
kubectl apply -f crd.yml
kubectl apply -f clusterrole.yml
kubectl apply -f serviceaccount.yml
kubectl apply -f clusterrolebinding.yml
kubectl apply -f deployment.yml
kubectl apply -f service.yml
動作確認用サンプルアプリのデプロイ
マニフェスト(sample-app.yaml)を作成します。
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
namespace: default
name: sample-route
spec:
entryPoints:
- web
routes:
- match: PathPrefix(`/`)
kind: Rule
services:
- name: sample-svc
port: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: default
name: sample-svc
spec:
selector:
app: sample-nginx
ports:
- name: http
port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-deploy
spec:
selector:
matchLabels:
app: sample-nginx
replicas: 1
template:
metadata:
labels:
app: sample-nginx
spec:
containers:
- name: sample-nginx
image: nginx:1.7.9
ports:
- containerPort: 80
デプロイします。
kubectl apply -f sample-app.yaml
kubectl get po -w
Traefikの動作確認
kubectl port-forward
を実行して、localhost:8000にアクセスします。
# pod=$(kubectl -n kube-system get po --selector name=traefik -o=jsonpath={.items[0].metadata.name})
kubectl -n kube-system port-forward deployment.apps/traefik 8000:8000
ALBの構築
Ingressリソースを作成すると、ALB Ingress Contollerは指定したServiceに接続するALBを自動作成します。
Ingressの適用
次の内容でalb-ingress.yaml
を作成します。
Fargateの場合、target-type
はip
のみに対応していることに注意してください。
独自ドメインの場合は、追加で次の対応をします。
- 証明書のARNを指定
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: alb-ing
namespace: kube-system
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
# alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:ap-northeast-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
alb.ingress.kubernetes.io/healthcheck-port: "8080"
alb.ingress.kubernetes.io/healthcheck-path: /ping
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: traefik
servicePort: 8008
作成したファイルを適用します。
kubectl apply -f alb-ingress.yaml
独自ドメインの場合は、追加で次の対応をします。
- Route53にてレコードを設定
- レコードの宛先はIngress Controllerにより自動作成されたALBのドメインとする
ALBの接続確認
Webブラウザから接続確認をします。 HTTPSとHTTPの両方から接続できることを確認してください。
ALBの接続確認がうまくいかない場合
ログを確認します。
kubectl logs -n kube-system deployment.apps/alb-ingress-controller
クラスタのバージョンアップ
コントロールプレーンをバージョンアップします。 まずはバージョンアップの内容を確認します。
eksctl update cluster --name your-cluster-name
バージョンアップの内容に問題がなければ、適用します。
eksctl update cluster --name your-cluster-name --approve
クラスタのアドオンを更新します。 まずはバージョンアップの内容を確認します。
eksctl utils update-kube-proxy --cluster your-cluster-name
eksctl utils update-aws-node --cluster your-cluster-name
eksctl utils update-coredns --cluster your-cluster-name
バージョンアップの内容に問題がなければ、適用します。
eksctl utils update-kube-proxy --cluster your-cluster-name --approve
eksctl utils update-aws-node --cluster your-cluster-name --approve
eksctl utils update-coredns --cluster your-cluster-name --approve
# Fargateを有効にする
kubectl patch deployment coredns -n kube-system --type json \
-p='[{"op": "remove", "path": "/spec/template/metadata/annotations/eks.amazonaws.com~1compute-type"}]'