ALB Ingress Controllerを試す

ALB Ingress Controllerを試してみたメモ。

参考リンク

環境

コンポーネント バージョン 備考
eksctl 0.13.0
Kubernetes バージョン 1.14
プラットフォームのバージョン eks.7
aws-alb-ingress-controller v1.1.4

注意点

  • ALB Ingress Controllerで管理してもらうためには、Ingressアノテーションkubernetes.io/ingress.class: albを指定する
  • トラフィックモードが2種類あり、alb.ingress.kubernetes.io/target-typeで指定する
    • インスタンス」の場合、NodePort経由でPodにルーティングされるので、ServiceはNodePortで公開する必要がある
    • 「IP」の場合、PodのIPに直接ルーティングされる

クラスターの作成

クラスターを作成する。

eksctl create cluster --name=mycluster --nodes=3 --managed --ssh-access --ssh-public-key=sotosugi

ALB Ingress Controlerに必要なRoleはWorkerノードのインスタンスに付与してもよいし、よりセキュアな方法としてIAM Roles for ServiceAccount(IRSA)でPodに付与することもできる。 eksctlでのクラスターの作成時に--alb-ingress-accessのフラグをつけることで、WorkerノードにIAMロールを付与できるが、今回はマニュアルの記載にしたがってIRSAを使う。

サブネットにタグ付けが必要だが、eksctlで作っていればタグ付けされている。

全てのサブネットに以下が必要。

キー
kubernetes.io/cluster/<cluster-name> shared

パブリックサブネットに以下を必要。

キー
kubernetes.io/role/elb 1

プライベートサブネットに以下をが必要。

キー
kubernetes.io/role/internal-elb 1

ALB Ingress Controllerのデプロイ

ALB Ingress Controllerをデプロイする。

IRSAの設定

IAM OIDC プロバイダーを作成し、クラスターに関連づける。eksctlがやってくれる。

eksctl utils associate-iam-oidc-provider \
    --cluster mycluster \
    --approve

AWS CLIでやることも可能だが、サムプリントの取得がやや面倒。

作成されたOIDCプロバイダーを確認する。

aws iam list-open-id-connect-providers

ALB Ingress ControllerのPodに割り当てるためのIAMポリシーを作成する。

curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.4/docs/examples/iam-policy.json
aws iam create-policy \
    --policy-name ALBIngressControllerIAMPolicy \
    --policy-document file://iam-policy.json

出力されるこのポリシーのARNが後で必要になるのでメモしておく。

alb-ingress-controllerという名前のServiceAccount、ClusterRole、ClusterRoleBindingを作成する。

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

ALB Ingress Controller用のIAMロールを作成し、このロールに前のステップで作成したServiceAccountをアタッチし、作成済みのIAMポリシーをアタッチする。eksctlを使うとまとめてやってくれる。

eksctl create iamserviceaccount \
    --name alb-ingress-controller \
    --namespace kube-system \
    --cluster mycluster \
    --attach-policy-arn <ALBIngressControllerIAMPolicyのARN> \
    --override-existing-serviceaccounts \
    --approve

ServiceAccountへのアノテーションの付与もやってくれている。

$ kubectl get sa -n kube-system alb-ingress-controller -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::XXXXXXXXXXXX:role/eksctl-mycluster-addon-iamserviceaccount-kub-Role1-V4WM5Y6XVY6J
  creationTimestamp: "2020-02-26T13:29:55Z"
  name: alb-ingress-controller
  namespace: kube-system
  resourceVersion: "5890"
  selfLink: /api/v1/namespaces/kube-system/serviceaccounts/alb-ingress-controller
  uid: 1359da05-589c-11ea-8f07-0a9b53daa8b6
secrets:
- name: alb-ingress-controller-token-q6qlt
$

IAMロールを確認する。信頼関係の部分が独特。

