필자는 온프레미스 환경에서 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의 활용 방법은 매우 다양하지만 여기서는 이 정도로만 소개하고 글을 마무리한다.