AWS EKS에서 ALB Ingress Controller 활용기

Coinone Tech Team
Coinone Tech Blog
Published in
13 min readOct 28, 2020

들어가며

안녕하세요. 코인원 Platform Engineer 허민입니다. Amazon의 EKS 한국 region 오픈 후 코인원은 자사의 핵심 서비스들을 EKS로 이전하는 작업을 진행하였습니다.

그러던 중에 Ingress controller 구성 과정에서, Nginx controller와 AWS ALB를 지원하는 AWS ALB Ingress Controller에서의 선택에 대해 아래와 같은 고민을 하게 되었습니다.

  • 실제 서비스에서 별다른 문제 없이 동작할 수 있을까?
  • 기존에 사용하던 LB구성을 EKS 환경에서도 그대로 사용 할 수 있는가?
  • 구성 가이드 및 사용 예제에 대한 자료가 충분한가?

결국 최종 결정은 AWS 환경에 구성과 운영 이점이 있는 ALB Ingress controller를 선택하게 되었습니다.

이번 글에서는 ALB Ingress Controller를 구성하면서 경험했던 이슈들과 활용 팁을 소개하고자 합니다.

ALB Ingress Controller Architecture

ALB Ingress Controller를 구성하기 전에 먼저 동작을 이해해 보도록 하겠습니다.

해당 내용은 AWS Open Source Blog의 내용에서 발췌하였습니다.

  1. Ingress Contriller는 API 서버로 부터 ingress event를 감시합니다. ingress 자원이 확인되면 AWS에 리소스를 생성합니다.
  2. Ingress 리소스에 대해 ALB가 생성 됩니다.
  3. Ingress 리소스에 할당된 백엔드에 대해 Target Group이 생성 됩니다.
  4. Ingress 리소스에 지정된 모든 포트에 대해 Listener가 생성됩니다. 포트를 지정하지 않으면 기본값으로 80 또는 443이 사용됩니다.
  5. 각각의 Ingress 리소스에 지정된 Path에 따라 Role이 생성 됩니다. 이후에는 특정 경로로 트래픽이 TargetGroup으로 라우팅 됩니다.

또한 ALB Ingress Controller는 Instance mode와 IP mode의 두가지 traffic mode를 지원하며, kubernetes에서 Ingress 생성할 때 annotations 항목에 alb.ingress.kubernetes.io/target-type을 선언하여 명시적으로 지정할 수 있습니다.

  • Instance mode: 외부에서 수신된 트래픽은 ALB를 거쳐 서비스 용으로 열린 NodePort에 도달합니다. (라우팅 되기 위한 어플리케이션의 서비스 타입을 NodePort로 지정해애 됨)
  • IP mode: 외부에서 수신된 트래픽은 ALB를 거쳐 클러스터 내의 컨테이너 포트로 직접 도달합니다. 이 모드를 사용하려면 Kubernetes 클러스터의 네트워킹 플러그인이 ENI의 보조 IP 주소를 사용할 수 있어야 합니다.

ALB Ingress Controller 배포

ALB Ingress Controller를 사용하기 위해서는 kubernetes 환경에 해당 pod를 생성해야 합니다. pod는 helm chart를 이용해 간편하게 설치가 가능합니다.

설치에 앞서 AWS와 kubernetes의 리소스에 접근하기 위해 아래와 같이 role을 생성 및 적용해 주어야 합니다.

  • IAM Role 생성 ( iam-policy.json 적용 )
  • EKS worker node에 위에서 생성한 IAM policy 적용
  • kubernetes RBAC Role 적용
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.0.0/docs/examples/rbac-role.yaml
  • ALB Ingress Controller helm chart 설치
helm install --name ingress-controller \
--namespace kube-system \
--set awsRegion=<Region_Name> \
--set awsVpcID=<Cluster_VPC_ID> \
--set clusterName=<EKS_CLUSTER_NAME> \
--set extraArgs."feature-gates"='waf=false' \
incubator/aws-alb-ingress-controller

이 때, aws상에서 waf를 사용하지 않을 경우에는 extraArgs로 ‘waf=false’ 옵션을 추가해 주어야 합니다.

Ingress 정의

Ingress Controller의 설치가 완료되면 Ingress annotation을 정의하는 것으로 ALB를 관리할 수 있습니다.

코인원의 경우 서비스별로 ingress를 생성하지 않고 internal과 external 역할을 하는 ingress만 각각 생성하여 서비스 역할에 맞게 host 라우팅을 추가하였습니다.

또한, target type을 instance로 지정하여 각 worker node에 node port가 할당되고 해당 host와 node port로 라우팅이 되도록 설정하였습니다.

apiVersion: extensions/v1
kind: Ingress
metadata:
name: "external-ingress"
labels:
app.kubernetes.io/name: "external-ingress"
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/subnets: subnet-02xxxxxx,subnet-0dxxxxxx
alb.ingress.kubernetes.io/target-type: instance

