ncloud NKS에서 Nginx Ingress Controller 설치부터 HTTPS 적용하기

2025. 1. 3. 03:36·Kubernetes

이번 포스팅에서는 NKS에서 nginx ingress controller를 설치해서 등록된 도메인을 연결하고, cert-manager와 letsencrypt로 HTTPS를 적용하는 과정을 다룹니다.

 

실행 환경은 `kubectl config`를 통해 생성한 NKS 클러스터에 명령어를 입력가능한 상태입니다.

kubectl config는 이전 포스팅의 마지막 kubectl config 설정 부분을 참고하시면 됩니다.

(2025.01.01 - [Kubernetes] - ncloud NKS로 쿠버네티스 클러스터 구성하기)

 

0. Ingress?

https://kubernetes.io/ko/docs/concepts/services-networking/ingress/

Ingress는 쿠버네티스 클러스터에서 서비스 리소스와 완전히 독립적인 리소스입니다.

Ingress는 프라이빗 클러스터 내부의 서비스를 외부에 노출시키지 않고 라우팅을 할 수 있으며 SSL/TLS 처리와 로드밸런싱 등을 제공합니다.

 

Ingress를 사용하기 위해선 Ingress Controller가 있어야 리소스를 사용할 수 있습니다. 이를 위해 ncloud에서 제공하는 alb-ingress-controller를 이용할 수 있지만 좀 더 섬세한 제어를 위해 Nginx Ingress Controller를 이용하겠습니다.

Nginx Ingress Controller는 L7 로드밸런싱을 쉽게 할 수 있습니다.

1. Nginx Ingress Controller 설치

ncloud 공식 문서에 Ingress 활용 예제에 설치 가이드가 쉽게 설명되어 있습니다.

이 부분을 참고해서 설치하겠습니다.

 

먼저 공식 GitHub에서 지원하는 버전을 확인합니다.

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

 

GitHub - kubernetes/ingress-nginx: Ingress NGINX Controller for Kubernetes

Ingress NGINX Controller for Kubernetes. Contribute to kubernetes/ingress-nginx development by creating an account on GitHub.

github.com

NKS에서 생성한 쿠버네티스 클러스터 버전은 1.29 버전이므로 ingress-nginx 버전은 1.11.3으로 설치하겠습니다.

 

1. 아래 명령어로 ingress-nginx를 설치합니다.

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.3/deploy/static/provider/cloud/deploy.yaml

ingress-nginx는 기본적으로 ingress-nginx 네임스페이스에 설치됩니다.

설치되면 NKS 설정 시 등록했던 퍼블릭 로드밸랜서 전용 서브넷에 ingress-nginx-controller 인스턴스가 생성됩니다.

 

2. 아래 명령어로 파드와 서비스를 확인합니다.

# 파드 확인
kubectl get pods -n ingress-nginx

# 실행 결과
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-8w86q        0/1     Completed   0          33h
ingress-nginx-admission-patch-9xsxb         0/1     Completed   1          33h
ingress-nginx-controller-7bf4d86ccc-4mgwj   1/1     Running     0          26h

# 서비스 접속 정보 확인
kubectl get svc -n ingress-nginx

# 실행 결과
NAME                                 TYPE           CLUSTER-IP       EXTERNAL-IP                                                                PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   198.19.220.90    ingress-ngi-ingress-ngin-bb6c1-101440325-.kr.lb.naverncp.com   80:31580/TCP,443:31172/TCP   33h
ingress-nginx-controller-admission   ClusterIP      198.19.190.226   <none>                                                                     443/TCP                      33h

 

3. Ingress를 설정합니다.

위에서 확인한 ingress-nginx의 EXTERNAL-IP가 외부 주소에 해당하며, `ingress-ngi-ingress-ngin-bb6c1-101440325-.kr.lb.naverncp.com`으로 되어 있습니다.

 

ncloud 콘솔의 Load Balancer 메뉴에서도 확인할 수 있는데요, 로드밸런서가 위치한 서브넷은 이전에 생성해 둔 퍼블릭 로드밸랜서 전용 서브넷에 위치한 것을 확인할 수 있습니다.

 

Ingress 설정에서 URI 기반으로 라우팅을 하는 예시를 보여드리겠습니다.

 

지금 당장은 TLS를 적용하지 않았기 때문에 `nginx.ingress.kubernetes.io/ssl-redirect: 'false'`로 설정해 강제 리다이렉션을 방지합니다.

ingress-nginx 서비스에서 확인한 EXTERNAL IP인 `ingress-ngi-ingress-ngin-bb6c1-101440325-.kr.lb.naverncp.com`를 통해 들어온 요청을 path별로 라우팅을 합니다.

 

아래 메니페스트를 보겠습니다.

