이는 PKOS2 스터디를 진행하면서 공부했던 내용인데 이제서야 블로깅해 본다!

External DNS에 대해 알게 되었고 도메인을 하나 구매하여 스터디하였다.

Harbor 설치 과정에서 영감을 받아 Kubernetes Dashboard를 설치하려고 한다!

External DNS 란

Untitled

External DNS는 service/ingress  생성 시 도메인을 설정하면, DNS Provider에 A 레코드(TXT 레코드)로 자동 생성/삭제한다.

KubeDNS와 비슷한 기능을 하지만 KubeDNS처럼 클러스터 내부 DNS 서버는 아니고 DNS Provider에 구성할 뿐이라 특정 DNS Provider에 종속되지 않아도 된다.

DNS Provider로는 AWS Route53, Google Cloud DNS, AzureDNS 등이 있다.

Kubernetes Dashboard를 External DNS로 노출!

나는 업무환경이 폐쇄망에다가 인프라영역이나 클러스터영역은 권한이 없어서 각종 테스트가 어렵다.

다행히 구글 검색은 허용이 된다. 다시 말해서 오픈되어 있는 프로토콜 및 포트는 https(443)과 http(80) 뿐이다!

내 개인 테스트 영역으로 사용하려면 aws에서 ssh 대신 ssm을 사용해야 하고, 대시보드를 사용하려면 로컬호스트도 노드포트도 안되고 80 또는 443으로 접속할 수 있게 만들어야 한다 ㅠ!

대시보드는 https로 동작한다. http로 동작하게 설정을 바꿔줄 수 있지만 나는 그대로 사용할 것이다

설정 조건은 아래와 같다

  • Ingress Controller는 alb 사용
  • External DNS로 Route53에 퍼블릭도메인 등록
  • ACM에서 발급받은 퍼블릭인증서를 붙여서 무조건 https로 동작
  • http → https 리다이렉션 설정

이 모든 조건을 부합하는건 어느 블로그에서도 찾지 못했다 (구글링 잘못했나(?))

Untitled 1

일단 kubernetes dashboard 워크로드를 생성한다.

# kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
	namespace/kubernetes-dashboard created
	serviceaccount/kubernetes-dashboard created
	service/kubernetes-dashboard created
	secret/kubernetes-dashboard-certs created
	secret/kubernetes-dashboard-csrf created
	secret/kubernetes-dashboard-key-holder created
	configmap/kubernetes-dashboard-settings created
	role.rbac.authorization.k8s.io/kubernetes-dashboard created
	clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
	rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
	clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
	deployment.apps/kubernetes-dashboard created
	service/dashboard-metrics-scraper created
	deployment.apps/dashboard-metrics-scraper created

kubernetes-dashboarddashboard-metrics-scraper가 설치되는데 kubernetes-dashboard는 쿠버네티스 클러스터를 대시보드 형태로 제공해 주는 웹 기반 UI 이고, dashboard-metrics-scrapermetric-server가 수집한 메트릭을 스크래핑하고 저장하고 대시보드에 뿌려주기 위해 사용한다.

아래는 생성된 대시보드 리소스다.

# kubectl get ing,all -n kubernetes-dashboard
	NAME                                            READY   STATUS    RESTARTS   AGE
	pod/dashboard-metrics-scraper-8c47d4b5d-ttkxj   1/1     Running   0          4h5m
	pod/kubernetes-dashboard-67bd8fc546-k4zf6       1/1     Running   0          4h5m
	
	NAME                                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
	service/dashboard-metrics-scraper   ClusterIP   100.68.151.232   <none>        8000/TCP   4h5m
	service/kubernetes-dashboard        ClusterIP   100.71.131.246   <none>        443/TCP    4h5m
	
	NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
	deployment.apps/dashboard-metrics-scraper   1/1     1            1           4h5m
	deployment.apps/kubernetes-dashboard        1/1     1            1           4h5m

주로 쿠버네티스 대시보드는 프록시 또는 노드포트로 서비스를 노출시키는데, 나는 alb로 연결하기 위해 아래처럼 ingress까지 생성해 줄 것이다.

aws-load-balancer-controller/annotations.md at main · kubernetes-sigs/aws-load-balancer-controller

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "alb"
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
    alb.ingress.kubernetes.io/certificate-arn: ${CERT_ARN}
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
    alb.ingress.kubernetes.io/backend-protocol: HTTPS
    alb.ingress.kubernetes.io/healthcheck-protocol: HTTPS
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  rules:
  - host: k8s.yooga.in
    http:
      paths:
      - backend:
          service:
            name: kubernetes-dashboard
            port:
              number: 443
        path: /
        pathType: Prefix
      - backend:
          service:
            name: ssl-redirect
            port:
              name: use-annotation
        path: /ssl-redirect
        pathType: Prefix

${CERT_ARN} 부분은 아래 명령어를 통해 나오는 값을 대신 넣어주면 된다. 내가 사전에 AWS Certificate Manager에서 만들어준 퍼블릭 인증서이다.

# aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text

내가 가장 삽질을 많이 했던 부분이 ingress annotaion에 backend-protocol을 지정하지 않은 부분이었다.

쿠버네티스 대시보드 서비스 자체가 args 설정에서 --auto-generate-certificates 옵션때문에 HTTPS로만 동작한다는 부분은 알고 있었지만,,, deployment에서 컨테이너 포트는 8443으로 지정되어 있기에 별도 설정은 필요하지 않은줄 알았다..

