Helm을 사용하여 Kubernetes에서 Nginx 인그레스를 설정하는 방법


저자는 Write for DOnations 프로그램을 선택했습니다.

소개

Kubernetes 수신은 클러스터 외부에서 내부 Kubernetes 서비스로 트래픽을 라우팅하는 유연한 방법을 제공합니다. Ingress 리소스는 HTTP 및 HTTPS 트래픽을 서비스로 라우팅하기 위한 규칙을 정의하는 Kubernetes의 객체입니다. 이것이 작동하려면 인그레스 컨트롤러가 트래픽을 수락하고(대부분 로드 밸런서를 통해) 적절한 서비스로 라우팅하여 규칙을 구현해야 합니다. 대부분의 인그레스 컨트롤러는 모든 인그레스에 대해 하나의 전역 로드 밸런서만 사용하므로 노출하려는 모든 서비스마다 로드 밸런서를 만드는 것보다 효율적입니다.

Helm은 Kubernetes를 관리하기 위한 패키지 관리자입니다. Kubernetes와 함께 Helm 차트를 사용하면 Kubernetes 애플리케이션을 업데이트, 롤백 및 삭제할 수 있는 구성 가능성 및 수명 주기 관리가 제공됩니다.

이 가이드에서는 인그레스를 보호할 Let's Encrypt TLS 인증서를 자동으로 프로비저닝하기 위해 Kubernetes에서 유지 관리하는 Cert Manager를 클러스터에 설정합니다.

전제 조건

  • 버전 1.20 이상의 Kubernetes 클러스터는 kubectl 기본값으로 구성된 연결 구성으로 설정됩니다. 이 설정에서는 Kubernetes Quickstart를 사용합니다.\n
  • 로컬 환경에 설치되고 클러스터에 연결하도록 구성된 kubectl 명령줄 도구. DigitalOcean Kubernetes 클러스터 문서에 연결하는 방법에서 kubectl 설치에 대한 자세한 내용을 읽을 수 있습니다.\n
  • doctl 사용에 대한 자세한 내용은 DigitalOcean 명령줄 클라이언트, doctl 사용 방법을 참조하십시오.\n
  • 개발 환경에서 사용할 수 있는 Helm 3 패키지 관리자. Helm 3 패키지 관리자 튜토리얼을 사용하여 Kubernetes 클러스터에 소프트웨어를 설치하는 방법의 1단계를 완료하십시오.\n
  • 두 개의 사용 가능한 A 레코드가 있는 완전히 등록된 도메인 이름. 이 자습서에서는 전체적으로 hw1.your_domainhw2.your_domain을 사용합니다. Freenom에서 도메인 이름을 구입하거나 선택한 도메인 등록 기관을 사용할 수 있습니다. 이러한 A 레코드는 2단계에서 생성할 로드 밸런서로 전달됩니다.\n

1단계 - Hello World 배포 설정

Nginx 인그레스를 배포하기 전에 hello-kubernetes라는 "Hello World\ 앱을 배포하여 트래픽을 라우팅할 일부 서비스를 확보합니다. Nginx 인그레스가 제대로 작동하는지 확인하려면 다음 단계에서는 브라우저에서 액세스할 때 표시되는 다른 환영 메시지와 함께 두 번 배포합니다.

로컬 컴퓨터에 배포 구성을 저장합니다. 원하는 경우 구성을 저장할 이 자습서용 디렉터리를 만들 수도 있습니다. 첫 번째 배포 구성은 hello-kubernetes-first.yaml이라는 파일에 있습니다. 선호하는 텍스트 편집기로 작성하십시오.

  1. nano hello-kubernetes-first.yaml

다음 줄을 추가합니다.

apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes-first
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-kubernetes-first
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes-first
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes-first
  template:
    metadata:
      labels:
        app: hello-kubernetes-first
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.10
        ports:
        - containerPort: 8080
        env:
        - name: MESSAGE
          value: Hello from the first deployment!

