Post

[Kubernetes] Ingress와 Service 트래픽 흐름 완전 정리: NLB → Traefik → Pod

Kubernetes Ingress와 Service 동작 흐름 완전 정리

1. 기본 구성 요소

1.1. Service (ClusterIP)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
  - name: http
    port: 80
    targetPort: 8080
    protocol: TCP

역할: Traefik → 애플리케이션 Pod 연결

1.2. Ingress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "traefik"
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app-service
            port:
              number: 80

역할: 라우팅 규칙 정의 (Traefik에게 주는 설정 파일)

1.3. 기본 동작 흐름

1
2
3
4
5
6
7
8
9
사용자 요청
  ↓
http://myapp.example.com
  ↓
Ingress (Traefik)
  ↓
Service (my-app-service:80)
  ↓
Pod (app=my-app, port 8080)

2. NLB를 포함한 전체 아키텍처

2.1. 전체 구조

1
2
3
4
5
6
7
8
9
10
11
12
13
사용자
  ↓
DNS (myapp.example.com → NLB IP)
  ↓
AWS NLB (Network Load Balancer)
  ↓
Traefik Ingress Controller (NodePort Service)
  ↓
Ingress 규칙 매칭
  ↓
Service (ClusterIP)
  ↓
Pod

2.2. Traefik Service (NodePort 타입)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
  name: traefik
  namespace: api-gateway-system
spec:
  type: NodePort
  selector:
    app: traefik
  ports:
  - name: websecure
    port: 443
    targetPort: 8443
    nodePort: 31443

역할: NLB → Traefik Pod 연결

2.3. 상세 패킷 흐름

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[사용자] curl https://myapp.example.com/api
    ↓
[DNS] myapp.example.com → 52.78.123.45 (NLB)
    ↓
[NLB] 52.78.123.45:443
    ↓ (Target Group)
[Worker Node 1] 10.0.1.10:31443 (NodePort)
    ↓
[Traefik Pod] 10.244.1.5:8443 (Ingress Controller)
    ↓ (Ingress 규칙 매칭: host + path)
[Service] my-app-service:80 (ClusterIP: 10.100.50.20)
    ↓ (kube-proxy iptables)
[Pod] 10.244.2.15:8080 (실제 애플리케이션)
    ↓
[응답] 역순으로 반환

2.4. NLB vs ALB 비교

항목NLB (Network LB)ALB (Application LB)
OSI 계층L4 (TCP/UDP)L7 (HTTP/HTTPS)
성능매우 빠름 (백만 RPS)상대적으로 느림
라우팅IP/Port만Host, Path, Header 기반
SSL 종료Traefik에서 처리ALB에서 처리 가능
HyperCloud주로 사용선택적 사용

3. Service 2개의 역할

3.1. 구성

Service 1 — Traefik Service (NodePort)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
  name: traefik
  namespace: api-gateway-system
spec:
  type: NodePort
  selector:
    app: traefik
  ports:
  - name: websecure
    port: 443
    targetPort: 8443
    nodePort: 31443

Service 2 — Application Service (ClusterIP)

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
  - name: http
    port: 80
    targetPort: 8080

3.2. 흐름 요약

1
2
3
4
5
6
7
8
9
[NLB]
  ↓
[Service 1: traefik (NodePort 31443)]    ← 외부 진입점
  ↓
[Traefik Pod (Ingress Controller)]       ← L7 라우팅
  ↓ (Ingress 규칙 확인)
[Service 2: my-app-service (ClusterIP 80)] ← 내부 연결
  ↓
[Application Pod (8080)]

3.3. 왜 Service가 2개 필요한가?

Service 1 (Traefik Service):

  • 목적: 외부에서 Traefik Pod에 접근
  • 타입: NodePort (또는 LoadBalancer)
  • 이유: NLB는 Kubernetes 클러스터 외부에 있으므로 NodePort로 노출 필요

Service 2 (Application Service):

  • 목적: Traefik에서 애플리케이션 Pod로 트래픽 전달
  • 타입: ClusterIP (내부 통신 전용)
  • 이유: Ingress 리소스가 이 Service를 참조하여 Pod로 라우팅

4. Ingress 리소스의 역할

4.1. 핵심 개념

Ingress = Traefik에게 주는 라우팅 지시서 (설정 파일)

  • Service가 아님 ❌
  • 직접 트래픽을 받지 않음 ❌
  • Ingress Controller(Traefik)가 읽고 적용하는 규칙 ✅

4.2. Ingress vs Ingress Controller

항목IngressIngress Controller
종류Kubernetes 리소스 (설정)실제 Pod (프로그램)
역할“어디로 보낼지” 규칙 정의규칙을 읽고 실제 라우팅
형태YAML 매니페스트Traefik, Nginx 등
위치etcd에 저장Worker Node에서 실행

4.3. Ingress 동작 원리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  namespace: default
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: my-app-service  # 이 Service로 보내라!
            port:
              number: 80
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 80

Traefik 라우팅 처리 흐름:

1
2
3
4
5
6
7
8
9
요청: https://myapp.example.com/api/users
  ↓
