前言

在上一篇文章中,我們學習了 Service 的基本概念和四種類型。本篇將更深入地探討 Kubernetes 的網路模型,包括:

  • 服務發現:Pod 如何找到其他服務?
  • Ingress:如何將外部流量路由到叢集內部?
  • 網路策略:如何控制 Pod 之間的網路通訊?

理解這些概念,你就能設計出安全、高效的 K8s 網路架構。


Kubernetes 網路模型

核心原則

K8s 網路模型基於幾個基本原則:

  1. 每個 Pod 有唯一 IP:Pod 不共享 IP,簡化通訊模型
  2. Pod 之間可直接通訊:無需 NAT,任何 Pod 可直接連線到任何其他 Pod
  3. 節點與 Pod 可直接通訊:節點上的程式可直接連線 Pod
  4. Pod 看到的 IP 與其他人看到的相同:沒有隱藏的 NAT
graph TD
    subgraph "Node 1 (10.0.1.1)"
        P1[Pod A<br/>10.244.1.5]
        P2[Pod B<br/>10.244.1.8]
    end

    subgraph "Node 2 (10.0.1.2)"
        P3[Pod C<br/>10.244.2.3]
        P4[Pod D<br/>10.244.2.7]
    end

    P1 <-->|直接通訊| P3
    P2 <-->|直接通訊| P4
    P1 <-->|同節點| P2

CNI(Container Network Interface)

CNI 是 K8s 網路的插件標準,常見的 CNI 實現:

CNI 插件 特點 適用場景
Calico 性能優異、支援網路策略 生產環境首選
Flannel 簡單易用 入門學習、小型叢集
Cilium 基於 eBPF、功能強大 高度可觀測性需求
Weave 多叢集支援 跨雲環境

服務發現機制

DNS 服務發現

K8s 內建 CoreDNS 提供 DNS 服務發現,這是最推薦的方式。

graph LR
    POD[Pod] -->|DNS 查詢| DNS[CoreDNS]
    DNS -->|返回 ClusterIP| POD
    POD -->|連線| SVC[Service]
    SVC -->|負載均衡| P1[Pod 1]
    SVC --> P2[Pod 2]

DNS 命名規則

1
2
3
4
5
6
7
8
9
# Service DNS 格式
<service-name>.<namespace>.svc.cluster.local

# 範例
nginx-service.default.svc.cluster.local

# 簡寫(同 namespace 內)
nginx-service
nginx-service.default

DNS 查詢實驗

1
2
3
4
5
6
7
8
9
10
11
12
# 進入一個 Pod
kubectl run debug --image=busybox --rm -it -- /bin/sh

# DNS 查詢
nslookup kubernetes
# Server: 10.96.0.10
# Address: 10.96.0.10:53
# Name: kubernetes.default.svc.cluster.local
# Address: 10.96.0.1

# 查詢其他 service
nslookup nginx-service.default.svc.cluster.local

環境變數發現

K8s 也會自動注入 Service 相關的環境變數到 Pod 中:

1
2
3
4
5
6
7
# 自動注入的環境變數格式
{SERVICE_NAME}_SERVICE_HOST
{SERVICE_NAME}_SERVICE_PORT

# 範例
echo $NGINX_SERVICE_SERVICE_HOST # 10.96.123.45
echo $NGINX_SERVICE_SERVICE_PORT # 80

注意:環境變數方式有順序依賴(Service 必須在 Pod 前創建),DNS 方式沒有這個限制,推薦使用 DNS。


Ingress:外部流量入口

為什麼需要 Ingress?

方式 問題
NodePort 每個服務需要一個端口,管理複雜
LoadBalancer 每個服務需要一個 LB,成本高昂
Ingress 一個入口管理多個服務,支援路由規則
graph TD
    USER[使用者] -->|HTTPS| ING[Ingress Controller]

    ING -->|/api| API[API Service]
    ING -->|/web| WEB[Web Service]
    ING -->|/admin| ADMIN[Admin Service]

    API --> AP1[API Pod 1]
    API --> AP2[API Pod 2]

    WEB --> WP1[Web Pod 1]
    WEB --> WP2[Web Pod 2]

    ADMIN --> ADP1[Admin Pod]

