배경
최근 몇가지 실험과 실습을 통해 내가 서비스하고 있는 docker image 하나를 올려보았다.
그동안 docker 만 이용해 봤는데 꽤 재미 있다.
중간에 시행 착오가 있었는데 이 글을 통해 전체 흐름을 한번에 정리해서 처음부터 끝까지 다시 해보려고 한다.
목표 흐름
| 구성 요소 | 위치/타입 | IP 주소 및 포트 | 주요 기능 및 역할 | HA (고가용성) 역할 |
| 1. pfSense | 외부 방화벽/라우터 | 공인 IP → 10.34.1.150 | 외부 트래픽을 내부 K8s 클러스터의 VIP로 포워딩하는 관문 역할. | 외부에서 클러스터로 들어오는 트래픽의 단일 진입점 제공. |
| 2. MetalLB | K8s 애드온 (Speaker) | 10.34.1.150 (VIP) | K8s LoadBalancer Service에 외부 접근 가능한 VIP를 할당하고, ARP/NDP 프로토콜로 이 VIP를 네트워크에 광고. | VIP가 항상 살아있는 노드로 라우팅되도록 보장 (노드 장애 시 자동 인계). |
| 3. Traefik Service | K8s LoadBalancer Service | 10.34.1.150 → Cluster IP | MetalLB가 할당한 VIP를 받아 외부 트래픽을 Traefik Pod로 전달. | MetalLB 덕분에 VIP를 통해 트래픽을 끊김 없이 수신할 수 있게 함. |
| 4. Traefik Pod | K8s Ingress Controller | 10.34.1.150 → Traefik Pod IP | 인증서는 CertManager 를 통해 발급 / 갱신 |
Pod 장애 시 다른 Traefik Pod로 트래픽이 대체됨. |
| 5. K8s Service | K8s Service (ClusterIP) | Cluster IP (예: 10.43.x.x) | Traefik으로부터 트래픽을 받아 해당 Deployment의 모든 Pod로 부하를 분산시키는 로드 밸런서 역할. | Pod 레벨의 로드 밸런싱 및 장애 감지를 수행. |
| 6. 최종 Pod | K8s Pod | Pod IP | 실제 요청을 처리하고 응답을 생성. (예: ggmoney-web-dev 애플리케이션 실행) |
일단 목표하는 데이터의 흐름은 위와 같다.
위 것들을 하기 위해서 다음과 같은 절차로 설정을 해보고자 한다.
진행순서
1. 클러스터의 노드 3개 준비 (ubuntu)
2. k3s HA 설치 (전부 master 모드)
3. metallb 를 통해 VIP 설정
- metaillb 동작 확인 (node를 죽여서 failover 확인)
4. 샘플 서비스 이미지 pod 배포
- 샘플 서비스 서비스 생성
- 샘플 서비스 ssl 설정
5. traefik 을 통한 통한 lets encrypt 설정
5. Cert Manager 를 통한 SSL 인증 설정
6. node failover 테스트
- 1번 죽여보고, 살려보고
- 2번도 죽여보고, 살려보고
이정도로 진행해 보려고 한다.
클러스터 노드 준비
VIP : 10.34.1.150
Node IP : 10.34.1.151 ~ 10.34.1.152 총 3개
서버를 위와 같이 3대를 proxmox 를 이용하여 만든다.
계정을 gglabadmin 으로 만들었고 ip는 10.34.1.151 고정으로
host는 k3s-node1 로 만든다.

생성이 되고 나면 2개를 복제하여 ip와 node host 를 변경하겠습니다.
해보니까...디스크 50G 로 했더니 복제보다. 새로 설치가 빠르다. -.-
설치 끝나면 22번 ssh 도 열어준다.

