NGINX Plus를 활용한 동적 A/B Kubernetes 멀티 클러스터 부하 분산 및 보안 제어

NGINX | 2024년 2월 15일

여러분은 현대적인 플랫폼 운영 또는 DevOps 엔지니어입니다. 개발팀을 위해 오픈 소스 도구(경우에 따라 일부 상용 도구도 포함) 모음을 활용하여 새로운 애플리케이션과 컨테이너를 테스트하고 배포하며 관리합니다. 개발, 테스트, 스테이징 및 프로덕션 환경에서 이러한 컨테이너와 파드를 실행하기 위해 Kubernetes를 선택했습니다. 마이크로서비스의 아키텍처와 개념을 도입했고, 대체로 꽤 잘 작동합니다. 하지만 이 여정에서 몇 가지 난관에 부딪히기도 했습니다.

예를 들어 새로운 클러스터, 서비스 및 애플리케이션을 구축하고 배포할 때, 트래픽 손실 없이 이러한 신규 리소스를 프로덕션 환경에 손쉽게 통합하거나 마이그레이션하려면 어떻게 해야 할까요? 기존 네트워크 어플라이언스는 DNS 레코드, 로드 밸런서, 방화벽 및 프록시의 구성을 변경할 때 다시 로드하거나 재부팅해야 합니다. DNS, 로드 밸런서 및 방화벽 규칙을 업데이트하려면 ‘서비스 중단’이나 ‘유지보수 시간’이 필요하므로, 다운타임 없이 이러한 설정을 변경할 수 없습니다. 대부분의 경우 번거로운 서비스 티켓을 제출한 뒤 다른 팀이 변경 사항을 승인하고 적용할 때까지 기다려야 합니다.

유지 관리 시간은 팀을 난관에 빠뜨리고 애플리케이션 제공을 지연시켜 “트래픽을 관리할 더 나은 방법이 분명 있을 텐데!”라고 외치게 만들 수 있습니다. 이제 다시 빠르게 나아갈 수 있도록 도와주는 솔루션을 살펴보겠습니다.

액티브-액티브 멀티 클러스터 부하 분산

Kubernetes 클러스터가 여러 개인 경우 두 클러스터 모두로 트래픽을 동시에 라우팅하는 것이 좋습니다. 더 나은 방법은 A/B, 카나리 또는 블루-그린 방식으로 트래픽을 분할하여 트래픽의 일부를 테스트용으로 전송하는 것입니다. 이를 위해 NGINX Plus와 ngx_http_split_clients_module을 함께 사용할 수 있습니다.

NGINX Plus를 사용하는 K8s 다이어그램

HTTP Split Clients 모듈은 NGINX Open Source에서 제공하며 키를 기준으로 요청을 지정된 비율에 따라 분산할 수 있습니다. 이 사용 사례에서 클러스터는 NGINX의 ‘업스트림’입니다. 따라서 클라이언트 요청이 들어오면 트래픽이 두 클러스터로 분할됩니다. 클라이언트 요청을 분배할 때 사용할 키로는 NGINX에서 사용 가능한 모든 클라이언트 $variable을 사용할 수 있습니다. 단, 모든 요청을 개별적으로 제어하려면 $request_id 변수를 사용합니다. 이 변수는 NGINX가 들어오는 각 요청에 할당하는 고유 번호입니다.

분할 비율을 구성하려면 각 클러스터로 보낼 트래픽의 비율을 결정합니다. 이 예에서는 K8s Cluster1을 프로덕션용 “대규모 클러스터”로, Cluster2를 프로덕션 전 테스트용 “소규모 클러스터”로 사용합니다. 스테이징용 소규모 클러스터가 있다면 90:10 비율을 사용하여 트래픽의 10%를 소규모 클러스터에서 테스트함으로써, 대규모 클러스터에 새로운 변경 사항을 배포하기 전에 모든 것이 제대로 작동하는지 확인할 수 있습니다. 위험 부담이 너무 크다고 생각되면 비율을 95:5로 변경할 수 있습니다. 실제로는 0~100% 범위에서 원하는 비율을 자유롭게 선택할 수 있습니다.