Ingress 與 Ingress Controller

Ingress 是一種 K8s 資源,定義外部存取規則。
Ingress Controller 是實際處理流量的組件,需要單獨安裝。

常見的 Ingress Controller:

Controller 特點
Nginx Ingress 最廣泛使用,功能豐富
Traefik 配置簡單,自動服務發現
Kong 豐富的 API 閘道功能
AWS ALB AWS 原生整合

安裝 Nginx Ingress Controller

1
2
3
4
5
6
7
8
9
10
# 使用 Helm 安裝
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx

# 或使用 kubectl(Minikube)
minikube addons enable ingress

# 驗證安裝
kubectl get pods -n ingress-nginx

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
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-based-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /api
pathType: Prefix # Exact, Prefix, ImplementationSpecific
backend:
service:
name: api-service
port:
number: 80
- path: /web
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80

基於主機的路由

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: host-based-ingress
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- host: web.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80

配置 TLS/HTTPS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- secure.example.com
secretName: tls-secret # 包含 TLS 憑證的 Secret
rules:
- host: secure.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: secure-service
port:
number: 443
1
2
3
4
# 創建 TLS Secret
kubectl create secret tls tls-secret \
--cert=path/to/cert.pem \
--key=path/to/key.pem

常用 Nginx 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
metadata:
annotations:
# 重寫路徑
nginx.ingress.kubernetes.io/rewrite-target: /$1

# 限制請求大小
nginx.ingress.kubernetes.io/proxy-body-size: "10m"

# 連線超時
nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"

# 啟用 CORS
nginx.ingress.kubernetes.io/enable-cors: "true"

# 速率限制
nginx.ingress.kubernetes.io/limit-rps: "10"

# 白名單 IP
nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,172.16.0.0/12"

# WebSocket 支援
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
nginx.ingress.kubernetes.io/upstream-hash-by: "$request_uri"

網路策略(Network Policy)

為什麼需要網路策略?

預設情況下,K8s 叢集中的所有 Pod 可以互相通訊。這在安全敏感的環境中可能造成風險。

網路策略允許你定義 Pod 之間的通訊規則。

graph LR
    subgraph "前端"
        FE[Frontend Pod]
    end

    subgraph "後端"
        BE[Backend Pod]
    end

    subgraph "資料庫"
        DB[(Database Pod)]
    end

    FE -->|允許| BE
    BE -->|允許| DB
    FE -.->|阻擋| DB

網路策略範例

拒絕所有入站流量

1
2
3
4
5
6
7
8
9
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
spec:
podSelector: {} # 選擇所有 Pod
policyTypes:
- Ingress # 規範入站流量
# 沒有 ingress 規則 = 拒絕所有

只允許特定 Pod 存取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
spec:
podSelector:
matchLabels:
app: backend # 適用於 backend Pod
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # 只允許 frontend Pod
ports:
- protocol: TCP
port: 8080

只允許同一 Namespace 內通訊

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: production # 只允許來自同 namespace

允許特定 IP 段

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: NetworkPolicy
metadata:
name: allow-external-ip
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/8
except:
- 10.0.1.0/24 # 排除特定子網
ports:
- protocol: TCP
port: 443

網路策略最佳實踐

  1. 預設拒絕:先設定拒絕所有,再開放必要的通訊
  2. 最小權限:只開放必要的端口和來源
  3. 分層防護:前端 → 後端 → 資料庫,逐層限制
  4. Namespace 隔離:不同環境(dev/prod)使用不同 Namespace

負載均衡策略

Service 負載均衡

K8s Service 預設使用 輪詢(Round Robin) 進行負載均衡。

