Helm으로 Traefik 설치하기

Page content

지금 집에 있는 서버(mac mini 2009)에서 nginx를 이용해서 블로그를 호스팅하는데 port를 구분해서 외부에 노출하고 있다. 외부에서의 >접근을 위해 NodePort를 사용하고, 각 nginx instance는 서로 다른 port를 이용하고 있는데 port번호가 아니라 URL 경로를 이용해서 서로 다른 서비스를 이용할 수 있는 reverse proxy 기능을 사용하면 좀 더 깔끔할 듯 하다. Kubernetes에서는 ingress와 ingress controller를 이용해서 이 reverse proxy를 구현할 수 있다고 한다. Kubernetes에서는 ingress는 기본적으로 제공하는 object 지만, ingress controller는 제공하고 있지 않아, 별도로 설치해야 한다.

Ingress와 Ingress controller의 차이에 대해 헷갈렸는데 Ingress는 결국 route rule만 설정하고, 실제로 외부에서의 request를 받아 적 >절한 service, pod로 전달하는 역할은 ingress controller가 담당한다. Ingress Controller로 유명한 것은 Kubernets가 알려지기 전 부터 reverse proxy로 잘 알려진 nginx외에 HA Proxy Ingess Controller 등이 있다. Kubernetes.io - Ingress Controller Ingress Controller는 실제 메시지를 받아 처리해야 하므로 Service/Pod형태로 deploy된다. Ingress가 입으로 일을 하면 Ingress Controller가 실제 손, 발로 뛰면서 일을 하는 듯한?

처음 kubernetes를 설치한 후 블로그를 띄우기 위해 nginx docker image와 Helm chart를 찾아 다닐 때 nginx web server가 아니라 nginx-ingress만 보여서 이게 뭔가 한 적이 있었는데 이제야 조금 이해를 하겠다는.

Ingress controller로 nginx-ingress가 아닌 Traefik을 설치해 보기로 했다. 그냥 에전부터 들었는데 뭐 하는 건지 이해를 하지 못해한참 바라만 보고 있던 터라 한번 사용해 보기로 마음 먹었다.

helm repo 추가하기

가급적 모든 app은 helm을 이용해서 설치하려고 하고 있어 Traefik역시 Helm chart를 찾는 것이 첫번째 단계다.

$ helm repo add traefik https://helm.traefik.io/traefik
"traefik" has been added to your repositories
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "myhelmrepo" chart repository
...Successfully got an update from the "nextcloud" chart repository
...Successfully got an update from the "infracloudio" chart repository
...Successfully got an update from the "influxdata" chart repository
...Successfully got an update from the "grafana" chart repository
...Successfully got an update from the "traefik" chart repository
Update Complete. ⎈Happy Helming!⎈

default 값을 사용하여 test deploy

$ helm install traefik traefik/traefik
NAME: traefik
LAST DEPLOYED: Mon Jan 25 22:25:30 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

Exposing Traefik dashboard

Traefik의 상태를 확인할 수 있는 dashboard가 있다고 하는데 기본적으로 disable된 상태라 port-forward 명령으로 동작시킬 수 있다고.

$ kubectl port-forward $(kubectl get pods --selector "app.kubernetes.io/name=traefik" --output=name) 9000:9000
Forwarding from 127.0.0.1:9000 -> 9000
Forwarding from [::1]:9000 -> 9000

다만 helm chart 페이지에 있는 대로만 하면 위의 로그처럼 listen하는 IP 주소가 localhost(127.0.0.1)을 사용하므로 같은 머신에서만 접근이 가능하다. 다른 머신에서도 접근할 수 있게 하려면 --address 옵션을 사용해서 listen 하는 IP 주소를 외부와의 통신이 가능한 IP를 지정하거나, 0.0.0.0과 같이 어느 IP로 접근해도 허용하겠다고 지정한다.(머신에 interface가 여러 개가 있는 경우 특정 interface에 할당된 IP를 지정하면, 해당 IP로 접근하는 것만 허용)

