[Kubernetes] NGINX Plus Ingress Controller 구축 및 VirtualServer 테스트

gweowe·2024년 4월 25일

Kubernetes 환경에서 효과적인 로드 밸런싱 및 트래픽 관리를 위해서는 Ingress Controller가 필요합니다. Ingress Controller는 다양한 솔루션이 있지만 이 중에서 가장 많은 점유율을 가지고 있는 NGINX Ingress Controller를 구성하는 방법을 살펴보겠습니다. NGINX Plus 이미지를 사용하여 NGINX Ingress Controller 구축하고 테스트를 해보겠습니다.

사전 준비 사항

1. Kubernetes 환경 구축

해당 가이드를 참고하여 서버를 구축해주세요.

2. NGINX Plus Trial License 준비

링크를 통해 NGINX Plus Trial License를 준비합니다.

.crt, .key, .jwt 파일을 준비합니다.

3. NGINX Plus Secret 생성

Ingress Controller에서 NGINX Plus 기능을 활성화하기 위해서 .jwt 파일을 Secret에 등록해야 합니다.

kubectl create secret docker-registry regcred --docker-server=private-registry.nginx.com --docker-username=<JWT Token 값> --docker-password=none -n nginx-ingress

준비한 .jwt 파일의 값을 사용하여 secret을 생성합니다.

4. 인증서 Secret 생성

해당 가이드를 참고하여 사설 인증서를 생성합니다. 인증서를 보유하고 있다면 그 인증서를 사용하시면 됩니다.

kubectl create secret tls tls-secret --key <key path> --cert <crt path>

NGINX Ingress Controller를 올리기 위해 필요한 인증서를 secret으로 생성합니다.

5. Metal LB 구축 (On-Premise 환경)

LB가 없으면 클러스터 내부의 서비스를 외부로 노출시키기 위한 외부 IP 주소를 할당할 수 없으므로 LB가 필요합니다.

일반적으로 Cloud 환경에서 구축한 Kubernetes(EKS, AKS GKE 등)는 자체적으로 LB를 제공해주지만, On-Premise 환경에서는 직접 구축해야 합니다.

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

metalLB 배포 후, 사용하기 위해서는 추가적으로 IP Pool을 설정해야 합니다.

vi metallb_ip_pool.yaml
metallb_ip_pool.yaml
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default
  namespace: metallb-system
spec:
  addresses:
    - <Kubernetes Cluster IP>/32
  autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system
spec:
  ipAddressPools:
    - default
  • addresses: Kubernetes Cluster의 실제 IP를 지정해야 합니다.
kubectl apply -f metallb_ip_pool.yaml

IP Pool을 배포하여 사전 준비를 마무리합니다.

NGINX Ingress Controller 구축

1. NGINX CRD 등록

kubectl apply -f https://raw.githubusercontent.com/nginxinc/kubernetes-ingress/v3.5.0/deploy/crds.yaml

NGINX Ingress Controller를 사용하기 위해 Kubernetes에 CRD를 등록합니다.

2. Helm Chart 가져오기

git clone https://github.com/kubernetes/ingress-nginx

Ingress Controller를 구축하기 위한 공식 Helm Chart를 가져옵니다.

3. values 파일 수정

cd ingress-nginx/charts/ingress-nginx
vi values.yaml
values.yaml
controller:

# ..............................생략..............................

  nginxplus: true # Nginx Plus 활성화
  
# ..............................생략..............................

  image:
    repository: private-registry.nginx.com/nginx-ic-nap-dos/nginx-plus-ingress # Nginx Plus Image 지정
    
# ..............................생략..............................

  defaultTLS:
    secret: "nginx-ingress/tls-secret"
    
  wildcardTLS:
    secret: "nginx-ingress/tls-secret"

# ..............................생략..............................

  serviceAccount:
    imagePullSecretName: regcred # JWT Token 값을 사용하여 Nginx Plus 인증
    
# ..............................생략..............................

NGINX Plus를 사용하기 위해 values 파일을 일부 수정합니다.

4. Helm Chart 배포

helm install nginx-ingress-controller -f values.yaml -n nginx-ingress ./

배포를 시작합니다.

kubectl get pod -n nginx-ingress
output:
NAME                                                 READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-controller-9f9c7bc8-g4bw7   1/1     Running   0          3m4s

정상적으로 pod가 올라감을 확인합니다.

Sample Application 구축

1. Test Deployment 배포

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: load-balancer-example
  name: hello-world
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: load-balancer-example
  template:
    metadata:
      labels:
        app.kubernetes.io/name: load-balancer-example
    spec:
      containers:
      - image: gcr.io/google-samples/node-hello:1.0
        name: hello-world
        ports:
        - containerPort: 8080

간단한 문구를 출력해주는 Test Deployment를 배포합니다.

2. Test Service 배포

apiVersion: v1
kind: Service
metadata:
  name: hello-world-service
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app.kubernetes.io/name: load-balancer-example
  sessionAffinity: None
  type: ClusterIP

VirtualServer가 대상으로 할 Service를 배포합니다.

3. Test VirtualServer 배포

apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: hello-world-vs
spec:
  host: hello.gweowe.com
  upstreams:
  - name: hello
    service: hello-world-service
    port: 8080

  routes:
  - path: /
    action:
      pass: hello

VirtualServer는 NGINX CRD를 사용하여 배포합니다.

기재되어 있는 spec에 대한 설명은 다음과 같습니다. 더 자세한 내용은 링크를 참고해주세요.

  • host: VirtualServer 리소스를 사용하여 외부로 노출시킬 도메인입니다. Ingress 및 VirtualServer 리소스에서 중복되서는 안됩니다.
  • upsteam: 라우팅할 upstream을 구성합니다.
    • name: upstream의 이름을 기재합니다.
    • service: 라우팅할 Service를 지정합니다. 해당 Service는 VirtualServer와 동일한 namespace에 존재해야 합니다.
    • port: 실제로 라우팅할 Service의 Port를 지정합니다.
  • routes: VirtualServer의 경로를 구성합니다.
    • path: 도메인으로 라우팅할 경로를 지정합니다. 이는 Pod에서 사용하고 있는 경로와 일치해야 합니다.
    • action: 요청에 대해 수행할 작업을 구성합니다.
      • pass: 요청을 전달할 upstream 이름을 지정합니다. 해당 이름은 upstream에서 기재한 이름과 일치해야 합니다.
/etc/hosts
255.255.255.255 broadcasthost
::1             localhost
<Kubernetes Cluster IP> hello.gweowe.com

테스트를 위해 Host에 넣은 도메인을 /etc/hosts 파일에 추가하여 진행했습니다.

kubectl get vs

VirtualServer가 제대로 배포되었는지 확인합니다.

Output:
NAME             STATE   HOST               IP              PORTS      AGE
hello-world-vs   Valid   hello.gweowe.com   xxx.xxx.xxx.xxx [80,443]   157m

STATE가 Valid임을 확인할 수 있습니다.

4. curl 테스트

curl hello.gweowe.com
Output:
Hello Kubernetes!

배포한 VirtualServer를 대상으로 curl 명령어를 날려서 정상적으로 출력되었음을 확인할 수 있습니다.

profile
정리하는 공간

0개의 댓글