k3s 설치
설치를 하기 전에 필요한 방화벽을 셋팅합니다.
pfSense + MetalLB + Traefik 기반 K3s 클러스터 구조를 위해 외부 및 내부 방화벽에서 반드시 열어야 할 포트 목록
🔒 1. 외부 방화벽 (pfSense) 설정
pfSense 방화벽은 공인 IP로 들어오는 트래픽을 클러스터의 VIP인 **10.34.1.150**으로 포트 포워딩(Port Forwarding)하는 규칙을 설정해야 합니다.
| 소스 IP | 프로토콜 | 외부 포트 (Destination) | 내부 포트 (Target) | 내부 IP (Target) | 목적 |
| Any | TCP | 80 (HTTP) | 80 | 10.34.1.150 | Let's Encrypt ACME 챌린지 및 HTTP 트래픽 |
| Any | TCP | 443 (HTTPS) | 443 | 10.34.1.150 | 최종 암호화된 웹 서비스 트래픽 |
Traefik 기본 포트 설정 시 주의 사항
Traefik은 기본적으로 web (80) 및 websecure (443) 엔트리포트를 사용합니다. 만약 Traefik이 기본 포트(80, 443)가 아닌 다른 포트로 설정되어 있다면, pfSense에서도 해당 포트를 10.34.1.150의 Traefik 서비스 포트로 포워딩해야 합니다. (예: Traefik이 8000/8443을 사용한다면, pfSense 포워딩도 80/443 → 8000/8443으로 변경)
🔑 2. 내부 방화벽 (K3s 노드) 설정
K3s를 설치할 때 기본적으로 필요한 포트는 k3s-node1, k3s-node2, k3s-node3 모든 노드 간에 허용되어야 합니다. K3s는 대부분의 포트를 자동으로 관리하지만, 기본적으로 알아야 할 필수 포트 목록입니다.
A. K3s 서버(컨트롤 플레인) 간 통신 포트
| 포트 번호 | 프로토콜 | 통신 방향 | 목적 |
| 6443 | TCP | Inbound (모든 노드 → 서버) | Kubernetes API Server 통신 (HA 서버/에이전트 통신 포함) |
| 2379-2380 | TCP | Inbound (서버 간) | 내장 etcd/dqlite 데이터베이스 통신 (HA 구성 시 필수) |
B. 네트워크 및 서비스 관련 포트
| 포트 번호 | 프로토콜 | 통신 방향 | 목적 |
| 8472 | UDP | Bidirectional | Flannel VXLAN 터널링 통신 (Pod 네트워킹) |
| 10250 | TCP | Inbound | Kubelet API (Control Plane → 노드 Pod 관리) |
| 30000-32767 | TCP/UDP | Inbound | NodePort 서비스 범위 (일반적으로 사용자가 직접 열 필요는 없음) |
C. MetalLB 관련 포트 (BGP 모드인 경우)
MetalLB가 BGP 모드로 설정되었다면 BGP 피어링 포트가 필요합니다. Layer 2(ARP/NDP) 모드라면 추가 포트가 필요하지 않습니다.
| 포트 번호 | 프로토콜 | 통신 방향 | 목적 |
| 179 | TCP | Bidirectional | BGP 피어링 통신 (라우터와 MetalLB Speaker 간) |
GPT 가 모두 정리해 주었다. 너무 편한데?..
이제 실제 우분투에 실행해보자.
# -----------------------------------------------------------
# 1. UFW 설치 및 활성화 (필요한 경우)
# -----------------------------------------------------------
# sudo apt update
# sudo apt install ufw -y
# 22번은 이미 설정 했을테니까 참고만 하고 넘어가자
sudo ufw enable
sudo ufw 22/tcp
# -----------------------------------------------------------
# 2. 외부에서 들어오는 HTTP/HTTPS 트래픽 허용 (Traefik 및 ACME 챌린지용)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# 3. 내부 네트워크 대역(10.34.1.0/24)에서 들어오는 필수 클러스터 통신 허용
# Kubernetes API Server (6443)
sudo ufw allow from 10.34.1.0/24 to any port 6443 proto tcp
# Flannel Pod 네트워킹 (8472)
sudo ufw allow from 10.34.1.0/24 to any port 8472 proto udp
# Kubelet API (10250)
sudo ufw allow from 10.34.1.0/24 to any port 10250 proto tcp
# NodePort 서비스 범위 (30000-32767)
sudo ufw allow from 10.34.1.0/24 to any port 30000:32767 proto tcp
sudo ufw allow from 10.34.1.0/24 to any port 30000:32767 proto udp
# -----------------------------------------------------------
# 4. HA 서버 노드 (Control Plane)에서만 추가 실행할 명령어
# (HA 데이터베이스 통신 2379-2380)
# -----------------------------------------------------------
# 만약 서버 노드와 에이전트 노드가 분리되어 있다면,
# 이 명령은 서버 노드에서만 실행해야 합니다.
sudo ufw allow from 10.34.1.0/24 to any port 2379:2380 proto tcp
# -----------------------------------------------------------
# 5. 설정 적용 및 확인
# -----------------------------------------------------------
sudo ufw reload
sudo ufw status verbose

