이재홍의 언제나 최신 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.5.1/deploy/static/provider/baremetal/deploy.yaml

베어메탈

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

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

MetalLB 설치하기

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

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

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

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

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

그림 6-5 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.13.7/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