대부분의 실시간 프로덕션 트래픽에는 두 클러스터의 크기가 동일한 50:50 비율이 적합할 것입니다. 하지만 클러스터 크기나 기타 세부 사항에 따라 다른 비율도 손쉽게 설정할 수 있습니다. 비율을 0:100(또는 100:0)으로 설정하면 다운타임 없이 전체 클러스터를 업그레이드, 패치, 복구하거나 교체할 수도 있습니다. 다른 클러스터의 문제를 해결하는 동안 NGINX의 split_clients가 요청을 정상 운영 중인 클러스터로 라우팅하도록 하세요.

# Nginx Multi Cluster Load Balancing
# HTTP Split Clients Configuration for Cluster1:Cluster2 ratios
# Provide 100, 99, 50, 1, 0% ratios  (add/change as needed)
# Based on
# https://www.nginx.com/blog/dynamic-a-b-testing-with-nginx-plus/
# Chris Akker – Jan 2024
#
 
split_clients $request_id $split100 {
   * cluster1-cafe;                     # All traffic to cluster1
   } 

split_clients $request_id $split99 {
   99% cluster1-cafe;                   # 99% cluster1, 1% cluster2
   * cluster2-cafe;
   } 
 
split_clients $request_id $split50 { 
   50% cluster1-cafe;                   # 50% cluster1, 50% cluster2
   * cluster2-cafe;
   }
    
split_clients $request_id $split1 { 
   1.0% cluster1-cafe;                  # 1% to cluster1, 99% to cluster2
   * cluster2-cafe;
   }

split_clients $request_id $split0 { 
   * cluster2-cafe;                     # All traffic to cluster2
   }
 
# Choose which cluster upstream based on the ratio
 
map $split_level $upstream { 
   100 $split100; 
   99 $split99; 
   50 $split50; 
   1.0 $split1; 
   0 $split0;
   default $split50;
}

필요한 비율(예: 90:10, 80:20, 60:40 등)에 맞게 위 구성을 추가하거나 수정할 수 있습니다.

참고: NGINX에는 스트림 컨텍스트의 TCP 연결을 위한 Split Clients 모듈도 있으며, 비 HTTP 트래픽에 사용할 수 있습니다. 이 모듈은 HTTP 요청이 아닌 새로운 TCP 연결을 기준으로 트래픽을 분할합니다.

NGINX Plus 키-값 저장소

다음으로 사용할 수 있는 기능은 NGINX Plus의 키-값 저장소입니다. 이는 NGINX 공유 메모리 영역에 있는 키-값 객체로, 다양한 데이터 저장 용도에 사용할 수 있습니다. 여기서는 위 섹션에서 언급한 분할 비율 값을 저장하는 데 사용합니다. NGINX Plus를 사용하면 NGINX를 다시 로드하지 않고도 모든 키-값 레코드를 변경할 수 있습니다. 따라서 API 호출로 이 분할 값을 변경하여 동적 분할 기능을 구현할 수 있습니다.

앞서 살펴본 예제를 기준으로 하면 다음과 같습니다:

{“cafe.example.com”:90}

이 KeyVal 레코드는 다음과 같이 해석됩니다.
키는 “cafe.example.com” 호스트 이름입니다.
값은 분할 비율을 나타내는 “90”입니다.

NGINX 구성 파일에 분할 비율을 하드 코딩하는 대신 키-값 메모리를 사용할 수 있습니다. 이렇게 하면 NGINX에서 정적 분할 값을 변경할 때 필요한 NGINX 재로드를 생략할 수 있습니다.

이 예에서는 분할 비율을 90:10으로 사용하도록 NGINX를 구성하여, 대규모 Cluster1에 90%를 할당하고 소규모 Cluster2에 나머지 10%를 할당합니다. 이 값은 키-값 레코드이므로 구성을 다시 로드하지 않고도 NGINX Plus API를 사용하여 동적으로 이 비율을 변경할 수 있습니다! 비율을 변경하면 Split Clients 모듈은 바로 다음 요청부터 새 비율 값을 사용합니다.

