Amazon EKS Ingress Grouping으로 비용 최적화하기

목차

개요

Amazon EKS에서 Ingress를 여러 개 사용할 때 생기는 비용 문제를 해결하고, AWS Load Balancer Controller의 Ingress Grouping 기능으로 Application Load Balancer(ALB)를 효율적으로 공유하는 방법을 알아보겠습니다.

문제 상황

기본 Ingress 동작

Kubernetes에서 Ingress는 클러스터 외부에서 내부 서비스에 접근할 수 있도록 HTTP/HTTPS 라우팅을 제공하는 API 객체입니다. AWS Load Balancer Controller를 사용하면 Ingress 리소스가 생성될 때마다 자동으로 ALB가 프로비저닝됩니다.

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  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: /
        pathType: Prefix
        backend:
          service:
            name: my-app-service
            port:
              number: 80

비용 문제

마이크로서비스 아키텍처에서는 여러 서비스가 각자 Ingress를 가지게 되고, 그러면 아래와 같은 문제가 생깁니다.

Ingress Grouping이란?

Ingress Grouping은 여러 Ingress 리소스가 하나의 ALB를 공유할 수 있게 해 주는 AWS Load Balancer Controller의 기능입니다.

Ingress Grouping으로 두 Namespace의 Ingress가 ALB 하나를 공유

Ingress Grouping으로 두 Namespace의 Ingress가 ALB 하나를 공유

Ingress Grouping으로 두 Namespace의 Ingress가 ALB 하나를 공유blue-green-ns와 orange-purple-ns의 두 Ingress가 같은 group.name app-color-lb를 쓴다. AWS Load Balancer Controller가 두 Ingress의 규칙을 병합해 ALB 하나에 적용하고, ALB의 path 규칙이 각 Namespace의 Service로 이어진다.EKS 클러스터blue-green-nsIngress blue-green-ingressgroup.name: app-color-lbblue-service, green-serviceorange-purple-nsIngress orange-purple-ingressgroup.name: app-color-lborange-service, purple-serviceAWS Load Balancer Controllerv2.0 이상ALB 하나k8s-appcolorlb-xxx 주소 공유같은 group.name같은 group.name규칙 자동 병합/blue, /green/orange, /purple
두 Namespace의 Ingress가 같은 group.name을 써서 AWS Load Balancer Controller가 ALB 하나로 합치고, 경로 규칙마다 각 Namespace의 Service로 보낸다.
그림 관계를 글로 읽기
  1. blue-green-ns의 blue-green-ingress가 group.name app-color-lb를 쓴다.
  2. orange-purple-ns의 orange-purple-ingress도 같은 group.name을 쓴다.
  3. AWS Load Balancer Controller가 두 Ingress 규칙을 자동 병합해 ALB 하나에 적용한다. 두 Ingress의 ADDRESS가 같다.
  4. ALB의 /blue, /green 규칙은 blue-green-ns의 blue-service, green-service로 간다.
  5. ALB의 /orange, /purple 규칙은 orange-purple-ns의 orange-service, purple-service로 간다.

주요 특징

사전 준비사항 및 설치

Ingress Grouping을 사용하려면 몇 가지 필수 구성요소를 미리 설치하고 설정해야 합니다.

1. EKS 클러스터 요구사항

기본 요구사항

bash
# EKS 클러스터 생성 (eksctl 사용 예시)
eksctl create cluster \
  --name my-cluster \
  --region us-west-2 \
  --nodegroup-name standard-workers \
  --node-type m5.large \
  --nodes 3 \
  --nodes-min 1 \
  --nodes-max 4 \
  --managed

2. AWS Load Balancer Controller 설치

Ingress Grouping은 AWS Load Balancer Controller v2.0 이상에서 지원됩니다.

2-1. IAM 정책 생성

먼저 AWS Load Balancer Controller가 사용할 IAM 정책을 생성합니다.

bash
# IAM 정책 다운로드
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.7.2/docs/install/iam_policy.json

# IAM 정책 생성
aws iam create-policy \
    --policy-name AWSLoadBalancerControllerIAMPolicy \
    --policy-document file://iam_policy.json

2-2. IAM 역할 및 서비스 계정 생성

bash
# OIDC 공급자 생성 (한 번만 실행)
eksctl utils associate-iam-oidc-provider --region=us-west-2 --cluster=my-cluster --approve

# 서비스 계정 생성 및 IAM 역할 연결
eksctl create iamserviceaccount \
  --cluster=my-cluster \
  --namespace=kube-system \
  --name=aws-load-balancer-controller \
  --role-name AmazonEKSLoadBalancerControllerRole \
  --attach-policy-arn=arn:aws:iam::ACCOUNT-ID:policy/AWSLoadBalancerControllerIAMPolicy \
  --approve

2-3. Helm을 통한 Controller 설치

bash
# Helm 차트 레포지토리 추가
helm repo add eks https://aws.github.io/eks-charts
helm repo update

# AWS Load Balancer Controller 설치
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=my-cluster \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller \
  --set region=us-west-2 \
  --set vpcId=vpc-xxxxxxxx

2-4. 설치 확인

