쿠버네티스에서 로드밸런서가 필요한 지점은 두 곳이며 서로 다른 문제다.
| 대상 | 포트 | 이유 |
|---|---|---|
| kube-apiserver | 6443 | 마스터 3중화 시 워커 · kubectl 이 바라볼 단일 진입점이 필요하다 |
| Ingress 컨트롤러 | 80 · 443 | 애플리케이션 트래픽의 단일 진입점 |
마스터를 3대로 늘려도 애플리케이션 진입점은 따로 설계해야 한다. 이 둘을 한 HAProxy 에서 프론트엔드만 나눠 처리하는 구성이 흔하다.
마스터 노드에 HAProxy 를 함께 올리는 구성은 동작하지만 권장하지 않는다. 마스터를 재부팅 · 업그레이드할 때 LB 까지 함께 흔들리고, apiserver 가 자원을 많이 쓰는 상황에서 LB 가 영향을 받는다. 노드를 더 뽑을 수 없을 때의 타협안으로 본다.
일반적인 형태는 LB 노드 2대에 HAProxy 를 두고 그 앞에 VIP 나 클라우드 LB 를 두는 것이다.
[Client / Worker]
|
VIP 또는 클라우드 LB
|
[HAProxy 1] [HAProxy 2]
| |
master1/2/3 : 6443
worker1/2/3 : 80,443
VIP 를 위해 NIC 를 추가할 필요는 없다. Keepalived 가 기존 인터페이스에 가상 주소를 얹는 방식이므로 같은 대역의 IP 하나만 더 확보하면 된다. 구성은 Keepalived 에 있다.
클라우드(Azure · AWS 등)에서는 사정이 다르다. Keepalived 의 VIP 이동은 ARP 광고에 의존하는데 클라우드 가상 네트워크에서는 그대로 통하지 않는 경우가 많다. 그래서 VIP 대신 클라우드 로드밸런서를 두고 백엔드 풀에 노드를 넣는 방식이 표준이다. 이때 추가되는 것은 NIC 가 아니라 LB 리소스의 프론트엔드 IP 다.
global
log /dev/log local0
maxconn 20000
daemon
defaults
log global
mode tcp
option tcplog
timeout connect 5s
timeout client 1m
timeout server 1m
# 1) kube-apiserver
frontend k8s-api
bind *:6443
default_backend k8s-api-backend
backend k8s-api-backend
balance roundrobin
option tcp-check
default-server inter 2s fall 3 rise 2
server master1 10.0.0.11:6443 check
server master2 10.0.0.12:6443 check
server master3 10.0.0.13:6443 check
# 2) Ingress HTTP
frontend ingress-http
bind *:80
default_backend ingress-http-backend
backend ingress-http-backend
balance roundrobin
option tcp-check
default-server inter 2s fall 3 rise 2
server worker1 10.0.0.21:30080 check
server worker2 10.0.0.22:30080 check
server worker3 10.0.0.23:30080 check
# 3) Ingress HTTPS
frontend ingress-https
bind *:443
default_backend ingress-https-backend
backend ingress-https-backend
balance roundrobin
option tcp-check
default-server inter 2s fall 3 rise 2
server worker1 10.0.0.21:30443 check
server worker2 10.0.0.22:30443 check
server worker3 10.0.0.23:30443 check
mode tcp 로 TLS 를 그대로 흘려보낸다. 인증서 처리는 Ingress 컨트롤러가 한다. HAProxy 에서 TLS 를 끊고 싶다면 mode http 로 바꾸고 bind *:443 ssl crt ... 를 쓰지만, 인증서 관리 지점이 둘로 늘어나므로 Ingress 를 쓰는 구성에서는 대개 패스스루로 둔다.
kube-apiserver 백엔드는 반드시 mode tcp 여야 한다. 클라이언트 인증서를 쓰는 mTLS 연결이므로 중간에서 끊으면 인증이 깨진다.
Ingress 백엔드 포트는 컨트롤러 서비스의 NodePort 로 맞춘다. hostNetwork 나 hostPort 구조라면 80 · 443 을 그대로 쓴다. 확인 방법은 firewalld 를 올리면 NodePort 접속이 끊길 때 에 정리했다.
# kubeadm-config.yaml
controlPlaneEndpoint: "k8s-api.example.com:6443"
클러스터를 처음 만들 때 이 값을 넣어야 마스터를 나중에 추가할 수 있다. 단일 마스터로 만들어 놓고 뒤에 3중화하려면 인증서 SAN 과 이 값을 바꾸는 작업이 따로 필요하다.
값에는 VIP 또는 LB 의 주소 · 이름을 넣는다. 특정 마스터의 IP 를 넣으면 그 노드가 죽을 때 클러스터 접근이 막힌다.
# LB 를 통해 apiserver 가 응답하는지
curl -k https://k8s-api.example.com:6443/version
# 실제로 어느 마스터가 받았는지 확인하려면 각 노드의 apiserver 로그를 본다
kubectl -n kube-system logs -l component=kube-apiserver --tail=20
# 상태
echo "show stat" | socat stdio /var/run/haproxy.sock | cut -d, -f1,2,18
전환 시험은 마스터 한 대의 apiserver 를 멈추고 kubectl get nodes 가 끊기지 않는지 보는 것이다. 몇 초 정도 지연은 정상이며, 감지 시간은 inter × fall 로 정해진다.