이재홍의 언제나 최신 Kubernetes - Unit 6.5 인그레스와 LoadBalancer 서비스 생성하기

저작권 안내
  • 책 또는 웹사이트의 내용을 복제하여 다른 곳에 게시하는 것을 금지합니다.
  • 책 또는 웹사이트의 내용을 발췌, 요약하여 강의 자료, 발표 자료, 블로그 포스팅 등으로 만드는 것을 금지합니다.

로컬에서 Kubernetes 클러스터 구축하기

이재홍 http://www.pyrasis.com

인그레스와 LoadBalancer 서비스 생성하기

지금까지 NodePort로 생성된 서비스에 접근해보았습니다. 하지만, NodePort는 해당 노드에 랜덤한 포트로 접속하기 때문에 실제 서비스에 사용하기는 힘듭니다. 이번에는 도메인과 연동할 수 있는 인그레스와 LoadBalancer 서비스를 생성하고 사용해보겠습니다.

인그레스 컨트롤러 설치하기

인그레스를 사용하려면 먼저 인그레스 컨트롤러를 설치해야 합니다. 여기서는 Nginx 인그레스 컨트롤러를 사용하겠습니다.

다음 명령을 실행하여 베어메탈용 Nginx 인그레스 컨트롤러를 설치합니다.

$ kubectl create -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.3/deploy/static/provider/baremetal/deploy.yaml

베어메탈

베어메탈은 하드웨어상에 어떤 소프트웨어도 설치되지 않은 상태를 뜻합니다. 즉, 물리서버 그 자체를 말합니다. 여기에 사용자가 운영체제를 설치한 것이 베어메탈 서버라고 할 수 있습니다.

이 실습을 위해 우리는 물리서버 여러 대를 구입하기 힘들므로, 가상화 소프트웨어인 VirtualBox, Parallels Desktop Pro로 베어메탈 환경을 임시로 구성한 상황입니다.

MetalLB 설치하기

쿠버네티스를 클라우드에 구축했다면 로드밸런서(Load Balancer)를 클라우드에서 제공하는 것을 사용했을 것입니다(예: AWS의 ELB).

