AWS Elastic Kubernetes Service: запуск ALB Ingress controller

Автор: | 26/03/2020
 

UPD: тут описывается ALB Controller v1. См. AWS: миграция AWS ALB Ingress Controller (v1) на AWS Load Balancer Controller (v2).

AWS ALB Ingress Controller for Kubernetes – контроллер Kubernetes, который управляет соданием Application Load Balancer (ALB) при создании в кластере ресурса типа Ingress с аннотацией вида kubernetes.io/ingress.class: alb.

Ingress-ресурс в свою очередь определяет настройки ALB для роутинга HTTP или HTTPS трафика к различным подам кластера.

Документация:

Ingress controller types

AWS ALB Ingress controller поддерживает два типа передачи трафика –  instance mode и ip mode:

  • instance mode: трафик попадает на ALB, затем на сервис NodePort, после чего роутится к подам внутри кластера
  • ip mode: рафик попадает на ALB, затем попадает напрямую к подам в кластере. В документации говорится, что требуется установка AWS CNI plugin for Kubernetes, но с EKS работает “из коробки”

См. документацию тут>>>.

eksctl – create cluster

Создаём тестовый кластер:

[simterm]

$ eksctl create cluster --profile arseniy --region eu-north-1 --name eks-alb-testing
[ℹ]  eksctl version 0.15.0
[ℹ]  using region eu-north-1
[ℹ]  setting availability zones to [eu-north-1b eu-north-1c eu-north-1a]
[ℹ]  subnets for eu-north-1b - public:192.168.0.0/19 private:192.168.96.0/19
[ℹ]  subnets for eu-north-1c - public:192.168.32.0/19 private:192.168.128.0/19
[ℹ]  subnets for eu-north-1a - public:192.168.64.0/19 private:192.168.160.0/19
[ℹ]  nodegroup "ng-c408bab3" will use "ami-0d40170cbe0b51e62" [AmazonLinux2/1.14]
[ℹ]  using Kubernetes version 1.14
[ℹ]  creating EKS cluster "eks-alb-testing" in "eu-north-1" region with un-managed nodes
...
[ℹ]  node "ip-192-168-11-166.eu-north-1.compute.internal" is ready
[ℹ]  node "ip-192-168-35-128.eu-north-1.compute.internal" is ready
[ℹ]  kubectl command should work with "/home/setevoy/.kube/config", try 'kubectl get nodes'
[✔]  EKS cluster "eks-alb-testing" in "eu-north-1" region is ready

[/simterm]

IAM OIDC provider

Документация – https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html.

Потребуется для ServiceAccount, см. https://eksctl.io/usage/iamserviceaccounts.

Создаём:

[simterm]

$ eksctl --profile arseniy --region=eu-north-1 utils associate-iam-oidc-provider --cluster eks-alb-testing  --approve
[ℹ]  eksctl version 0.15.0
[ℹ]  using region eu-north-1
[ℹ]  will create IAM Open ID Connect provider for cluster "eks-alb-testing" in "eu-north-1"
[✔]  created IAM Open ID Connect provider for cluster "eks-alb-testing" in "eu-north-1"

[/simterm]

Проверяем:

[simterm]

$ aws --profile arseniy. --region=eu-north-1 eks describe-cluster --name eks-alb-testing --query "cluster.identity.oidc.issuer" --output text
https://oidc.eks.eu-north-1.amazonaws.com/id/B59F43D7826EB61861FC73EE13216CD8

[/simterm]

Или в панели управления AWS > Identity providers:

ALB IAM policty

Далее требуется добавить IAM политику, которая будет управлять доступами для пода с ALB Ingress Controller, который будет выполнять API-запросы к AWS для создания и настройки Application Load Balancer.

Можно создать вручную так:

[simterm]

$ aws --profile arseniy --region=eu-north-1 iam create-policy --policy-name ALBIngressControllerIAMPolicy --policy-document https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.4/docs/examples/iam-policy.json

[/simterm]

Либо добавить ещё один ресурс в CloudFormation используя AWS::IAM::Role, но это потом (пост пока в черновиках).

В выводе результата будет ARN ресурса – “Arn”: “arn:aws:iam::534***385:policy/ALBIngressControllerIAMPolicy” – он нам сейчас понадобится.

ALB Ingress IAM Role

См. https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/

1 iamserviceaccount (kube-system/alb-ingress-controller) was excluded

