이번 포스팅에서는 NKS에서 nginx ingress controller를 설치해서 등록된 도메인을 연결하고, cert-manager와 letsencrypt로 HTTPS를 적용하는 과정을 다룹니다.
실행 환경은 `kubectl config`를 통해 생성한 NKS 클러스터에 명령어를 입력가능한 상태입니다.
kubectl config는 이전 포스팅의 마지막 kubectl config 설정 부분을 참고하시면 됩니다.
(2025.01.01 - [Kubernetes] - ncloud NKS로 쿠버네티스 클러스터 구성하기)
0. 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
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가 인증을 하는 방식은 아래 이미지와 같습니다.
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' 카테고리의 다른 글
쿠버네티스에서 트래픽 유실 없는 무중단 배포 적용하기 (0) | 2025.01.06 |
---|---|
ncloud NKS로 쿠버네티스 클러스터 구성하기 (0) | 2025.01.01 |
[k8s] 쿠버네티스 핵심 개념 (0) | 2024.09.11 |
[k8s] 쿠버네티스 시작하기 (0) | 2024.09.11 |