이 구성은 배포서비스를 정의합니다. Deploymentpaulbouwer/hello-kubernetes:1.7 이미지의 복제본 3개와 MESSAGE라는 환경 변수로 구성됩니다. 당신은 앱에 액세스). 여기서 서비스는 포트 80에서 클러스터 내 배포를 노출하도록 정의됩니다.

파일을 저장하고 닫습니다.

그런 다음 다음 명령을 실행하여 Kubernetes에서 hello-kubernetes 앱의 첫 번째 변형을 생성합니다.

  1. kubectl create -f hello-kubernetes-first.yaml

-f 옵션은 create 명령이 hello-kubernetes-first.yaml 파일을 사용하도록 지시합니다.

다음과 같은 결과가 표시됩니다.

Output
service/hello-kubernetes-first created deployment.apps/hello-kubernetes-first created

서비스 생성을 확인하려면 다음 명령을 실행합니다.

  1. kubectl get service hello-kubernetes-first

출력은 다음과 같습니다.

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hello-kubernetes-first ClusterIP 10.245.124.46 <none> 80/TCP 7s

새로 생성된 서비스에 ClusterIP가 할당되어 제대로 작동하고 있음을 알 수 있습니다. 전송된 모든 트래픽은 포트 8080에서 선택한 배포로 전달됩니다. 이제 hello-kubernetes 앱의 첫 번째 변형을 배포했으므로 두 번째 변형을 작업할 것입니다.

hello-kubernetes-second.yaml이라는 새 파일을 만듭니다.

  1. nano hello-kubernetes-second.yaml

다음 줄을 추가합니다.

apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes-second
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-kubernetes-second
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes-second
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes-second
  template:
    metadata:
      labels:
        app: hello-kubernetes-second
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.10
        ports:
        - containerPort: 8080
        env:
        - name: MESSAGE
          value: Hello from the second deployment!

이 변형은 이전 구성과 동일한 구조를 가집니다. 충돌을 방지하려면 배포 및 서비스 이름에 사용되는 이름을 변경합니다. 또한 브라우저에 로드될 메시지을 업데이트합니다.

파일을 저장하고 닫습니다.

이제 다음 명령을 사용하여 Kubernetes에서 생성합니다.

  1. kubectl create -f hello-kubernetes-second.yaml

출력은 다음과 같습니다.

Output
service/hello-kubernetes-second created deployment.apps/hello-kubernetes-second created

모든 서비스를 나열하여 두 번째 서비스가 실행 중인지 확인합니다.

  1. kubectl get service

출력은 다음과 유사합니다.

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hello-kubernetes-first ClusterIP 10.245.124.46 <none> 80/TCP 49s hello-kubernetes-second ClusterIP 10.245.254.124 <none> 80/TCP 10s kubernetes ClusterIP 10.245.0.1 <none> 443/TCP 65m

hello-kubernetes-firsthello-kubernetes-second가 모두 나열되며 이는 Kubernetes가 성공적으로 생성했음을 의미합니다.

함께 제공되는 서비스와 함께 hello-kubernetes 앱의 두 가지 배포를 만들었습니다. 각각은 배포 사양에 다른 메시지 세트가 있어 테스트 중에 구분됩니다. 다음 단계에서는 Nginx 수신 컨트롤러 자체를 설치합니다.

2단계 - Kubernetes Nginx 인그레스 컨트롤러 설치

이제 Helm을 사용하여 Kubernetes에서 유지 관리하는 Nginx 수신 컨트롤러를 설치합니다.

Nginx 수신 컨트롤러는 포드와 서비스로 구성됩니다. 포드는 사용 가능한 인그레스 리소스에 대한 업데이트를 위해 클러스터의 API 서버에서 /ingresses 엔드포인트를 지속적으로 폴링하는 컨트롤러를 실행합니다. 서비스는 LoadBalancer 유형입니다. DigitalOcean Kubernetes 클러스터에 배포하기 때문에 클러스터는 모든 외부 트래픽이 컨트롤러로 흐르는 DigitalOcean 로드 밸런서를 자동으로 생성합니다. 그런 다음 컨트롤러는 인그레스 리소스에 정의된 대로 트래픽을 적절한 서비스로 라우팅합니다.

