Ops/PublicCloud

[Azure] Application Gateway 환경에서 Graceful Pod Termination 구현하기

록흐 2026. 6. 6. 12:04
반응형

 

 

Graceful하게 Pod 종료하기

graceful하게 pod를 종료하려면 큰 틀에서 두 가지 조건을 만족해야 한다. 1) 신규 트래픽이 종료 중인 파드로 전달되면 안된다. 2) 이미 들어온 트래픽이 처리가 될 때까지 파드는 종료되면 안된다.

lordofkangs.tistory.com

 

 

이전 포스팅에서 K8s 환경에서 Graceful하게 pod 종료하는 방법을 다루어 보았다. 

 

요약하면

graceful하게 pod를 종료하려면 큰 틀에서 두 가지 조건을 만족해야 하는데,

 

1) 신규 트래픽이 종료 중인 파드로 전달되면 안된다. 

2) 이미 들어온 트래픽이 처리가 될 때까지 파드는 종료되면 안된다. 

 

신규 트래픽은 endpoint로 막히게 되고 

기존 트래픽은 Linux의 conntrack 모듈로 인해 [ ClientIP - PodIP ] TCP세션으로 유지되므로, 클라이언트와의 세션이 안전하게 종료될때까지 파드만 정상상태를 유지하면 된다는 것이다. 

 

그래서 파드에 두 가지 설정이 필요했다. 

 

1) 파드에 preStop 설정 추가

2) 파드에 terminationGracePeriodSeconds 설정 추가 

 

 

여기서 만약 Azure 환경의 Application Gateway를 사용한다면 Graceful한 파드 종료를 위해서 Ingress에 한 가지 설정을 더 추가해야 한다. 

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx
  namespace: test
  annotations:
    kubernetes.io/ingress.class: azure-application-gateway
    # Connection Draining 활성화
    appgw.ingress.kubernetes.io/connection-draining: "true"
    # 기존 연결을 최대 90초간 유지
    appgw.ingress.kubernetes.io/connection-draining-timeout: "90"

 

 

 

해당 어노테이션 설정이 필요한 이유는 Azure 환경의 Application Gateway이 동작하는 독특한 과정 때문이다. 

 

 

 

 

Azure 환경의 Application Gateway는 일반적인 K8s LB가 아니라 Azure에서 커스텀하게 만든 서비스이다.

 

AKS는 AGIC라는 파드가 떠있는데, 이는 ingress 생성을 감지하여 ingress-> 서비스 -> endpoint -> 파드로의 정보를 수집하고 이를 토대로 Azure 환경에 Listener, Rule, BackendPool, BackendSetting을 생성하는 API를 호출한다. 이렇게 생성된 것들이 모여 트래픽을 파드로 라우팅하는 것이 Azure Application Gateway이다. 

 

 

일반적인 K8S는 Client 와 파드 사이에 세션이 형성된다. 

Azure에서는 Application Gateway가 Client와 Pod 사이의 Proxy 역할을 한다. 

 

Client -> Application Gateway -> Pod 

 

이것이 가능한 이유는 Application Gateway Subnet과 AKS Subet이 동일한 vnet에 있기에 가능하다.

 

# application-gateway subnet 정보
az network application-gateway show \
  -g <AG_RG>  \
  -n <AG_NAME> \
  --query "gatewayIPConfigurations[].subnet.id" \
  -o tsv


# aks subnet 정보
az aks show \
  -g <AKS_RG> \
  -n <AKS_NAME> \
  --query "agentPoolProfiles[0].vnetSubnetId" \
  -o tsv

 

 

위 커맨드로 subnet 정보를 조회하면 동일한 vnet에 있음을 확인할 수 있다. 

 

그럼 여기서 graceful하게 pod를 종료하기 위한 두 가지 조건에 하나가 더 추가됨을 알 수 있다. 

 

1) 신규 트래픽이 종료 중인 파드로 전달되면 안된다. 

2) 이미 들어온 트래픽이 처리가 될 때까지 파드는 종료되면 안된다. 

3) ApplicationGateway와 Pod 사이의 연결이 끊기면 안된다. 

 

파드가 종료명령을 받으면 AGIC는 azure api를 호출하여 ApplicationGateway의 BackendPool 데이터에서 삭제된 Pod IP를 제거하여 더이상 client의 신규 요청이 종료된 pod로 보내지 않도록 해야한다. 이때 1번 조건을 만족하기 위해 제거된다.

 

문제는 2번 조건 만족을 위해 ApplicationGateway와 종료 요청 받은 Pod 사이의 세션을 유지해야 하는데, 별다른 설정이 없다면ApplicationGateway는 파드와의 세션 유지를 보장하지 않는다는 것이다. 그렇다면 파드에 preStop, terminationGracePeriodSeconds 설정을 하더라도 ApplicationGateway이 파드 사이와의 세션을 끊기에 세션은 유지가 되지 않고 Client는 영문 모를 502 에러를 마주하게 된다.

 

그러므로  preStop, terminationGracePeriodSeconds 과 더불어

아래 설정도 ingress에 추가하여 세션유지를 보장해야 graceful한 파드 종료를 보장할 수 있다.

 

    appgw.ingress.kubernetes.io/connection-draining: "true"
    appgw.ingress.kubernetes.io/connection-draining-timeout: "90"
반응형