bash
# Controller 팟 상태 확인
kubectl get deployment -n kube-system aws-load-balancer-controller

# 로그 확인
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller

3. VPC 및 서브넷 설정

3-1. 서브넷 태깅

ALB가 올바른 서브넷에 생성되도록 서브넷에 태그를 설정해야 합니다.

bash
# 퍼블릭 서브넷 태깅 (인터넷 대면 ALB용)
aws ec2 create-tags \
    --resources subnet-12345678 subnet-87654321 \
    --tags Key=kubernetes.io/role/elb,Value=1

# 프라이빗 서브넷 태깅 (내부 ALB용)
aws ec2 create-tags \
    --resources subnet-abcdefgh subnet-hgfedcba \
    --tags Key=kubernetes.io/role/internal-elb,Value=1

# 클러스터별 태깅 (여러 클러스터 사용 시)
aws ec2 create-tags \
    --resources subnet-12345678 subnet-87654321 \
    --tags Key=kubernetes.io/cluster/my-cluster,Value=shared

3-2. 보안 그룹 설정 확인

bash
# 클러스터 보안 그룹에 태그 추가 (필요시)
aws ec2 create-tags \
    --resources sg-xxxxxxxxx \
    --tags Key=kubernetes.io/cluster/my-cluster,Value=owned

4. 필수 어노테이션 및 IngressClass 설정

4-1. IngressClass 생성 (Kubernetes 1.18+)

yaml
# ingress-class.yaml
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: alb
spec:
  controller: ingress.k8s.aws/alb
bash
kubectl apply -f ingress-class.yaml

4-2. 기본 설정 검증

bash
# AWS Load Balancer Controller 버전 확인
kubectl get deployment aws-load-balancer-controller -n kube-system -o yaml | grep image:

# 서비스 계정 확인
kubectl get serviceaccount aws-load-balancer-controller -n kube-system -o yaml

# IAM 역할 확인
kubectl describe serviceaccount aws-load-balancer-controller -n kube-system

5. 설치 검증을 위한 테스트

5-1. 간단한 테스트 애플리케이션 배포

yaml
# test-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: test-app
  template:
    metadata:
      labels:
        app: test-app
    spec:
      containers:
      - name: app
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: test-service
  namespace: default
spec:
  type: NodePort
  selector:
    app: test-app
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  namespace: default
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: test-service
            port:
              number: 80
bash
# 테스트 앱 배포
kubectl apply -f test-app.yaml

# Ingress 상태 확인
kubectl get ingress test-ingress

# ALB 생성 확인
kubectl describe ingress test-ingress

6. 문제 해결 가이드

6-1. 일반적인 문제들

문제 1: Controller Pod가 시작되지 않음

bash
# 서비스 계정 권한 확인
kubectl describe serviceaccount aws-load-balancer-controller -n kube-system

# IAM 역할 정책 확인
aws iam list-attached-role-policies --role-name AmazonEKSLoadBalancerControllerRole

문제 2: ALB가 생성되지 않음

bash
# Controller 로그 확인
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller

# 서브넷 태그 확인
aws ec2 describe-subnets --subnet-ids subnet-12345678 --query 'Subnets[*].Tags'

문제 3: 권한 부족 오류

bash
# IAM 정책이 최신인지 확인
aws iam get-policy-version \
    --policy-arn arn:aws:iam::ACCOUNT-ID:policy/AWSLoadBalancerControllerIAMPolicy \
    --version-id v1

6-2. 설치 완료 체크리스트

실습: Ingress Grouping 구현

이제 사전 준비가 끝났으니 Ingress Grouping을 실제로 구현해 보겠습니다.

1. 기본 환경 준비

먼저 두 개의 네임스페이스에 각각 애플리케이션을 배포합니다.

bash
# 네임스페이스 생성
kubectl create namespace blue-green-ns
kubectl create namespace orange-purple-ns

2. 애플리케이션 배포

각 네임스페이스에 색상별 애플리케이션을 배포합니다.

yaml
# blue-green-ns 네임스페이스의 애플리케이션
apiVersion: apps/v1
kind: Deployment
metadata:
  name: blue-app
  namespace: blue-green-ns
spec:
  replicas: 2
  selector:
    matchLabels:
      app: blue-app
  template:
    metadata:
      labels:
        app: blue-app
    spec:
      containers:
      - name: blue-app
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: blue-service
  namespace: blue-green-ns
spec:
  type: NodePort
  selector:
    app: blue-app
  ports:
  - port: 80
    targetPort: 80

3. Ingress Grouping 설정

가장 중요한 부분인 Ingress Grouping 설정입니다. alb.ingress.kubernetes.io/group.name 어노테이션을 사용합니다.

yaml
# blue-green-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blue-green-ingress
  namespace: blue-green-ns
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/group.name: app-color-lb  # 그룹 이름 지정
spec:
  ingressClassName: alb
  rules:
  - http:
      paths:
      - path: /blue
        pathType: Prefix
        backend:
          service:
            name: blue-service
            port:
              number: 80
      - path: /green
        pathType: Prefix
        backend:
          service:
            name: green-service
            port:
              number: 80