Traefik: "Ingress 규칙 확인"
  ↓
Traefik: "host = myapp.example.com, path = /api 로 시작"
  ↓
Traefik: "Ingress에 my-app-service:80으로 보내라고 정의됨"
  ↓
Traefik: my-app-service로 프록시

4.4. Ingress가 필요한 이유

Ingress 없이 NodePort만 사용하면?

1
2
3
4
# 서비스마다 다른 NodePort 필요
Service 1: NodePort 31001 (app1.example.com)
Service 2: NodePort 31002 (app2.example.com)
Service 3: NodePort 31003 (app3.example.com)

Ingress 사용하면?

1
2
3
4
5
6
7
8
# NodePort는 Traefik 하나만 (30001)
# Ingress로 도메인/Path 기반 라우팅

Ingress:
  app1.example.com       → app1-service
  app2.example.com       → app2-service
  app3.example.com/api   → app3-service
  app3.example.com/admin → admin-service

장점: NodePort 하나만 열면 되고, 도메인/Path 기반 라우팅과 SSL 인증서 관리를 Traefik에서 중앙 처리할 수 있습니다.


5. Traefik Service 포트 분석

5.1. 실제 포트 구성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
apiVersion: v1
kind: Service
metadata:
  name: traefik
  namespace: api-gateway-system
spec:
  type: NodePort
  selector:
    app: traefik
  ports:
  - name: web
    nodePort: 30000
    port: 80
    protocol: TCP
    targetPort: web
  - name: websecure
    nodePort: 30001
    port: 443
    protocol: TCP
    targetPort: websecure
  - name: traefik
    nodePort: 30900
    port: 9000
    protocol: TCP
    targetPort: traefik
  - name: metrics
    nodePort: 31958
    port: 9100
    protocol: TCP
    targetPort: metrics
  - name: k8s
    nodePort: 30266
    port: 6443
    protocol: TCP
    targetPort: k8s

5.2. 포트별 역할

포트 이름NodePortService PorttargetPort역할
web3000080webHTTP 트래픽 (주 진입점)
websecure30001443websecureHTTPS 트래픽 (주 진입점)
traefik309009000traefikTraefik Dashboard
metrics319589100metricsPrometheus 메트릭
k8s302666443k8sKubernetes API 프록시

5.3. NLB Target Group 설정

1
2
3
4
5
6
7
8
9
Target Group 1 (HTTP)
- Protocol: TCP
- Port: 30000
- Targets: Worker Node 1~N의 IP

Target Group 2 (HTTPS)
- Protocol: TCP
- Port: 30001
- Targets: Worker Node 1~N의 IP

5.4. targetPort를 이름으로 쓰는 이유

Service에서:

1
2
3
4
5
ports:
- name: web
  nodePort: 30000
  port: 80
  targetPort: web   # 포트 이름으로 매칭

Traefik Pod에서:

1
2
3
4
5
containers:
- name: traefik
  ports:
  - name: web       # Service의 targetPort와 매칭
    containerPort: 8080

포트 번호 대신 이름을 사용하면 컨테이너 포트 번호가 바뀌어도 Service를 수정할 필요가 없어 유지보수가 편리합니다.


6. 실제 패킷 흐름

6.1. HTTP 트래픽 (포트 80)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[사용자] http://myapp.example.com
  ↓
[DNS] myapp.example.com → NLB IP
  ↓
[NLB] :80 → Worker Node들의 30000 포트로 분산
  ↓
[Worker Node] 10.0.1.10:30000 (NodePort)
  ↓
[Service: traefik] port:80 → targetPort:web
  ↓
[Traefik Pod] web 포트 (8080)
  ↓
[Ingress 규칙 확인]
  ↓
[ClusterIP Service: my-app-service:80]
  ↓
[Application Pod:8080]

6.2. HTTPS 트래픽 (포트 443) — 실무 주 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[사용자]
curl https://myapp.example.com/api/users
  ↓
[DNS 조회]
myapp.example.com → 52.78.123.45 (NLB)
  ↓
[NLB]
52.78.123.45:443
  ↓ Target Group (30001)
[Worker Node 1]
10.0.1.10:30001
  ↓ iptables (kube-proxy)
[Service: traefik]
port:443 → targetPort:websecure
  ↓
[Traefik Pod]
10.244.1.5:8443 (websecure 포트)
  ↓ TLS 종료 (인증서 검증)
  ↓ Ingress 규칙 확인
      - Host: myapp.example.com ✅
      - Path: /api              ✅
      - Backend: my-app-service:80
  ↓
[Service: my-app-service]
ClusterIP 10.100.50.20:80
  ↓ kube-proxy
[Application Pod]
10.244.2.15:8080
  ↓
[응답] 역순으로 반환

6.3. 관리 포트 접근

Traefik Dashboard:

1
2
3
4
5
6
# 외부에서 접근 (NodePort)
http://<worker-node-ip>:30900/dashboard/

# 또는 Port Forward
kubectl port-forward -n api-gateway-system svc/traefik 9000:9000
# 브라우저: http://localhost:9000/dashboard/