$ kubectl port-forward --address 0.0.0.0 $(kubectl get pods --selector "app.kubernetes.io/name=traefik" --output=name) 9000:9000
Forwarding from 0.0.0.0:9000 -> 9000
Handling connection for 9000

Try again with value.yaml from Traefik

동작시키는 환경에 맞게 옵션을 변경하기 위해 helm chart value.yaml 파일을 사용한다. values.yaml 파일은 helm chart가 위치한 git repo에서 받을 수 있다. traefik-helm-chart/traefik at master · traefik/traefik-helm-chart · GitHub

$ helm install -f value.yaml traefik traefik/traefik
NAME: traefik
LAST DEPLOYED: Tue Jan 26 19:04:47 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
$ helm list | grep traefik
traefik    	default  	1       	2021-01-26 19:04:47.633224266 +0900 KST	deployed	traefik-9.13.0   	2.4.0

pod는 정상적으로 동작하는 것처럼 보이는데

$ kubectl get pods
NAME                             READY   STATUS      RESTARTS   AGE
...
traefik-6fd6fbd4ff-v96bk         1/1     Running     0          21s

Service가 제대로 동작하고 있지 않네. EXTERNAL-IPpending 상태라는 건 거의 대부분(100%?) Service type을 LoadBalancer 로 되어 있어서 그렇다는.

$ kubectl get svc
NAME            TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
...
traefik         LoadBalancer   10.98.42.130     <pending>       80:32480/TCP,443:32398/TCP   24s

service.typeNodePort로 변경

Value파일을 수정해서 LoadBalancer 대신 NodePort를 사용하도록 한다. On-premise환경에서는 MetalLB같은 Load Balancer를 설치하지 않는 이상 NodePort를 사용해야 외부로부터의 접근이 가능하다.

service:
...
   type: NodePort 	#LoadBalancer
..

수정된 value 파일을 helm upgrade 명령으로 적용해 본다.

$ vi value.yaml
$ helm upgrade -f value.yaml traefik traefik/traefik
Release "traefik" has been upgraded. Happy Helming!
NAME: traefik
LAST DEPLOYED: Tue Jan 26 19:19:06 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None

다시 Pod 확인해 보고. Pod 설정에는 변경된 것이 없어 이전에 만들어진 pod가 그대로 동작하고 있다.

$ kubectl get pods
NAME                             READY   STATUS      RESTARTS   AGE
...
traefik-6fd6fbd4ff-v96bk         1/1     Running     0          14m

Service는 설정을 변경한 대로 더 이상 Pending 상태가 아니라 None으로. 가만. None이 아니라 host의 IP 주소가 나와야 하는데. NodePort를 사용할 때는 그냥 service type만 변경하는 것이 아니라 명시적으로 IP 주소도 지정해야 한다.

$ kubectl get svc
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
...
traefik         NodePort    10.98.42.130     <none>          80:32480/TCP,443:32398/TCP   14m

service.externalIPs 설정

아래와 같이 IP 주소를 지정하고, 이전과 같은 방법으로 helm upgrade로 변경사항을 적용한다.

service:
   ...
  externalIPs: [192.168.0.100]
$ helm upgrade -f value.yaml traefik traefik/traefik
Release "traefik" has been upgraded. Happy Helming!
NAME: traefik
LAST DEPLOYED: Tue Jan 26 19:20:20 2021
NAMESPACE: default
STATUS: deployed
REVISION: 3
TEST SUITE: None

이젠 Service의 EXTERNAL-IP의 값이 제대로 보여진다.

$ kubectl get svc 
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
...
traefik         NodePort    10.98.42.130     192.168.0.100   80:32480/TCP,443:32398/TCP   15m
$ kubectl get pods --selector "app.kubernetes.io/name=traefik" --output=name
pod/traefik-6fd6fbd4ff-v96bk

dashboard expose 설정 변경