`/api/v1`으로 시작하는 경로는 backend-svc 서비스로 라우팅 합니다. 그 외 `/`으로 시작하는 경로는 frontend-svc 서비스로 라우팅 합니다. `/` 보다 먼저 처리돼야 하므로 백엔드 서비스가 가장 최상단에 있습니다.

# my-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-nginx
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: 'false'
spec:
  ingressClassName: nginx
  rules:
    - http:
        paths:
          - path: /api/v1
            pathType: Prefix
            backend:
              service:
                name: backend-svc
                port:
                  number: 8080
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-svc
                port:
                  number: 80

 

4. Ingress를 생성합니다.

kubectl apply -f ./my-ingress.yaml

 

이후 생성된 ingress를 확인합니다.

kubectl get ingress

# 실행 결과
NAME            CLASS   HOSTS   ADDRESS                                                         PORTS  
ingress-nginx   nginx   *       ingress-ngi-ingress-ngin-bb6c1-101440325-.kr.lb.naverncp.com    80, 443

 

curl 또는 Postman으로 API 호출이 정상적으로 되는지 확인할 수 있습니다.

curl ingress-ngi-ingress-ngin-bb6c1-101440325.kr.lb.naverncp.com/api/v1/users

2. 도메인 연결하기

구매한 도메인은 ncloud의 Global DNS+에 등록이 먼저 되어있어야 합니다.

레코드 추가를 눌러 A 레코드를 등록합니다.

LB VPC를 선택하고, 위에서 생성한 ingress 로드 밸런서를 선택하고 추가를 눌러 등록합니다.

몇 분 시간이 지나면 배포가 되니 기다립시다.

3. cert-manager, letsencrypt로 TLS 설정하기 (HTTPS)

cert-manager와 letsencrypt를 이용해 TLS를 설정하고, ingress-nginx 설정으로 HTTPS를 적용합니다.

cert-manager 공식 문서에서 튜토리얼을 기반으로 정리했습니다.

 

Ingress를 통해 cert-manager가 인증을 하는 방식은 아래 이미지와 같습니다.

https://cert-manager.io/docs/usage/ingress/

cert-manager는 Ingress에 annotation을 다는 것만으로도 TLS 인증을 처리할 수 있도록 합니다.

3-1. cert-manager 설치

아래 명령어로 cert-manager를 설치합니다.

kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.16.2/cert-manager.yaml

cert-manager는 `cert-manager` 네임스페이스에 설치됩니다.

 

설치 후 네임스페이스를 확인합니다.

3개의 파드가 모두 `Running`상태가 될 때 까지 잠시 기다립시다. `cert-manager-webhook` 파드가 올라오기까지 시간이 조금 걸립니다.

kubectl get pods --namespace cert-manager

# 실행 결과
NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-5c6866597-zw7kh               1/1     Running   0          2m
cert-manager-cainjector-577f6d9fd7-tr77l   1/1     Running   0          2m
cert-manager-webhook-787858fcdb-nlzsq      1/1     Running   0          2m

 

3-2. ClusterIssuer 생성

Issuer는 ACME(Automatic Certificate Management Environment)이며, 오픈 소스를 지원합니다.

인증 방식은 `http01`로 수행하며, `dns01`을 이용할 수도 있습니다.

  • `http01` 방식은 ACME 서버가 도메인 소유권을 확인하기 위해 HTTP 요청으로 키 값을 검증하는 방식입니다. 퍼블릭 도메인인 경우에만 사용할 수 있습니다.
  • `dns01` 방식은 ACME 서버가 DNS 조회 시 TXT 레코드를 참조해 인증서에 대한 도메인을 소유하고 있는지 확인하는 방식입니다. DNS TXT 레코드에 특정 키 값을 수동으로 설정해야 합니다.

더 자세한 내용은 이 링크를 참고해주세요.

 

1. ClusterIssuer 매니페스트를 작성합니다. `email` 부분만 사용할 이메일로 바꿔서 작성하면 됩니다.

저는 `dns01` 방식은 DNS TXT 레코드를 수동으로 설정해야 하는 불편함이 있어 `http01` 방식을 사용했습니다.

# cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: 이메일을 입력하세요
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod
    # Enable the HTTP-01 challenge provider
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx

 

2. 아래 명령어로 ClusterIssuer를 생성합니다.

kubectl apply -f ./cluster-issuer.yaml

3-3. ingress-nginx 수정

위에서 작성했던 ingress-nginx 메니페스트를 수정합니다. (my-ingress.yaml)

  • `nginx.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80},{"HTTPS":443}]'`를 추가해 80, 443 포트를 리스닝합니다.
  • `nginx.ingress.kubernetes.io/ssl-redirect: 'false'`부분을 `nginx.ingress.kubernetes.io/ssl-redirect: 'true'`로 변경하거나 제거합니다. (해당 애너테이션 기본값은 `true`입니다.)
  • 애너테이션에 `cert-manager.io/cluster-issuer: letsencrypt-prod`를 추가합니다.
    입력하는 이름은 위에서 생성한
    ClusterIssuer 이름입니다.

