Amazon EKS on AWS Fargate + ALB Ingress Controllerを試す

はじめに

f:id:hiroki-sawano:20201025192920p:plain

KubernetesのマネージドサービスであるAmazon EKSを試用します。
ポッドの実行環境としてはEC2とAWS Fargateが選択できますが、EC2インスタンスの管理が不要なFargateを使います。

実行環境

macOS Catalina Version 10.15.5

eksctlでEKSクラスタを作成

以下のリンク先を参考に進めていきます。

Getting started with eksctl - Amazon EKS

前提

  • AWS CLIのインストール
❯ curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
❯ sudo installer -pkg AWSCLIV2.pkg -target /

AWS CLIeksctlAWSとやり取りするために必要な設定を行います。

❯ aws configure
AWS Access Key ID [None]: <your-access-key>
AWS Secret Access Key [None]: <your-secret-access-key>
Default region name [None]: <region-code>
Default output format [None]: <json>
  • eksctl(とkubectl)のインストール

Homebrewで eksctl をインストールすると kubectl も一緒にインストールしてくれます。

❯ brew tap weaveworks/tap
❯ brew install weaveworks/tap/eksctl

EKSクラスタの作成

eksctl create clusterクラスタを作成します。
バージョンは公式マニュアルに従い 1.18 、リージョンは東京( ap-northeast-1 )を指定しました。
Fargateを使うので --fargate オプションが必要です。

❯ eksctl create cluster \
    --name <your-cluster-name> \
    --version 1.18 \
    --region ap-northeast-1 \
    --fargate

...
[✔]  EKS cluster "..." in "ap-northeast-1" region is ready

f:id:hiroki-sawano:20201022022101p:plain

この時点ではCoreDNSのポッド2つのみが存在します。

❯ kubectl get pods -A
NAMESPACE     NAME                                      READY   STATUS        RESTARTS   AGE
kube-system   coredns-84c76989c7-8s58g                  1/1     Running       0          4d8h
kube-system   coredns-84c76989c7-pb5cb                  1/1     Running       0          4d8h

サンプルアプリのデプロイ

続けてサンプルアプリをデプロイします。

Deploy a sample Linux application - Amazon EKS

名前空間は標準で作成される default を指定しました。

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: default
  labels:
    app: my-app
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  namespace: default
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: beta.kubernetes.io/arch
                operator: In
                values:
                - amd64
                - arm64
      containers:
      - name: nginx
        image: nginx:1.19.2
        ports:
        - containerPort: 80

作成したマニフェストを指定し、 kubectl apply でアプリケーションをデプロイします。

❯ kubectl apply -f sample-pod.yml
service/my-service created
deployment.apps/my-deployment created

kubectl get all で作成されたリソースを確認します。
Deploymentspec.replicas に3を設定したので3つのポッドが作成されました。

❯ kubectl get all
NAME                                 READY   STATUS    RESTARTS   AGE
pod/my-deployment-68f6fff96f-ccdkn   1/1     Running   0          2m21s
pod/my-deployment-68f6fff96f-gdv8t   1/1     Running   0          2m21s
pod/my-deployment-68f6fff96f-lxp54   1/1     Running   0          2m21s

NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.100.0.1       <none>        443/TCP   22h
service/my-service   ClusterIP   10.100.149.193   <none>        80/TCP    2m21s

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/my-deployment   3/3     3            3           2m21s

NAME                                       DESIRED   CURRENT   READY   AGE
replicaset.apps/my-deployment-68f6fff96f   3         3         3       2m21s

kubectl describe でリソースの詳細を確認できます。

❯ kubectl -n default describe service my-service
Name:              my-service
Namespace:         default
Labels:            app=my-app
...

❯ kubectl -n default describe pod my-deployment-68f6fff96f-ccdkn
Name:                 my-deployment-68f6fff96f-ccdkn
Namespace:            default
Priority:             2000001000
...

kubectl exec -it <ポッドの名前> -n <名前空間> -- /bin/bash でポッド(コンテナ)の中に入れます。

❯ kubectl exec -it my-deployment-68f6fff96f-ccdkn -n default -- /bin/bash
root@my-deployment-68f6fff96f-ccdkn:/#

ロードバランサの設定

この時点では外部からアクセスできないので、ALB Ingress ControllerをEKSクラスターにデプロイします。
(EKS on Fargateで使用できるロードバランサはALBのみ。)
ALB Ingress ControllerはIngressリソースの作成を契機にALBを作成してくれます。

