1. 배경 상황
작년 하반기에 CloudFront에서 Private ALB/NLB를 연결할 수 있는 기능(VPC Origin)이 출시되었다고 해서 내부적으로 PoC를 진행했었다. 이 테스트를 진행 중에 확인된 가장 큰 제약사항이 ap-northeast-2a 가용영역에서는 사용이 불가능하다는 점이었는데, 공교롭게도 지금 운영중인 모든 VPC에서 2a 가용영역을 사용했기 때문에 어떻게든 해당 가용영역을 사용하려고 테스트하다가 제목과 같은 시나리오로 테스트를 해보게 되었다.
2. ALB에서 선택하지 않은 Subnet에 배포된 Target(Pod)와의 연결 테스트 결과
결론적으로 말하면 ALB에서 선택하지 않은 Subnet에 배포된 target과는 통신이 되지 않는다.
EKS에서 해당 내용을 검증하려면 아래와 같이 테스트 해보면 된다.
1. ap-northeast-2 가용영역만 선택하는 nodepool을 생성한다.
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: alb-test-nodepool
spec:
template:
metadata:
labels:
nodepool: alb-test-nodepool
app: test-workload
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
expireAfter: Never
requirements:
- key: "karpenter.k8s.aws/instance-generation"
operator: Gt
values: ["2"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["m", "t"]
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot"]
- key: kubernetes.io/os
operator: In
values: ["linux"]
- key: topology.kubernetes.io/zone
operator: In
values: ["ap-northeast-2a"]
taints:
- key: nodepool.karpenter.sh/alb-test-nodepool
value: "true"
effect: NoSchedule
limits:
cpu: 1000
memory: 1000Gi
2. 샘플용 deployment, service, ingress를 생성한다. (Deployment에서 nodeSelector에 topology.kubernetes.io/zone: ap-northeast-2a 값을 추가해 2a 가용영역에만 파드를 배포하는 것이 핵심)
---
# ingress-2a2b2c.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress-2a2b2c
annotations:
alb.ingress.kubernetes.io/scheme: internal
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/subnets: <2a, 2b, 2c 서브넷 ID 입력>
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-workload
port:
number: 80
---
# ingress-2b2c.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress-2b2c
annotations:
alb.ingress.kubernetes.io/scheme: internal
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/subnets: <2b, 2c 서브넷 ID 입력>
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-workload
port:
number: 80
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: test-workload
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: test-workload
---
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
spec:
replicas: 3
selector:
matchLabels:
app: test-workload
template:
metadata:
labels:
app: test-workload
spec:
nodeSelector:
nodepool: alb-test-nodepool # NodePool로 생성된 노드에만 배포
topology.kubernetes.io/zone: ap-northeast-2a
tolerations:
- key: nodepool.karpenter.sh/alb-test-nodepool
operator: Equal
value: "true"
effect: NoSchedule
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
위에서 생성한 ingress wnd test-ingress-2b2c의 경우에는 ALB에서 ap-northeast-2a, 2b의 가용영역만 ALB를 생성하는 케이스다. 이 케이스에서는 선택되지 않은 2a의 Pod가 unused 상태로 Pod와 ALB가 연결되지 않는다.


반대로 2a, 2b, 2c에 있는 서브넷을 모두 선택한 test-ingress-2a2b2c의 경우에는 Pod와 ALB가 정상적으로 연결된 것을 확인할 수 있다.


사실 일부 가용영역에만 ALB를 배포해도 모든 가용영역의 타겟으로 트래픽을 보낼 것으로 예상했는데 실제로는 동작하지 않아서 찾아보니 AWS Documentation 상에서도 “가용 영역에 대상을 등록하지만 가용 영역은 활성화하지 않는 경우 이러한 등록된 대상은 트래픽을 수신하지 않습니다.”라고 설명이 되어있다. NLB는 다른 방식으로 동작해서 NLB까지 엮어서 구성하면 우리가 원하는 형태로 구성할 수 있었는데, 쓸데없는 네트워크 hop과 비용때문에 지금은 걷어냈다.