spec:
rules:
- host: "a.coinone.co.kr"
http:
paths:
- path: /*
backend:
serviceName: "coinone-a"
servicePort: 80
- host: "b.coinone.co.kr"
http:
paths:
- path: /*
backend:
serviceName: "coinone-b"
servicePort: 80
- host: "c.coinone.co.kr"
http:
paths:
- path: /*
backend:
serviceName: "coinone-c"
servicePort: 80

다만, 이 때 kubernetes namespace에 대한 제약사항이 있기 때문에 ALB를 이용해 접근해야 되는 서비스는 namespace 마다 Ingress를 생성해야 합니다.

위의 구성을 적용하면 ALB와 target group은 생성이 됩니다. 하지만 어떤 서비스들은 health check가 되지 않아 worker node의 target port가 unhealthy 상태 일 수 있습니다.

이를 해결하기 위해서는 각 service에 healthcheck-path annotation을 추가해야 합니다.

apiVersion: v1
kind: Service
metadata:
name: "coinone-a"
labels:
app: "coinone-a"
annotations:
alb.ingress.kubernetes.io/healthcheck-path: /healthy
spec:
type: "NodePort"
ports:
- name: "http"
port: 80
targetPort: 80
protocol: TCP

추가적인 Ingress 정의

위의 설정으로 ALB를 이용한 서비스 구성은 완료가 되었습니다만, ALB Ingress Controller를 좀 더 잘 사용하기 위해 아래 설정을 추가하도록 합니다.

공통 security-group 지정

위의 구성에서는 ingress가 생성되면 해당 worker node에 임의의 security group이 생성이 됩니다. 그런데 ingress가 계속 늘어나게 되면 어느순간 EC2 instance에 할당된 security group limit에 도달하게 됩니다.

위와 같은 문제를 방지하면서 불필요한 security group 생성을 막기위해 아래와 같은 공통 security-group annotation을 생성하고 Ingress annotation에 추가합니다.

apiVersion: extensions/v1
kind: Ingress
metadata:
name: "external-ingress"
labels:
app.kubernetes.io/name: "external-ingress"
annotations:
kubernetes.io/ingress.class: alb
...
alb.ingress.kubernetes.io/security-groups: sg-0f00000000000

SSL Certificate 지정

AWS Certificate Manager를 사용하고 있다면 아래 설정으로 ALB Controller에 SSL 인증서를 지정할 수 있습니다.

apiVersion: extensions/v1
kind: Ingress
metadata:
name: "external-ingress"
labels:
app.kubernetes.io/name: "external-ingress"
annotations:
kubernetes.io/ingress.class: alb
...
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-west-2:xxxxx:certificate/xxxxxxx
alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-2016-08

Redirection 지정

ALB의 redirection 기능을 사용하기 위해서는 아래와 같이 action annotation 설정과 host rule을 지정해야 합니다.

apiVersion: extensions/v1
kind: Ingress
metadata:
name: "external-ingress"
labels:
app.kubernetes.io/name: "external-ingress"
annotations:
kubernetes.io/ingress.class: alb
...
alb.ingress.kubernetes.io/actions.redirect-www: '{"Type": "redirect", "RedirectConfig": { "Host": "www.coinone.co.kr", "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
spec:
rules:
- host: "coinone.co.kr"
http:
paths:
- path: /*
backend:
serviceName: redirect-www
servicePort: use-annotation

또한 Protocol Rule을 사용한 redirection도 가능한데, 가장 많이 사용하는 https redirect의 경우에는 아래와 같이 설정이 가능합니다.

apiVersion: extensions/v1
kind: Ingress
metadata:
name: "external-ingress"
labels:
app.kubernetes.io/name: "external-ingress"
annotations:
kubernetes.io/ingress.class: alb
...
alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
hosts:
- host: "coinone.co.kr"
paths:
- path: /*
backend:
serviceName: ssl-redirect
servicePort: use-annotation
- path: /*
backend:
serviceName: coinone-aml
servicePort: 80

마무리하며

Kubernetes 환경에서는 NGINX Ingress Controller를 선호하시는 분들이 많으실꺼라 생각이 됩니다.

코인원에서는 ALB의 가장 큰 이점인 호스트 기반 또는 경로 기반 라우팅을 이용하기 위해서 ALB Ingress Controller를 선택하기는 했지만, 저희가 EKS 서비스를 구축할 당시에도 ALB Ingress Controller는 third party project에서 정식 버전으로 넘어온 지 얼마 되지 않아서 프로덕션에서의 안정성을 보장할 수 없었습니다. 실제 저희가 겪은 문제 중에도 ALB Ingress controller에서 에러가 발생하면서 pod의 메모리 사용량이 계속 증가하는 것을 목격하였고 이를 해결하기 위해 고생했던 기억이 있습니다.

그럼에도 불구하고 AWS 서비스 환경에서 ALB가 주는 편리한 옵션들 (security group 설정, health check 설정, SSL 인증서 지정 등)과 지속적으로 업데이트 되는 신규 추가 기능(로드밸런싱 알고리즘 지정, EKS Fargate mode IP 지원)의 이점을 얻을 수 있는 ALB Ingress Controller는 좋은 선택지라 생각이 됩니다.

허민, Platform Engineer

--

--