필자는 온프레미스 환경에서 k8s를 사용하기에 별도의 로드밸런서가 필요하다.
또한 HAProxy같은 리버스프록시를 사용하지 않기에 도메인 네임을 통해 서비스에 접근할 다른 방법이 필요하다.
MetalLB와 IngressController는 이런 상황에서 일반적으로 사용되는 솔루션이다.
이 글에서는 MetalLB와 IngressController를 통해 온프레미스 서버팜에서 k8s 서비스를 어떻게 로드밸런싱하고 도메인네임으로 접근할 수 있는지를 중점적으로 설명한다.
이전 글에서 구축한 Rocky Linux 9.5 + k8s + calico 환경을 사용한다.
0. 구성 방안
필자가 생각하는 k8s 구성 방안은 다음과 같다.
- MetalLB를 통한 공인 IP 부여 (공인 IP Pool 보유 중)
- 웹 서비스는 IngressController를 통해 통합 제공 (MetalLB로부터 부여된 IP 사용)
- 웹 이외의 서비스는 MetalLB에 직결하여 사용
이 구성을 통해 웹 서비스에 대한 도메인 기반 라우팅과 TLS 서비스가 가능하며, 웹 이외의 서비스에 대해서도 공인 IP를 부여할 수 있다.
중요한 점은 웹 서비스 여부에 따라 서비스를 ClusterIP로 할 지, LoadBalancer로 할 지가 달라진다는 점이다.
웹 서비스인 경우 IngressContoller에 의해 라우팅되므로 ClusterIP로 서비스해야하지만 웹 서비스가 아닌 경우 고유 IP를 부여받아야 하므로 LoadBalancer로 서비스해야 한다.
1. MetalLB 설치
커맨드를 복사하기 쉽도록 쉘 표시($)를 생략하였다.
MetalLB는 ARP를 사용하기에 kube-proxy에서 ARP를 사용하도록 강제해야 한다.
kubectl edit configmap -n kube-system kube-proxy # 파일 내에서 strictARP: false -> true로 변경
그 후 MetalLB를 설치한다. [MetalLB]
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml
MetalLB가 사용할 설정 파일을 새로 만들고 적용한다.
다음은 metallb-config.yaml 파일의 예시이다.
apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: first-pool namespace: metallb-system spec: addresses: - 10.1.1.0/24 # 사용 가능한 IP 범위로 변경 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: default namespace: metallb-system spec: ipAddressPools: - first-pool
kubectl apply -f metallb-config.yaml
MetalLB 설치가 완료되었다.
2. IngressController 설치
본인의 k8s 버전에 맞추어 IngressController를 설치한다. [IngressController]
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.1/deploy/static/provider/cloud/deploy.yaml
IngressController 설치가 완료되었다.
참고로 v1.12.1 버전에서는 IngressController의 default 네트워크가 LoadBalancer로 되어있다.
필자처럼 IP를 고정해 사용하고 싶은 경우 wget으로 위 yaml 파일을 내려받아 loadBalancerIP 구문을 추가하여 배포하면 된다. (가장 마지막 줄 참고)
# deploy.yaml 파일 중 apiVersion: v1 kind: Service metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx app.kubernetes.io/version: 1.12.1 name: ingress-nginx-controller namespace: ingress-nginx spec: externalTrafficPolicy: Local ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - appProtocol: http name: http port: 80 protocol: TCP targetPort: http - appProtocol: https name: https port: 443 protocol: TCP targetPort: https selector: app.kubernetes.io/component: controller app.kubernetes.io/instance: ingress-nginx app.kubernetes.io/name: ingress-nginx type: LoadBalancer loadBalancerIP: <고정할 IP>
3. 서비스 배포
이제 서비스를 배포해보자.
이전 글에서 만든 서비스와 더불어 Ingress를 만들어주면 된다.
여기서부터는 커맨드와 출력 결과를 구분하기 위해 셀 기호($)를 표시하였다.
Ingress는 서비스와 분리하여 yaml로 관리하는 게 편리하나 편의상 하나의 파일로 만들어 설명한다.
다음은 세 개의 nginx replica를 ingress로 서비스하는 web-ingress.yaml 파일의 내용이다.
파일을 만들어 배포해주자.
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - protocol: TCP port: 80 # 서비스 포트 (클러스터 내부) targetPort: 80 # 컨테이너 포트 (Pod 내부) type: ClusterIP # 웹 서비스이기에 MetalLB를 사용하지 않고 Ingress를 사용할 것이다. apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-web-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: ingressClassName: nginx rules: - host: my-web-test-service.com # 실제 도메인으로 변경하세요 http: paths: - path: / pathType: Prefix backend: service: name: nginx-service port: number: 80
$ kubectl apply -f web-ingress.yaml
서비스가 잘 배포되었는지 확인해보자.
마스터 노드에서 아래 커맨드를 실행했을 때 nginx 응답이 출력되면 정상이다.
참고로 http://10.1.1.0은 IngressController의 외부 IP 주소이며 아래 커맨드를 통해 확인할 수 있다.
$ kubectl get svc -n ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller LoadBalancer 10.111.189.38 10.1.1.0 80:32464/TCP,443:32359/TCP 19m ingress-nginx-controller-admission ClusterIP 10.109.170.26 <none> 443/TCP 19m $ curl -H "Host: my-web-test-service.com" http://10.1.1.0 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } 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>
참고로 외부에서 이 서비스에 접근하려면 my-web-test-service.com가 DNS에 등록되어있어야 한다.
필자의 경우 MetalLB의 IP Pool로 공인 IP 대역을 사용하며 이를 이용해 DNS 서버를 운영하고 있기에 외부에서도 위 서비스에 정상적으로 접근할 수 있다.
MetalLB와 IngressController의 활용 방법은 매우 다양하지만 여기서는 이 정도로만 소개하고 글을 마무리한다.