실습
- Traefik 설치
- Traefik 공인 인증서 변경, 복수 Port 설정 등 기능 검증
Why traefik ingress?
MetalLB LoadBalancer는 순수 L4 기능만 필요한 경우 사용하고 TLS 인증서, 도메인 또는 Path 기반의 추가 L7 부가 기능이 필요한 경우 Ingress Controller를 사용해야 합니다.
Kubernetes Ingress Controller로는 잘 알려진 NGINX, HAPROXY 등이 있습니다. 그 중 저는 Traefik을 사용합니다. NGINX가 점유율은 가장 높고 저희도 일부 실 서비스에도 사용 중이지만 NGINX Ingress Controller는 경험 상 POD가 재시작되면 hang이 걸리는 등 사소한 문제가 있었습니다. F5가 NGINX 인수 후 Community 버전은 제대로 지원이 안되는 느낌적인 느낌도 있었구요. 그래서 나름 Admin UI도 있고 업계 사례도 풍부한 Traefik을 검증하였고 성공적으로 테스트를 완료하여 실 서비스에서 잘 사용하고 있습니다.
Ingress Controller 개념 설명은 여기로..
https://twofootdog.tistory.com/23
Ingress는 외부로부터 들어오는 요청에 대한 로드밸런싱, TLS/SSL 인증서 처리, 도메인 기반 가상 호스팅 제공, 특정 HTTP 경로의 라우팅 등의 규칙들을 정의해 둔 자원이며, 이런 규칙들을 실제로 동작하게 해주는건 Ingress-Controller다.
Traefik 설치
설치는 역시 Helm 이용하여 쉽게 가능합니다.
[spkr@erdia22 57.Traefik (spkn02:prometheus)]$ helm pull traefik/traefik [spkr@erdia22 57.Traefik (spkn02:prometheus)]$ tar xvfz traefik-9.17.2.tgz traefik/Chart.yaml traefik/values.yaml (생략) (Helm 설치 시 항상 pull 다운받아서 copy values.yml to my-values.yml 수정해서 설치합니다.)
설치 시 my-values.yml 설정 파일 변경한 내역입니다.
1. Deployment 이중화 및 access log enable
: POD 이중화는 당연하고 access log는 초기 장애 처리 시 필요하여 enable 합니다. 물론 용량은 많이 차지 합니다. 실 사용량에 따라 Loki에서 적절한 PVC 용량 설정이 필요합니다. 개별 상황에 따른 선택이 필요합니다.
2. 외부 admin page open 및 loadbalancerIP 지정
: Traefik Admin UI IP가 매번 변경되면 안되므로 미리 지정합니다. (LoadBalancer 사용하기 위해서 MetalLB 등 미리 설치가 필요합니다.)
: admin ui 와 traefik pod 모두 loadbalancer 설정을 합니다.
3. resource 및 podAntiaffinity 설정
: POD가 같은 노드에 실행되면 Node 다운 시 서비스 이중화가 안되므로 anti-affinity 까지 설정합니다.
[spkr@erdia22 traefik-9.17.2 (spkn02:prometheus)]$ k create ns traefik namespace/traefik created [spkr@erdia22 traefik-9.17.2 (spkn02:prometheus)]$ kns traefik Context "spkn02" modified. Active namespace is "traefik". [spkr@erdia22 traefik-9.17.2 (spkn02:traefik)]$ helm install traefik -f my-native-values.yaml . NAME: traefik LAST DEPLOYED: Tue Apr 27 04:03:33 2021 NAMESPACE: traefik STATUS: deployed REVISION: 1 TEST SUITE: None
정상 설치 완료 되었습니다.
[spkr@erdia22 ~ (dzbumin:default)]$ kgp NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES traefik-67b4c7db7d-4x5x4 1/1 Running 0 57s 10.233.96.61 node2 <none> <none>
다음으로 Ingress 설정이 필요합니다. Traefik은 자체 CRD(Custom Resource Definition), IngressRoute를 이용하여 ingress를 설정합니다. Ingress란 외부 Traffic이 어떠한 서비스 그리고 어떤 path에 적용할 것인지 정의하는 Object 입니다.
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: simpleingressroute namespace: default spec: entryPoints: - web routes: - match: Host(`your.example.com`) && PathPrefix(`/notls`) kind: Rule services: - name: coffee-svc port: 80 --- apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: ingressroutetls namespace: default spec: entryPoints: - websecure routes: - match: Host(`my.example.com`) && PathPrefix(`/tls`) kind: Rule services: - name: tea-svc port: 80 tls: certResolver: myresolver
IngressRoute 설정은 native ingress 설정과 매우 유사합니다. 먼저 entrypoints를 지정합니다. entrypoints는 Traefik deploy에서 사용하는 외부 트래픽을 구분하기 사용하는 구분자 정도라 생각하시면 됩니다. entryPoint, web은 web 이라는 이름을 가지는 트래픽에 대하여 정책을 세우겠다 입니다.
entrypoints는 traefik deploy YAML에서 확인 가능합니다. deploy YAML 파일은 아래와 같이 export하여 확인 합니다.
[spkr@erdia22 57.Traefik (dzbumin:traefik)]$ k get deployments.apps traefik -o yaml |k neat > traefik-deploy.yml (k neat 사용)
- 중간 정도 containers - args 부문을 확인하면 entrypoint를 확인 하실 수 있습니다. default로 web, websecure 가 지정되었습니다.
다음으로, entrypoints - web 에 대하여 redirect 해야 할 domain을 지정합니다.
routes: - match: Host(`your.example.com`) && PathPrefix(`/notls`) kind: Rule services: - name: coffee-svc port: 80
Host, your.example.com 도메인 이름과 /notls path로 들어오는 요청에 대하여 coffee-svc 라는 service의 80 port로 Redirect 하도록 설정하였습니다.
이제 ingressroute 적용 하겠습니다.
[spkr@erdia22 57.Traefik (spkn02:traefik)]$ ka cafe-crd-ingressRoute.yml ingressroute.traefik.containo.us/simpleingressroute created ingressroute.traefik.containo.us/ingressroutetls created [spkr@erdia22 57.Traefik (spkn02:traefik)]$ k get ingressroute ingressroutes.traefik.containo.us ingressroutetcps.traefik.containo.us ingressrouteudps.traefik.containo.us [spkr@erdia22 57.Traefik (spkn02:traefik)]$ k get ingressroute -n default NAME AGE ingressroutetls 28s simpleingressroute 28s
ingressroute가 지정하는 Service와 Deploy를 만듭니다. (미리 만들었어야..)
apiVersion: apps/v1 kind: Deployment metadata: name: coffee namespace: default spec: replicas: 2 selector: matchLabels: app: coffee template: metadata: labels: app: coffee spec: containers: - name: coffee image: nginxdemos/nginx-hello:plain-text ports: - containerPort: 8080 resources: limits: cpu: 500m requests: cpu: 200m --- apiVersion: v1 kind: Service metadata: name: coffee-svc namespace: default spec: ports: - port: 80 targetPort: 8080 protocol: TCP name: http selector: app: coffee --- apiVersion: apps/v1 kind: Deployment metadata: name: tea namespace: default spec: replicas: 3 selector: matchLabels: app: tea template: metadata: labels: app: tea spec: containers: - name: tea image: nginxdemos/nginx-hello:plain-text ports: - containerPort: 8080 resources: limits: cpu: 500m requests: cpu: 200m --- apiVersion: v1 kind: Service metadata: name: tea-svc namespace: default spec: ports: - port: 80 targetPort: 8080 protocol: TCP name: http selector: app: tea
YAML 적용 후 생성된 POD, SVC 확인 합니다.
[spkr@erdia22 57.Traefik (kspray:default)]$ ka cafe-svc-deploy.yml deployment.apps/coffee created service/coffee-svc created deployment.apps/tea created service/tea-svc created [spkr@erdia22 57.Traefik (spkn02:default)]$ k get pod,svc NAME READY STATUS RESTARTS AGE pod/coffee-6c8998cf9c-cdqq4 1/1 Running 0 23s pod/coffee-6c8998cf9c-x4tvz 1/1 Running 0 23s pod/tea-86cf945d9c-952rm 1/1 Running 0 23s pod/tea-86cf945d9c-hg4pb 1/1 Running 0 23s pod/tea-86cf945d9c-mlh48 1/1 Running 0 23s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/coffee-svc ClusterIP 10.233.7.182 <none> 80/TCP 23s service/tea-svc ClusterIP 10.233.23.150 <none> 80/TCP 23s
그럼, 실제로 Load Balancing 잘되는지 확인해 보겠습니다.
먼저, /etc/hosts 파일 수정합니다.
[spkr@erdia22 ~ (spkn02:traefik)]$ k get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE traefik LoadBalancer 10.233.27.240 172.17.28.161 9000:30540/TCP,80:32241/TCP,443:31027/TCP 17m [spkr@erdia22 57.Traefik (spkn02:default)]$ sudo vi /etc/hosts
curl 통해서 LB 동작 여부를 확인해 보겠습니다.
[spkr@erdia22 ~ (spkn02:traefik)]$ curl your.example.com/notls Server address: 10.233.92.45:8080 Server name: coffee-6c8998cf9c-x4tvz Date: 26/Apr/2021:19:22:22 +0000 URI: /notls Request ID: 390f9c6499480e24fd32fc38c6251940 [spkr@erdia22 ~ (spkn02:traefik)]$ curl your.example.com/notls Server address: 10.233.96.62:8080 Server name: coffee-6c8998cf9c-cdqq4 Date: 26/Apr/2021:19:22:25 +0000 URI: /notls Request ID: ce00abf6148b8ee25142a5e1adf42fef [spkr@erdia22 ~ (spkn02:traefik)]$ curl your.example.com/notls Server address: 10.233.92.45:8080 Server name: coffee-6c8998cf9c-x4tvz Date: 26/Apr/2021:19:22:29 +0000 URI: /notls Request ID: 8a775651714608254f5d3f78bfa470ad
위와 같이 2개의 Server( coffee-6c8998cf9c-x4tvz, coffee-6c8998cf9c-cdqq4)에서 차례로 응답하고 있습니다. LoadBalance 기능이 정상적으로 잘 동작합니다.
흥미로운건 별다른 설정없이도 TLS가 잘되는 것 입니다.
[spkr@erdia22 ~ (spkn02:traefik)]$ curl -k https://my.example.com/tls Server address: 10.233.90.68:8080 Server name: tea-86cf945d9c-mlh48 Date: 26/Apr/2021:19:28:01 +0000 URI: /tls Request ID: a1471fd835c1827fee9bf4a98654a432 [spkr@erdia22 ~ (spkn02:traefik)]$ curl -k https://my.example.com/tls Server address: 10.233.92.46:8080 Server name: tea-86cf945d9c-952rm Date: 26/Apr/2021:19:28:03 +0000 URI: /tls Request ID: bee246b76b05778281d11ea1322cb653 [spkr@erdia22 ~ (spkn02:traefik)]$ curl -k https://my.example.com/tls Server address: 10.233.96.63:8080 Server name: tea-86cf945d9c-hg4pb Date: 26/Apr/2021:19:28:05 +0000 URI: /tls Request ID: 3b73da88d7e9a33ea5b36ce6415a94e5
TLS 설정이라고는 ingressroute 설정에 아래 문구만 추가한 것 뿐입니다.
tls: certResolver: myresolver
위 문구만으로 traefik에서 제공하는 default 인증서를 사용 가능합니다. (참으로 편리합니다) 브라우저에서 확인하면 아래의 Traefik 사에 제공하는 인증서를 확인 할 수 있습니다.
Admin 대시보드
이제 Traefik에서 제공하는 Admin 웹페이지를 확인해 보겠습니다. 웹페이지 IP는 Traefik Service IP로 확인 할 수 있습니다.
[spkr@erdia22 traefik-9.17.2 (kspray:traefik)]$ k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE traefik LoadBalancer
10.233.29.240 172.17.30.171 9000:31688/TCP,80:31839/TCP,443:31173/TCP 21m
IP로 접속하시면 아래와 같은 dashboard 확인 가능합니다. (/dashboard/# 까지 다 붙혀야 합니다.)
http://172.17.29.111:9000/dashboard/#/
현재 설정된 내역을 UI로 바로 확인이 가능합니다. UI도 제공하고 확실히 NGINX Ingress 보다 낫습니다.
HTTP 설정 내역 및 TLS도 확인 가능합니다.
이상 기본 기능에 대하여 검증 하였습니다. 다음으로 실제 운영 환경 시 필요한 몇가지 기능들을 검증해 보았습니다.
1. 인증서 변경
기본 traefik에서 제공하는 인증서가 아닌 회사에서 사용하는 공인 인증서를 사용합니다. 인증서는 Kubernetes 환경에서 secret 형태로 저장하므로 먼저, 인증서를 secret type으로 생성합니다.
[spkr@erdia22 ~ (dzbumin:jitsi-meet)]$ k create secret tls dzbm-tls --key STAR.bizcubex.co.kr_key.pem --cert STAR.bizcubex.co.kr_crt.pem
secret/dzbm-tls created
인증서 관련 설정은 IngressRoute YAML tls.secretName를 지정합니다.
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: nginx-ingressroute
namespace: nginx
spec:
entryPoints:
- websecure
routes:
- match: Host(`bm.bizcubex.co.kr`)
kind: Rule
services:
- name: nginx-svc
port: 80
tls:
secretName: dzbm-tls
적용하고 웹 사이트를 확인하면 아래와 같이 정상적으로 공인 인증서 확인 가능합니다.
2. Http to Https Redirect 설정
사용자가 Http로 접속하는 것을 Https로 자동으로 Redirect 하는 기능이 필요합니다.
참조
https://doc.traefik.io/traefik/routing/entrypoints/
해당 설정은 Deploy YAML에 적용합니다. 앞에서 다운받은 Traefik deploy YAML 파일을 아래와 같이 수정합니다.
containers:
- args:
- --global.checknewversion
- --global.sendanonymoususage
- --entryPoints.traefik.address=:9000/tcp
- --entryPoints.web.address=:8000/tcp
- --entrypoints.web.http.redirections.entryPoint.to=:443
- --entryPoints.websecure.address=:8443/tcp
설정에 containers - args - --entrypoints.web.http.redirections.entryPoint.to=:443 부문을 추가 합니다. 주의해야 할 점은 포트 번호를 “443” 이 아니라 : 추가하여 “:443”로 설정하는 것입니다.
[spkr@erdia22 23.Traefik (dzbumin:traefik)]$ curl http://your.example.com Moved Permanently
정상적으로 redirect 된 걸 확인 가능합니다.
3. 특정 Port 추가
참조
https://doc.traefik.io/traefik/routing/entrypoints/
http, https 이 외 특정 Port를 추가하기 위해서는 위와 동일하게 Deploy YAML 수정이 필요합니다.
(생략)
containers:
- args:
- --global.checknewversion
- --global.sendanonymoususage
- --entryPoints.traefik.address=:9000/tcp
- --entryPoints.web.address=:8000/tcp
- --entrypoints.web.http.redirections.entryPoint.to=:443
- --entryPoints.websecure.address=:8443/tcp
- --entryPoints.mqtt.address=:11887/tcp
- --entryPoints.mysql.address=:3106/tcp (생략)
위와 같이 Deploy YAML 파일의 containers - args 부문에 추가 합니다.
주의점은 POD Port 추가 후 해당 포트를 Service 에도 추가해야 하는 것입니다. 외부에서 접속하기 위해서는 Service Port를 사용합니다.
apiVersion: v1
kind: Service
metadata:
name: traefik
namespace: traefik
spec:
loadBalancerIP: 192.168.1.146
ports:
- name: traefik
nodePort: 32246
port: 9000
targetPort: traefik
- name: web
nodePort: 32299
port: 80
targetPort: web
- name: websecure
nodePort: 30933
port: 443
targetPort: websecure
- name: mysql
port: 3106
targetPort: 54321
- name: mqtt
port: 11887
targetPort: 11887
selector:
app.kubernetes.io/instance: traefik
app.kubernetes.io/name: traefik
type: LoadBalancer
4. Traefik 로그 확인
traefik 설정 후 이상 여부(redirect 등)를 파악하기 위해서는 traefik pod 로그를 보셔야 합니다. 아래와 같이 kubetail 이용하여 복수의 POD 로그 확인이 가능합니다.
[spkr@erdia22 traefik-9.17.2 (dzbumin:traefik)]$ kubetail traefik-5d5cfb4cc4
- Will tail 2 logs...
traefik-5d5cfb4cc4-lfgf9
traefik-5d5cfb4cc4-qc4vh
[traefik-5d5cfb4cc4-qc4vh] 192.168.1.155 - - [30/Apr/2021:04:45:35 +0000] "GET /ping HTTP/1.1" 200 2 "-" "-" 6418 "ping@internal" "-" 0ms
[traefik-5d5cfb4cc4-qc4vh] 192.168.1.155 - - [30/Apr/2021:04:45:38 +0000] "GET /ping HTTP/1.1" 200 2 "-" "-" 6419 "ping@internal" "-" 0ms
[traefik-5d5cfb4cc4-qc4vh] 192.168.1.155 - - [30/Apr/2021:04:45:33 +0000] "POST /http-bind?room=test2 HTTP/2.0" 200 342 "-" "-" 6417 "jitsi-meet-jitsiweb-ingressroute-756c0161f63cb1f927d2@kubernetescrd" "http://10.233.96.184:80" 9083ms
[traefik-5d5cfb4cc4-lfgf9] 10.233.96.0 - - [30/Apr/2021:04:45:26 +0000] "POST /http-bind?room=test2 HTTP/2.0" 200 342 "-" "-" 8081 "jitsi-meet-jitsiweb-ingressroute-756c0161f63cb1f927d2@kubernetescrd" "http://10.233.96.184:80" 14664ms
[traefik-5d5cfb4cc4-lfgf9] 192.168.1.158 - - [30/Apr/2021:04:45:42 +0000] "GET /ping HTTP/1.1" 200 2 "-" "-" 8086 "ping@internal" "-" 0ms
[traefik-5d5cfb4cc4-lfgf9] 192.168.1.158 - - [30/Apr/2021:04:45:47 +0000] "GET /ping HTTP/1.1" 200 2 "-" "-" 8087 "ping@internal" "-" 0ms
[traefik-5d5cfb4cc4-qc4vh] 192.168.1.155 - - [30/Apr/2021:04:45:42 +0000] "POST /http-bind?room=test2 HTTP/2.0" 200 148 "-" "-" 6420 "jitsi-meet-jitsiweb-ingressroute-756c0161f63cb1f927d2@kubernetescrd" "http://10.233.96.184:80" 2129ms
[traefik-5d5cfb4cc4-lfgf9] 10.233.96.0 - - [30/Apr/2021:04:45:41 +0000] "POST /http-bind?room=test2 HTTP/2.0" 200 2497 "-" "-" 8085 "jitsi-meet-jitsiweb-ingressroute-756c0161f63cb1f927d2@kubernetescrd" "http://10.233.96.184:80" 8515ms
[traefik-5d5cfb4cc4-qc4vh] 192.168.1.155 - - [30/Apr/2021:04:45:44 +0000] "POST /http-bind?room=test2 HTTP/2.0" 200 358 "-" "-" 6421 "jitsi-meet-jitsiweb-ingressroute-756c0161f63cb1f927d2@kubernetescrd"
이상 Traefik 실습이었습니다.
Kubernetes 교육 및 기술 지원 문의 : leejunghoon@spkr.co.kr
'쿠버네티스 교육' 카테고리의 다른 글
Diamanti 교육 - dctl, kubectl Tool 설치 (0) | 2021.06.17 |
---|---|
25. Kube 교육 - 중간 점검 (0) | 2021.06.16 |
23. Kube 교육 - Polaris(보안 취약점 확인) (0) | 2021.06.04 |
22. Kube 교육 - HA 및 부하 테스트 (0) | 2021.06.04 |
21. Kube 교육 - ArgoCD for GitOps (0) | 2021.06.04 |