Kubernetes에서 NGINX를 사용하여 TCP 및 UDP 트래픽 로드 밸런싱
Kubernetes 에서 NGINX Ingress Controller는 TCP 및 UDP 트래픽의 부하를 분산하므로 이를 사용하여 다음을 포함한 해당 프로토콜을 기반으로 하는 광범위한 앱 및 유틸리티에 대한 트래픽을 관리할 수 있습니다.
- MySQL, LDAP 및 MQTT – 많은 인기 있는 애플리케이션에서 사용되는 TCP 기반 앱
- DNS, syslog 및 RADIUS – Edge 장치 및 비트랜잭션 애플리케이션에서 사용하는 UDP 기반 유틸리티
NGINX Ingress Controller를 사용한 TCP 및 UDP 로드 밸런싱은 다음과 같은 상황에서 네트워크 트래픽을 Kubernetes 애플리케이션에 분산하는 효과적인 솔루션이기도 합니다.
- 종단 간 암호화(EE2E)를 사용하고 있으며 NGINX Ingress Controller가 아닌 애플리케이션에서 암호화 및 암호 해독을 처리하도록 합니다.
- TCP 또는 UDP를 기반으로 하는 애플리케이션을 위한 고성능 로드 밸런싱이 필요합니다.
- 기존 네트워크(TCP/UDP) 부하 분산 장치를 Kubernetes 환경으로 마이그레이션할 때 변경 사항을 최소화하려는 경우
NGINX Ingress Controller는 TCP/UDP 부하 분산을 지원하는 두 개의 NGINX Ingress 리소스와 함께 제공됩니다.
- GlobalConfiguration 리소스는 일반적으로 클러스터 관리자가 DevOps 팀에서 사용할 수 있는 TCP/UDP 포트(listener)를 지정하는 데 사용됩니다. 각 NGINX Ingress Controller 배포에는 하나의 GlobalConfiguration 리소스만 있을 수 있습니다.
- TransportServer 리소스는 일반적으로 DevOps 팀에서 애플리케이션에 대한 TCP/UDP 로드 밸런싱을 구성하는 데 사용됩니다. NGINX Ingress Controller는 GlobalConfiguration 리소스에서 관리자가 인스턴스화한 포트에서만 수신 대기합니다. 이는 포트 간의 충돌을 방지하고 DevOps 팀이 관리자가 미리 결정한 포트만 공개 외부 서비스에 노출하도록 하여 추가 보안 계층을 제공합니다.
다음 다이어그램은 GlobalConfiguration 및 TransportServer 리소스에 대한 샘플 사용 사례를 보여줍니다. gc.yaml에서 클러스터 관리자는 GlobalConfiguration 리소스에 TCP 및 UDP listener를 정의합니다. ts.yaml에서 DevOps 엔지니어는 트래픽을 MySQL 배포로 라우팅하는 TransportServer 리소스의 TCP listener를 참조합니다.