3개 노드가 모두 동일하게 master 이므로 똑같이 해준다.
k3s를 설치해보자.
#node 1 에서 실행
sudo curl -sfL https://get.k3s.io | sh -s - server \
--cluster-init \
--tls-san 10.34.1.150 \
--tls-san 10.34.1.151 \
--disable servicelb
K3s 서버 설치 명령어 옵션 분석
| 옵션 | 설정 값 | 역할 및 기능 | 사용자 환경에서의 의미 |
| server | (없음) | K3s를 서버 (Control Plane) 역할로 실행하도록 지정합니다. | 클러스터 관리, API 서버, 스케줄러 등을 담당하는 노드가 됩니다. |
| --cluster-init | (없음) | 새로운 HA 클러스터를 처음 부트스트랩할 때 사용합니다. | 이 명령을 실행하는 노드가 클러스터의 첫 번째 서버 노드가 됩니다. (다른 노드는 이 서버에 합류합니다.) |
| --tls-san | 10.34.1.150 | 쿠버네티스 API 서버의 TLS 인증서에 추가할 주체 대체 이름(Subject Alternative Name)을 지정합니다. | MetalLB VIP를 통해 API 서버(6443 포트)에 접속할 때 인증서 오류를 방지합니다. |
| --disable | servicelb | K3s에 내장된 간단한 LoadBalancer 구현체를 비활성화합니다. | MetalLB와 같은 외부 LoadBalancer 솔루션을 사용하기 위해 필수적으로 내장 LoadBalancer의 충돌을 방지합니다. |
| --server | https://[IP]:6443 | (두 번째 노드부터 사용) 클러스터에 합류할 서버의 주소를 지정합니다. | 이전에 설정된 첫 번째 서버 노드의 API 주소를 지정하여 클러스터에 참여합니다. |
| --token | [토큰 값] | (두 번째 노드부터 사용) 클러스터의 인증 토큰을 지정합니다. | 이 토큰을 통해 새 서버 노드가 기존 HA 클러스터에 합법적으로 합류할 수 있습니다. |
| --cluster-cidr | 10.42.0.0/16 | Pod가 할당받을 IP 주소 대역을 지정합니다. | Pod 간의 통신에 사용되는 사설 네트워크 대역을 정의합니다. (기본값 사용) |
| --service-cidr | 10.43.0.0/16 | Service가 할당받을 Cluster IP 대역을 지정합니다. | 클러스터 내부에서 Service에 접근할 때 사용되는 대역을 정의합니다. (기본값 사용) |
2, 3번 노드 설치를 위한 토큰 확인
#node 1번에서 실행
gglabadmin@k3s-node1:~$ sudo cat /var/lib/rancher/k3s/server/node-token
K1061da67ae6927dd477b0f98be1e70b2b9897f271e312b7bcb4a6ad8c9230d1b28::server:488d8a96f522680f47ee571cdc32fc6b
gglabadmin@k3s-node1:~$
2, 3번 노드에 설치
#node 2, 3 에서 실행
sudo curl -sfL https://get.k3s.io | sh -s - server \
--server https://10.34.1.151:6443 \
--token K10678f8aac02dd03640881822ba1b5e9ad982ecce40ff945c9b82b798d7c42b6b3::server:248fe529f4a1655e9a55b634e78d702e \
--tls-san 10.34.1.150 \
--tls-san 10.34.1.151 \
--disable servicelb
잘 설치되었는지 확인
gglabadmin@k3s-node1:~$ sudo kubectl get nodes
NAME STATUS ROLES AGE VERSION
k3s-node1 Ready control-plane,etcd,master 9m25s v1.33.5+k3s1
k3s-node2 Ready control-plane,etcd,master 20s v1.33.5+k3s1
k3s-node3 Ready control-plane,etcd,master 9s v1.33.5+k3s1
gglabadmin@k3s-node1:~$
3개 노드가 잘 설치 되었다.
HA 구성을 위해 모두 master 로 설치 되었다.
metallb 설치
MetalLB의 주요 역할은 쿠버네티스 클러스터에 외부 접근 가능한 로드 밸런서 서비스(Service Type: LoadBalancer)를 제공하는 것