В официальной документации порядок выполнения другой – там сначала создаётся RBAC-роль и RoleBinding, а затем – iamserviceaccount.

На деле это может привести к тому, что создании serviceaccount “kube-system/alb-ingress-controller” eksctl сообщает, что такой якобы уже есть, и пропускает его:

[simterm]

[ℹ] eksctl version 0.15.0                                                                                                                        
[ℹ] using region eu-north-1                                                                                                                      
[ℹ] 1 iamserviceaccount(s) that already exist (kube-system/alb-ingress-controller) will be excluded                                              
[ℹ] combined exclude rules: kube-system/alb-ingress-controller                                                                                   
[ℹ] 1 iamserviceaccount (kube-system/alb-ingress-controller) was excluded (based on the include/exclude rules)                                   
[!] serviceaccounts that exists in Kubernetes will be excluded, use --override-existing-serviceaccounts to override                              
[ℹ] no tasks

[/simterm]

После общения с тех. поддержкой AWS – мы поменяли порядок выполнения – сначала создаём IAM-роль, а уже потом – RBAC Role и биндинг.

Продолжаем.

Проверяем к какому кластеру мы сейчас подключены – just in case:

[simterm]

$ kubectl config current-context
[email protected]

[/simterm]

Окей.

Далее, с помощью eksctl, создаём IAM роль для ALB Ingress контроллера, и используя ARN IAM политики, созданной выше – подключаем к этой роли, для чего будет создан ещё один стек CloudFormation:

[simterm]

$ eksctl --profile arseniy --region=eu-north-1 create iamserviceaccount --name alb-ingress-controller --namespace kube-system  --override-existing-serviceaccounts --approve --cluster eks-alb-testing --attach-policy-arn arn:aws:iam::534***385:policy/ALBIngressControllerIAMPolicy
[ℹ]  eksctl version 0.15.0
[ℹ]  using region eu-north-1
[ℹ]  1 task: { 2 sequential sub-tasks: { create IAM role for serviceaccount "kube-system/alb-ingress-controller", create serviceaccount "kube-system/alb-ingress-controller" } }
[ℹ]  building iamserviceaccount stack "eksctl-eks-alb-testing-addon-iamserviceaccount-kube-system-alb-ingress-controller"
[ℹ]  deploying stack "eksctl-eks-alb-testing-addon-iamserviceaccount-kube-system-alb-ingress-controller"
[ℹ]  created serviceaccount "kube-system/alb-ingress-controller"

[/simterm]

Ждём завершения создания стека:

ALB Ingress ServiceAccount

Создаём ServiceAccount с именем alb-ingress-controller в kube-system namespace, к нему ClusterRoleBinding и ClusterRole с именем alb-ingress-controller с правилами доступа:

[simterm]

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.4/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

[/simterm]

Проверяем:

[simterm]

$ kubectl -n kube-system get serviceaccounts | grep alb
alb-ingress-controller               1         32s

[/simterm]

Запуск ALB Ingress Controller

Используем деплоймент https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.4/docs/examples/alb-ingress-controller.yaml, который создаст под с образом docker.io/amazon/aws-alb-ingress-controller.

Копируем к себе на машину:

[simterm]

$ wget https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.4/docs/examples/alb-ingress-controller.yaml

[/simterm]

Редактируем, и в блоке:

...
    spec:
      containers:
        - name: alb-ingress-controller
          args:
...

Добавляем параметры:

  • --cluster-name=eks-alb-testing
  • --aws-vpc-id=vpc-06a182dd0e5ef1b70
  • --aws-region=eu-north-1

VPC ID есть в Outputs корневого стека кластера – eksctl-eks-alb-testing-cluster:

Приводим файл к виду:

И запускаем ALB Ingress Controller:

[simterm]

$ kubectl apply -f alb-ingress-controller.yaml
deployment.apps/alb-ingress-controller created

[/simterm]

Проверяем его под:

[simterm]

$ kubectl -n kube-system get pod
NAME                                     READY   STATUS    RESTARTS   AGE
alb-ingress-controller-c47448d84-49tsc   1/1     Running   0          36s

[/simterm]

И логи самого контроллера:

[simterm]

$ kubectl logs -n kube-system deployment.apps/alb-ingress-controller -f
-------------------------------------------------------------------------------
AWS ALB Ingress controller
  Release:    v1.1.4