Dashboard를 접근하기 위해 매번 port-forward 명령을 실행하는 것이 번거롭고, value 파일을 이용해서 customize 할 수 있는 상황이 되었으므로, values 파일에 있는 설정을 변경한다.

ports:
    # You SHOULD NOT expose the traefik port on production deployments.
    # If you want to access it from outside of your cluster,
    # use `kubectl port-forward` or create a secure ingress
    expose: true  #false

위 코멘트대로 외부 네트워크에서의 접근은 보안상 이유로 권장하지 않긴 한데, 어차피 집 내에서만 접근하도록 설정할 거라 문제는 없을 듯.

$ helm upgrade -f value.yaml traefik traefik/traefik
Release "traefik" has been upgraded. Happy Helming!
NAME: traefik
LAST DEPLOYED: Tue Jan 26 22:13:04 2021
NAMESPACE: default
STATUS: deployed
REVISION: 4
TEST SUITE: None

다시 service 를 확인해 보면 이전과 다른 점이 보인다.

$ kubectl get svc
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP     PORT(S)                                     AGE
...
traefik         NodePort    10.98.42.130     192.168.0.100   9000:31769/TCP,80:32480/TCP,443:32398/TCP   3h8m

이전의 PORT 필드와 비교해 보면 없던 9000 번 포트를 포워딩 하는 내용이 추가되었다.

  • 변경 전 : 80:32480/TCP,443:32398/TCP
  • 변경 후 : 9000:31769/TCP,80:32480/TCP,443:32398/TCP

Value 파일에서 9000 포트의 expose 항목을 true로 설정하면 아래와 같이 port-forward를 별도로 실행할 필요는 없다. 이미 9000번 포트를 kube-proxy가 listen하고 있는 상황이라…

$ kubectl port-forward --address 0.0.0.0 $(kubectl get pods --selector "app.kubernetes.io/name=traefik" --output=name) 9000:9000
Unable to listen on port 9000: Listeners failed to create with the following errors: [unable to create listener: Error listen tcp4 0.0.0.0:9000: bind: address already in use]
error: unable to listen on any of the requested ports: [{9000 9000}]

실행 옵션 변경

Traefik의 실행 옵션을 변경하려면 value 파일에서 다음 항목에 원하는 내용을 추가한다.

additionalArguments:
  - "--providers.kubernetesingress.ingressclass=traefik-internal"
  - "--log.level=DEBUG"

Dashboard is now working - Mar 30, 2021 4:23 PM

이전에 동작하지 않은 이유는 어이없게도 URL 마지막에 / 을 넣지 않아서 라는… 헐..

Fail to access dashboard · Issue #320 · traefik/traefik-helm-chart · GitHub

Hello @Yalafeg ,
Did you try with a trailing slash / at the end of your URL ? /dashboard/
Without this slash, Traefik also gives me 404 page not found
If it is still not working, can you provide logs of your Traefik pod ?

역시 해결책은 본진부터 확인을 해 보는 게 가장 빠른 방법인 듯. (Traefik helm chart의 GitHub repo에 있는 Issue 목록을 뒤져서 찾아냈다는. 역시 이런 실수는 나만 하는게 아니었어 라고 위안도 얻고)

values.yaml 수정 사항

151c151
<     level: ERROR
---
>     level: DEBUG
225c225
<     # hostPort: 9000
---
>     hostPort: 9000
243c243
<     expose: false
---
>     expose: true            << dashboard을 외부에 expose 할 지 말지 판단
300c300
<   type: LoadBalancer
---
>   type: NodePort            << NodePort 사용
307,308c307,308
<   spec: {}
<     # externalTrafficPolicy: Cluster
---
>   spec:
>     externalTrafficPolicy: Local
314c314
<   externalIPs: []
---
>   externalIPs: [192.168.0.100]  << NodePort 사용을 위해 Host IP 지정 

install Traefik in its own namespace

kubectl create ns traefik-v2
# Install in the namespace “traefik-v2”
helm install -—namespace=traefik-v2 \
    traefik traefik/traefik

reference