배경
Kubernetes Service type중 LoadBalancer Type은 External IP를 할당받아 외부 트래픽을 내부 서비스로 Routing 하는 역할을 수행합니다. 하지만 CRD는 명세 되어있음에도 Bare-metal 환경에서 LoadBalancing이 구현 되어있지 않습니다. 따라서 CSP(AWS, Azure 등)를 사용하지 않으면 External IP를 할당받을 수 없습니다.
Kubeadm등으로 구성한 On-prem k8s cluster에는 별도의 Load Balancer를 도입해야 합니다. 이 문서에서는 그러한 환경에 Metal LB 를 구성하는 과정에 대해 다룹니다.
요구사항
k8s network addon | Antrea, Calico, Canal, Cilium, Flannel, Kube-ovn, Kube-router, Weave Net |
IPv4 Address | MetalLB가 Service에 할당할 IP 대역(없다면 단일 서버 IP도 가능) |
L2 Operating mode | k8s 노드간 7946 포트(TCP&UDP)가 사용 가능해야함 |
BGP Operating mode | 각 노드의 BGP 기능을 지원하는 라우터 |
설치
준비
IPVS모드에서 kube-proxy를 경우, k8s v1.14.2이후부터 strict ARP모드를 활성화 해야 합니다.
💡kube-proxy, IPVS, ARP, strict ARP가 무엇인가요?
kube-proxy
Pod에 클러스터 내부 IP를 할당 및 추적하는 요소입니다. 동시에, 서비스에 대한 네트워크 트래픽을 서비스를 구성하는 여러 Pod중 하나로 분산시키는 로드밸런싱을 수행합니다.
IPVS
kube-proxy가 동작하는 세가지 모드(User space, iptables, IPVS)중 하나로, 다른 두가지 모드에 비해 높은 성능을 보입니다.
ARP
논리주소(IP)를 물리주소(MAC)으로 변환하는 프로토콜입니다.
Strict ARP
kube-proxy는 k8s리소스(Service, Pod)에 대한 가상 논리주소(VIP), 가상 물리주소(VMAC)를 알고 있으므로, 일반적인 ARP처럼 ARP 요청을 모든 Cilent에게 브로드캐스트하여 MAC주소를 받을 필요가 없습니다. 따라서, kube-proxy가 직접 ARP에 대한 응답을 하게 합니다.
먼저, strictARP모드가 활성화 되어있는지 확인합니다.
# see what changes would be made, returns nonzero returncode if different
kubectl get configmap kube-proxy -n kube-system -o yaml | \\
grep strictARP
아래 명령어를 통해 kube-proxy configmap을 수정합니다.
kubectl edit configmap -n kube-system kube-proxy
아래와 같이 설정합니다.
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true
또는 아래와 같은 명령어를 통해 변경합니다.
# actually apply the changes, returns nonzero returncode on errors only
kubectl get configmap kube-proxy -n kube-system -o yaml | \\
sed -e "s/strictARP: false/strictARP: true/" | \\
kubectl apply -f - -n kube-system
Manifest File로 설치
kubectl apply -f <https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/namespace.yaml>
kubectl apply -f <https://raw.githubusercontent.com/metallb/metallb/v0.14.3/manifests/metallb.yaml>
Configuration
IP Address Pool 설정
서비스에 할당할 IP를 정의하기 위해 IPAddressPool이라는 CR(Custom Resourece)를 정의해야 합니다. cluster에 할당된 IP만을 사용할 수 있다는 점에 주의하세요.
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.10.0/24
- 192.168.9.1-192.168.9.5
- fc00:f853:0ccd:e799::/124
이렇게 정의한 metallb_ipaddresspool.yaml 을 아래와 같이 적용합니다.
kubectl apply -f metallb_ipaddresspool.yaml
Istio Gateway
Istio-ingress gateway를 기존에 사용하고있던 경우, ClusterIP타입 서비스를 LoadBalancer타입으로 변경하여 클러스터 외부 IP를 할당할 수 있습니다.
kubectl edit svc/istio-ingressgateway -n istio-system
spec:
type: LoadBalancer # ClusterIP -> LoadBalancer
loadBalancerIP: 192.168.10.0 # IP를 명세
spec.loadBalancerIP를 명세하면 명시적으로 특정 IP를 사용할 수 있습니다. 명세하지 않는다면 IPAddressPool에 명세된 주소중 사용되지 않은 주소가 순차적으로 할당됩니다.