...
I0325 14:18:03.203499       1 leaderelection.go:205] attempting to acquire leader lease  kube-system/ingress-controller-leader-alb...
I0325 14:18:03.211928       1 leaderelection.go:214] successfully acquired lease kube-system/ingress-controller-leader-alb
I0325 14:18:03.312309       1 controller.go:134] kubebuilder/controller "level"=0 "msg"="Starting Controller"  "controller"="alb-ingress-controller"
I0325 14:18:03.412486       1 controller.go:154] kubebuilder/controller "level"=0 "msg"="Starting workers"  "controller"="alb-ingress-controller" "worker count"=1

[/simterm]

Запустился, работает – отлично.

Работает ли?

Проверяем.

Запуск приложения

Для проверки – запустим контейнер с NGINX.

Создаём:

  1. Kubernetes deployment для управления контейнерами
  2. добавляем NodePort Service для роутинга трафика к контейнерам
  3. и сам Ingress объект, которому передаём тип internet-facing ALB – этот Ingress увидит наш ALB Controller, который должен будет запустить создание AWS Application Load Balancer

Деплоймент:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: "eks-alb-testing-deployment"
spec:
  selector:
    matchLabels:
      app: "eks-alb-testing-web"
  replicas: 1
  template:
    metadata:
      labels:
        app: "eks-alb-testing-web"
    spec:
      containers:
      - image: nginx
        imagePullPolicy: Always
        name: "eks-alb-testing-web-nginx"
        ports:
        - containerPort: 80  
          
---
apiVersion: v1
kind: Service
metadata:
  name: "eks-alb-testing-web-service"
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  type: NodePort
  selector:          
    app: "eks-alb-testing-web"
    
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: "eks-alb-testing-web-ingress"
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
  labels:
    app: bttrm-eks-dev-0-web