LoadBalancer 서비스만이 자동으로 생성된 Load Balancer의 IP 주소를 알고 있습니다. 일부 앱(예: ExternalDNS)은 IP 주소를 알아야 하지만 Ingress 구성을 읽을 수만 있습니다. 컨트롤러는 helm 설치 중에 controller.publishService.enabled 매개변수를 true로 설정하여 각 Ingress에서 IP 주소를 게시하도록 구성할 수 있습니다. 로드 밸런서의 IP 주소에 의존할 수 있는 애플리케이션을 지원하려면 이 설정을 활성화하는 것이 좋습니다.

클러스터에 Nginx 인그레스 컨트롤러를 설치하려면 먼저 다음을 실행하여 해당 리포지토리를 Helm에 추가해야 합니다.

  1. helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

출력은 다음과 같습니다.

Output
"ingress-nginx" has been added to your repositories

포함된 내용을 Helm에 알리도록 시스템을 업데이트합니다.

  1. helm repo update

로드하는 데 시간이 걸릴 수 있습니다.

Output
Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "ingress-nginx" chart repository Update Complete. ⎈Happy Helming!⎈

마지막으로 다음 명령을 실행하여 Nginx 인그레스를 설치합니다.

  1. helm install nginx-ingress ingress-nginx/ingress-nginx --set controller.publishService.enabled=true

이 명령은 stable 차트 리포지토리에서 Nginx 수신 컨트롤러를 설치하고 Helm 릴리스 이름을 nginx-ingress로 지정하고 publishService 매개변수를 참.

실행되면 다음과 유사한 출력이 표시됩니다(이 출력은 잘렸습니다).

Output
NAME: nginx-ingress LAST DEPLOYED: Thu Dec 1 11:40:28 2022 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: ...

Helm은 차트 설치의 일부로 Kubernetes에서 생성한 리소스를 기록했습니다.

이 명령을 실행하여 로드 밸런서를 사용할 수 있는지 확인합니다.

  1. kubectl --namespace default get services -o wide -w nginx-ingress-ingress-nginx-controller

이 명령은 default 네임스페이스에서 Nginx Ingress 서비스를 가져와 해당 정보를 출력하지만 명령이 즉시 종료되지는 않습니다. -w 인수를 사용하면 변경 사항이 발생할 때 출력을 감시하고 새로 고칩니다.

Load Balancer를 사용할 수 있을 때까지 기다리는 동안 pending 응답을 받을 수 있습니다.

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR nginx-ingress-ingress-nginx-controller LoadBalancer 10.245.3.122 <pending> 80:30953/TCP,443:30869/TCP 36s ...

일정 시간이 지나면 새로 만든 로드 밸런서의 IP 주소가 나타납니다.

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR nginx-ingress-ingress-nginx-controller LoadBalancer 10.245.3.122 167.99.16.184 80:30953/TCP,443:30869/TCP 2m29s ...

다음으로 두 도메인이 A 레코드를 통해 로드 밸런서를 가리키는지 확인해야 합니다. 이는 DNS 공급자를 통해 수행됩니다. DigitalOcean에서 DNS 레코드를 구성하려면 DNS 레코드 관리 방법을 참조하십시오.

Kubernetes 커뮤니티에서 유지 관리하는 Nginx Ingress를 설치했습니다. 로드 밸런서에서 인그레스 리소스에 구성된 적절한 백엔드 서비스로 HTTP 및 HTTPS 트래픽을 라우팅합니다. 다음 단계에서는 Ingress 리소스를 사용하여 hello-kubernetes 앱 배포를 노출합니다.

3단계 - Ingress를 사용하여 앱 노출

이제 Ingress 리소스를 생성하고 이를 사용하여 원하는 도메인에서 hello-kubernetes 앱 배포를 노출합니다. 그런 다음 브라우저에서 액세스하여 테스트합니다.

인그레스를 hello-kubernetes-ingress.yaml이라는 파일에 저장합니다. 편집기를 사용하여 생성합니다.

  1. nano hello-kubernetes-ingress.yaml