매니페스트

# my-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-nginx
  annotations:
    nginx.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80},{"HTTPS":443}]'
    nginx.ingress.kubernetes.io/ssl-redirect: 'true'
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
    - hosts:
        - dev2.mydomain.com
      secretName: mydomain-cert
  ingressClassName: nginx
  rules:
    - host: dev2.mydomain.com
      http:
        paths:
          - path: /api/v1
            pathType: Prefix
            backend:
              service:
                name: backend-svc
                port:
                  number: 8080
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-svc
                port:
                  number: 80

 

매니페스트 변경 사항 적용

변경 사항을 적용합니다.

kubectl apply -f ./my-ingress.yaml

 

만약 변경이 잘 적용되지 않는다면 ingress-nginx-controller를 재시작합니다.

kubectl rollout restart deployment ingress-nginx-controller -n ingress-nginx

 

클러스터에서 Certificate 및 Secret 리소스 확인

아래 명령어로 cert-manager가 생성한 certificate 리소스를 확인할 수 있습니다.

kubectl get certificate -o wide

# 실행 결과
NAME        READY   SECRET      ISSUER             STATUS                                          AGE
dev2-cert   True    dev2-cert   letsencrypt-prod   Certificate is up to date and has not expired   1h

 

아래 명령어로 위의 인증서를 Secret으로 등록된 것을 확인할 수 있습니다.

kubectl get secret
NAME             TYPE                DATA   AGE
dev2-cert        kubernetes.io/tls   2      27h

 

이제 TLS 적용이 완료되어 인증서가 유효함을 확인할 수 있습니다.

추가. CORS 설정

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-nginx
  annotations:
    nginx.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80},{"HTTPS":443}]'
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://dev2.mydomain.com"
    nginx.ingress.kubernetes.io/cors-allow-methods: "HEAD, GET, POST, PUT, PATCH, DELETE, OPTIONS"
    nginx.ingress.kubernetes.io/cors-allow-headers: "Authorization, Content-Type, X-Refresh-Token, Cache-Control"
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
# 이하 생략

만약 CORS 설정이 필요하면 Ingress에서 처리할 수 있습니다. 그 외에도 annotation을 활용해 기존 Nginx에서 사용했던 설정들을 대체할 수 있으니 이 링크를 확인하시면 됩니다.

 

참고

  • https://kubernetes.io/ko/docs/concepts/services-networking/ingress/
  • https://matthewpalmer.net/kubernetes-app-developer/articles/kubernetes-ingress-guide-nginx-example.html

 

도움이 되셨길 바라며, 읽어주셔서 감사합니다.

'Kubernetes' 카테고리의 다른 글

쿠버네티스에서 MySQL dump 하기 (uuid 필드를 사용할 때)  (0) 2025.02.28
쿠버네티스에서 트래픽 유실 없는 무중단 배포 적용하기  (2) 2025.01.06
ncloud NKS로 쿠버네티스 클러스터 구성하기  (0) 2025.01.01
[k8s] 쿠버네티스 핵심 개념  (0) 2024.09.11
[k8s] 쿠버네티스 시작하기  (0) 2024.09.11
'Kubernetes' 카테고리의 다른 글
  • 쿠버네티스에서 MySQL dump 하기 (uuid 필드를 사용할 때)
  • 쿠버네티스에서 트래픽 유실 없는 무중단 배포 적용하기
  • ncloud NKS로 쿠버네티스 클러스터 구성하기
  • [k8s] 쿠버네티스 핵심 개념
옐리yelly
옐리yelly
  • 옐리yelly
    개발 갤러리
    옐리yelly
  • 전체
    오늘
    어제
    • 모든 글 보기 (86)
      • Project (22)
      • Java (5)
      • Spring (8)
      • Kubernetes (6)
      • Docker (2)
      • JPA (3)
      • Querydsl (2)
      • MySQL (9)
      • ElasticSearch (7)
      • DevOps (4)
      • Message Broker (3)
      • Git & GitHub (2)
      • Svelte (1)
      • Python (8)
        • Python Distilled (4)
        • Anaconda (1)
        • Django (0)
        • pandas (3)
      • Algorithm (1)
      • Computer Science (0)
      • 내 생각 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    querydsl
    커넥션 풀
    포텐데이
    pandas
    gitops
    devops
    Python
    MySQL
    elasticsearch
    ncloud
    비사이드
    Message Broker
    svelte
    프로젝트
    nks
    성능 테스트
    OOP
    k8s
    mybatis
    Spring
    RabbitMQ
    예약 시스템
    docker
    Project
    pymysql
    JPA
    데드락
    리팩토링
    argocd
    blue-green 배포
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
옐리yelly
ncloud NKS에서 Nginx Ingress Controller 설치부터 HTTPS 적용하기
상단으로

티스토리툴바