Amazon EKS에서 여러 개의 Ingress를 사용할 때 발생하는 비용 문제를 해결하고, AWS Load Balancer Controller의 Ingress Grouping 기능을 활용하여 Application Load Balancer(ALB)를 효율적으로 공유하는 방법을 알아보겠습니다.
Kubernetes에서 Ingress는 클러스터 외부에서 내부 서비스에 접근할 수 있도록 HTTP/HTTPS 라우팅을 제공하는 API 객체입니다. AWS Load Balancer Controller를 사용하면 Ingress 리소스가 생성될 때마다 자동으로 ALB가 프로비저닝됩니다.
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은 AWS Load Balancer Controller의 기능으로, 여러 Ingress 리소스가 하나의 ALB를 공유할 수 있게 해주는 기능입니다.
Ingress Grouping을 사용하기 위해서는 몇 가지 필수 구성요소들이 사전에 설치되고 설정되어야 합니다.
# 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
Ingress Grouping은 AWS Load Balancer Controller v2.0 이상에서 지원됩니다.
먼저 AWS Load Balancer Controller가 사용할 IAM 정책을 생성합니다.
# 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
# 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
# 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
# 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
ALB가 올바른 서브넷에 생성되도록 서브넷에 태그를 설정해야 합니다.
# 퍼블릭 서브넷 태깅 (인터넷 대면 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
# 클러스터 보안 그룹에 태그 추가 (필요시)
aws ec2 create-tags \
--resources sg-xxxxxxxxx \
--tags Key=kubernetes.io/cluster/my-cluster,Value=owned
# ingress-class.yaml
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: alb
spec:
controller: ingress.k8s.aws/alb
kubectl apply -f ingress-class.yaml
# 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
# 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
# 테스트 앱 배포
kubectl apply -f test-app.yaml
# Ingress 상태 확인
kubectl get ingress test-ingress
# ALB 생성 확인
kubectl describe ingress test-ingress
문제 1: Controller Pod가 시작되지 않음
# 서비스 계정 권한 확인
kubectl describe serviceaccount aws-load-balancer-controller -n kube-system
# IAM 역할 정책 확인
aws iam list-attached-role-policies --role-name AmazonEKSLoadBalancerControllerRole
문제 2: ALB가 생성되지 않음
# 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: 권한 부족 오류
# IAM 정책이 최신인지 확인
aws iam get-policy-version \
--policy-arn arn:aws:iam::ACCOUNT-ID:policy/AWSLoadBalancerControllerIAMPolicy \
--version-id v1
이제 모든 사전 준비가 완료되었으므로 Ingress Grouping을 실제로 구현해보겠습니다.
먼저 두 개의 네임스페이스에 각각 애플리케이션을 배포합니다.
# 네임스페이스 생성
kubectl create namespace blue-green-ns
kubectl create namespace orange-purple-ns
각 네임스페이스에 색상별 애플리케이션을 배포합니다.
# 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
가장 중요한 부분인 Ingress Grouping 설정입니다. alb.ingress.kubernetes.io/group.name
어노테이션을 사용합니다.
# 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
# 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
배포 후 Ingress 상태를 확인해보면 두 Ingress가 동일한 ALB 주소를 공유하는 것을 볼 수 있습니다.
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
Ingress 규칙의 평가 순서를 제어하려면 group.order
어노테이션을 사용합니다.
metadata:
annotations:
alb.ingress.kubernetes.io/group.name: my-group
alb.ingress.kubernetes.io/group.order: '10' # 낮은 숫자가 우선순위 높음
-
, .
만 사용 가능# 올바른 예시
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 # 대문자와 언더스코어 사용 불가
동일한 Ingress Group에 속한 모든 사용자는 같은 신뢰 경계 내에 있어야 합니다. 다른 사용자가 동일한 그룹 이름을 사용하여 Ingress를 생성하면 기존 규칙을 덮어쓸 수 있습니다.
# 권장: 명확하고 고유한 이름 사용
alb.ingress.kubernetes.io/group.name: team-a-production-services
# 비권장: 일반적인 이름 사용
alb.ingress.kubernetes.io/group.name: my-group
Ingress 리소스에 대한 적절한 RBAC 정책을 설정하여 권한이 있는 사용자만 특정 그룹에 접근할 수 있도록 제한해야 합니다.
기본적으로 Ingress 간의 규칙 순서는 네임스페이스/이름의 사전적 순서로 결정됩니다. 명시적인 순서 제어를 위해서는 group.order
를 사용해야 합니다.
여러 Ingress가 하나의 ALB를 공유하므로 문제 발생 시 원인 파악이 복잡할 수 있습니다.
kubectl logs -f -n kube-system -l app.kubernetes.io/instance=aws-load-balancer-controller
# 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
kubectl describe ingress <ingress-name> -n <namespace>
# API Gateway 패턴
alb.ingress.kubernetes.io/group.name: api-gateway
# /api/users -> user-service
# /api/orders -> order-service
# /api/products -> product-service
# 개발 환경
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 비용을 크게 절감할 수 있는 강력한 기능입니다. 특히 마이크로서비스 아키텍처를 사용하는 환경에서는 필수적으로 고려해야 할 기능입니다.
핵심 포인트:
alb.ingress.kubernetes.io/group.name
어노테이션으로 간단히 설정다음에는 Target Group Binding을 활용한 고급 로드밸런싱 패턴에 대해서도 다뤄보겠습니다.