spec:
  rules:
    - http:
        paths:
          - path: /*
            backend:
              serviceName: "eks-alb-testing-web-service"
              servicePort: 80

Применяем:

[simterm]

$ kubectl apply -f nginx-testing-app.yml 
deployment.apps/eks-alb-testing-deployment created
service/eks-alb-testing-web-service created
ingress.extensions/eks-alb-testing-web-ingress created

[/simterm]

Смотрим логи контроллера:

[simterm]

E0325 14:24:06.627453       1 controller.go:217] kubebuilder/controller "msg"="Reconciler error" "error"="no object matching key \"default/eks-alb-testing-web-ingress\" in local store"  "controller"="alb-ingress-controller" "request"={"Namespace":"default","Name":"eks-alb-testing-web-ingress"}
I0325 14:24:09.257834       1 security_group.go:36] default/eks-alb-testing-web-ingress: creating securityGroup dbd770cc-default-eksalbtes-09fa:managed LoadBalancer securityGroup by ALB Ingress Controller
I0325 14:24:09.340734       1 tags.go:69] default/eks-alb-testing-web-ingress: modifying tags {  kubernetes.io/namespace: "default",  kubernetes.io/ingress-name: "eks-alb-testing-web-ingress",  ingress.k8s.aws/cluster: "eks-alb-testing",  ingress.k8s.aws/stack: "default/eks-alb-testing-web-ingress",  ingress.k8s.aws/resource: "ManagedLBSecurityGroup",  kubernetes.io/cluster-name: "eks-alb-testing"} on sg-021899dacc4559be8
I0325 14:24:09.436719       1 security_group.go:75] default/eks-alb-testing-web-ingress: granting inbound permissions to securityGroup sg-021899dacc4559be8: [{    FromPort: 80,    IpProtocol: "tcp",    IpRanges: [{        CidrIp: "0.0.0.0/0",        Description: "Allow ingress on port 80 from 0.0.0.0/0"      }],    ToPort: 80  }]
I0325 14:24:09.665207       1 loadbalancer.go:191] default/eks-alb-testing-web-ingress: creating LoadBalancer dbd770cc-default-eksalbtes-09fa
I0325 14:24:10.187386       1 loadbalancer.go:208] default/eks-alb-testing-web-ingress: LoadBalancer dbd770cc-default-eksalbtes-09fa created, ARN: arn:aws:elasticloadbalancing:eu-north-1:534***385:loadbalancer/app/dbd770cc-default-eksalbtes-09fa/979c262ea2e12983
I0325 14:24:10.286302       1 targetgroup.go:119] default/eks-alb-testing-web-ingress: creating target group dbd770cc-fe1e32fc96596dcf2c1
I0325 14:24:10.433821       1 targetgroup.go:138] default/eks-alb-testing-web-ingress: target group dbd770cc-fe1e32fc96596dcf2c1 created: arn:aws:elasticloadbalancing:eu-north-1:534***385:targetgroup/dbd770cc-fe1e32fc96596dcf2c1/ef783b9fead58965
I0325 14:24:10.448670       1 tags.go:43] default/eks-alb-testing-web-ingress: modifying tags {  kubernetes.io/ingress-name: "eks-alb-testing-web-ingress",  ingress.k8s.aws/cluster: "eks-alb-testing",  ingress.k8s.aws/stack: "default/eks-alb-testing-web-ingress",  kubernetes.io/service-name: "eks-alb-testing-web-service",  kubernetes.io/service-port: "80",  ingress.k8s.aws/resource: "default/eks-alb-testing-web-ingress-eks-alb-testing-web-service:80",  kubernetes.io/cluster/eks-alb-testing: "owned",  kubernetes.io/namespace: "default"} on arn:aws:elasticloadbalancing:eu-north-1:534***385:targetgroup/dbd770cc-fe1e32fc96596dcf2c1/ef783b9fead58965
I0325 14:24:10.636180       1 targets.go:80] default/eks-alb-testing-web-ingress: Adding targets to arn:aws:elasticloadbalancing:eu-north-1:534***385:targetgroup/dbd770cc-fe1e32fc96596dcf2c1/ef783b9fead58965: i-0622ff000570f32c7:31095, i-062329ba6419ba845:31095
I0325 14:24:10.821148       1 listener.go:110] default/eks-alb-testing-web-ingress: creating listener 80
E0325 14:24:10.854943       1 controller.go:217] kubebuilder/controller "msg"="Reconciler error" "error"="failed to reconcile listeners due to failed to reconcile rules due to ListenerNotFound: One or more listeners not found\n\tstatus code: 400, request id: d09ccc73-7f21-4d19-aca3-9fefad546a43"  "controller"="alb-ingress-controller" "request"={"Namespace":"default","Name":"eks-alb-testing-web-ingress"}
I0325 14:24:12.301420       1 rules.go:60] default/eks-alb-testing-web-ingress: creating rule 1 on arn:aws:elasticloadbalancing:eu-north-1:534***385:listener/app/dbd770cc-default-eksalbtes-09fa/979c262ea2e12983/455a07658116adcd
I0325 14:24:12.324525       1 rules.go:77] default/eks-alb-testing-web-ingress: rule 1 created with conditions [{    Field: "path-pattern",    Values: ["/*"]  }]
I0325 14:24:12.561377       1 instance_attachment_v2.go:192] default/eks-alb-testing-web-ingress: granting inbound permissions to securityGroup sg-0005aadfa599d071c: [{    FromPort: 0,    IpProtocol: "tcp",    ToPort: 65535,    UserIdGroupPairs: [{        GroupId: "sg-021899dacc4559be8"      }]  }]
I0325 14:24:13.171590       1 rules.go:82] default/eks-alb-testing-web-ingress: modifying rule 1 on arn:aws:elasticloadbalancing:eu-north-1:534***385:listener/app/dbd770cc-default-eksalbtes-09fa/979c262ea2e12983/455a07658116adcd
I0325 14:24:13.192456       1 rules.go:98] default/eks-alb-testing-web-ingress: rule 1 modified with conditions [{    Field: "path-pattern",    Values: ["/*"]  }]

[/simterm]

Проверяем Ingress:

[simterm]

$ kubectl get ingress -o wide
NAME                          HOSTS   ADDRESS                                                                   PORTS   AGE
eks-alb-testing-web-ingress   *       dbd770cc-default-eksalbtes-09fa-1532296804.eu-north-1.elb.amazonaws.com   80      114s

[/simterm]

И пробуем подключиться:

[simterm]

$ curl -I dbd770cc-default-eksalbtes-09fa-1532296804.eu-north-1.elb.amazonaws.com
HTTP/1.1 200 OK
Date: Wed, 25 Mar 2020 14:26:27 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Server: nginx/1.17.9
Last-Modified: Tue, 03 Mar 2020 14:32:47 GMT
ETag: "5e5e6a8f-264"
Accept-Ranges: bytes

[/simterm]

Готово.