k8s 이용해서 웹 서버 구축하기 - 1부. install k3s with Calico
k8s 이용해서 웹 서버 구축하기 - 2부. setup nginx-ingress, ipvs, metalb
k8s 이용해서 웹 서버 구축하기 - 3부. deploy nextjs (with. bun.js)
👉 k8s 이용해서 웹 서버 구축하기 - 4부. nginx ingress 에 https 적용 (cert-manager 이용)
k8s 이용해서 웹 서버 구축하기 - 5부. MariaDB 배포 및 연동
k8s 이용하서 웹 서버 구축하기 - 5-1부. (번외편) PostgreSQL 배포 및 연동
k8s 이용해서 웹 서버 구축하기 - 6부. MiniO 구축하기
개요
실제 운영되는 서비스에는 HTTP 프로토콜을 그대로 사용하는 경우는 드물다. 보안에 취약하기 때문이다. TLS(SSL) 인증서를 발급받고 이를 이용하여 HTTPS 프로토콜을 주로 사용한다.
이를 위해서는 Ingress 에 TLS 설정을 추가해 주어야 한다.
많이 사용하는 것 중에는 LetsEncrypt 가 있다. 여기서 인증서를 발급받고 적용할 수 있다. 단, 3개월 마다 갱신인증을 해 주어야 한다.
그래서 cert-manager 를 사용하여 자동갱신을 하도록 하자.
Cert-Manager 설치
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml
만약,
no kind "ClusterIssuer" is registered for version "
cert-manager.io/v1
" in scheme
이라는 오류가 보인다면, helm 을 이용하여 CRDs 를 함께 설치하면 된다.helm repo add jetstack https://charts.jetstack.io && \ helm repo update && \ helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.9.1 \ --set installCRDs=true # 아래는 GKE, EKS 등에서 Custom CNI 를 사용한다면 적용! # https://cert-manager.io/docs/installation/compatibility/ #--set webhook.hostNetwork=true \ #--set webhook.securePort=10260
cluster-issuer 생성
Issuer 와 ClusterIssuer 가 존재한다. 이 둘의 차이는 네임스페이스 범위인가, 클러스터 범위인가에 있다. 꼭! 참고하도록 한다. 발급에는 staging, prod 두 가지가 있으니 이 또한 주의하도록 한다.
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: # The ACME server URL server: https://acme-staging-v02.api.letsencrypt.org/directory # Email address used for ACME registration email: test@test.com # Name of a secret used to store the ACME account private key privateKeySecretRef: name: letsencrypt-staging # Enable the HTTP-01 challenge provider solvers: # An empty 'selector' means that this solver matches all domains - selector: {} http01: ingress: class: nginx --- 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: test@test.com # 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: class: nginx
- 2 : Issuer 는 네임스페이스 범위이므로 ClusterIssuer 를 사용한다.
- 4,13,26,35 : staging 과 prod 가 나뉜다.
- 15-20, 37-40 : 만약 cloudfalre 를 이용한다면 아래와 같이 변경할 수 있다.
# ... solvers: - dns01: cloudflare: email: <your-email> apiTokenSecretRef: name: cloudflare-api-token-secret key: <token>
최종적으로 작성한 Issuer/ClusterIssuer 를 실행하면된다.
kubectl create -f cluster-issuer.yaml
확인은 아래 명령어로 할 수 있다.
kubectl get clusterissuer
생성 후에 timeout 등으로 dns 오류가 난다면, coredns 헬스체크를 해보자.
COREDNSPOD1=$(kubectl get pod -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[0].status.podIP}') echo $COREDNSPOD1 && \ curl $COREDNSPOD1:8080/health; echo && \ curl $COREDNSPOD1:8181/ready; echo
POD 을 생성한 후, nslookup 으로 테스트 해 볼 수 도 있다.
# 파드 생성 kubectl run -it --rm netdebug --image=nicolaka/netshoot --restart=Never -- zsh ------------- # 파드에서 네임서버 확인 cat /etc/resolv.conf nameserver 10.96.0.10 search default.svc.cluster.local svc.cluster.local cluster.local options ndots:5 # 도메인 쿼리 기본 방식 : ndots:5 설정으로 최종 호출 전에 설정되어 있는 검색 도메인(search)을 추가하여 먼저 쿼리 호출 nslookup -type=A -debug google.com # | grep QUESTIONS -A1
그래도 안된다면, 방화벽을 확인하자!
테스트할 때는 잠시 꺼두어도 좋다.
Ingress 에 인증서 적용
공식 문서를 보면, 버전마다 조금씩 다르고 사용방법도 조금씩 다르다. 대표적인 방법 두 가지로 나누어 작성하겠다. (참고로 두 번째 방법이 조금 더 간단하다.)
1. Certificate 작성 → 실행 → 적용
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: <certificate-name> namespace: <ACC-deployment-namespace> spec: secretName: <certificate-secret-name> duration: 2160h # 90d renewBefore: 360h # 15d commonName: 'test.domain.com' dnsNames: # 사용하고 발급할 도메인 입력 - 'test.domain.com' - 'test2.domain.com' issuerRef: kind: ClusterIssuer name: letsencrypt-staging # issuer 이름이므로 변경해야 한다.
Wildcard Domain SSL (*.domain.com) 인증서를 발급받을 수 도 있다.
[열기] Wildcard Domain 발급하기!
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: <certificate-name> namespace: <ACC-deployment-namespace> spec: secretName: <certificate-secret-name> duration: 2160h # 90d renewBefore: 360h # 15d # 사용하고 발급할 도메인 입력 #commonName: domain.com dnsNames: - domain.com - '*.domain.com' issuerRef: kind: ClusterIssuer name: letsencrypt-staging # issuer 이름이므로 변경해야 한다.
주의!
최근 업데이트로 와일드카드에 대한 오류가 있는 듯 하다.
https://stackoverflow.com/questions/68219076/cert-manager-no-configured-challenge-solvers-can-be-used-for-this-challenge작성한 파일을 실행하는 순간, let’s encrypt 로 인증서 생성을 요청한다.
kubectl create -f certificate.yaml
아래 명령어로 인증서 상태를 확인할 수 있다.
kubectl get certificate
만약, READY 상태가 False 라고 나온다면, 도메인 소유 검증을 실패한 것일 수 도 있다. (주의!)
이제 Ingress 에서 hosts 부분과, secretName 부분을 수정하면 된다.
# ... spec: tls: - hosts: - test.domain.com secretName: <certificate-name> # 인증서 이름을 입력하면된다. # ...
2. Ingress 에 바로 적용
이 때는 annotations 부분과 tls 부분을 함께 수정해야 한다.
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-ingress annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" # kubernetes.io/ingress.class: nginx # 아래 ingressClassName 으로 대체 kubernetes.io/tls-acme: "true" cert-manager.io/cluster-issuer: letsencrypt-prod # ClusterIssuer 이름 nginx.ingress.kubernetes.io/backend-protocol: HTTPS spec: ingressClassName: nginx tls: - hosts: - test.domain.com # 인증서를 적용할 도메인으로 변경 secretName: <certificate-name> # 인증서 key가 저장되는 secret rules: - host: test.domain.com # 인증서를 적용할 도메인으로 변경 http: paths: - path: / backend: serviceName: web servicePort: 443 status: loadBalancer: ingress: - {}
참고로, kubernetes/nginx-ingress 와 nginx/nginx-ingress 는 다른 것이다.
HTTPS 를 적용하고 싶다면, kubernetes/nginx-ingress 를 설치해서 사용하도록 하자.