写在前面
本文是 K8s 学习笔记系列的第四篇,介绍 K8s 的服务发现和网络机制:Service、Ingress 和 DNS。前置知识:工作负载管理(第三篇)。
一、Service 概述
Pod 的 IP 是不固定的(重启后会变),Service 提供稳定的访问入口。
1
|
客户端 → Service(固定 IP + 固定 DNS)→ Pod(通过标签选择器自动转发)
|
1.1 Service 工作原理
1
2
3
4
|
1. Service 通过 selector 匹配 Pod 的标签
2. kube-proxy 在每个节点上配置转发规则
3. 客户端访问 Service IP,流量被转发到后端 Pod
4. Pod 变化时,Service 自动更新后端列表(Endpoints)
|
二、Service 类型
2.1 ClusterIP(默认)
集群内部访问,外部不可达。
1
2
3
4
5
6
7
8
9
10
11
|
apiVersion: v1
kind: Service
metadata:
name: web-app
spec:
type: ClusterIP # 默认值,可省略
selector:
app: web-app
ports:
- port: 80 # Service 端口
targetPort: 8080 # Pod 端口
|
1
2
3
4
|
集群内访问方式:
- Service 名称:http://web-app:80
- Service IP:http://10.100.200.50:80
- 完整 DNS:http://web-app.default.svc.cluster.local:80
|
2.2 NodePort
通过节点端口暴露服务,外部可以通过 节点IP:端口 访问。
1
2
3
4
5
6
7
8
9
10
11
12
|
apiVersion: v1
kind: Service
metadata:
name: web-app
spec:
type: NodePort
selector:
app: web-app
ports:
- port: 80 # Service 端口
targetPort: 8080 # Pod 端口
nodePort: 30080 # 节点端口(30000-32767,可省略自动分配)
|
1
2
|
外部访问方式:
- http://<任意节点IP>:30080
|
NodePort 适合测试和小规模使用,生产环境一般用 Ingress 或 LoadBalancer。
2.3 LoadBalancer
云厂商提供的负载均衡器(AWS ELB、GCP LB 等)。
1
2
3
4
5
6
7
8
9
10
11
|
apiVersion: v1
kind: Service
metadata:
name: web-app
spec:
type: LoadBalancer
selector:
app: web-app
ports:
- port: 80
targetPort: 8080
|
本地环境(minikube)没有真正的 LoadBalancer。可以用 minikube tunnel 模拟。
2.4 ExternalName
将 Service 映射到外部 DNS 名称,不创建 Endpoints。
1
2
3
4
5
6
7
|
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
type: ExternalName
externalName: db.example.com # 外部数据库地址
|
1
2
|
集群内访问:mysql://external-db:3306
实际解析到:mysql://db.example.com:3306
|
三、Headless Service
不分配 ClusterIP,直接返回后端 Pod 的 IP。常配合 StatefulSet 使用。
1
2
3
4
5
6
7
8
9
10
|
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
clusterIP: None # Headless
selector:
app: mysql
ports:
- port: 3306
|
1
2
3
4
|
DNS 解析结果:
mysql-0.mysql.default.svc.cluster.local → Pod-0 的 IP
mysql-1.mysql.default.svc.cluster.local → Pod-1 的 IP
mysql-2.mysql.default.svc.cluster.local → Pod-2 的 IP
|
StatefulSet 的每个 Pod 有固定的 DNS 名称,适合需要知道具体连接哪个实例的场景(如 MySQL 主从)。
四、Endpoints
Endpoints 是 Service 和 Pod 之间的桥梁。
1
2
3
4
5
6
7
|
# 查看 Service 对应的 Endpoints
kubectl get endpoints web-app
# NAME ENDPOINTS AGE
# web-app 10.244.1.5:8080,10.244.2.3:8080,10.244.3.7:8080
# Service 没有 selector 时,需要手动创建 Endpoints
# 用于代理集群外部的服务
|
手动 Endpoints 示例(代理外部服务):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# Service(不指定 selector)
apiVersion: v1
kind: Service
metadata:
name: external-api
spec:
ports:
- port: 80
targetPort: 80
---
# 手动指定 Endpoints
apiVersion: v1
kind: Endpoints
metadata:
name: external-api # 和 Service 同名
subsets:
- addresses:
- ip: 192.168.1.100 # 外部服务 IP
ports:
- port: 80
|
五、Ingress
Ingress 是 K8s 的 HTTP 路由层,类似 Nginx 反向代理,根据域名和路径转发到不同 Service。
5.1 为什么需要 Ingress
1
2
3
4
5
6
7
8
|
没有 Ingress:
每个 Service 都需要 NodePort/LoadBalancer
端口管理混乱,无法按域名路由
有 Ingress:
只需要一个入口(LoadBalancer 或 NodePort)
按域名和路径路由到不同 Service
支持 TLS 证书
|
5.2 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
28
29
30
|
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx # 指定 Ingress Controller
rules:
- host: app.example.com # 域名
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app # 转发到这个 Service
port:
number: 80
- host: api.example.com # 另一个域名
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
|
5.3 路径路由
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
|
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /static
pathType: Prefix
backend:
service:
name: static-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: web-app
port:
number: 80
|
5.4 TLS 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
spec:
tls:
- hosts:
- app.example.com
secretName: tls-secret # 包含 TLS 证书的 Secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app
port:
number: 80
|
5.5 安装 Ingress Controller
1
2
3
4
5
|
# minikube 启用 Ingress 插件
minikube addons enable ingress
# 验证 Ingress Controller
kubectl get pods -n ingress-nginx
|
六、DNS
K8s 集群内置 DNS 服务(CoreDNS),Pod 自动配置 DNS 解析。
6.1 DNS 命名规则
1
2
3
4
|
<service-name> # 同命名空间
<service-name>.<namespace> # 跨命名空间
<service-name>.<namespace>.svc # 完整写法
<service-name>.<namespace>.svc.cluster.local # 完整 FQDN
|
6.2 跨命名空间访问
1
2
3
4
5
|
# 在 dev 命名空间访问 prod 命名空间的 Service
mysql://mysql.prod.svc.cluster.local:3306
# 简写
mysql://mysql.prod:3306
|
6.3 DNS 调试
1
2
3
4
5
6
7
8
9
10
|
# 启动调试 Pod
kubectl run debug --image=busybox --rm -it --restart=Never -- sh
# 在调试 Pod 中
nslookup web-app # 同命名空间
nslookup web-app.default.svc.cluster.local # 完整域名
nslookup web-app.prod # 跨命名空间
# 查看Pod 的 DNS 配置
cat /etc/resolv.conf
|
七、网络策略
NetworkPolicy 控制 Pod 之间的网络访问(默认全部互通)。
7.1 网络策略示例
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: api-policy
namespace: prod
spec:
podSelector:
matchLabels:
app: api-server # 策略应用到这些 Pod
policyTypes:
- Ingress # 入站规则
ingress:
- from:
- podSelector: # 只允许这些 Pod 访问
matchLabels:
app: web-app
ports:
- port: 8080
protocol: TCP
|
7.2 常见策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
# 拒绝所有入站(默认拒绝)
spec:
podSelector: {}
policyTypes:
- Ingress
# 允许同命名空间访问
spec:
podSelector: {}
ingress:
- from:
- podSelector: {}
# 允许指定命名空间访问
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
env: dev
|
NetworkPolicy 需要网络插件支持(Calico、Cilium 等),minikube 默认不支持。
八、开发者视角:服务接入
8.1 微服务间的调用方式
1
2
3
|
// 不要硬编码 IP,用 Service 名称
resp, err := http.Get("http://user-service:8080/api/users")
resp, err := http.Get("http://order-service.prod.svc.cluster.local:8080/api/orders")
|
8.2 服务接入检查清单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
1. Service selector 是否匹配 Pod 的 labels?
→ kubectl get endpoints <service> 检查是否有后端
2. 端口是否正确?
→ Service port → targetPort → containerPort 要对应
3. Pod 是否 Ready?
→ readinessProbe 没通过的 Pod 不会接收流量
4. 跨命名空间是否用了完整 DNS?
→ 用 <service>.<namespace> 格式
5. 外部访问是否配置了 Ingress?
→ 检查 Ingress 规则和域名解析
|
九、小结
本文学习了 K8s 的服务发现与网络:
- Service 四种类型(ClusterIP、NodePort、LoadBalancer、ExternalName)
- Headless Service 和 StatefulSet 的配合
- Endpoints 和外部服务代理
- Ingress HTTP 路由和 TLS
- DNS 命名规则和跨命名空间访问
- NetworkPolicy 网络策略
- 开发者视角的服务接入
下一篇将学习配置与存储:ConfigMap、Secret、PV/PVC。