파일에 다음 줄을 추가합니다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-kubernetes-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: "hw1.your_domain_name"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: hello-kubernetes-first
            port:
              number: 80
  - host: "hw2.your_domain_name"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: hello-kubernetes-second
            port:
              number: 80

hello-kubernetes-ingress라는 이름으로 인그레스 리소스를 정의합니다. 그런 다음 hw1.your_domainhello-kubernetes-first 서비스로 라우팅되도록 두 개의 호스트 규칙을 지정하고 hw2.your_domain은 두 번째 배포(hello-kubernetes-second)에서 서비스로 라우팅됩니다.

강조 표시된 도메인을 자신의 도메인으로 바꾼 다음 파일을 저장하고 닫으십시오.

다음 명령을 실행하여 Kubernetes에서 생성합니다.

  1. kubectl apply -f hello-kubernetes-ingress.yaml

이제 브라우저에서 hw1.your_domain으로 이동할 수 있습니다. 첫 번째 배포가 로드됩니다.

두 번째 변형(hw2.your_domain)은 다른 메시지를 표시합니다.

인그레스 컨트롤러가 요청을 올바르게 라우팅하는지 확인했습니다. 이 경우 두 도메인에서 서로 다른 두 서비스로 라우팅됩니다.

도메인에서 hello-kubernetes 앱 배포를 제공하기 위해 Ingress 리소스를 만들고 구성했습니다. 다음 단계에서는 Let’s Encrypt의 무료 TLS 인증서로 Ingress 리소스를 보호하도록 Cert-Manager를 설정합니다.

4단계 - Cert-Manager를 사용하여 인그레스 보안

Ingress 리소스를 보호하려면 Cert-Manager를 설치하고 프로덕션용 ClusterIssuer를 만들고 TLS 인증서를 사용하도록 Ingress 구성을 수정합니다. 설치 및 구성이 완료되면 앱이 HTTPS 뒤에서 실행됩니다.

ClusterIssuers는 전체 클러스터에 대한 TLS 인증서를 프로비저닝하는 Kubernetes의 Cert-Manager 리소스입니다. ClusterIssuer는 특정 유형의 Issuer입니다.

Helm을 통해 클러스터에 Cert-Manager를 설치하기 전에 이를 위한 네임스페이스를 생성합니다.

  1. kubectl create namespace cert-manager

Cert-Manager 차트를 호스팅하는 Helm에 Jetstack Helm 리포지토리를 추가해야 합니다. 이렇게 하려면 다음 명령을 실행합니다.

  1. helm repo add jetstack https://charts.jetstack.io

Helm은 다음 출력을 반환합니다.

Output
"jetstack" has been added to your repositories

그런 다음 Helm의 차트 캐시를 업데이트합니다.

  1. helm repo update

업데이트에 시간이 걸릴 수 있습니다.

Output
Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "ingress-nginx" chart repository ...Successfully got an update from the "jetstack" chart repository Update Complete. ⎈Happy Helming!⎈

마지막으로 다음 명령을 실행하여 Cert-Manager를 cert-manager 네임스페이스에 설치합니다.

  1. helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.10.1 --set installCRDs=true

이 명령에서 Helm 설치 중에 cert-manager CustomResourceDefinition 매니페스트를 설치하기 위해 installCRDs 매개변수를 true로 설정합니다. 작성 당시에는 v1.10.1이 최신 버전이었습니다. ArtifactHub를 참조하여 최신 버전 번호를 찾을 수 있습니다.

다음 출력을 받게 됩니다.

Output
NAME: cert-manager LAST DEPLOYED: Wed Nov 30 19:46:39 2022 NAMESPACE: cert-manager STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: cert-manager v1.10.1 has been deployed successfully! ...

출력은 설치가 성공했음을 나타냅니다.

출력의 NOTES(위 디스플레이에서 잘림)는 TLS 인증서를 발급하기 위해 발급자를 설정해야 함을 나타냅니다.

이제 Let’s Encrypt 인증서를 발급하는 인증서를 만들고 구성을 production_issuer.yaml이라는 파일에 저장합니다. 다음 파일을 만들고 엽니다.

  1. nano production_issuer.yaml