10.34.1.151~153 의 아이피를 갖는 노드들중에서 master 에 vip 10.34.1.150 으로 셋팅해준다.
그러면 외부에서 직접 151, 152, 153 을 지정해주지 않아도 항상 살아있는 노드로 접근하도록 해준다.
만약 이것이 없다면?
traefik 에서 loadbalancer 가 아닌 nodeport 타입으로 설정해서 각노드로 직접 지정을 해야하고 추후 노드가 추가/삭제될때 수정으로 제어를 해야한다. 물론 한번 하면 문제가 없겠지만 장애가 났을때 자동으로 해주지는 못할 것이므로 셋팅으르 해주는 것이 좋다.
# MetalLB 네임스페이스 생성 및 설치
sudo kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml
# 설치 확인 (모든 Pod가 Running 상태가 될 때까지 대기)
sudo kubectl get pods -n metallb-system
gglabadmin@k3s-node1:/k8s$ sudo kubectl get pods -n metallb-system
NAME READY STATUS RESTARTS AGE
controller-bb5f47665-dcznh 1/1 Running 0 51s
speaker-8skn7 1/1 Running 0 51s
speaker-knwf6 1/1 Running 0 51s
speaker-zz5bb 1/1 Running 0 51s
잘 설치되었다.
노드2, 3에서 확인해도 잘 된걸로 나온다.
gglabadmin@k3s-node3:~$ sudo kubectl get pods -n metallb-system
[sudo] password for gglabadmin:
NAME READY STATUS RESTARTS AGE
controller-bb5f47665-flkd5 1/1 Running 0 5m16s
speaker-7xmff 1/1 Running 0 5m16s
speaker-pbjzd 1/1 Running 0 5m16s
speaker-r8vzt 1/1 Running 0 5m16s
gglabadmin@k3s-node3:~$
이제 설정 파일을 만들어보자.
gglabadmin@k3s-node1:/k8s$ pwd
/k8s
gglabadmin@k3s-node1:/k8s$ sudo vi metallb-config.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default-pool
namespace: metallb-system
spec:
addresses:
- 10.34.1.150/32
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default-pool
gglabadmin@k3s-node1:/k8s$ sudo kubectl apply -f metallb-config.yaml
ipaddresspool.metallb.io/default-pool created
metallb failover test
여기까지 하고 외부에서 ping 을 날려보았다. 궁금해서
% ping 10.34.1.150
PING 10.34.1.150 (10.34.1.150): 56 data bytes
92 bytes from 10.34.1.151: Time to live exceeded
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 691e 0 0000 01 01 3aca 10.8.0.2 10.34.1.150
Request timeout for icmp_seq 0
92 bytes from 10.34.1.151: Time to live exceeded
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 4740 0 0000 01 01 5ca8 10.8.0.2 10.34.1.150
Request timeout for icmp_seq 1
92 bytes from 10.34.1.151: Time to live exceeded
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 e5de 0 0000 01 01 be09 10.8.0.2 10.34.1.150
Request timeout for icmp_seq 2
92 bytes from 10.34.1.151: Time to live exceeded
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 3822 0 0000 01 01 6bc6 10.8.0.2 10.34.1.150
^C
--- 10.34.1.150 ping statistics ---
뭔가... 151 로 전달되었다가 lose 로 리턴이 온것같다.
metallb 가 1번 노드로 보내고 있는듯 하다.
그런데 아직 생성된 서비스가 하나도 없다보니. 저렇게 나오는것으로 추정된다.
그 서비스로의 연결을 traefik 이 해주는 것이겠지
그럼 이번에 강제로 네트워크 어댑터를 제거하여 node 1번을 죽여봐야겠다.
Request timeout for icmp_seq 36
Request timeout for icmp_seq 37
Request timeout for icmp_seq 38
Request timeout for icmp_seq 39
92 bytes from 10.34.1.153: Destination Host Unreachable
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 39db 0 0000 3e 01 2d0d 10.8.0.2 10.34.1.150
92 bytes from 10.34.1.153: Destination Host Unreachable
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 5b35 0 0000 3e 01 0bb3 10.8.0.2 10.34.1.150
92 bytes from 10.34.1.153: Destination Host Unreachable
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 17a6 0 0000 3e 01 4f42 10.8.0.2 10.34.1.150
92 bytes from 10.34.1.153: Destination Host Unreachable
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 e04e 0 0000 3e 01 8699 10.8.0.2 10.34.1.150
Request timeout for icmp_seq 40
Request timeout for icmp_seq 41
Request timeout for icmp_seq 42
Request timeout for icmp_seq 43
92 bytes from 10.34.1.153: Destination Host Unreachable
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 9fb1 0 0000 3e 01 c736 10.8.0.2 10.34.1.150
92 bytes from 10.34.1.153: Destination Host Unreachable
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 581a 0 0000 3e 01 0ece 10.8.0.2 10.34.1.150
92 bytes from 10.34.1.153: Destination Host Unreachable
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 c678 0 0000 3e 01 a06f 10.8.0.2 10.34.1.150
92 bytes from 10.34.1.153: Destination Host Unreachable
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 46fe 0 0000 3e 01 1fea 10.8.0.2 10.34.1.150
한참동안 timeout 만 나더니 153번으로 바뀐아이피로 뭔가가 나온다.
그런데 아까와는 다르게 나왔다 안나왔다. 반복한다.
단순히 출력 순서가 잘못 된것 같다.이번엔 ... 두개를 죽여볼까? 1, 3번을 죽여봐야겠다.