그림 6-7 클라우드 환경의 로드밸런서(출처: https://kubernetes.github.io/ingress-nginx/deploy/baremetal/)

하지만 우리는 로컬에 베어메탈 환경을 가정하고 클러스터를 구축했기 때문에 따로 로드밸런서가 없습니다.

그림 6-8 베어메탈 환경(출처: https://kubernetes.github.io/ingress-nginx/deploy/baremetal/)

따라서 우리는 MetalLB라는 베어메탈용 로드밸런서를 사용하겠습니다. 완전한 클라우드 로드밸런서를 사용하는 방법은 뒤에서 다시 설명하겠습니다.

그림 6-9 MetalLB: Layer 2(출처: https://kubernetes.github.io/ingress-nginx/deploy/baremetal/)

다음 명령을 실행하여 kube-proxy에서 strictARP 설정을 false에서 true로 변경해줍니다. 왜냐하면 MetalLB는 ARP 프로토콜(OSI Layer 2)을 이용하기 때문입니다.

리눅스 macOS
$ kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl apply -f - -n kube-system
윈도우 PowerShell
kubectl get configmap kube-proxy -n kube-system -o yaml | %{$_ -replace "strictARP: false", "strictARP: true"} | kubectl apply -f - -n kube-system

그리고 MetaLB를 설치합니다.

$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml

이제 로드밸런서로 사용할 IP 대역을 설정해야 합니다. 다음 내용을 metallb-config.yaml 파일로 저장합니다.

metallb-config.yaml
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default
  namespace: metallb-system
spec:
  addresses:
    - 192.168.56.100-192.168.56.200
  autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system
spec:
  ipAddressPools:
    - default

저장이 끝났으면 설정을 생성합니다.

$ kubectl create -f metallb-config.yaml

webhook 에러가 발생한다면?

다음과 같이 Internal error occurred: failed calling webhook 에러가 발생할 수도 있습니다.

Error from server (InternalError): error when creating "metallb-config.yaml": Internal error occurred: failed calling webhook "ipaddresspoolvalidationwebhook.metallb.io": failed to call webhook: Post "https://webhook-service.metallb-system.svc:443/validate-metallb-io-v1beta1-ipaddresspool?timeout=10s": context deadline exceeded
Error from server (InternalError): error when creating "metallb-config.yaml": Internal error occurred: failed calling webhook "l2advertisementvalidationwebhook.metallb.io": failed to call webhook: Post "https://webhook-service.metallb-system.svc:443/validate-metallb-io-v1beta1-l2advertisement?timeout=10s": dial tcp 10.106.129.209:443: i/o timeout

이때는 다음 명령을 입력하여 metallb-webhook-configuration webhook 설정을 삭제해줍니다. 지금은 이 webhook을 사용하지 않으므로 삭제해도 괜찮습니다.

$ kubectl delete validatingwebhookconfigurations metallb-webhook-configuration

삭제되었다면 다시 설정을 생성해봅니다.

$ kubectl create -f metallb-config.yaml

Nginx 인그레스 컨트롤러를 LoadBalancer로 바꾸기

이제 필요한 것들을 모두 설치하고 설정했습니다. 다음 명령을 입력하여 Nginx 인그레스 컨트롤러의 서비스를 출력해봅니다.

$ kubectl -n ingress-nginx get service
NAME                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.101.223.167   <none>        80:32580/TCP,443:30309/TCP   3m4s
ingress-nginx-controller-admission   ClusterIP   10.104.113.40    <none>        443/TCP                      3m4s

ingress-nginx-controller의 TYPE을 보면 NodePort로 되어 있습니다.

다음 명령을 실행하여 ingress-nginx-controller의 TYPE을 LoadBalancer로 변경합니다.

리눅스, macOS
$ kubectl -n ingress-nginx patch service ingress-nginx-controller -p '{"spec":{"type":"LoadBalancer"}}'
윈도우 PowerShell
kubectl -n ingress-nginx patch service ingress-nginx-controller -p '{\"spec\":{\"type\":\"LoadBalancer\"}}'

다시 Nginx 인그레스 컨트롤러의 서비스를 출력해봅니다.

$ kubectl -n ingress-nginx get service
NAME                                 TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.101.223.167   192.168.56.100   80:32580/TCP,443:30309/TCP   26m
ingress-nginx-controller-admission   ClusterIP      10.104.113.40    <none>           443/TCP                      26m

ingress-nginx-controller의 TYPE이 LoadBalancer로 바뀌었고, EXTERNAL-IP 부분에 192.168.56.100 IP 주소가 할당된 것을 볼 수 있습니다. 이 EXTERNAL-IP가 외부에서 접속할 수 있는 IP 주소입니다. 만약 도메인 설정을 한다면 이 IP 주소로 A 레코드를 만들면 되는 것입니다. 하지만, 지금은 도메인을 구입하지 않았으므로 로컬에서 설정하는 방법을 뒤에서 설명하겠습니다.

인그레스 만들기

이제 인그레스를 만들 차례입니다. 다음 내용을 ingress.yaml 파일로 저장합니다.

ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-localhost
spec:
  ingressClassName: nginx
  rules:
    - host: demo.localdev.me
      http:
        paths:
          - backend:
              service:
                name: hello-nginx
                port:
                  number: 80
            path: /
            pathType: Prefix

저장이 끝났으면 인그레스를 생성합니다.

$ kubectl create -f ingress.yaml

webhook 에러가 발생한다면?

다음과 같이 Internal error occurred: failed calling webhook 에러가 발생할 수도 있습니다.

error: failed to create ingress: Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io": failed to call webhook: Post "https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networking/v1/ingresses?timeout=10s": context deadline exceeded

이때는 다음 명령을 입력하여 ingress-nginx-admission webhook 설정을 삭제해줍니다. 지금은 이 webhook을 사용하지 않으므로 삭제해도 괜찮습니다.

$ kubectl delete validatingwebhookconfiguration ingress-nginx-admission

삭제되었다면 다시 인그레스를 생성해봅니다.

$ kubectl create -f ingress.yaml

이제 kubectl get ingress 명령으로 인그레스를 출력해보겠습니다.

$ kubectl get ingress
NAME             CLASS   HOSTS              ADDRESS         PORTS   AGE
demo-localhost   nginx   demo.localdev.me   192.168.56.11   80      2m1s

HOSTS에 도메인으로 demo.localdev.me가 설정된 것을 볼 수 있습니다. ADDRESS의 IP 주소는 사용하지 않을 것이므로 신경쓰지 않아도 됩니다. 여기서는 Nginx 인그레스 컨트롤러를 사용할 것이므로 위에서 만든 ingress-nginx-controllerEXTERNAL-IP가 중요합니다.

호스트 설정하기

우리는 실제로 demo.localdev.me 도메인을 구입하지 않았으므로, 로컬에서 임시로 사용할 수 있도록 설정해야 합니다. 운영체제별로 설정 파일이 조금 다른데, 각자 운영체제에 맞는 파일을 수정합니다.

리눅스, macOS는 /etc/hosts 파일을 수정해야 합니다. root 권한이 있어야 하므로 sudo vim으로 수정합니다.

리눅스, macOS
$ sudo vim /etc/hosts

/etc/hosts 파일의 마지막 부분에 다음 내용을 추가한 뒤 저장합니다.

/etc/hosts
192.168.56.100 demo.localdev.me

윈도우는 C:\Windows\System32\drivers\etc\hosts 파일을 수정해야 합니다. 관리자 권한이 필요하므로, 메모장을 관리자 권한으로 실행한 뒤 파일을 엽니다.

C:\Windows\System32\drivers\etc\hosts 파일의 마지막 부분에 다음 내용을 추가한 뒤 저장합니다.

C:\Windows\System32\drivers\etc\hosts
192.168.56.100 demo.localdev.me

메모장에서 hosts 파일이 보이지 않는다면?

메모장에서 hosts 파일이 보이지 않는다면, 열기 창에서 열기(O) 버튼 위의 텍스트 문서(*.txt)모든 파일 (*.*)로 바꿔주면 됩니다.

웹 브라우저를 열고 http://demo.localdev.me 접속하면 Welcome to nginx!가 표시될 것입니다.

인그레스 삭제

인그레스를 삭제하려면 kubectl delete -f 명령을 사용합니다.

$ kubectl delete -f ingress.yaml

Vagrant 가상머신 삭제하기

사용이 끝난 Vagrant 가상머신은 vagrant destroy 명령으로 삭제할 수 있습니다. [y/N]이 나오면 모두 y를 입력하여 삭제합니다.

$ vagrant destroy
    worker3: Are you sure you want to destroy the 'worker3' VM? [y/N] y
==> worker3: Forcing shutdown of VM...
==> worker3: Destroying VM and associated drives...
    worker2: Are you sure you want to destroy the 'worker2' VM? [y/N] y
==> worker2: Forcing shutdown of VM...
==> worker2: Destroying VM and associated drives...
    worker1: Are you sure you want to destroy the 'worker1' VM? [y/N] y
==> worker1: Forcing shutdown of VM...
==> worker1: Destroying VM and associated drives...
    master: Are you sure you want to destroy the 'master' VM? [y/N] y
==> master: Forcing shutdown of VM...
==> master: Destroying VM and associated drives...

MetalLB 설정과 인그레스 구조 살펴보기

MetalLb 설정

이제 YAML 파일을 자세히 살펴보겠습니다. 먼저 MetalLB 설정 파일인 metallb-config.yaml입니다. 이 파일에는 IPAddressPoolL2Advertisement 두 가지가 함께 들아있습니다. YAML에서는 ---으로 여러 설정을 구분하여 파일 하나에 넣을 수 있습니다.

metallb-config.yaml
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default
  namespace: metallb-system
spec:
  addresses:
    - 192.168.56.100-192.168.56.200
  autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system
spec:
  ipAddressPools:
    - default
  • .apiVersion: 현재 MetalLB IPAddressPool의 버전은 metallb.io/v1beta1입니다.
  • .kind: MetalLB의 IP 주소 풀이라 IPAddressPool로 설정했습니다.
  • .metadata.name: IP 주소 풀의 이름은 default입니다.
  • .metadata.namespace: 네임스페이스는 일종의 디렉터리 역할을 합니다. 즉, 각 오브젝트들을 네임스페이스별로 구분하여 관리할 수 있습니다. 여기서는 metallb-system으로 설정했습니다.
  • .spec.addresses: 서비스의 LoadBalancer에 할당할 IP 주소 대역을 설정합니다. 노드의 IP 주소와는 겹치지 않게 해야 합니다. 여기서는 192.168.56.100-192.168.56.200로 설정했습니다.
  • .spec.autoAssign: 서비스의 LoadBalancer에 IP 주소를 자동 할당한다는 설정입니다. true로 설정합니다.

  • .apiVersion: 현재 MetalLB L2Advertisement의 버전은 metallb.io/v1beta1입니다.
  • .kind: MetalLB의 L2 레이어 전파(Advertisement) 설정이라 L2Advertisement으로 설정했습니다.
  • .metadata.name: L2 레이어 전파 설정의 이름은 default입니다.
  • .metadata.namespace: 물론 여기서도 네임스페이스는 metallb-system으로 설정했습니다.
  • .spec.ipAddressPools: L2 레이어로 전파할 IP 주소풀을 설정합니다. 위에서 만든 default를 설정했습니다.

인그레스

드디어 인그레스입니다. 인그레스는 앞으로도 자주 접하게 될 설정입니다.

ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-localhost
spec:
  ingressClassName: nginx
  rules:
    - host: demo.localdev.me
      http:
        paths:
          - backend:
              service:
                name: hello-nginx
                port:
                  number: 80
            path: /
            pathType: Prefix
  • .apiVersion: 현재 인그레스의 버전은 networking.k8s.io/v1입니다.
  • .kind: 인그레스를 생성하므로 Ingress로 설정했습니다.
  • .metadata.name: 인그레스의 이름은 demo-localhost로 설정했습니다.
  • .spec.ingressClassName: 인그레스 클래스 설정입니다. 우리는 앞에서 Nginx 인그레스 컨트롤러를 설치했으므로 nginx로 설정합니다.
  • .rules: 여기서부터 인그레스 규칙 설정입니다. 배열 형태이며 여러 개를 넣을 수 있습니다.
  • .rules[0].host: 인그레스와 연동할 도메인입니다. 구입한 도메인을 설정해도 되고, 가상의 도메인을 설정해도 됩니다. 여기서는 가상의 테스트용 도메인인 demo.localdev.me를 설정했습니다.
  • .rules[0].http: HTTP 프로토콜 설정입니다.
  • .rules[0].http.paths: 도메인에 접속했을 때 하위 경로(path) 설정입니다. 배열 형태이며 여러 개를 넣을 수 있습니다. 여기서는 최상위 경로인 /만 처리하고 있습니다.
  • .rules[0].http.paths[0].backend: 현재 경로의 트래픽을 어디로 보낼 것인지 설정하는 부분입니다. 여기서는 service로 보내며 서비스의 이름(name)은 hello-nginx, 포트 번호(port.number)는 80으로 설정했습니다.
  • .rules[0].http.paths[0].path: 처리할 하위 경로입니다. 여기서는 최상위 경로를 처리할 것이므로 /로 설정했습니다.
  • .rules[0].http.paths[0].pathType: 경로를 처리할 방식입니다. Prefix, ImplementationSpecific, Exact를 설정할 수 있는데, 우리는 /로 시작하는 모든 경로를 처리할 것이므로 Prefix로 설정했습니다. ImplementationSpecific는 인그레스 클래스에 따라 달라지며, Exact는 경로의 대소문자까지 정확하게 일치시킵니다.

Nginx 인그레스 컨트롤러와 MetalLB 삭제

Nginx 인그레스 컨트롤러와 MetalLB를 삭제하려면 kubectl delete -f 명령을 사용합니다.

$ kubectl delete -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.5.1/deploy/static/provider/baremetal/deploy.yaml
$ kubectl delete -f https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml

저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

2022-10-22