KV 레코드를 생성하고 50/50 비율로 시작합니다:

NGINX Plus에 API 명령을 전송하여 KeyValue 저장소에 새 레코드를 추가합니다:

curl -iX POST -d '{"cafe.example.com":50}' http://nginxlb:9000/api/8/http/keyvals/split

KV 레코드를 변경하여 비율을 90/10으로 조정합니다:

HTTP PATCH 메서드를 사용하여 메모리의 KeyVal 레코드를 업데이트하고 KeyVal 분할 비율을 90으로 변경합니다:

curl -iX PATCH -d '{"cafe.example.com":90}' http://nginxlb:9000/api/8/http/keyvals/split

그런 다음 사전 프로덕션 테스트 팀이 새 애플리케이션 코드가 준비되었는지 확인하면, 이를 대규모 Cluster1에 배포하고 비율을 100%로 변경합니다. 그러면 즉시 모든 트래픽이 Cluster1으로 전송되고, 트래픽 중단이나 서비스 장애, 유지보수 시간, 재부팅, 재로드 또는 수많은 티켓 처리 없이 새 애플리케이션이 “라이브” 상태가 됩니다. 원하는 시점에 API 호출 한 번만으로 이 분할 비율을 변경할 수 있습니다.

물론 90%에서 100%로 손쉽게 전환할 수 있다는 것은 비율을 100:0에서 50:50(또는 0:100)으로도 쉽게 변경할 수 있다는 의미입니다. 따라서 핫 백업 클러스터를 운영하거나 새로운 리소스를 추가해 클러스터를 수평 확장할 수 있습니다. 더 나아가 최신 소프트웨어와 하드웨어, 소프트웨어 패치를 적용한 새 클러스터를 완전히 구축한 후, 단 하나의 연결도 끊지 않고 일정 기간에 걸쳐 애플리케이션을 배포하고 트래픽을 이전할 수도 있습니다!

사용 사례

HTTP 클라이언트 분할 모듈을 동적 키-값 저장소와 함께 사용하면 다음과 같은 사용 사례를 구현할 수 있습니다:

  • 액티브-액티브 부하 분산 – 여러 클러스터로 부하를 분산합니다.
  • 액티브-패시브 부하 분산 – 기본, 백업 및 재해 복구(DR) 클러스터와 애플리케이션으로 부하를 분산합니다.
  • A/B, 블루-그린 및 카나리 테스트 – 새로운 Kubernetes 애플리케이션에 사용됩니다.
  • 수평 클러스터 확장 – 클러스터 리소스를 추가하고 준비가 되면 비율을 변경합니다.
  • 무중단 클러스터 업그레이드 – 한 클러스터를 업그레이드, 패치 또는 복구하는 동안 다른 클러스터를 사용할 수 있습니다.
  • 즉각적인 장애 조치 – 한 클러스터에 심각한 문제가 발생하면 비율을 변경하여 다른 클러스터를 사용할 수 있습니다.

구성 예시

다음은 키-값 구성의 예입니다:

# Define Key Value store, backup state file, timeout, and enable sync 
keyval_zone zone=split:1m state=/var/lib/nginx/state/split.keyval timeout=365d sync;

keyval $host $split_level zone=split;

다음은 cafe.example.com 애플리케이션 구성의 예입니다:

