Traefik Gateway API — 포트 불일치
Ingress 스펙은 HTTP 라우팅밖에 표현하지 못하고 벤더별 어노테이션으로
확장하는 구조라, 진입점을 새로 만드는 김에 Gateway API 로 가보기로 했습니다.
컨트롤러는 Traefik 을 썼습니다. 그런데 파드가 CrashLoopBackOff 로 돌고, 겨우 띄워놓으니 이번엔
요청이 404 로 떨어지고, 그다음엔 Gateway 가 Accepted 로 안 넘어갔습니다.
증상이 셋 다 달라 보여서 따로따로 파고들었는데, 막힌 자리는 매번 같은
곳이었습니다.
컨테이너 내 80번 포트 바인딩 실패
traefik-xxx 0/1 CrashLoopBackOff 4 2m25s
ERR Command error: error while building entryPoint web:
building listener: error opening listener: listen tcp :80: bind: permission denied
ports.web.port: 80 으로 설정하면 Traefik 이 컨테이너 안에서 직접 80번에
바인딩을 시도합니다. 1024 미만은 privileged port 라 root 권한 없이는 열 수
없습니다.
port(내부 바인딩)와 exposedPort(서비스 외부 노출)를 나눠야 합니다.
# 잘못된 설정
ports:
web:
port: 80 # 컨테이너 안에서 80으로 직접 바인딩 시도 → 실패
# 올바른 설정
ports:
web:
port: 8000 # 컨테이너 내부 바인딩 포트 (non-privileged)
exposedPort: 80 # Service가 외부에 노출하는 포트
Gateway listener port = Traefik entrypoint port
파드는 떴는데 요청이 404 로 돌아옵니다.
curl http://whoami.example.com
→ 404 page not found
Traefik 의 Gateway API provider 는 Gateway 리소스의 port 와 Traefik
entrypoint 의 port 가 일치해야 라우팅을 붙입니다.
Gateway listener port: 80 ← 설정한 값
Traefik entrypoint port: 8000 ← 실제 내부 포트
→ 매칭 실패 → 404
앞에서 내부 포트를 8000으로 바꿨으니 Gateway 쪽도 8000으로 맞춰야 합니다.
# 잘못된 설정
spec:
listeners:
- port: 80 # Traefik entrypoint 8000과 불일치
# 올바른 설정
spec:
listeners:
- port: 8000 # Traefik entrypoint와 동일하게
외부에서 보이는 포트는 exposedPort 와 로드밸런서가 담당합니다. Gateway
listener 에 적는 값은 그것과 별개입니다.
websecure entrypoint의 TLS 기대
Gateway 가 Accepted 되지 않습니다.
kubectl describe gateway test-gateway -n traefik
→ Message: Cannot find entryPoint for Gateway:
no matching entryPoint for port 8443 and protocol "HTTP"
→ Accepted: False
Traefik 의 websecure entrypoint(8443)는 기본이 HTTPS 입니다. 여기에
protocol: HTTP 로 붙으려 하면 맞는 entrypoint 가 없다고 나옵니다.
로드밸런서가 TLS 를 종료하고 plain HTTP 를 뒤로 보내는 구성이었습니다. Traefik 은 TLS 를 기대하고 있으니 충돌합니다.
Service 의 443 포트가 web entrypoint 로 가도록 targetPort 를 바꿨습니다.
kubectl patch svc traefik -n traefik --type='json' -p='[
{"op": "replace", "path": "/spec/ports/1/targetPort", "value": 8000}
]'
Gateway 에서도 websecure 리스너를 빼고 web 하나만 남겼습니다.
spec:
listeners:
- name: web
protocol: HTTP
port: 8000
allowedRoutes:
namespaces:
from: All
Helm chart v40의 ports.websecure.tls 제거
Error: values don't meet the specifications of the schema(s):
traefik:
- ports.websecure: Additional property tls is not allowed
Traefik Helm chart v40.x 에서 ports.websecure.tls 필드가 스키마에서
제거됐습니다. 값을 지우면 됩니다. websecure entrypoint 는 인증서가 없으면
TLS 없이 동작하거나, 위처럼 web entrypoint 하나로 통일해도 됩니다.
로드밸런서는 IP가 아닌 hostname 발급
NCloud NPLB 를 쓰는 환경이었습니다. AWS ALB 처럼 IP 를 DNS 에 직접 등록해야 한다고 생각했는데 아니었습니다.
NPLB 는 xxx.lb.naverncp.com 형태의 hostname 을 발급합니다. DNS 에
A(LB VPC) 타입으로 이 hostname 을 값으로 등록하면 IP 관리는 NCloud 가
합니다.
kubectl get svc -n traefik traefik
# EXTERNAL-IP: traefik-traefik-xxx.lb.naverncp.com
Namespace가 Terminating에서 멈춤
테스트 네임스페이스를 지우는데 멈췄습니다.
kubectl get namespace gateway-test
NAME STATUS AGE
gateway-test Terminating 16m
metrics.k8s.io/v1beta1 API 그룹 discovery 가 실패해서, 네임스페이스
컨트롤러가 리소스 정리가 끝났는지 확인하지 못하고 멈춘 상태였습니다.
spec.finalizers 를 빈 배열로 만들어 finalize 서브리소스에 직접 넣습니다.
kubectl get namespace gateway-test -o json | \
python3 -c "import sys,json; d=json.load(sys.stdin); d['spec']['finalizers']=[]; print(json.dumps(d))" | \
kubectl replace --raw /api/v1/namespaces/gateway-test/finalize -f -
남은 리소스 확인을 건너뛰고 지우는 방식이라, 정리가 덜 된 리소스가 있으면 그대로 고아로 남습니다. discovery 가 깨진 게 확실할 때만 씁니다.
댓글 0