[Retry, k8s] 14. 서비스 API - LoadBalancer (MetalLB)
카테고리: KUBERNETES
태그: kubernetes
[Retry, k8s] 14. 서비스 API - LoadBalancer (MetalLB)
🔔 LoadBalancer
-
LoadBalancer 서비스는 쿠버네티스 클러스터 외부의 로드 밸런서에 외부 통신이 가능한 가상 IP를 할당할 수 있다.
-
외부 로드 밸런서를 사용하려면 쿠버네티스 클러스터가 구축된 인프라가 이 구조에 맞도록 설계되어 있어야 하는데, 현재는 GCP/AWS/애저(Azure)/OpenStack을 비롯한 클라우드 프로바이더가 LoadBalancer 서비스를 사용할 수 있는 환경을 제공하고 있다.
-
NodePort/ExternalIP에서는 하나의 쿠버네티스 노드에 할당된 IP 주소로 통신하기 때문에 그 노드가 단일 장애점(SPOF)이 되어 버리지만, LoadBalancer에서는 쿠버네티스 노드와 별도로 외부 로드 밸런서를 사용하기 때문에 노드 장애가 발생해도 크게 문제가 없다.
-
구조는 NodePort 서비스를 생성하고 클러스터 외부의 로드 밸런서에서 쿠버네티스 노드로 밸런싱을 하는 형태로, k8s 클러스터 노드에 장애가 발생한 경우 그 노드에 트래픽을 전송하지 않음으로써 자동으로 복구하게 되어 있다.
🔔 MetalLB
-
Kubernetes 사용 시 AWS, GCP, Azure 와 같은 클라우드 플랫폼에서는 자체적으로 로드 벨런서(Load Balancer)를 제공해 주지만, 온프레미스 클러스터에서는 로드 벨런싱 기능을 제공하는 모듈을 추가적으로 설치해야 한다.
-
MetalLB는 온프레미스 환경에서 쿠버네티스의 로드밸런서 서비스를 제공하는 프로젝트이다.
-
MetaLB는 L2 네트워크(ARP/NDP)와 L3 네트워크(BGP) 두가지 방식으로 로드 밸런서를 구현할 수 있다.
| 방식 | 설명 |
|---|---|
| L2 네트워크(ARP/NDP) 방식 | ㆍARP 요청에 응답하여 서비스 IP와 노드의 MAC 주소를 알려주는 방식 ㆍ설정이 간단하지만 네트워크 장비와 호환되어야 하고, 같은 브로드캐스트 도메인에 있어야함 ㆍ라우팅 제어가 불가능 |
| L3 네트워크(BGP) 방식 | ㆍBGP 방식은 외부 BGP 라우터와 세션을 맺고 서비스 IP에 대한 라우팅 정보를 교환하는 방식 ㆍ설정이 복잡하지만 네트워크 장비와 독립적 ㆍ라우팅 제어가 가능하고, 서비스 IP가 변경되면 BGP 업데이트 메시지를 통해 라우팅 정보를 갱신함 |
🔔 NodePort / (Cloud) LoadBalancer / (MetalLB) LoadBalancer동작 차이
(1) NodePort
-
사용자가 워크 노드에 있는 포트에 접속
-
접속 한 이후에 해당 워크 노드가 서비스로 이를 바인딩
-
서비스가 현재 노드의 상태 등의 기준으로 노드에 연결 시킴

(2) (Cloud) LoadBalancer

(3) (MetalLB) LoadBalancer
-
MetalLB은 “컨트롤러”와 “스피커”라는 두 가지 구성 요소로 이루어져 있다.
-
컨트롤러는 작동 방식과 EXTERNAL-IP를 정의하고 관리하며, 스피커는 네트워크 정보를 광고하고 수집하여 각 파드의 경로를 제공한다.

🔔 MetalLB 설치
(1) strict ARP mode 활성화
kubectl edit configmap -n kube-system kube-proxy
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true # <- false에서 true로 변경
(2) Manifest를 이용해 MetalLB 설치
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml
(3) IP Address Pool + L2Advertisement 설정
$ cat <<EOF > my-network.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.219.190-192.168.219.199
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: mt-network-l2
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
EOF
(4) MetalLB 동작 확인
cat <<EOF > test.yaml
apiVersion: v1
kind: Pod
metadata:
name: almighty
labels:
app: almighty
spec:
containers:
- name: almighty
image: docker.io/andrewloyolajeong/almighty:0.2.4
---
apiVersion: v1
kind: Service
metadata:
name: almighty
spec:
type: LoadBalancer
externalTrafficPolicy: Local
selector:
app: almighty
ports:
- name: myweb
protocol: TCP
port: 8080
targetPort: 8080
- name: yourweb
protocol: TCP
port: 8081
targetPort: 8081
EOF
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/almighty 1/1 Running 0 4m9s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/almighty LoadBalancer 10.96.105.251 192.168.219.190 8080:31468/TCP,8081:31823/TCP 4m9s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4h36m
$ curl 192.168.219.190:8080
Hello from example application. (written by Andrew)
$ curl 192.168.219.190:8081
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
🔔 LoadBalancer 서비스 생성
| 설정 | 개요 |
|---|---|
| spec.ports[].port | LoadBalancer에 할당되는 가상 IP와 ClusterIP에서 수신할 포트 번호 |
| spec.ports[].targetPort | 목적지 컨테이너 포트 번호 |
| spec.ports[].nodePort | 모든 쿠버네티스 노드 IP 주소에서 수신할 포트 번호 |
cat <<EOF > sample-lb.yaml
apiVersion: v1
kind: Service
metadata:
name: sample-lb
spec:
type: LoadBalancer
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80
nodePort: 30082
selector:
app: sample-app
EOF
$ kubectl get service sample-lb
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
sample-lb LoadBalancer 10.96.194.169 192.168.219.191 8080:32659/TCP 5s
$ curl -s http://192.168.219.191:8080
Host=192.168.219.191 Path=/ From=sample-deployment-7f47966499-k7vk7 ClientIP=10.40.0.0 XFF=
$ curl -s http://192.168.219.191:8080
Host=192.168.219.191 Path=/ From=sample-deployment-7f47966499-82lld ClientIP=10.40.0.0 XFF=
$ curl -s http://192.168.219.191:8080
Host=192.168.219.191 Path=/ From=sample-deployment-7f47966499-llctj ClientIP=10.40.0.0 XFF=

🔔 로드밸런서에 할당되는 가상 IP 정적 지정
cat <<EOF > sample-lb-fixip.yaml
apiVersion: v1
kind: Service
metadata:
name: sample-lb-fixip
spec:
type: LoadBalancer
loadBalancerIP: 192.168.219.195
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80
selector:
app: sample-app
EOF
$ kubectl get service sample-lb-fixip
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
sample-lb-fixip LoadBalancer 10.109.42.211 192.168.219.195 8080:30202/TCP 11s
🔔 로드 밸런서 방화벽 정책 설정
- 외부 로드 밸런서에서 접속 제어가 구현되지 않은 쿠버네티스 환경에서 이 loadBalancerSourceRanges를 설정하면, 쿠버네티스 노드 측의 iptables를 사용하여 접속 제어 처리가 이루어진다.
apiVersion: v1
kind: Service
metadata:
name: sample-lb-fw
spec:
type: LoadBalancer
ports:
- name: "http-port"
protocol: "TCP"
port: 8080
targetPort: 80
selector:
app: sample-app
loadBalancerSourceRanges:
- 10.0.0.0/8
댓글 남기기