둘다 죽였더니 약 20초 후에 152도 붙기 시작했다.
metallb 가 잘 동작하고 있다고 봐야겠지?
% curl -k http://10.34.1.150/
404 page not found
외부에서 80 접속시에도 404 가 나오면 잘 나온다는 의미라고 한다.
traefik 이 잘 동작하지 않으면 connection refused 나 timeout 이 나온다고 하니.
여기까지 보면 일단 metallb, traefik 의 기본설정은 잘 된것으로 보면 될것 같다.
샘플 서비스 배포
이제 함쓰 개발시 사용하는 개발 이미지를 배포 해본다.
/k8s 에 앱 디렉토리를 만든다.
연습때는 /k8s/system/apps 이렇게 했는데 그냥 system 은 빼고 해야겠다.
config.yaml

이런식으로 했다.
내용은 비밀
다음은 이미지 배포용 파일
deployment.yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ggmoney-web-deployment
labels:
app: ggmoney-web
spec:
# restart: always는 Kubernetes의 기본 설정이므로 replica 설정만 합니다.
replicas: 2 # 안정성을 위해 2개로 시작
selector:
matchLabels:
app: ggmoney-web
template:
metadata:
labels:
app: ggmoney-web
spec:
imagePullSecrets:
- name: vultr-registry-secret
containers:
- name: ggmoney-web-container
image: icn.vultrcr.com/gglab/ggmoney-web:latest # 이미지 설정
ports:
- containerPort: 3000 # 컨테이너 내부 포트
# 환경 변수 설정 (ConfigMap 연결)
envFrom:
- configMapRef:
name: ggmoney-web-config # 위에서 만든 ConfigMap 연결
내용을 자세히 보면 vultr-registry-secret 라는 부분이 있다.
보통은 docker hub 에서 땡겨오겠지만 나는 vultr 의 container registry 를 사용하고 있으므로 인증 설정을 미리 해두어야 한다.
vultr cloud 설정에 보면

