[Traefik] K8s Traefik 설치, External-IP 설정 및 HTTPS 적용 방법 본문
사용하던 서버의 리소스들을 Docker-Compose에서 Kubernetes를 사용하는 방식으로 마이그레이션을 진행하는 과정에서 Reverse Proxy 겸, LoadBalancer로 사용했던 Traefik 또한 Kubernetes Cluster로 옮겨야 했다.
마이그레이션을 진행하는 것을 계기로 겸사겸사 Kubernetes의 Ingress Controller로 사용되는 Traefik에 외부 접속이 가능하도록 External-IP를 할당해주는 방법과 Letsencrypt의 acme를 사용하여 HTTPS 인증서 사용이 가능하도록 하는 방법에 대한 포스팅을 적어보려고 한다.
Traefik에 대한 대략적인 내용은 아래의 포스팅을 참조하자
사전 준비 사항
1. 외부 접속이 가능한 공인 DNS 필요
2. Kubernetes Cluster가 구성되어 있는 환경 필요 (필자는 On-Premise 환경에서 진행했다.)
3. On-Premise 환경에 구축된 Kubernetes Cluster에 외부 접속을 하기 위한 LoadBalancer가 필요
4. 인증서 저장을 위한 PVC 필요
Metallb LoadBalancer IPAddressPool
Metallb LoadBalancer를 사용하게 되면, Metallb가 할당할 수 있는 IP 대역폭을 지정해주어야 하는데 이때 대역폭을 외부 접근이 가능한 IP 주소가 포함되도록 설정해야 한다. 예를 들어 외부 접근이 가능한 IP 주소가 123.123.123.123이라면 Address Pool은 123.123.123.123 - 123.123.123.133 과 같이 설정되어야 한다.
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: address-pool
namespace: metallb
spec:
addresses:
- 123.123.123.123 - 123.123.123.133
IPAddressPool을 할당하기 이전에 아래의 명령어로 이미 사용되고 있는 IP 주소인지 아닌지 확인하는 것을 권장한다.
for i in {1..9}; do ping -c 1 123.123.123.12$i; done
위의 IP는 어디까지나 예시이기 때문에 본인 환경의 IP 주소 상황을 고려하여 각자 다르게 적용하도록 하자. 참고로 IP 주소는 ifconfig
명령어를 통해 확인할 수 있다.
Helm을 통해 Traefik 설치
Helm을 통해 바로 Traefik을 설치하지 않고 환경에 맞게 커스터 마이징 하기 위해 pull 명령어를 통해 Traefik의 리소스 파일들을 내려받는다.
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
helm pull traefik/traefik
tar xvfz traefik-28.3.0.tgz
rm -rf traefik-28.3.0.tgz
mv traefik traefik-28.3.0
cd traefik-28.3.0/
cp values.yaml my-values.yaml
기존의 설정 파일을 my-values.yaml로 복사하여 새로운 Helm value 파일을 생성한다. 복사한 my-values.yaml 파일을 환경에 맞도록 다음과 같이 수정한다.
ports:
traefik:
port: 9000
expose:
default: true
exposedPort: 9000
protocol: TCP
...
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- traefik
topologyKey: kubernetes.io/hostname
Traefik Dashboard 접근을 위해 traefik EntryPoint에 외부 접속이 허용되도록 만들고, 동일한 Node에 Traefik Pod가 추가 실행되지 않도록 Affinity 설정을 한다.
my-values.yaml 파일은 추후 HTTPS 인증서 적용을 위해 다시 살펴봐야 하기 때문에 어느 정도 눈에 익혀두는 편이 좋다. 여기까지 진행이 완료됐다면 Traefik 전용 네임스페이스를 생성하자.
kubectl create ns traefik
kubectl ns traefik
네임스페이스가 제대로 변경됐는지 확인하고 Helm을 통해 변경된 변수 파일을 적용하여 Traefik을 설치하자.
helm install traefik -f my-values.yaml .
큰 문제가 없다면 정상적으로 설치가 진행되고 Pod와 SVC 같은 리소스가 정상적으로 동작하는 것을 확인할 수 있을 것이다. SVC를 조회하여 External-IP가 Metallb에서 지정한 AddressPool에 맞게 설정되었는지 확인하자.
확인을 위해 브라우저에 http://{External-IP}:9000/dashboard/# 을 입력하여 Traefik Dashboard에 정상적으로 접근이 가능한지 확인해보자. 정상적으로 리소스가 실행되고 있다면 아래의 사진과 같은 Traefik Dashboard에 접근할 수 있다.
여기까지 됐다면, Traefik 설치는 정상적으로 완료된 것이다.
IngressRoute 설정
Traefik은 EntryPoint로 들어온 요청을 Router로 분기하여 각 SVC에 전달한다. 요청을 분기하기 위한 IngressRouter를 작성해보자.
우선 요청이 들어오는 것을 확인할 수 있도록 Pod를 생성해보자.
# coffee-svc-deploy.yaml
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
---
apiVersion: v1
kind: Service
metadata:
name: coffee-svc
namespace: default
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: coffee
coffee라는 이름의 nginx-hello 이미지를 사용한 컨테이너를 배포하는 yaml 파일이다. nginx-hello 는 서버의 IP 주소와 이름 등을 화면에 출력하는 간단한 서비스다.
kubectl apply -f coffee-svc-deploy.yaml
위의 명령어를 통해 실행시키면 Pod 2개와 SVC, Delpoyment가 동작하는 것을 확인할 수 있다. 이제 coffee의 SVC와 Traefik의 EntryPoint를 연결시켜야 한다. SVC와 Traefik EntryPoint의 연결을 담당하는 것이 위에서 설명했던 IngressRoute다.
IngressRoute에 분기 조건을 적용하면 해당 조건에 맞게 Traefik이 트래픽을 라우팅하여 알맞은 SVC로 전달한다. Traefik은 사용자가 편리하게 해당 기능을 구현할 수 있도록 자체적으로 IngressRoute라는 CRD를 제공한다.
# coffee-crd-ingressroute.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: coffee-ingressroutetls
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`your.domain.example`)
kind: Rule
services:
- name: coffee-svc
port: 80
web EntryPoint에 전달되는 트래픽 중 your.domain.example 이라는 호스트를 가진 트래픽만 coffee-svc에 전달한다는 내용이다. web의 경우 my-values.yaml을 살펴보면 기본적으로 지정되어 있는 EntryPoint 중 하나이다. 이외에도 websecure, traefik 등이 있다.
kubectl apply -f coffee-crd-ingressroute.yaml
위의 명령어로 IngressRoute 리소스를 생성하자. 공인 도메인을 사용 중이라면 match.Host에 설정한 도메인으로 접속할 수 있다. 아직 HTTPS 적용이 되지 않아 안전한지 않은 사이트라고 표시되겠지만 접속은 가능하다.
만약 공인 도메인이 없다면, /etc/hosts 파일에 Traefik SVC의 External-IP와 match.Host에 설정한 도메인을 입력해두면 브라우저를 통해 접속이 가능하지만 외부 네트워크에서의 접속은 불가능하다.
Let'sEncrypt ACME를 통해 HTTPS 인증서 등록하기
우리가 만든 사이트를 안전하게 만들기 위해 Let'sEncrypt를 통해 인증서를 발급받아 Traefik에 적용시켜보자. Traefik 인그레스를 사용할 경우 사용자는 인증서를 다수의 웹서버에 등록할 필요 없이 단일 Traefik 설정 파일을 통해 관리할 수 있다.
우선 Let'sEncrypt 는 CA로 ACME 프로토콜을 사용하여 x509 인증서를 자동으로 발급받는 것이 가능하도록 해준다. 즉, Let'sEncrypt 는 유효한 인증서를 무료로 사용자에게 제공해주며 ACME 프로토콜을 통해 자동으로 인증서를 발급받도록 한다. 라는 것이 요점이다.
Traefik은 Let'sEncrypt를 공식적으로 지원하기 때문에 굉장히 간편하게 사용이 가능하다. 우선 인증서를 저장하기 위해 PVC를 생성하도록 하자. 필자는 OpenEBS를 사용했다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: traefik-acme-pvc
namespace: traefik
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: "openebs-hostpath"
Storage 할당을 꽤 과하게 한 것 같지만 우선 무시하고 진행하도록 하자.
k apply -f traefik-acme-pvc.yaml
PVC가 정상적으로 생성됐다면, 이전에 커스터 마이징 했던 my-values.yaml 파일을 살펴보도록 하자. 볼륨 마운트를 위해 persistence 부분을 찾아 아래와 같이 수정해보자.
persistence:
# -- Enable persistence using Persistent Volume Claims
# ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
# It can be used to store TLS certificates, see `storage` in certResolvers
enabled: true
name: data
# existingClaim: ""
accessMode: ReadWriteOnce
size: 1Gi
storageClass: openebs-hostpath
# volumeName: ""
path: /data/letsencrypt
annotations: {}
existingClaim: traefik-acme-pvc
# -- Only mount a subpath of the Volume into the pod
# subPath: ""
그리고 인증서 적용을 위해 certResolvers, additionalArguments 부분을 수정해줘야 한다.
# Ref: https://doc.traefik.io/traefik/https/acme/#certificate-resolvers
# See EXAMPLES.md for more details.
certResolvers:
myresolver:
acme:
email: your@email.com
storage: /data/letsencrypt/acme.json
httpChallenge:
entryPoint: web
...
additionalArguments:
- "--certificatesresolvers.myresolver.acme.email=your@email.com"
- "--certificatesresolvers.myresolver.acme.storage=/data/letsencrypt/acme.json"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
위처럼 수정이 완료된 my-values.yaml 파일을 저장하고 해당 내용을 다시 적용시키자. 특별한 사유가 없다면 안전하게 기존의 리소스들을 삭제하고 다시 설치하는 것을 추천한다.
helm uninstall traefik
helm install traefik -f my-values.yaml .
Traefik 리소스들이 재시작 되었다면, 이전 작성해두었던 IngressRoute 파일을 수정해줘야 한다.
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: coffee-ingressroutetls
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`your.domain.com`)
kind: Rule
services:
- name: coffee-svc
port: 80
tls:
certResolver: myresolver
web EntryPoint를 websecure로 변경하고 tls.certResolver를 추가했다. 이제 변경사항이 적용되도록 IngressRoute도 다시 실행시키자.
kubectl apply -f coffee-crd-ingressroute.yaml
여기까지 됐다면 이전처럼 안전하지 않은 사이트라는 경고 없이 HTTPS로 접속이 가능해진다.
'Infra' 카테고리의 다른 글
[k8s] k8s Security basic (0) | 2024.11.11 |
---|---|
[k8s] Kubernetes Network (0) | 2024.11.08 |
[k8s] K8s Storage with OpenEBS (0) | 2024.08.02 |
[Network] TCP 프로토콜에 대한 이해 (1) | 2024.07.23 |
[k8s] etcd & Raft Alogorithm (2) (0) | 2024.07.12 |