ALB Ingress Controller on Amazon EKS - Amazon EKS

IAM OIDCプロバイダーの作成

❯ eksctl utils associate-iam-oidc-provider --region ap-northeast-1 --cluster <your-cluster-name> --approve
[ℹ]  eksctl version 0.30.0
[ℹ]  using region ap-northeast-1
[ℹ]  will create IAM Open ID Connect provider for cluster "<your-cluster-name>" in "ap-northeast-1"
[✔]  created IAM Open ID Connect provider for cluster "<your-cluster-name>" in "ap-northeast-1"

ALB Ingress Controllerポッド用のIAMポリシーを作成

ALB Ingress ControllerがAWSAPIを呼び出すために必要となるIAMポリシー <ALBIngressControllerIAMPolicy> を作成します。
ポリシーを作成した際に出力されるARNをメモしておきます。

❯ curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.8/docs/examples/iam-policy.json
❯ aws iam create-policy --policy-name ALBIngressControllerIAMPolicy --policy-document file://iam-policy.json
{
    "Policy": {
        "PolicyName": "ALBIngressControllerIAMPolicy",
        ...
    }
}
❯ rm iam-policy.json

alb-ingress-controllerサービスアカウント、ClusterRole、ClusterRoleBindingの作成

❯ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.8/docs/examples/rbac-role.yaml

clusterrole.rbac.authorization.k8s.io/alb-ingress-controller created
clusterrolebinding.rbac.authorization.k8s.io/alb-ingress-controller created
serviceaccount/alb-ingress-controller created

ALB Ingress ControllerのIAMロールを作成し、ロールをサービスアカウントに割り当て

--attach-policy-arn にはALB Ingress Controllerポッド用のIAMポリシーを作成で確認したARNを指定します。

❯ eksctl create iamserviceaccount \
    --region ap-northeast-1 \
    --name alb-ingress-controller \
    --namespace kube-system \
    --cluster <your-cluster-name> \
    --attach-policy-arn arn:aws:iam::<111122223333>:policy/<ALBIngressControllerIAMPolicy> \
    --override-existing-serviceaccounts \
    --approve

[ℹ]  eksctl version 0.30.0
[ℹ]  using region ap-northeast-1
[ℹ]  2 iamserviceaccounts (kube-system/alb-ingress-controller, kube-system/aws-node) were included (based on the include/exclude rules)
...
[ℹ]  updated serviceaccount "kube-system/aws-node"

ALB Ingress Controllerをデプロイ

❯ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.8/docs/examples/alb-ingress-controller.yaml
deployment.apps/alb-ingress-controller created

ALB Ingress Controllerデプロイメントのマニフェストを編集

❯ kubectl edit deployment.apps/alb-ingress-controller -n kube-system

spec.containers.args--cluster-name--aws-vpc-id--aws-region を設定します。

    spec:
      containers:
      - args:
        - --ingress-class=alb
        - --cluster-name=<your-cluster-name>
        - --aws-vpc-id=<your-vpc-id>
        - --aws-region=ap-northeast-1

ALB Ingress Controllerのポッドを確認

kube-systemalb-ingress-controller のポッドが出来上がりました。

❯ kubectl get pods -n kube-system
NAME                                      READY   STATUS    RESTARTS   AGE
alb-ingress-controller-65fcfcd9d4-nzpdr   1/1     Running   1          2m15s
coredns-84c76989c7-8s58g                  1/1     Running   0          23h
coredns-84c76989c7-pb5cb                  1/1     Running   0          23h

Ingressリソースを作成

Ingressリソースを作成し、サンプルアプリのService my-service に接続するALBを用意します。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: "ingress"
  namespace: "default"
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
  labels:
    app: ingress
spec:
  rules:
    - http:
        paths:
          - path: /*
            backend:
              serviceName: my-service
              servicePort: 80
❯ kubectl apply -f ingress.yaml
ingress.extensions/ingress created

動作確認

kubectl get ingress で取得したアドレスにアクセスできることを確認します。

❯ kubectl get ingress
NAME      CLASS    HOSTS   ADDRESS                                                                    PORTS   AGE
ingress   <none>   *       ...   80      2m6s

f:id:hiroki-sawano:20201022023633p:plain

後片付け

最後に kubectl delete でデプロイしたサンプルアプリを削除します。

❯ kubectl delete -f sample-pod.yml
service "my-service" deleted
deployment.apps "my-deployment" deleted