Prometheus 메트릭:

1
curl http://<worker-node-ip>:31958/metrics

7. 전체 구조 다이어그램

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
┌─────────────────────────────────────────────────────────┐
│                         사용자                            │
└────────────────────┬────────────────────────────────────┘
                     │
                     │ DNS 조회
                     │ myapp.example.com → 52.78.123.45
                     ▼
┌─────────────────────────────────────────────────────────┐
│              AWS NLB (52.78.123.45)                     │
│  Target Group: Worker Nodes :30001 (HTTPS)              │
└────────────────────┬────────────────────────────────────┘
                     │
                     │ TCP :30001
                     ▼
┌─────────────────────────────────────────────────────────┐
│           Worker Node (10.0.1.10:30001)                 │
│                  NodePort Service                        │
└────────────────────┬────────────────────────────────────┘
                     │
                     │ kube-proxy (iptables)
                     ▼
┌─────────────────────────────────────────────────────────┐
│   Service: traefik (NodePort)                           │
│   Selector: app=traefik                                 │
│   Port: 443 → targetPort: websecure                     │
└────────────────────┬────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│   Traefik Pod (10.244.1.5:8443)                         │
│   - TLS 종료                                             │
│   - Ingress 리소스 읽기 (etcd에서)                        │
│   - 라우팅 규칙 적용                                       │
└────────────────────┬────────────────────────────────────┘
                     │
                     │ Ingress 규칙:
                     │ host: myapp.example.com
                     │ path: /api
                     │ → my-app-service:80
                     ▼
┌─────────────────────────────────────────────────────────┐
│   Service: my-app-service (ClusterIP)                   │
│   Selector: app=my-app                                  │
│   Port: 80 → targetPort: 8080                           │
└────────────────────┬────────────────────────────────────┘
                     │
                     │ kube-proxy (iptables)
                     ▼
┌─────────────────────────────────────────────────────────┐
│   Application Pod (10.244.2.15:8080)                    │
│   Label: app=my-app                                     │
│   실제 애플리케이션 실행                                    │
└─────────────────────────────────────────────────────────┘

8. 확인 명령어 모음

Service 확인

1
2
3
4
5
6
7
8
# Traefik Service 확인 (NLB IP 확인)
kubectl get svc -n api-gateway-system traefik

# 애플리케이션 Service 확인
kubectl get svc -n default my-app-service

# Service 상세 정보
kubectl describe svc -n api-gateway-system traefik

Ingress 확인

1
2
3
4
5
6
7
8
# Ingress 목록
kubectl get ingress --all-namespaces

# Ingress 상세 정보 (Host, Path, Backend 확인)
kubectl describe ingress my-app-ingress -n default

# Ingress YAML 확인
kubectl get ingress my-app-ingress -n default -o yaml

Pod 확인

1
2
3
4
5
6
7
8
9
10
11
# Traefik Pod 확인
kubectl get pods -n api-gateway-system -l app=traefik

# 애플리케이션 Pod 확인
kubectl get pods -n default -l app=my-app

# Traefik Pod 로그
kubectl logs -n api-gateway-system <traefik-pod> -f

# Traefik Pod의 실제 리스닝 포트 확인
kubectl exec -it -n api-gateway-system <traefik-pod> -- netstat -tlnp

Endpoint 확인

1
2
3
4
5
# Service Endpoint 확인 (Pod 연결 상태)
kubectl get endpoints my-app-service -n default

# Traefik Service Endpoint
kubectl get endpoints traefik -n api-gateway-system

트러블슈팅 체크리스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. DNS → NLB 연결 확인
nslookup myapp.example.com

# 2. NLB → Node 연결
# AWS Console에서 Target Group Health 확인

# 3. Node → Traefik Service 확인
kubectl get svc -n api-gateway-system traefik

# 4. Traefik → Service (Ingress 규칙 확인)
kubectl describe ingress my-app-ingress -n default

# 5. Service → Pod (Endpoint 확인)
kubectl get endpoints my-app-service -n default

# 6. Traefik이 Ingress를 인식했는지 확인
kubectl logs -n api-gateway-system <traefik-pod> | grep -i ingress

# 7. 실제 연결 테스트
curl -v https://myapp.example.com

9. 핵심 정리

각 구성 요소의 역할을 한 줄로 정리하면 아래와 같습니다.

구성 요소역할
NLB외부에서 Kubernetes 클러스터로 진입하는 L4 로드밸런서
NodePort Service (traefik)NLB와 Traefik Pod를 연결 (30001 포트)
Traefik PodIngress Controller로 실제 L7 라우팅 수행
Ingress 리소스Traefik에게 주는 라우팅 규칙 (설정 파일, etcd 저장)
ClusterIP ServiceTraefik과 애플리케이션 Pod 연결 (내부 통신)
Application Pod실제 애플리케이션이 실행되는 컨테이너

데이터 흐름 한 줄 요약:

1
NLB → NodePort(traefik) → Traefik Pod → (Ingress 규칙 확인) → ClusterIP Service → Application Pod

참고 자료

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.