graph LR
    SVC[Service] -->|請求 1| P1[Pod 1]
    SVC -->|請求 2| P2[Pod 2]
    SVC -->|請求 3| P3[Pod 3]
    SVC -->|請求 4| P1

Session Affinity(會話親和性)

如果需要將同一客戶端的請求路由到同一 Pod:

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Service
metadata:
name: sticky-service
spec:
selector:
app: my-app
ports:
- port: 80
sessionAffinity: ClientIP # 基於客戶端 IP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 3600 # 親和性持續時間

實戰範例:完整網路配置

應用架構

graph TD
    USER[使用者] -->|HTTPS| ING[Ingress]

    ING -->|/api| APISVC[API Service]
    ING -->|/| WEBSVC[Web Service]

    APISVC --> API1[API Pod 1]
    APISVC --> API2[API Pod 2]

    WEBSVC --> WEB1[Web Pod 1]
    WEBSVC --> WEB2[Web Pod 2]

    API1 --> DBSVC[DB Service]
    API2 --> DBSVC

    DBSVC --> DB[(Database)]

完整配置

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# 1. Namespace
apiVersion: v1
kind: Namespace
metadata:
name: myapp
labels:
name: myapp

---
# 2. Database Deployment & Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: database
namespace: myapp
spec:
replicas: 1
selector:
matchLabels:
app: database
template:
metadata:
labels:
app: database
spec:
containers:
- name: postgres
image: postgres:15-alpine
ports:
- containerPort: 5432
env:
- name: POSTGRES_PASSWORD
value: secretpassword

---
apiVersion: v1
kind: Service
metadata:
name: database
namespace: myapp
spec:
selector:
app: database
ports:
- port: 5432

---
# 3. API Deployment & Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: myapp
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: my-api:latest
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
value: postgres://postgres:secretpassword@database:5432/mydb

---
apiVersion: v1
kind: Service
metadata:
name: api
namespace: myapp
spec:
selector:
app: api
ports:
- port: 80
targetPort: 8080

---
# 4. Web Deployment & Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: myapp
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:alpine
ports:
- containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
name: web
namespace: myapp
spec:
selector:
app: web
ports:
- port: 80

---
# 5. Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
namespace: myapp
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- host: myapp.local
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80

---
# 6. Network Policies
# 拒絕所有入站
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: myapp
spec:
podSelector: {}
policyTypes:
- Ingress

---
# 允許 Ingress 存取 Web 和 API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress
namespace: myapp
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- port: 80

---
# 允許 API 存取 Database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-to-db
namespace: myapp
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- port: 5432

本章重點回顧

網路模型

  1. 每個 Pod 有唯一 IP
  2. Pod 之間可直接通訊
  3. CNI 負責實現網路

服務發現

  1. DNS 優先:使用 <service>.<namespace>.svc.cluster.local
  2. CoreDNS:K8s 內建 DNS 服務

Ingress

  1. 統一入口:一個 Ingress 管理多個 Service
  2. 需要 Controller:Nginx Ingress 最常用
  3. 支援 TLS:配置 HTTPS 憑證

網路策略

  1. 預設全通:需要主動設定限制
  2. 白名單模式:先拒絕所有,再開放必要
  3. 分層防護:按應用層級設定策略

下一篇預告

在下一篇文章中,我們將探討 配置與存儲

  • ConfigMap 配置管理
  • Secret 密鑰管理
  • Volume 類型與使用場景
  • PersistentVolume 與 PersistentVolumeClaim

系列文章導覽

  • Part 1:入門篇 - 認識 K8s 與核心架構
  • Part 2:基礎篇 - Pod、Deployment 與 Service
  • Part 3:網路篇 - 服務發現與流量管理(本篇)
  • Part 4:配置與存儲篇 - ConfigMap、Secret 與 Volume
  • Part 5:進階篇 - 資源管理與自動擴展
  • Part 6:實戰篇 - 部署完整微服務應用

參考資源