(참고로 8443가 디폴트로 지정되어 있는 이유는 Kubernetes Dashboard가 HTTPS 연결을 처리하는 기본 포트이기 때문이다.)

backend-protocol을 지정하지 않았을 때는, 서비스 접속 시에 브라우저 상에 Client sent an HTTP request to an HTTPS server. 또는 400 Bad Request 에러가 발생하였다.

클라이언트 쪽에서 아무리 https로 접근도 해보고 https로 auto redirection도 걸어 보았지만 소용이 없었다. 대시보드 서비스 특성 상 HTTPS로만 동작하게 로직이 짜여 있지만 ingress 규칙에 아예 Default가 HTTP로 되어 있기에, 요청이 HTTP로 가게 되어 에러가 발생하였던 것이었다!

해결하게 된 계기는 ALB 헬스체크하는 과정부터 에러가 나길래 콘솔에서 확인해 보니 HTTP로 헬스체크 설정이 되어 있었고 ingress annotation에서 헬스체크 프로토콜 지정하는 부분을 찾다 보니 알게 되었다ㅠㅠ…

alb 로그, pod 로그, event에는 특이점도 없고 오로지 브라우저 에러코드만 보고 접근하려니 삽질을 오래 하였다 흑흑…

아래와 같이 ingress까지 모든 준비는 끝났다!

# kubectl get all,ing -n kubernetes-dashboard
	NAME                                            READY   STATUS    RESTARTS   AGE
	pod/dashboard-metrics-scraper-8c47d4b5d-ttkxj   1/1     Running   0          4h11m
	pod/kubernetes-dashboard-67bd8fc546-k4zf6       1/1     Running   0          4h11m
	
	NAME                                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
	service/dashboard-metrics-scraper   ClusterIP   100.68.151.232   <none>        8000/TCP   4h11m
	service/kubernetes-dashboard        ClusterIP   100.71.131.246   <none>        443/TCP    4h11m
	
	NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
	deployment.apps/dashboard-metrics-scraper   1/1     1            1           4h11m
	deployment.apps/kubernetes-dashboard        1/1     1            1           4h11m
	
	NAME                                                  DESIRED   CURRENT   READY   AGE
	replicaset.apps/dashboard-metrics-scraper-8c47d4b5d   1         1         1       4h11m
	replicaset.apps/kubernetes-dashboard-67bd8fc546       1         1         1       4h11m
	
	NAME                                             CLASS    HOSTS          ADDRESS                                                                        PORTS   AGE
	ingress.networking.k8s.io/kubernetes-dashboard   <none>   k8s.yooga.in   k8s-kubernet-kubernet-1f9299bfbe-1461493809.ap-northeast-2.elb.amazonaws.com   80      14s

ingress 생성하자마자 external-dns의 로그를 보면 내가 정의한대로 route53에 레코드를 생성하고 있다.

# kubectl logs -n kube-system external-dns-7c84576fbc-pnkhq
	time="2023-05-06T11:38:16Z" level=info msg="Desired change: CREATE cname-k8s.yooga.in TXT [Id: /hostedzone/Z069356534F34N4U5WX5J]"
	time="2023-05-06T11:38:16Z" level=info msg="Desired change: CREATE k8s.yooga.in A [Id: /hostedzone/Z069356534F34N4U5WX5J]"
	time="2023-05-06T11:38:16Z" level=info msg="Desired change: CREATE k8s.yooga.in TXT [Id: /hostedzone/Z069356534F34N4U5WX5J]"
	time="2023-05-06T11:38:16Z" level=info msg="3 record(s) in zone yooga.in. [Id: /hostedzone/Z069356534F34N4U5WX5J] were successfully updated"
	time="2023-05-06T11:39:17Z" level=info msg="Applying provider record filter for domains: [yooga.in. .yooga.in.]"
	time="2023-05-06T11:39:17Z" level=info msg="All records are already up to date"

콘솔에서 확인하면 생성되어 있다!

Untitled 2

그리고 바로 도메인 접속하면 서비스가 쫘라란~!

Untitled 3

접근에 성공하면 아래 과정처럼 토큰으로 접속하면 된다.

  1. sa, clusterrolebinding 생성

     apiVersion: v1
     kind: ServiceAccount
     metadata:
       name: admin-user
       namespace: kube-system
     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: ClusterRoleBinding
     metadata:
       name: admin-user
     roleRef:
       apiGroup: rbac.authorization.k8s.io
       kind: ClusterRole
       name: cluster-admin
     subjects:
     - kind: ServiceAccount
       name: admin-user
       namespace: kube-system
    
  2. secret 생성하여 수동으로 토큰 발급

     apiVersion: v1
     kind: Secret
     metadata:
       name: secret-sa-admin-user
       namespace: kube-system
       annotations:
         kubernetes.io/service-account.name: "admin-user"
     type: kubernetes.io/service-account-token
    
  3. deployment.yaml > spec.containers.args에 설정 추가
    1. 토큰은 유효기간 제거 ⇒ --token-ttl=0 추가
    2. 인증 skip 부분 있지만 퍼블릭도메인이라 설정하지 않음 ⇒ --disable-skip
  4. 참고로 아래는 인증서 안붙이고 HTTP로 동작하게 하고 싶을 때 deployment.yaml > spec.containers.args에 추가해줘야 하고 --auto-generate-certificates는 제거해 줘야 한다.
    1. --insecure-bind-address=0.0.0.0
    2. --enable-insecure-login

Leave a comment