이런식으로 인증 아이디와 패스워들 알려준다.
그 정보를 이용하여 vultr-registry-secret 를 미리 만들어 둔다.
sudo kubectl create secret docker-registry vultr-registry-secret \
--docker-server=icn.vultrcr.com/gglab \
--docker-username=<vulr 에서 확인> \
--docker-password='<vultr에서 확인>' \
--namespace=default
다음은 service
service.yaml
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: ggmoney-web-service
labels:
app: ggmoney-web
spec:
type: ClusterIP
selector:
app: ggmoney-web # Deployment의 Pod 레이블과 일치
ports:
- protocol: TCP
port: 80 # Service의 포트 (클러스터 내부에서 접근할 포트)
targetPort: 3000 # Pod 내부 컨테이너 포트 (Docker Compose의 컨테이너 포트)
# NodePort는 K3s가 30000-32767 범위에서 자동으로 할당
여기서 눈여겨 볼 부분은 spec: type 이었던것 같다.
본 서비스는 클러스터 내부에서만 통신한다는 뜻이다.
traefik 을 거쳐서 올테니까 당연하겠지
다음은 ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ggmoney-web-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: traefik
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: traefik
# ----------------------------------------------------
# 443 포트 활성화 및 인증서가 저장될 Secret 이름 지정
# ----------------------------------------------------
tls:
- hosts:
- money-dev.gglab.app
secretName: money-dev-tls-secret
# ----------------------------------------------------
rules:
- host: money-dev.gglab.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
# 연결할 ClusterIP 서비스 이름
name: ggmoney-web-service
# 서비스의 포트 (Service.yaml의 port: 80)
port:
number: 80
이제 좀 어려운 부분인것 같다.
서비스로의 진입점인 traefik 을 사용하면 host 기반 라우팅을 할때 어디로 갈지 모르게 될것이다.
또한 인증서 부분이 있는데 저렇게 해주면 letsencrypt 를 이용하여 자동으로 ssl 인증서 갱신도 해준다.
그런데 갱신할때 사용할 traefik 기본설정을 해줘야 한다.
내 서비스의 도메인은 .app 도메인인데 이 도메인은 https 필수 도메인이다. 즉 http 로는 테스트 자체가 안된다.
브라우저에서 막아버린다.
Cert-Manager 설정
Cert-manager 설치
kubectl apply -f kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
ClusterIssuer 생성 (Let's Encrypt 설정)
cert-manager 설치 후에 서비스가 올라와야 하니까 30초 쯤뒤에 아래 파일도 적용시켜준다.
cluster-issuer.yaml
$ sudo vi /k8s/cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging # 테스트용 (Rate Limit 방지)
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: gglab.app@gmail.com # 사용자님의 이메일 주소
privateKeySecretRef:
name: letsencrypt-staging-key
solvers:
- http01:
ingress:
class: traefik # Traefik 인그레스 컨트롤러를 사용하도록 명시
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod # 실제 프로덕션용
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: gglab.app@gmail.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: traefik
$ sudo kubectl apply -f cluster-issuer.yaml
이제 yaml 준비가 모두 되었으니 하나씩 적용해보자.
gglabadmin@k3s-node1:/k8s$ sudo kubectl apply -f cluster-issuer.yaml
helmchartconfig.helm.cattle.io/traefik created
gglabadmin@k3s-node1:/k8s$ cd apps/ggmoney-web/
gglabadmin@k3s-node1:/k8s/apps/ggmoney-web$ sudo kubectl apply -f config.yaml
configmap/ggmoney-web-config created
gglabadmin@k3s-node1:/k8s/apps/ggmoney-web$ sudo kubectl apply -f deployment.yaml
deployment.apps/ggmoney-web-deployment created
gglabadmin@k3s-node1:/k8s/apps/ggmoney-web$ sudo kubectl apply -f service.yaml
service/ggmoney-web-service created
gglabadmin@k3s-node1:/k8s/apps/ggmoney-web$ sudo kubectl apply -f ingress.yaml
ingress.networking.k8s.io/ggmoney-web-ingress created
모두 잘 적용되었다.
일단 한번 브라우저 테스트를 해볼까.

ㅋㅋ 역시 한방에 되면 이상하지..
인증서 문제가 있다.

브라우저의 인증서를 열어보면 이런식으로 나온다.
발급 자체가 안되었다는 건데...
이 부분에서 일주일이 넘게 고생을 했다.
별도 포스팅을 연결하겠다.
Node Failover
이제 잘 된 정리된 버전으로 github 에 소스로 올려두고 마무리.
끝.
'인프라 > Kubernetes' 카테고리의 다른 글
| k3s 에서 dnszi 유동아이피 연동 스케쥴 추가하기 (0) | 2025.11.30 |
|---|---|
| pfSense 와 CertManager 연동 오류 (0) | 2025.11.29 |
| (연습) k3s HA 구성 트래픽 흐름 구조 (0) | 2025.11.21 |
| (연습) k3s VIP 설정 (MetalLB) (0) | 2025.11.20 |
| (연습) k3s 설치하기 (마스터1, 워커2 설치) (0) | 2025.11.17 |