다음 줄을 추가합니다.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # Email address used for ACME registration
    email: your_email_address
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      # Name of a secret used to store the ACME account private key
      name: letsencrypt-prod-private-key
    # Add a single challenge solver, HTTP01 using nginx
    solvers:
    - http01:
        ingress:
          class: nginx

이 구성은 인증서를 발급하기 위해 Let’s Encrypt에 접속하는 ClusterIssuer를 정의합니다. 인증서의 보안 및 만료에 관한 알림을 받으려면 your_email_address를 이메일 주소로 바꿔야 합니다.

파일을 저장하고 닫습니다.

kubectl로 롤아웃합니다.

  1. kubectl apply -f production_issuer.yaml

다음 출력을 받게 됩니다.

Output
clusterissuer.cert-manager.io/letsencrypt-prod created

Cert-Manager가 설치되면 이전 단계에서 정의한 인그레스 리소스에 인증서를 도입할 준비가 된 것입니다. 편집을 위해 hello-kubernetes-ingress.yaml을 엽니다.

  1. nano hello-kubernetes-ingress.yaml

강조 표시된 줄을 추가합니다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-kubernetes-ingress
annotations:
  kubernetes.io/ingress.class: nginx
  cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - hw1.your_domain
    - hw2.your_domain
    secretName: hello-kubernetes-tls
  rules:
  - host: "hw1.your_domain_name"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: hello-kubernetes-first
            port:
              number: 80
  - host: "hw2.your_domain_name"
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: hello-kubernetes-second
            port:
              number: 80

spec 아래의 tls 블록은 letsencrypt-prod ClusterIssuer 문제. secretName은 생성하는 Ingress마다 달라야 합니다.

hw1.your_domainhw2.your_domain을 자신의 도메인으로 교체해야 합니다. 편집이 끝나면 파일을 저장하고 닫습니다.

다음 명령을 실행하여 이 구성을 클러스터에 다시 적용합니다.

  1. kubectl apply -f hello-kubernetes-ingress.yaml

다음 출력을 받게 됩니다.

Output
ingress.networking.k8s.io/hello-kubernetes-ingress configured

Let’s Encrypt 서버가 도메인에 대한 인증서를 발급할 때까지 몇 분 정도 기다려야 합니다. 그동안 다음 명령의 출력을 검사하여 진행 상황을 추적할 수 있습니다.

  1. kubectl describe certificate hello-kubernetes-tls

출력의 끝은 다음과 유사합니다.

Output
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Issuing 2m34s cert-manager-certificates-trigger Issuing certificate as Secret does not exist Normal Generated 2m34s cert-manager-certificates-key-manager Stored new private key in temporary Secret resource "hello-kubernetes-tls-hxtql" Normal Requested 2m34s cert-manager-certificates-request-manager Created new CertificateRequest resource "hello-kubernetes-tls-jnnwx" Normal Issuing 2m7s cert-manager-certificates-issuing The certificate has been successfully issued

출력의 마지막 줄에 인증서가 성공적으로 발급되었습니다라고 표시되면 CTRL + C를 눌러 종료할 수 있습니다.

브라우저에서 도메인 중 하나로 이동합니다. 이제 연결이 안전하다는 것을 나타내는 자물쇠가 URL 옆에 나타납니다.

이 단계에서는 Helm을 사용하여 Cert-Manager를 설치하고 Let’s Encrypt ClusterIssuer를 생성했습니다. 그런 다음 TLS 인증서 생성을 위해 Issuer를 활용하도록 Ingress 리소스를 업데이트했습니다. 결국 브라우저에서 도메인 중 하나로 이동하여 HTTPS가 올바르게 작동함을 확인했습니다.

결론

이제 Helm을 사용하여 DigitalOcean Kubernetes 클러스터에서 Nginx Ingress Controller 및 Cert-Manager를 성공적으로 설정했습니다. 이제 Let’s Encrypt TLS 인증서를 사용하여 보호된 도메인의 인터넷에 앱을 노출할 수 있습니다.

Helm 패키지 관리자에 대한 자세한 내용은 이 Helm 소개를 참조하세요.