gc.yaml의 GlobalConfiguration 리소스는 syslog 서비스 연결을 위한 포트 514의 UDP listener와 MySQL 서비스 연결을 위한 포트 5353의 TCP listener라는 두 개의 listener를 정의합니다.
apiVersion: k8s.nginx.org/v1alpha1
kind: GlobalConfiguration
metadata:
name: nginx-configuration
namespace: nginx-ingress
spec:
listeners:
- name: syslog-udp
port: 541
protocol: UDP
- name: mysql-tcp
port: 5353
protocol: TCP
ts.yaml에 있는 TransportServer 리소스의 6-8행은 gc.yaml에 이름(mysql-tcp)으로 정의된 TCP listener를 참조하고 9-14행은 TCP 트래픽을 mysql-db 업스트림으로 보내는 라우팅 규칙을 정의합니다.
apiVersion: k8s.nginx.org/v1alpha1
kind: TransportServer
metadata:
name: mysql-tcp
spec:
listener:
name: mysql-tcp
protocol: TCP
upstreams:
- name: mysql-db
service: mysql
port: 3306
action:
pass: mysql-db
이 예에서 DevOps 엔지니어는 MySQL 배포 내부의 rawdata_content_schema 데이터베이스에 있는 테이블 목록이 포함된 출력으로 확인된 대로 구성이 작동하는지 확인하기 위해 MySQL 클라이언트를 사용합니다.
$ echo “SHOW TABLES” | mysql –h <external_IP_address> -P <port> -u <user> –p rawdata_content_schema
Enter Password: <password>
Tables_in_rawdata_content_schema
authors
posts
UDP 트래픽에 대한 TransportServer 리소스는 유사하게 구성됩니다. 고급 NGINX 사용자는 스트림 스니펫 ConfigMap 키를 사용하여 기본 NGINX 구성으로 TransportServer 리소스를 확장할 수 있습니다.
목차
1. 전체 예제
2. 전제 조건
3. 예제실행
3-1. Ingress Controller 배포
3-2. DNS 서버 배포
3-3. Load Balancing 구성
3-4. DNS 서버 테스트
1. 전체 예제
이 예에서는 DNS 서버인 NGINX 또는 NGINX Plus Ingress Controller를 배포한 다음 stream-snippets ConfigMap 키를 사용하여 DNS 서버에 대한 TCP 및 UDP 로드 밸런싱을 모두 구성합니다.
표준 Kubernetes Ingress 리소스는 모든 트래픽이 HTTP 기반이라고 가정합니다. 기본 TCP 또는 UDP 로드 밸런싱의 경우에는 적합하지 않습니다. 이 예시에서는 stream-snippets ConfigMap 키를 사용하여 필요한 TCP 및 UDP 부하 분산 구성을 NGINX 구성 파일의 stream{} 블록에 직접 포함합니다.
NGINX를 사용하면 DNS 이름 또는 가상 IP 주소를 사용하여 서비스를 식별하고 kube-proxy에 의존하여 파드 풀에서 내부 로드 밸런싱을 수행합니다. NGINX Plus를 사용하면 headless 서비스와 해당 DNS 이름을 사용하여 서비스 뒤에 있는 파드의 실제 IP 주소를 얻고 이들 간에 로드 밸런싱을 수행할 수 있습니다. NGINX Plus는 DNS 이름을 자주 다시 확인하므로 새 파드가 배포되거나 제거될 때 자동으로 업데이트됩니다.
2. 전제 조건
- 우리는 테스트를 위해 dig를 사용합니다. 컴퓨터에 설치되어 있는지 확인하십시오.
- 기본 NGINX 구성을 사용하여 TCP/UDP 로드 밸런싱을 구성합니다. 예제 구성을 더 잘 이해하려면 NGINX/NGINX Plus의 TCP/UDP 로드 밸런싱 및 DNS 서비스 검색에 대해 읽어보세요.
3. 예제 실행
3-1. Ingress Controller 배포
- 설치 지침에 따라 Ingress Controller를 배포합니다. TCP 및 UDP 트래픽 모두에 대해 Ingress Controller의 포트 5353을 노출해야 합니다.
- Ingress Controller의 공용 IP 주소를 shell 변수에 저장합니다.
$ IC_IP=XXX.YYY.ZZZ.III
참고: LoadBalancer 유형의 서비스를 통해 Ingress Controller를 노출하려는 경우 TCP 및 UDP 프로토콜 모두에 대해 유형 LoadBalancer 서비스를 생성할 수 없습니다. 이 제한을 극복하려면 TCP용 서비스와 UDP용 서비스의 두 가지 개별 서비스를 만드십시오. 이 경우 TCP용과 UDP용의 두 개의 개별 공용 IP로 끝납니다. 4.2단계에서 전자를 사용하고 4.1단계에서 후자를 사용합니다.
3. Ingress Controller의 포트 5353을 shell 변수에 저장합니다.
$ IC_5353_PORT=<port number>
3-2. DNS 서버 배포
DNS 쿼리를 8.8.8.8로 전달하도록 구성된 CoreDNS의 두 복제본을 배포합니다. 또한 CoreDNS 파드에 대해 coredns 및 coredns-headless의 두 가지 서비스를 만듭니다. 그 이유는 단계 3.1 및 3.2에 설명되어 있습니다.
DNS 서버에 배포:
$ kubectl apply -f dns.yaml
3-3. Load Balancing 구성
stream-snippets ConfigMap 키를 사용하여 CoreDNS 파드에 대한 TCP 및 UDP 로드 밸런싱을 구성합니다.
- 부하 분산 구성을 만듭니다. 이 예에서는 포트 5353에서 TCP 트래픽을 수신하는 서버 하나와 동일한 포트에서 UDP 트래픽을 수신하는 서버 하나를 만듭니다. 두 서버 모두 CoreDNS 파드로 들어오는 트래픽을 로드 밸런싱합니다.
- NGINX의 경우 다음 구성을 사용합니다:
upstream coredns-udp {
server coredns.default.svc.cluster.local:53;
}
server {
listen 5353 udp;
listen [::]:5353 udp;
proxy_pass coredns-udp;
proxy_responses 1;
}
upstream coredns-tcp {
server coredns.default.svc.cluster.local:53;
}
server {
listen 5353;
listen [::]:5353;
proxy_pass coredns-tcp;
}
DNS 이름을 사용하여 업스트림 서버를 정의합니다. NGINX가 다시 로드되면 DNS 이름이 coredns 서비스의 가상 IP로 확인됩니다.
참고: DNS 이름 coredns.default.svc.cluster.local을 확인할 수 없으면 NGINX를 다시 로드하지 못합니다. 이를 피하기 위해 DNS 이름 대신 coredns 서비스의 가상 IP를 사용하여 업스트림 서버를 정의할 수 있습니다.
NGINX의 경우 다음 구성을 사용합니다:
resolver kube-dns.kube-system.svc.cluster.local valid=5s;
upstream coredns-udp {
zone coredns-udp 64k;
server coredns-headless.default.svc.cluster.local service=_dns._udp resolve;
}
server {
listen 5353 udp;
listen [::]:5353 udp;
proxy_pass coredns-udp;
proxy_responses 1;
status_zone coredns-udp;
}
upstream coredns-tcp {
zone coredns-tcp 64k;
server coredns-headless.default.svc.cluster.local service=_dns-tcp._tcp resolve;
}
server {
listen 5353;
listen [::]:5353;
proxy_pass coredns-tcp;
status_zone coredns-tcp;
}
NGINX Plus는 업스트림 지시문의 resolve 매개변수를 사용하여 DNS 이름 재확인을 지원합니다. 또한 resolve 매개변수를 사용하면 NGINX와 달리 업스트림 이름을 확인할 수 없는 경우 NGINX Plus가 다시 로드되지 않습니다. IP 주소 외에도 NGINX Plus는 DNS SRV 레코드를 통해 포트를 검색합니다.
IP 주소와 포트를 확인하기 위해 NGINX Plus는 resolver 지시문으로 정의된 Kube-DNS를 사용합니다. 또한 NGINX Plus가 5초마다 DNS 이름을 다시 확인하도록 유효한 매개변수를 5초로 설정합니다.
coredns 서비스 대신 coredns-headless 서비스를 사용합니다. 이 서비스는 헤드리스 서비스로 생성됩니다. 즉, 해당 서비스에 가상 IP가 할당되지 않고 NGINX Plus가 모든 CoreDNS 포드의 IP 주소를 확인할 수 있습니다.
참고: NGINX Plus는 resolver 지시문에 지정된 DNS 이름을 확인할 수 없는 경우 다시 로드하지 못합니다. 이를 피하기 위해 DNS 이름 대신 kube-dns 서비스의 가상 IP를 사용하여 resolver를 정의할 수 있습니다.
2. 로드 밸런싱 구성이 포함된 stream-snippets으로 ConfigMap을 업데이트합니다.
NGINX의 경우 다음을 실행합니다:
$ kubectl apply -f nginx-config.yaml
NGINX Plus의 경우 다음을 실행합니다:
$ kubectl apply -f nginx-plus-config.yaml
3. NGINX 또는 NGINX Plus가 성공적으로 다시 로드되었는지 확인합니다.
$ kubectl describe configmap nginx-config -n nginx-ingress
. . .
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Updated 3s nginx-ingress-controller Configuration from nginx-ingress/nginx-config was updated
3-4. DNS 서버 테스트
구성된 TCP/UDP 부하 분산이 작동하는지 테스트하기 위해 Ingress Controller를 통해 사용할 수 있는 DNS 서버를 사용하여 kubernetes.io라는 이름을 확인합니다.
- UDP를 통해 kubernetes.io를 해결합니다.
$ dig @$IC_IP -p $IC_5353_PORT kubernetes.io
; <<>> DiG 9.10.6 <<>> @<REDACTED>> -p 5353 kubernetes.io
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33368
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;kubernetes.io. IN A
;; ANSWER SECTION:
kubernetes.io. 299 IN A 45.54.44.100
;; Query time: 111 msec
;; SERVER:<REDACTED>#5353(<REDACTED>)
;; WHEN: Fri Aug 17 12:49:54 BST 2018
;; MSG SIZE rcvd: 71
2. TCP를 통해 kubernetes.io를 해결합니다.
$ dig @$IC_IP -p $IC_5353_PORT kubernetes.io +tcp
; <<>> DiG 9.10.6 <<>> @<REDACTED> -p 5353 kubernetes.io +tcp
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49032
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;kubernetes.io. IN A
;; ANSWER SECTION:
kubernetes.io. 146 IN A 45.54.44.100
;; Query time: 95 msec
;; SERVER: <REDACTED>#5353(<REDACTED>)
;; WHEN: Fri Aug 17 12:52:25 BST 2018
;; MSG SIZE rcvd: 71
3. Ingress Controller 로그(Log)를 확인합니다.
$ kubectl logs <nginx-ingress-pod> -n nginx-ingress
. . .
<REDACTED> [17/Aug/2018:11:49:54 +0000] UDP 200 71 42 0.016
<REDACTED> [17/Aug/2018:11:52:25 +0000] TCP 200 73 44 0.098
댓글을 달려면 로그인해야 합니다.