kubernetes(K8s)学习笔记(第七期):网络与服务暴露
本笔记为 Kubernetes 系列第七期,聚焦集群网络与服务暴露的核心机制。涵盖:Service 概述与基本管理、Service 三种发现方式、五种 Service 类型、会话保持与金丝雀发布、kube-proxy 的 iptables 与 IPVS 两种工作模式详解、Ingress 控制器部署与生产级规则实践(多域名、多路径、重写、TLS、限流、跨域等 10+ 种注解)。所有命令和 YAML 示例均已经过整理和注释。全文约 4700 字 ,包含 35+ YAML 示例 、80+ 命令示例 和 18 张对比表格,是 Kubernetes 网络与服务暴露的完整指南。
--- Compiled and Authored by Whisky --- June 29th, 2026
目录
- Service 概述与基本管理
- Service 发现
- Service 类型
- Service 高级特性
- kube-proxy 工作原理
- Ingress 概述与控制器部署
- Ingress 规则实践
- 总结与知识点一览表
一、Service 概述与基本管理
1.1 为什么需要 Service?
在 Kubernetes 中,Pod 是临时的、动态的资源:
- 每个 Pod 有自己的 IP 地址(由网络插件分配)
- Pod 可能因故障、滚动更新、扩缩容而被销毁和重建
- 每次重建后 IP 地址会变化
这就带来一个问题:前端应用如何找到并连接到后端 Pod?
答案是 Service。
Service 的核心作用:
- 固定 IP 和 DNS 名称:无论后端 Pod 如何变化,Service 的 IP 和 DNS 不变
- 负载均衡:将流量分发到多个后端 Pod
- 服务发现:通过 DNS 或环境变量让应用自动发现服务
通俗比喻:Service 就像"前台总机"。每个员工(Pod)都有分机号(IP),分机号经常变动。但客户只需要打总机号码(Service IP),前台会自动转接到可用的员工(Pod)。
1.2 Service 与 Endpoints 的关系
Service 通过标签选择器(selector) 匹配后端 Pod,被匹配的 Pod IP 和端口会记录在 Endpoints 对象中。
bash
root@master30:~# kubectl create deployment web --image=httpd --replicas=3
root@master30:~# kubectl expose deployment web --port=8080 --target-port=80
root@master30:~# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web ClusterIP 10.103.19.150 <none> 8080/TCP 6m58s
root@master30:~# kubectl describe svc web
Name: web
IP: 10.103.19.150
Port: 8080-80 8080/TCP
TargetPort: 80/TCP
Endpoints: 10.224.193.67:80,10.224.193.68:80,10.224.41.131:80
root@master30:~# kubectl get endpoints
NAME ENDPOINTS AGE
web 10.224.193.67:80,10.224.193.68:80,10.224.41.131:80 7m
关键理解:Endpoints 是 Service 和 Pod 之间的桥梁。Service 不直接连接 Pod,而是通过 Endpoints 获取所有匹配 Pod 的地址列表。当 Pod 发生变动时,Endpoints 会自动更新,Service 无需任何配置变更即可感知新 Pod。
1.3 通过 YAML 创建 Service
bash
root@master30:~# kubectl create service clusterip web --tcp=8080:80 -o yaml --dry-run=client > svc-web.yaml
yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
spec:
ports:
- name: web-8080-80
port: 8080
protocol: TCP
targetPort: 80
selector:
app: web
type: ClusterIP
注意 :spec.selector 中指定的标签必须与 Pod 的标签完全匹配,否则 Service 将无法发现后端 Pod,Endpoints 列表将为空。
二、Service 发现
所谓 Service 发现,是指集群内应用如何访问 Service。我们介绍三种方式:
| 方式 | 说明 | 适用场景 |
|---|---|---|
| IP 访问 | 直接使用 Service 的 ClusterIP | 临时调试、硬编码(不推荐) |
| 环境变量 | Pod 启动时注入 Service 信息 | 简单场景,但需注意创建顺序 |
| DNS 访问 | 通过 DNS 名称访问(CoreDNS) | 生产环境推荐 |
2.1 通过 IP 访问 Service
实验:部署 MySQL Service,使用 IP 访问。
bash
# 1. 创建 MySQL Pod
root@master30:~# kubectl run mysql --image=mysql \
--env=MYSQL_ROOT_PASSWORD=redhat \
--env=MYSQL_USER=tom \
--env=MYSQL_PASSWORD=redhat \
--env=MYSQL_DATABASE=blog
# 2. 创建 Service
root@master30:~# kubectl expose pod mysql --port=3306 --target-port=3306
root@master30:~# kubectl get svc mysql
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mysql ClusterIP 10.111.69.45 <none> 3306/TCP 25m
# 3. 测试连接
root@master30:~# apt install -y mysql-client
root@master30:~# mysql -u tom -predhat -h 10.111.69.45 -e 'show databases;'
+--------------------+
| Database |
+--------------------+
| information_schema |
| blog |
+--------------------+
2.2 通过环境变量访问 Service
当 Pod 启动时,Kubernetes 会自动注入所有 Service 的环境变量。
bash
root@master30:~# kubectl run test --rm -it --image=busybox sh
/ # env | grep MYSQL
MYSQL_PORT_3306_TCP_ADDR=10.111.69.45
MYSQL_PORT_3306_TCP_PORT=3306
MYSQL_SERVICE_HOST=10.111.69.45
MYSQL_SERVICE_PORT=3306
MYSQL_PORT=tcp://10.111.69.45:3306
/ # exit
环境变量命名规则:
<SERVICE_NAME>_SERVICE_HOST:Service IP<SERVICE_NAME>_SERVICE_PORT:Service 端口<SERVICE_NAME>_PORT_<port>_TCP_ADDR:具体端口对应的 IP
⚠️ 前提条件 :Service 必须在 Pod 之前创建,否则环境变量不会注入。如果 Service 后创建,Pod 需要重启才能获取环境变量。
实验:WordPress 通过环境变量连接 MySQL。
bash
root@master30:~# kubectl run wordpress \
--image=wordpress \
--env=WORDPRESS_DB_USER=tom \
--env=WORDPRESS_DB_PASSWORD=redhat \
--env=WORDPRESS_DB_NAME=blog \
--env=WORDPRESS_DB_HOST='$(MYSQL_SERVICE_HOST)'
2.3 通过 DNS 名称访问 Service(推荐)
Kubernetes 集群默认部署 CoreDNS 作为 DNS 服务器。
bash
root@master30:~# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 3d2h
DNS 记录格式 :<service-name>.<namespace>.svc.cluster.local
简化写法:
- 同 Namespace:直接使用 Service 名称(如
wordpress) - 跨 Namespace:使用
<service>.<namespace>(如wordpress.default)
bash
root@master30:~# kubectl run busybox --rm -it --image=busybox sh
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search service.svc.cluster.local svc.cluster.local cluster.local
/ # wget -q -O- wordpress:80
<html><body><h1>It works!</h1></body></html>
三、Service 类型
Kubernetes Service 支持以下五种类型:
| 类型 | 说明 | 访问范围 |
|---|---|---|
| ClusterIP(默认) | 集群内部 IP | 仅集群内 |
| NodePort | 节点端口映射 | 集群内外均可(通过节点 IP+端口) |
| LoadBalancer | 外部负载均衡器 IP | 集群内外均可(通过 LB IP) |
| ExternalName | DNS CNAME 映射 | 集群内(DNS 级别) |
| Headless | ClusterIP=None | 直接访问 Pod IP |
3.1 ClusterIP(默认)
ClusterIP 是默认类型,只能在集群内部访问。
yaml
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP
ports:
- port: 8080
targetPort: 80
selector:
app: web
3.2 NodePort
NodePort 在每个节点上打开一个端口(默认范围 30000-32767),将流量转发到 Service。
bash
root@master30:~# kubectl expose deployment web --type=NodePort --port=8080 --target-port=80
root@master30:~# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web NodePort 10.110.40.0 <none> 8080:31917/TCP 48s
三个端口的关系:
| 端口 | 含义 | 示例 |
|---|---|---|
| nodePort | 节点上监听的端口(用户访问入口) | 31917 |
| port | ClusterIP 上监听的端口 | 8080 |
| targetPort | Pod 监听的端口 | 80 |
NodePort 端口分配机制:
- Kubernetes 从
--service-node-port-range标志指定的范围内分配端口 - 默认范围:30000-32767
- 如果用户没有指定,系统自动分配一个空闲端口
- 用户也可以手动指定,但需确保端口不冲突
bash
root@client:~# curl http://10.1.8.30:31917 # 通过任意节点 IP 访问
root@client:~# curl http://10.1.8.31:31917
root@client:~# curl http://10.1.8.32:31917
指定固定 NodePort:
yaml
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: NodePort
ports:
- port: 8080
targetPort: 80
nodePort: 30080 # 固定端口,需在 30000-32767 范围内
selector:
app: web
3.3 LoadBalancer
LoadBalancer 类型需要外部负载均衡器支持。在裸金属环境中,可以使用 MetalLB。
部署 MetalLB:
bash
root@master30:~# wget http://192.168.42.200/course-materials/softwares/stage03/metallb-0.14.8.tar.gz
root@master30:~# tar -xf metallb-0.14.8.tar.gz
root@master30:~# sed -i 's/quay.io/hub.whisky.cloud/g' metallb-0.14.8/config/manifests/metallb-native.yaml
root@master30:~# kubectl apply -f metallb-0.14.8/config/manifests/metallb-native.yaml
# 等待所有 Pod 正常运行
root@master30:~# kubectl get all -n metallb-system
配置 IP 地址池:
yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 10.1.8.40-10.1.8.80 # 可用的 IP 范围
配置 L2 通告:
yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
创建 LoadBalancer Service:
bash
root@master30:~# kubectl expose deployment web --type=LoadBalancer --port=80 --target-port=80
root@master30:~# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web LoadBalancer 10.109.101.67 10.1.8.40 80:32101/TCP 5s
[root@client ~]# curl 10.1.8.40:80
<html><body><h1>It works!</h1></body></html>
MetalLB 工作流程图:
text
客户端 → MetalLB VIP (10.1.8.40) → 节点 kube-proxy → Service → 后端 Pod
MetalLB 只做 ARP 宣告 + IP 占坑,实际的流量转发由 kube-proxy 完成。
3.4 ExternalName
ExternalName 将 Service 映射到外部 DNS 名称,在 DNS 级别返回 CNAME 记录。
yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ExternalName
externalName: database.example.com
访问 my-service.prod.svc.cluster.local 会被解析为 database.example.com。
适用场景:将集群内服务访问透明地重定向到外部服务,无需修改应用代码。
3.5 Headless Service
当不需要负载均衡和 ClusterIP 时,可以将 clusterIP 设为 None。
yaml
apiVersion: v1
kind: Service
metadata:
name: headless-web
spec:
clusterIP: None
selector:
app: web
ports:
- port: 80
targetPort: 80
行为差异:
- 带 selector:DNS 返回 Pod IP 列表(A 记录),适合 StatefulSet 直接访问 Pod
- 无 selector:需要手动配置 Endpoints,适合接入外部服务
四、Service 高级特性
4.1 会话保持(sessionAffinity)
默认情况下,Service 将请求轮询分发到所有后端 Pod。如果希望同一客户端的请求始终发往同一 Pod,可以启用会话保持。
bash
# 默认无会话保持
root@master30:~# for i in {1..20}; do curl -s 10.111.90.183; done | sort | uniq -c
10 web-6db76cb4fc-5gbx2
10 web-6db76cb4fc-b8f7l
# 启用会话保持(基于 ClientIP)
root@master30:~# kubectl patch svc web -p '{"spec":{"sessionAffinity":"ClientIP"}}'
# 再次测试:所有请求都发往同一个 Pod
root@master30:~# for i in {1..20}; do curl -s 10.111.90.183; done | sort | uniq -c
20 web-6db76cb4fc-5gbx2
会话保持与 IPVS 的关系:
- Service 配置
sessionAffinity: ClientIP→ kube-proxy 自动使用 IPVS 的 SH(源地址哈希) 算法 - 默认情况下,IPVS 使用 rr(轮询) 算法
- 超时时间:
.spec.sessionAffinityConfig.clientIP.timeoutSeconds(默认 10800 秒,即 3 小时)
配置超时时间示例:
yaml
apiVersion: v1
kind: Service
metadata:
name: web
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 7200 # 2 小时
selector:
app: web
ports:
- port: 80
4.2 金丝雀发布
利用 Service 标签选择器 的灵活性,可以实现金丝雀发布------同时运行稳定版和测试版,通过调整副本数控制流量比例。
核心思想 :同一个 Service 匹配多个 Deployment(它们有相同的 app 和 tier 标签,但 track 不同)。
bash
# 创建 ConfigMap
root@master30:~# echo "hello nginx 1.28" > web/index28.html
root@master30:~# echo "hello nginx 1.29" > web/index29.html
root@master30:~# kubectl create configmap web --from-file=./web
# 部署稳定版(track: stable)
root@master30:~# kubectl apply -f webapp-1.28.yaml
# 部署金丝雀版(track: canary)
root@master30:~# kubectl apply -f webapp-1.29.yaml
# 创建 Service(匹配 app: web, tier: frontend)
root@master30:~# kubectl apply -f webapp-svc.yaml
# 调整副本数控制流量比例
root@master30:~# kubectl scale deployment web-28 --replicas=8
root@master30:~# kubectl scale deployment web-29 --replicas=2
root@master30:~# for i in {1..50}; do curl -s 10.98.235.36; done | sort | uniq -c
39 hello nginx 1.28
11 hello nginx 1.29
五、kube-proxy 工作原理
kube-proxy 是 Kubernetes 网络的核心组件,负责实现 Service 到后端 Pod 的流量转发与负载均衡。
5.1 三种工作模式对比
| 模式 | 地位 | 性能 | 适用场景 |
|---|---|---|---|
| iptables | 默认模式 | 中(服务数 < 1000) | 小规模集群 |
| IPVS | 推荐模式 | 极高(服务数 10w+) | 中大规模生产环境 |
| Userspace | 已废弃 | 低 | 仅测试、兼容旧版 |
5.2 iptables 模式详解
iptables 模式是 kube-proxy 的默认模式。它利用 Linux 内核的 netfilter 框架,通过动态生成 iptables 规则实现流量转发。
工作原理:
客户端访问 Service IP → 进入 KUBE-SERVICES 链 → 匹配到 KUBE-SVC-XXX 链 → 随机概率选择 KUBE-SEP-XXX 链 → DNAT 到后端 Pod
iptables-save 分析:
bash
# 保存防火墙规则
root@master30:~# iptables-save > iptables.list
# 1. 服务入口链:匹配 ClusterIP
-A KUBE-SERVICES -d 10.103.143.120/32 -p tcp --dport 80 -j KUBE-SVC-7D76YWGERGEPC4GC
# 2. 服务调度链:负载均衡(概率匹配)
-A KUBE-SVC-7D76YWGERGEPC4GC -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-HYZM2VM7RCC7M2HX
-A KUBE-SVC-7D76YWGERGEPC4GC -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CHPZVFCOFL4YLCYM
-A KUBE-SVC-7D76YWGERGEPC4GC -j KUBE-SEP-HM7RLUR2RXSQ3D6F
# 3. 后端端点链:DNAT 到 Pod
-A KUBE-SEP-HYZM2VM7RCC7M2HX -p tcp -j DNAT --to-destination 10.224.113.164:80
iptables 模式流程图:
ini
┌─────────────────────────────────────────────────────────────────────────────┐
│ iptables 模式流量转发全链路 │
└─────────────────────────────────────────────────────────────────────────────┘
客户端
│ 访问 ClusterIP 10.103.143.120:80
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ ① PREROUTING 链 (nat 表) │
│ 拦截所有进入本机的数据包 │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ ② KUBE-SERVICES(服务总入口链) │
│ 匹配条件:目的 IP = 10.103.143.120,目的端口 = 80 │
│ 动作:跳转到 KUBE-SVC-7D76YWGERGEPC4GC │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ ③ KUBE-SVC-XXX(Service 专属调度链) │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 检查:源 IP 是否在 Pod 网段(10.224.0.0/16)内? │ │
│ │ 否 → SNAT 标记(跳转 KUBE-MARK-MASQ)后继续处理 │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 分支 1 │ │ 分支 2 │ │ 分支 3 │ │
│ │ 概率 1/3 │ │ 概率 1/3 │ │ 概率 1/3 │ │
│ │ KUBE-SEP-A │ │ KUBE-SEP-B │ │ KUBE-SEP-C │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ ④ DNAT │ │ ④ DNAT │ │ ④ DNAT │
│ 转发到: │ │ 转发到: │ │ 转发到: │
│ Pod 1 │ │ Pod 2 │ │ Pod 3 │
│ 10.224 │ │ 10.224 │ │ 10.224 │
│ .113.164:80 │ │ .113.165:80 │ │ .19.38:80 │
└─────────────┘ └─────────────┘ └─────────────┘
缺点:服务数超过 1000 时,规则链膨胀,CPU 占用飙升,延迟显著增加。
5.3 IPVS 模式详解(生产推荐)
IPVS(IP Virtual Server)是 Linux 内核的负载均衡模块,使用哈希表存储规则,查找效率为 O(1)。
切换为 IPVS 模式:
bash
# 1. 修改 kube-proxy ConfigMap
root@master30:~# kubectl edit configmap -n kube-system kube-proxy
# 将 mode: "" 改为 mode: "ipvs"
# 2. 重启 kube-proxy
root@master30:~# kubectl rollout restart daemonset -n kube-system kube-proxy
# 3. 验证模式
root@master30:~# kubectl logs -n kube-system kube-proxy-72b7j | grep Using
I0415 13:22:14.052593 1 server_linux.go:233] "Using ipvs Proxier"
IPVS 内核模块要求:
bash
# 加载 IPVS 内核模块
root@master30:~# modprobe ip_vs
root@master30:~# modprobe ip_vs_rr
root@master30:~# modprobe ip_vs_wrr
root@master30:~# modprobe ip_vs_lc
root@master30:~# modprobe ip_vs_sh
root@master30:~# modprobe nf_conntrack
验证 IPVS 规则:
bash
root@master30:~# ipvsadm -Lnt 10.103.143.120:80
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.103.143.120:80 rr
-> 10.224.19.38:80 Masq 1 0 0
-> 10.224.113.164:80 Masq 1 0 0
-> 10.224.113.165:80 Masq 1 0 0
IPVS 调度算法:
| 算法 | 说明 | 适用场景 |
|---|---|---|
rr |
轮询 | 默认,通用场景 |
wrr |
加权轮询 | 节点性能不均 |
lc |
最少连接 | 长连接、WebSocket |
sh |
源地址哈希 | 配合 sessionAffinity |
sed |
最短预期延迟 | 低延迟场景 |
nq |
最少队列 | 公平分配 |
IPVS vs iptables 性能对比:
| 对比项 | iptables | IPVS |
|---|---|---|
| 规则查找 | O(n) 线性 | O(1) 哈希 |
| 服务数上限 | ~1000 | 100000+ |
| 规则同步延迟 | 随规则数增加 | 恒定 |
| 调度算法 | 仅随机概率 | 8 种算法 |
六、Ingress 概述与控制器部署
6.1 什么是 Ingress?
Ingress 是 Kubernetes 中用于管理外部访问集群服务的 API 对象,提供 HTTP/HTTPS 路由能力。
Ingress vs Service:
| 对比项 | Service(NodePort/LoadBalancer) | Ingress |
|---|---|---|
| 协议 | TCP/UDP | HTTP/HTTPS(7 层) |
| 路由能力 | 仅端口映射 | 域名、路径、SSL 等 |
| 成本 | 每个服务一个 LB IP | 多个服务共享一个 LB IP |
Ingress 架构:
text
客户端 → Ingress Controller (Nginx) → Service → Pod
Ingress 资源 定义路由规则,Ingress Controller 负责执行这些规则。
6.2 ingress-nginx 部署
前提:集群中已部署 MetalLB(用于提供 LoadBalancer IP)。
bash
root@master30:~# kubectl apply -f ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
查看部署状态:
bash
root@master30:~# kubectl get all -n ingress-nginx
NAME READY STATUS
pod/ingress-nginx-controller-596db54d7-cgbdd 1/1 Running
NAME TYPE CLUSTER-IP EXTERNAL-IP
service/ingress-nginx-controller LoadBalancer 10.107.255.83 10.1.8.40
七、Ingress 规则实践
7.1 基础规则
规则一:多域名虚拟主机(多 host 路由)
场景:不同域名转发到不同 Service。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-host-ingress
spec:
ingressClassName: nginx
rules:
- host: webapp01.whisky.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
- host: webapp02.whisky.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp02
port:
number: 80
规则二:同一域名多路径路由(path 分流)
场景:同一个域名,不同路径转发给不同 Service。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-path-ingress
spec:
ingressClassName: nginx
rules:
- host: www.whisky.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
- path: /games
pathType: Prefix
backend:
service:
name: webapp02
port:
number: 80
7.2 生产级注解规则
规则三:路径重写(rewrite-target)
场景 :前端访问 /webapp01/api,后端只识别 /api,需要剥离前缀。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rewrite-ingress
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
ingressClassName: nginx
rules:
- host: www.whisky.cloud
http:
paths:
- path: /webapp01/(.*)
pathType: ImplementationSpecific
backend:
service:
name: webapp01
port:
number: 80
原理说明 :rewrite-target: /$1 表示将正则表达式中第一个括号匹配的内容作为新路径。例如 /webapp01/api/hello 会被重写为 /api/hello 转发给后端。
规则四:TLS 证书绑定 + 强制 HTTPS
bash
# 1. 生成自签名证书
root@master30:~# openssl genrsa -out www.key 2048
root@master30:~# openssl req -new -key www.key -out www.csr -subj "/CN=www.whisky.cloud"
root@master30:~# openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt
# 2. 创建 Secret
root@master30:~# kubectl create secret tls www-tls --cert=./www.crt --key=./www.key
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- www.whisky.cloud
secretName: www-tls
rules:
- host: www.whisky.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
验证:
bash
[root@client ~]# curl -Lk http://www.whisky.cloud/ # 自动跳转 HTTPS
[root@client ~]# curl -k https://www.whisky.cloud/
规则五:限流与防刷
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rate-limit-ingress
annotations:
nginx.ingress.kubernetes.io/limit-rps: "20"
nginx.ingress.kubernetes.io/limit-connections: "50"
spec:
ingressClassName: nginx
rules:
- host: www.whisky.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
规则六:自定义超时时间
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: timeout-ingress
annotations:
nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
spec:
ingressClassName: nginx
rules:
- host: www.whisky.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
规则七:跨域配置
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cors-ingress
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET,POST,PUT,DELETE,OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization"
spec:
ingressClassName: nginx
rules:
- host: api.whisky.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
规则八:IP 白名单
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: whitelist-ingress
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "10.1.8.0/24,127.0.0.1/32"
spec:
ingressClassName: nginx
rules:
- host: admin.whisky.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
规则九:透传真实客户端 IP
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: xff-ingress
annotations:
nginx.ingress.kubernetes.io/x-forwarded-for: "true"
nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "10.0.0.0/8"
spec:
ingressClassName: nginx
rules:
- host: www.whisky.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01
port:
number: 80
规则十:金丝雀发布(权重分流)
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: canary-ingress
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
ingressClassName: nginx
rules:
- host: www.whisky.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp01-canary
port:
number: 80
说明 :此规则需要与稳定版的 Ingress 配合使用。稳定版 Ingress 没有
canary: "true"注解,金丝雀版添加此注解和权重,10% 的流量会进入金丝雀 Service。
7.3 生产高频注解速查表
| 注解 | 作用 | 示例 |
|---|---|---|
ssl-redirect: "true" |
80 端口强制跳转 HTTPS | nginx.ingress.kubernetes.io/ssl-redirect: "true" |
rewrite-target |
路径重写,裁剪前缀 | nginx.ingress.kubernetes.io/rewrite-target: /$1 |
use-regex |
启用正则表达式匹配 | nginx.ingress.kubernetes.io/use-regex: "true" |
limit-rps |
单 IP 每秒请求数限制 | nginx.ingress.kubernetes.io/limit-rps: "20" |
limit-connections |
单 IP 最大并发连接数 | nginx.ingress.kubernetes.io/limit-connections: "50" |
enable-cors |
启用跨域 | nginx.ingress.kubernetes.io/enable-cors: "true" |
cors-allow-origin |
跨域允许的源 | nginx.ingress.kubernetes.io/cors-allow-origin: "*" |
whitelist-source-range |
IP 白名单 | nginx.ingress.kubernetes.io/whitelist-source-range: "10.1.8.0/24" |
proxy-read-timeout |
读取超时时间 | nginx.ingress.kubernetes.io/proxy-read-timeout: "60" |
x-forwarded-for |
透传真实客户端 IP | nginx.ingress.kubernetes.io/x-forwarded-for: "true" |
canary |
启用金丝雀发布 | nginx.ingress.kubernetes.io/canary: "true" |
canary-weight |
金丝雀流量权重 | nginx.ingress.kubernetes.io/canary-weight: "10" |
八、总结与知识点一览表
8.1 Service 类型对比
| 类型 | ClusterIP | NodePort | LoadBalancer | ExternalName | Headless |
|---|---|---|---|---|---|
| 访问范围 | 集群内 | 节点 IP+端口 | 外部 LB IP | DNS CNAME | 集群内 |
| 负载均衡 | ✅ | ✅ | ✅ | ❌ | ❌ |
| 适用场景 | 内部服务 | 简单外部暴露 | 生产外部暴露 | 外部服务别名 | StatefulSet |
8.2 Service 发现方式对比
| 方式 | 优点 | 缺点 |
|---|---|---|
| IP | 简单直接 | IP 变化,硬编码不推荐 |
| 环境变量 | 自动注入 | 依赖创建顺序 |
| DNS | 灵活、动态 | 需要 CoreDNS |
8.3 kube-proxy 模式对比
| 模式 | 性能 | 规则结构 | 调度算法 | 适用场景 |
|---|---|---|---|---|
| iptables | 中 | 线性链表 | 随机概率 | 小规模集群 |
| IPVS | 极高 | 哈希表 | rr/wrr/lc/sh 等 | 大规模生产环境 |
8.4 Ingress 注解分类速查
| 分类 | 注解 |
|---|---|
| 路由 | rewrite-target, use-regex |
| 安全 | ssl-redirect, whitelist-source-range |
| 限流 | limit-rps, limit-connections |
| 跨域 | enable-cors, cors-allow-origin |
| 超时 | proxy-read-timeout, proxy-connect-timeout |
| 灰度 | canary, canary-weight |
| 客户端 | x-forwarded-for |
8.5 常见错误排查
| 错误 | 原因 | 解决方法 |
|---|---|---|
Connection refused |
Service 端口或 targetPort 不匹配 | 检查 port 和 targetPort |
No endpoints |
Service selector 不匹配任何 Pod | 检查 Pod 标签 |
ExternalIP 不通 |
MetalLB 未配置 | 检查 IPAddressPool 和 L2Advertisement |
| Ingress 404 | 路径匹配规则不正确 | 检查 pathType 和路径格式 |
| Ingress 证书错误 | TLS Secret 不存在或格式错误 | 检查 Secret 名称和 key 名称 |
| kube-proxy 切换 IPVS 失败 | 内核未加载 IPVS 模块 | modprobe ip_vs |
| 限流不生效 | 未正确配置注解 | 确认注解拼写,查看 Ingress Controller 日志 |
8.6 生产环境最佳实践
| 实践 | 说明 |
|---|---|
| 优先使用 DNS 发现 | 避免硬编码 IP 和依赖创建顺序 |
| 生产环境使用 IPVS 模式 | 性能更优,支持更多调度算法 |
| Ingress 统一管理入口 | 多个服务共享一个 LB,降低成本 |
| 配置合理的限流 | 防止单 IP 攻击和流量突增 |
| 启用 TLS/HTTPS | 生产环境必须加密传输 |
| 使用路径重写适配后端 | 保持前后端路由一致性 |
| 金丝雀发布验证新版本 | 降低上线风险 |
下一期预告:Kubernetes 调度与资源管理------节点亲和性、Pod 亲和性/反亲和性、污点与容忍、资源请求与限制、Horizontal Pod Autoscaler(HPA)。
--- Compiled and Authored by Whisky --- June 29th, 2026