$ aws iam get-role --role-name eksctl-mycluster-addon-iamserviceaccount-kub-Role1-V4WM5Y6XVY6J
{
    "Role": {
        "Path": "/",
        "RoleName": "eksctl-mycluster-addon-iamserviceaccount-kub-Role1-V4WM5Y6XVY6J",
        "RoleId": "AROAYXO4ULJGYQS6MY7J3",
        "Arn": "arn:aws:iam::XXXXXXXXXXXX:role/eksctl-mycluster-addon-iamserviceaccount-kub-Role1-V4WM5Y6XVY6J",
        "CreateDate": "2020-02-26T13:29:24+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Federated": "arn:aws:iam::XXXXXXXXXXXX:oidc-provider/oidc.eks.ap-northeast-1.amazonaws.com/id/ABBA5808E08E5733D7FEF998BD06C077"
                    },
                    "Action": "sts:AssumeRoleWithWebIdentity",
                    "Condition": {
                        "StringEquals": {
                            "oidc.eks.ap-northeast-1.amazonaws.com/id/ABBA5808E08E5733D7FEF998BD06C077:sub": "system:serviceaccount:kube-system:alb-ingress-controller",
                            "oidc.eks.ap-northeast-1.amazonaws.com/id/ABBA5808E08E5733D7FEF998BD06C077:aud": "sts.amazonaws.com"
                        }
                    }
                }
            ]
        },
        "Description": "",
        "MaxSessionDuration": 3600,
        "Tags": [
            {
                "Key": "alpha.eksctl.io/cluster-name",
                "Value": "mycluster"
            },
            {
                "Key": "eksctl.cluster.k8s.io/v1alpha1/cluster-name",
                "Value": "mycluster"
            },
            {
                "Key": "alpha.eksctl.io/iamserviceaccount-name",
                "Value": "kube-system/alb-ingress-controller"
            }
        ],
        "RoleLastUsed": {}
    }
}
$ aws iam list-attached-role-policies --role-name eksctl-mycluster-addon-iamserviceaccount-kub-Role1-V4WM5Y6XVY6J
{
    "AttachedPolicies": [
        {
            "PolicyName": "ALBIngressControllerIAMPolicy",
            "PolicyArn": "arn:aws:iam::XXXXXXXXXXXX:policy/ALBIngressControllerIAMPolicy"
        }
    ]
}
$ aws iam list-role-policies --role-name eksctl-mycluster-addon-iamserviceaccount-kub-Role1-V4WM5Y6XVY6J
{
    "PolicyNames": []
}

AWS CLIでも可能だが面倒で、以下の手順とアノテーション設定が必要。

ALB Ingress Controllerのデプロイ

ALB Ingress ControllerをDeploymentを作成する。

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

Deployment定義の一部を編集する。

kubectl edit deployment.apps/alb-ingress-controller -n kube-system
    spec:
      containers:
      - args:
        - --ingress-class=alb
+       - --cluster-name=mycluster
        image: docker.io/amazon/aws-alb-ingress-controller:v1.1.4
        imagePullPolicy: IfNotPresent
        name: alb-ingress-controller

稼働を確認する。

$ kubectl get po -n kube-system -l app.kubernetes.io/name=alb-ingress-controller
NAME                                      READY   STATUS    RESTARTS   AGE
alb-ingress-controller-577cb9c49b-rvk7b   1/1     Running   0          76s

稼働確認

Deploymentを作成する。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
kubectl apply -f nginx-deployment.yaml

Serviceを作成する。

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
kubectl apply -f nginx-service.yaml

Ingressを作成する。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  rules:
  - http:
      paths:
      - path: /*
        backend:
          serviceName: nginx
          servicePort: 80
kubectl apply -f nginx-ingress.yaml

作成したリソースを確認する。

$ kubectl get deployment
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   2/2     2            2           4m57s
$ kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.100.0.1       <none>        443/TCP   81m
nginx        ClusterIP   10.100.155.164   <none>        80/TCP    2m55s
$ kubectl get ingress
NAME    HOSTS   ADDRESS                                                                   PORTS   AGE
nginx   *       80934e0c-default-nginx-ef8b-1267588155.ap-northeast-1.elb.amazonaws.com   80      25m

作成されたALBを確認する。

aws elbv2 describe-load-balancers

URLにアクセスして確認。

$ curl 80934e0c-default-nginx-ef8b-1267588155.ap-northeast-1.elb.amazonaws.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>