yaml
# orange-purple-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: orange-purple-ingress
  namespace: orange-purple-ns
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/group.name: app-color-lb  # 동일한 그룹 이름
spec:
  ingressClassName: alb
  rules:
  - http:
      paths:
      - path: /orange
        pathType: Prefix
        backend:
          service:
            name: orange-service
            port:
              number: 80
      - path: /purple
        pathType: Prefix
        backend:
          service:
            name: purple-service
            port:
              number: 80

4. 결과 확인

배포 후 Ingress 상태를 확인해 보면 두 Ingress가 동일한 ALB 주소를 공유하는 것을 볼 수 있습니다.

bash
kubectl get ingress -A

NAMESPACE          NAME                    ADDRESS
blue-green-ns      blue-green-ingress      k8s-appcolorlb-xxx.elb.amazonaws.com
orange-purple-ns   orange-purple-ingress   k8s-appcolorlb-xxx.elb.amazonaws.com

고급 설정

1. 그룹 순서 제어 (Group Order)

Ingress 규칙의 평가 순서를 제어하려면 group.order 어노테이션을 사용합니다.

yaml
metadata:
  annotations:
    alb.ingress.kubernetes.io/group.name: my-group
    alb.ingress.kubernetes.io/group.order: '10'  # 낮은 숫자가 우선순위 높음

2. 그룹 이름 규칙

yaml
# 올바른 예시
alb.ingress.kubernetes.io/group.name: my-app-group
alb.ingress.kubernetes.io/group.name: production.web-services

# 잘못된 예시
alb.ingress.kubernetes.io/group.name: -my-group-  # 잘못된 시작/끝
alb.ingress.kubernetes.io/group.name: My_Group   # 대문자와 언더스코어 사용 불가

보안 고려사항

1. 신뢰 경계(Trust Boundary)

동일한 Ingress Group에 속한 모든 사용자는 같은 신뢰 경계 내에 있어야 합니다. 다른 사용자가 동일한 그룹 이름을 사용하여 Ingress를 생성하면 기존 규칙을 덮어쓸 수 있습니다.

2. 그룹 이름 충돌 방지

yaml
# 권장: 명확하고 고유한 이름 사용
alb.ingress.kubernetes.io/group.name: team-a-production-services

# 비권장: 일반적인 이름 사용
alb.ingress.kubernetes.io/group.name: my-group

3. RBAC 설정

Ingress 리소스에 대한 적절한 RBAC 정책을 설정하여 권한이 있는 사용자만 특정 그룹에 접근할 수 있도록 제한해야 합니다.

제한사항 및 주의사항

1. ALB 규칙 제한

2. 충돌 해결

기본적으로 Ingress 간의 규칙 순서는 네임스페이스/이름의 사전적 순서로 결정됩니다. 명시적인 순서 제어를 위해서는 group.order를 사용해야 합니다.

3. 디버깅 복잡성

여러 Ingress가 하나의 ALB를 공유하므로 문제 발생 시 원인 파악이 복잡할 수 있습니다.

모니터링 및 트러블슈팅

1. AWS Load Balancer Controller 로그 확인

bash
kubectl logs -f -n kube-system -l app.kubernetes.io/instance=aws-load-balancer-controller

2. ALB 규칙 확인

bash
# ALB ARN 확인
ALB_ARN=$(aws elbv2 describe-load-balancers --query 'LoadBalancers[?contains(LoadBalancerName, `k8s-mygroup`)].LoadBalancerArn' --output text)

# 리스너 규칙 확인
LISTENER_ARN=$(aws elbv2 describe-listeners --load-balancer-arn $ALB_ARN --query 'Listeners[0].ListenerArn' --output text)
aws elbv2 describe-rules --listener-arn $LISTENER_ARN

3. Ingress 상태 확인

bash
kubectl describe ingress <ingress-name> -n <namespace>

실제 사용 사례

1. 마이크로서비스 환경

yaml
# API Gateway 패턴
alb.ingress.kubernetes.io/group.name: api-gateway
# /api/users -> user-service
# /api/orders -> order-service  
# /api/products -> product-service

2. 환경별 분리

yaml
# 개발 환경
alb.ingress.kubernetes.io/group.name: dev-services

# 스테이징 환경  
alb.ingress.kubernetes.io/group.name: staging-services

# 프로덕션 환경
alb.ingress.kubernetes.io/group.name: prod-services

비용 절감 효과

예시 계산

마무리

Ingress Grouping을 쓰면 Amazon EKS에서 ALB 비용을 크게 절감할 수 있습니다. 특히 마이크로서비스 아키텍처를 사용하는 환경이라면 꼭 고려해야 할 기능입니다.

핵심 포인트:

다음에는 Target Group Binding을 활용한 고급 로드밸런싱 패턴도 다뤄 보겠습니다.

참고 자료

도식

100%

끌어서 이동, 두 손가락이나 휠로 확대·축소. 키보드: 화살표 이동, + − 확대·축소, 0 맞춤, Esc 닫기. 같은 내용은 그림 아래 “그림 관계를 글로 읽기”에 있다.