# Define server and location blocks for cafe.example.com, with TLS
server {
   listen 443 ssl;
   server_name cafe.example.com; 

   status_zone https://cafe.example.com;
      
   ssl_certificate /etc/ssl/nginx/cafe.example.com.crt; 
   ssl_certificate_key /etc/ssl/nginx/cafe.example.com.key;
   
   location / {
   status_zone /;
   
   proxy_set_header Host $host;
   proxy_http_version 1.1;
   proxy_set_header "Connection" "";
   proxy_pass https://$upstream;   # traffic split to upstream blocks
   
   }

# Define 2 upstream blocks – one for each cluster
# Servers managed dynamically by NLK, state file backup

# Cluster1 upstreams
 
upstream cluster1-cafe {
   zone cluster1-cafe 256k;
   least_time last_byte;
   keepalive 16;
   #servers managed by NLK Controller
   state /var/lib/nginx/state/cluster1-cafe.state; 
}
 
# Cluster2 upstreams
 
upstream cluster2-cafe {
   zone cluster2-cafe 256k;
   least_time last_byte;
   keepalive 16;
   #servers managed by NLK Controller
   state /var/lib/nginx/state/cluster2-cafe.state; 
}

업스트림 서버의 IP:포트는 NGINX Loadbalancer for Kubernetes에서 관리합니다. 이 새로운 컨트롤러는 NGINX Plus API를 사용하여 NGINX Plus를 동적으로 구성하기도 합니다. 자세한 내용은 다음 섹션을 참조하세요.

인기 있는 모니터링 및 시각화 도구인 Grafana를 사용하여 시간 경과에 따른 HTTP 분할 트래픽을 살펴보겠습니다. NGINX Prometheus Exporter(njs 기반)를 사용하여 모든 NGINX Plus 메트릭을 내보내면 Grafana가 이를 수집하여 그래프로 표시합니다. Prometheus 및 Grafana 구성에 대한 자세한 내용은 여기에서 확인할 수 있습니다.

그래프에는 4개의 업스트림 서버가 있습니다. Cluster1용 서버 2개와 Cluster2용 서버 2개입니다. HTTP 부하 생성 도구를 사용하여 HTTP 요청을 생성하고 NGINX Plus로 전송합니다.

아래 세 개의 그래프를 보면 그래프 시작 부분에서 분할 비율이 50:50임을 확인할 수 있습니다.

LB 업스트림 요청 다이어그램

그런 다음 12:56:30에 비율이 10:90으로 변경됩니다.

LB 업스트림 요청 다이어그램

그런 다음 13:00:00에 90:10으로 변경됩니다.

LB 업스트림 요청 다이어그램

Prometheus와 Grafana의 실제 작동하는 구성은 NGINX Loadbalancer for Kubernetes GitHub 리포지토리에서 확인할 수 있습니다.

동적 HTTP 업스트림: Kubernetes용 NGINX 로드 밸런서

NGINX Plus API와 NGINX Loadbalancer for Kubernetes 컨트롤러를 사용하면 정적 NGINX 업스트림 구성을 동적 클러스터 업스트림으로 변경할 수 있습니다. 이 무료 프로젝트는 Kubernetes 컨트롤러로, NGINX Ingress Controller를 모니터링하고 TCP/HTTP 부하 분산용으로 구성된 외부 NGINX Plus 인스턴스를 자동으로 업데이트합니다. 설계가 매우 직관적이며 설치와 운영도 간단합니다. 이 솔루션을 적용하면 Kubernetes 환경에서 TCP/HTTP 부하 분산을 구현할 수 있으며, 새 앱과 서비스가 즉시 감지되어 다시 로드할 필요 없이 트래픽을 처리할 수 있습니다.

아키텍처 및 흐름

NGINX Loadbalancer for Kubernetes는 Kubernetes 클러스터 내부에서 실행됩니다. Kubernetes에 등록되어 NGINX Ingress Controller(nginx-ingress) 서비스를 감시합니다. Ingress 컨트롤러에 변경 사항이 발생하면 NGINX Loadbalancer for Kubernetes가 워커 IP와 NodePort TCP 포트 번호를 수집한 다음, IP:포트 정보를 NGINX Plus API를 통해 NGINX Plus로 전송합니다.

NGINX 업스트림 서버는 다시 로드할 필요 없이 업데이트되며, NGINX Plus는 올바른 업스트림 서버와 Kubernetes NodePort로 트래픽을 부하 분산합니다. 고가용성을 확보하기 위해 NGINX Plus 인스턴스를 추가할 수 있습니다.

NGINX 로드 밸런서의 작동 방식 다이어그램

실제 작동 중인 Kubernetes용 NGINX 로드 밸런서 살펴보기

아래 스크린샷에는 NGINX Loadbalancer for Kubernetes가 배포되어 정상적으로 작동하는 모습을 보여 주는 두 개의 창이 있습니다:

  1. 서비스 유형 – LoadBalancer 대상: nginx-ingress
  2. 외부 IP – NGINX Plus 서버에 연결
  3. 포트 – NodePort는 443:30158에 매핑되며, 이에 대응하는 NGINX 업스트림 서버가 있습니다(NGINX Plus 실시간 대시보드에 표시된 것과 같음)
  4. 로그 – Kubernetes용 NGINX Loadbalancer가 NGINX Plus로 데이터를 성공적으로 전송하고 있음을 나타냅니다

NGINX Plus 창

참고: 이 예시에서 Kubernetes 워커 노드는 10.1.1.8 및 10.1.1.10입니다

NGINX Plus 보안 기능 추가

Kubernetes에서 실행되는 애플리케이션이 개방형 인터넷에 점점 더 많이 노출됨에 따라 보안의 필요성이 커지고 있습니다. 다행히 NGINX Plus는 계층화된 심층 방어 아키텍처를 구축하는 데 사용할 수 있는 엔터프라이즈급 보안 기능을 제공합니다.

클러스터 앞단에 NGINX Plus를 배치하여 split_clients 기능을 수행하고 있다면, 이를 활용해 유용한 보안 기능도 추가해 보는 것은 어떨까요? 다음은 보안을 강화하는 데 사용할 수 있는 몇 가지 NGINX Plus 기능입니다. 각 기능을 구성, 테스트 및 배포하는 데 참고할 수 있는 관련 문서의 링크와 참조 자료도 함께 제공합니다.

지금 시작하세요

Kubernetes 클러스터의 에지에서 발생하는 네트워킹 문제로 어려움을 겪고 있다면 이 NGINX 멀티 클러스터 솔루션을 사용해 보세요. NGINX Loadbalancer for Kubernetes 소프트웨어를 직접 사용해 보고 의견을 들려주세요. 소스 코드는 오픈 소스(Apache 2.0 라이선스)이며, 모든 설치 지침은 GitHub에서 확인할 수 있습니다.

피드백을 보내려면 리포지토리에 댓글을 남기거나 NGINX Community Slack에서 메시지를 보내주세요.


공유

관련 블로그 게시물

시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric
NGINX | 2023. 11. 30.

시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric

이 영상에서는 KubeCon의 NGINX 부스를 찾아가, 저희가 공개한 Kubernetes Gateway API 구현을 살펴봅니다.

F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법
NGINX | 2023. 03. 23.

F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법

앱 보안을 강화하는 두 가지 방법을 소개합니다. NGINX Management Suite를 통해 WAF 운영에 대한 가시성을 높이고, NGINX App Protect WAF를 활용해 코드형 보안을 구현하는 것입니다.

Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션
NGINX | 2021. 09. 27.

Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션

개발 주체, 개발 철학, 프로덕션 환경 준비도, 보안 및 지원을 기준으로 어떤 NGINX Ingress 컨트롤러가 가장 적합한지 알아보세요.

진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법
NGINX | 2021. 07. 06.

진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법

NGINX App Protect Denial of Service(DoS)가 계층 7 DoS 공격을 방어하기 위해 완화 방법을 실시간으로 조정하는 방식을 설명합니다. 정상적인 사용자 행동과 서버 상태에 대한 모델을 생성하여 공격을 나타내는 이상 징후를 감지하고 맞춤형 완화 시그니처를 적용할 수 있습니다.

NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리
NGINX | 2021. 06. 30.

NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리

NGINX Instance Manager 버전 1.0에는 두 가지 새로운 기능이 도입되었습니다. NGINX 인스턴스에 태그와 사용자 역할을 지정하면 전체 그룹에 구성을 한 번에 적용할 수 있습니다. 인증서 검사는 만료 예정인 인증서를 감지하여 서비스 중단을 방지할 수 있도록 인증서를 교체할 수 있게 해줍니다.

Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유
NGINX | 2015. 03. 25.

Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유

Netflix가 글로벌 콘텐츠 전송 네트워크인 Open Connect의 스트리밍 미디어 기술로 NGINX를 선택한 이유를 NGINX 개발자 Gleb Smirnoff에게서 알아보세요.