GitOps를 도입하는 과정에서 Load Balancer(LB) 구성을 코드로 선언하고 버전 관리하는 것은 인프라 일관성 측면에서 중요하다. 이 글에서는 AWS EKS 환경에서 Helm 차트를 통해 AWS Load Balancer Controller를 설치하고, Kubernetes Gateway API를 사용해 ALB/NLB를 선언적으로 관리하는 방법을 설명한다.
1. 구성 요소
AWS Load Balancer Controller (LBC)
AWS Load Balancer Controller는 Kubernetes 리소스를 감시하여 AWS Elastic Load Balancing 리소스를 자동으로 프로비저닝하는 컨트롤러다. Ingress 리소스로부터 ALB를, Service 리소스로부터 NLB를 생성하는 기존 방식에 더해, v2.13.0부터는 Kubernetes Gateway API를 지원한다.
- L4 라우팅(TCPRoute, UDPRoute, TLSRoute): AWS NLB 프로비저닝 (v2.13.3 이상)
- L7 라우팅(HTTPRoute, GRPCRoute): AWS ALB 프로비저닝 (v2.14.0 이상)
Kubernetes Gateway API
Gateway API는 Kubernetes의 네트워크 라우팅을 위한 차세대 표준 API다. 기존 Ingress API의 한계를 극복하기 위해 설계되었으며, 역할 기반의 리소스 분리와 풍부한 라우팅 표현력을 제공한다. AWS Load Balancer Controller는 Gateway API v1.5.0을 기준으로 구현되어 있다.
2. Ingress API vs Gateway API
| 구분 | Ingress | Gateway API |
| 역할 분리 | 단일 리소스에 모든 설정 집중 | GatewayClass / Gateway / Route 로 역할 분리 |
| 프로토콜 지원 | HTTP/HTTPS 중심 | HTTP, TCP, UDP, TLS 등 다양한 프로토콜 지원 |
| 라우팅 표현 | annotation 의존적 | 표준 스펙으로 표현 가능 |
| 확장성 | 구현체마다 annotation 방식이 상이 | 표준화된 커스터마이징 인터페이스 |
| 멀티 테넌시 | 네임스페이스 간 설정 공유가 어려움 | ReferenceGrant 등으로 세밀한 접근 제어 가능 |
Ingress 방식에서는 LB 동작을 변경하기 위해 수십 개의 annotation을 관리해야 했다. Gateway API에서는 LoadBalancerConfiguration, TargetGroupConfiguration 같은 전용 CRD를 통해 타입 안전성이 보장된 방식으로 설정을 관리할 수 있다. GitOps 관점에서도 CRD 기반의 구조화된 YAML이 annotation보다 변경 이력 관리에 유리하다.
3. 사전 작업: CRD 설치 및 컨트롤러 배포
3-1. Gateway API CRD 설치
# Standard CRD (필수) - HTTPRoute, GatewayClass, Gateway 등 포함
kubectl apply --server-side=true \
-f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.0/standard-install.yaml
# Experimental CRD (선택) - TCPRoute, UDPRoute, TLSRoute 등 L4 라우팅에 필요
kubectl apply --server-side=true \
-f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.0/experimental-install.yaml
3-2. AWS LBC 전용 CRD 설치
Gateway API 기능을 위한 AWS 전용 CRD(LoadBalancerConfiguration, TargetGroupConfiguration, ListenerRuleConfiguration)를 추가로 설치한다.
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/refs/heads/main/config/crd/gateway/gateway-crds.yaml
4. AWS Load Balancer Controller Helm 설치
4-1. IAM 정책 및 서비스 어카운트 생성
# IAM 정책 다운로드
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.14.1/docs/install/iam_policy.json
# IAM 정책 생성
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://iam_policy.json
# IRSA 기반 서비스 어카운트 생성
eksctl create iamserviceaccount \
--cluster= \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam:::policy/AWSLoadBalancerControllerIAMPolicy \
--override-existing-serviceaccounts \
--region \
--approve
4-2. Helm으로 컨트롤러 설치
# eks-charts 저장소 추가
helm repo add eks https://aws.github.io/eks-charts
helm repo update eks
# AWS Load Balancer Controller 설치
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName= \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller \
--version 1.14.0
4-3. GitOps를 위한 values.yaml 관리
GitOps 환경에서는 helm install 명령을 직접 실행하는 대신 values.yaml을 Git으로 관리하고 ArgoCD를 통해 배포한다.
# values.yaml
clusterName: my-cluster
serviceAccount:
create: false
name: aws-load-balancer-controller
region: ap-northeast-2
vpcId: vpc-xxxxxxxxxxxxxxxxx
5. Gateway API 리소스 상세 설명
5-1. GatewayClass
GatewayClass는 클러스터 수준의 리소스로, 어떤 컨트롤러가 Gateway를 관리할지를 선언한다. 클러스터 관리자가 생성하며, ALB와 NLB 각각에 대해 별도의 GatewayClass를 정의한다.
주요 필드:
- controllerName: 해당 GatewayClass를 처리할 컨트롤러를 지정한다. AWS LBC에서는 ALB의 경우 gateway.k8s.aws/alb, NLB의 경우 gateway.k8s.aws/nlb를 사용한다.
- parametersRef: GatewayClass 수준의 기본 설정을 담은 LoadBalancerConfiguration CRD를 참조한다. 이 설정은 해당 GatewayClass를 사용하는 모든 Gateway에 기본값으로 적용된다.
5-2. Gateway
Gateway는 네임스페이스 수준의 리소스로, 실제 AWS Load Balancer를 나타낸다. 어떤 GatewayClass를 사용할지와 어떤 포트/프로토콜을 리스닝할지를 선언한다.
주요 필드:
- gatewayClassName: 사용할 GatewayClass의 이름을 지정한다.
- listeners: LB가 수신할 포트, 프로토콜, 허용할 Route의 네임스페이스를 정의한다.
- name: listener 식별자. Route에서 sectionName으로 참조한다.
- protocol: HTTP, HTTPS, TCP, TLS, UDP 중 선택한다.
- port: 수신 포트 번호를 지정한다.
- allowedRoutes.namespaces.from: Same(동일 네임스페이스), All(모든 네임스페이스), Selector(레이블 기반 선택) 중 선택한다.
- infrastructure.parametersRef: Gateway 수준의 LoadBalancerConfiguration을 참조한다.
5-3. LoadBalancerConfiguration
AWS LBC 전용 CRD로, AWS Load Balancer의 세부 동작을 구성한다. GatewayClass 또는 Gateway에 parametersRef로 연결한다.
주요필드:
| scheme | internal(VPC 내부) 또는 internet-facing(퍼블릭) | internal |
| ipAddressType | ipv4, dualstack, dualstack-without-public-ipv4 | ipv4 |
| loadBalancerSubnets | LB를 배치할 서브넷 목록. 미설정 시 태그 기반 자동 탐색 | Subnet Discovery |
| loadBalancerSubnetsSelector | 태그 기반 서브넷 자동 선택 | Subnet Discovery |
| securityGroups | LB에 연결할 보안 그룹 목록. 미설정 시 자동 생성 | 자동 생성 |
| sourceRanges | LB 접근을 허용할 CIDR 목록 | 없음 |
| loadBalancerAttributes | ELB 로드 밸런서 속성 키-값 목록 | 없음 |
| tags | LB에 적용할 AWS 태그 | 없음 |
| listenerConfigurations | 리스너별 인증서, SSL 정책, mTLS 등 세부 설정 | 없음 |
5-4. TargetGroupConfiguration
AWS LBC 전용 CRD로, Route의 백엔드 서비스에 대한 Target Group 설정을 담당한다. 특정 Service에 targetReference로 연결하거나, LoadBalancerConfiguration의 defaultTargetGroupConfiguration을 통해 기본값으로 설정할 수 있다.
주요필드:
| targetType | instance(노드 포트) 또는 ip(파드 직접 등록) | instance |
| protocol | 타겟 그룹 프로토콜 (HTTP, HTTPS, TCP 등) | - |
| protocolVersion | HTTP1, HTTP2, GRPC (ALB 전용) | - |
| healthCheckConfig | 헬스 체크 경로, 프로토콜, 임계값, 인터벌 등 | - |
| targetGroupAttributes | Target Group 속성 키-값 목록 | 없음 |
| nodeSelector | 특정 노드만 타겟으로 사용할 경우 레이블 셀렉터 | 없음 |
| tags | Target Group에 적용할 AWS 태그 | 없음 |
5-5. HTTPRoute
HTTPRoute는 HTTP/HTTPS 트래픽의 라우팅 규칙을 정의하며 ALB에 매핑된다.
주요 필드:
- parentRefs: 이 Route를 연결할 Gateway와 listener를 지정한다. sectionName으로 특정 listener를 선택한다.
- hostnames: 이 Route가 처리할 호스트명 목록이다.
- rules: 라우팅 규칙 목록이다.
- matches: 경로, 헤더, 쿼리 파라미터 기반 매칭 조건을 지정한다.
- backendRefs: 트래픽을 전달할 백엔드 서비스와 포트, 가중치를 지정한다.
- filters: 헤더 수정, URL 리다이렉트, URL 리라이트 등의 변환 규칙을 지정한다.
5-6. TCPRoute
TCPRoute는 TCP 트래픽의 라우팅 규칙을 정의하며 NLB에 매핑된다. HTTP 계층의 매칭은 지원하지 않으며, 포트 단위로 특정 서비스로 트래픽을 전달한다.
주요 필드:
- parentRefs: 연결할 Gateway와 listener를 지정한다.
- rules.backendRefs: 트래픽을 전달할 백엔드 서비스와 포트를 지정한다.
6. LB 종류별 구성 예시
6-1. ALB (Application Load Balancer) - L7 HTTP 라우팅
ALB는 HTTPRoute 또는 GRPCRoute를 사용할 때 프로비저닝된다. GatewayClass의 controllerName은 gateway.k8s.aws/alb를 사용한다.
# 1. GatewayClass (클러스터 수준 - 클러스터 관리자 담당)
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: aws-alb-class
spec:
controllerName: gateway.k8s.aws/alb
---
# 2. LoadBalancerConfiguration
apiVersion: gateway.k8s.aws/v1beta1
kind: LoadBalancerConfiguration
metadata:
name: alb-config
namespace: app-ns
spec:
scheme: internet-facing
loadBalancerAttributes:
- key: idle_timeout.timeout_seconds
value: "60"
listenerConfigurations:
- protocolPort: HTTPS:443
defaultCertificate: arn:aws:acm:ap-northeast-2:123456789012:certificate/xxxx
sslPolicy: ELBSecurityPolicy-TLS13-1-2-2021-06
---
# 3. TargetGroupConfiguration
apiVersion: gateway.k8s.aws/v1beta1
kind: TargetGroupConfiguration
metadata:
name: app-tgc
namespace: app-ns
spec:
targetReference:
name: app-service
defaultConfiguration:
targetType: ip
protocol: HTTP
healthCheckConfig:
healthCheckPath: /health
healthCheckInterval: 15
---
# 4. Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-alb
namespace: app-ns
spec:
gatewayClassName: aws-alb-class
infrastructure:
parametersRef:
group: gateway.k8s.aws
kind: LoadBalancerConfiguration
name: alb-config
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
- name: https
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: Same
---
# 5. HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
namespace: app-ns
spec:
parentRefs:
- name: my-alb
sectionName: http
- name: my-alb
sectionName: https
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app-service
port: 8080
6-2. NLB (Network Load Balancer) - L4 TCP 라우팅
NLB는 TCPRoute, UDPRoute, TLSRoute를 사용할 때 프로비저닝된다. GatewayClass의 controllerName은 gateway.k8s.aws/nlb를 사용한다.
# 1. GatewayClass (클러스터 수준 - 클러스터 관리자 담당)
apiVersion: gateway.networking.k8s.io/v1beta1
kind: GatewayClass
metadata:
name: aws-nlb-class
spec:
controllerName: gateway.k8s.aws/nlb
---
# 2. LoadBalancerConfiguration
apiVersion: gateway.k8s.aws/v1beta1
kind: LoadBalancerConfiguration
metadata:
name: nlb-config
namespace: app-ns
spec:
scheme: internal
enableICMP: true # Path MTU Discovery 허용
loadBalancerAttributes:
- key: load_balancing.cross_zone.enabled
value: "true"
---
# 3. TargetGroupConfiguration
apiVersion: gateway.k8s.aws/v1beta1
kind: TargetGroupConfiguration
metadata:
name: tcp-app-tgc
namespace: app-ns
spec:
targetReference:
name: my-tcp-service
defaultConfiguration:
targetType: ip
protocol: TCP
healthCheckConfig:
healthCheckProtocol: TCP
healthCheckInterval: 10
healthyThresholdCount: 3
---
# 4. Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-nlb
namespace: app-ns
spec:
gatewayClassName: aws-nlb-class
infrastructure:
parametersRef:
group: gateway.k8s.aws
kind: LoadBalancerConfiguration
name: nlb-config
listeners:
- name: tcp-app
protocol: TCP
port: 9000
allowedRoutes:
namespaces:
from: Same
---
# 5. TCPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: tcp-app-route
namespace: app-ns
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: my-nlb
sectionName: tcp-app
rules:
- backendRefs:
- name: my-tcp-service
port: 9000
참고 문서
'Cloud' 카테고리의 다른 글
| Istio 서비스 메쉬, kiali 대시보드 기초 실습 (0) | 2026.04.01 |
|---|---|
| AWS Cross-Account CloudWatch 메트릭 수집 (0) | 2026.02.25 |
| AWS IRSA 개념과 적용 방법 (0) | 2025.12.03 |
| AWS IAM Roles Anywhere - 외부 워크로드에 임시 자격 증명 사용하기 (0) | 2025.10.28 |