01. Service 是什么、为什么需要它
Pod 是临死重生的——挂掉重建后 IP 全变了。你怎么保证客户端总能找到正确的 Pod?这就是 Service 存在的意义。
Service 给一组 Pod 提供稳定的访问入口——一个固定不变的虚拟 IP(ClusterIP)和一 DNS 名。你访问 Service 的名字,Service 把请求转发到后端健康的 Pod。
Service 通过 Label Selector 找到它要代理的 Pod。你在 Service 里写 selector: app: myapp,这个 Service 就代理所有 label 为 app=myapp 的 Pod。这就是为什么 Pod 要打 label 的原因之一。
Service 有三种常用类型:ClusterIP(集群内部访问,默认)、NodePort(在每个 Node 上开一个端口对外暴露)、LoadBalancer(云厂商的负载均衡器,生产环境标准方式)。
yaml
# Service YAML
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: myapp
ports:
- port: 80 # Service 的端口
targetPort: 8080 # 后端 Pod 的端口
type: ClusterIP02. ClusterIP、NodePort、LoadBalancer 的区别
ClusterIP——默认类型,只在集群内部可达。其他 Pod 可以访问,集群外面的客户端不行。适合内部服务(数据库、后端 API)。
NodePort——在每个 Node 上开一个高端口(默认范围 30000-32767),外部客户端访问任意 Node 的 IP 加这个端口就进去了。NodePort 会自动创建 ClusterIP。适合开发测试或简单的对外暴露,生产环境不够灵活。
LoadBalancer——云厂商(AWS、GCP、Azure)提供的外部负载均衡器。自动创建 ClusterIP 和 NodePort,然后云厂商分配一个公网 IP 或域名。生产环境的标准方式,但每个 LoadBalancer 都要花钱。
还有一种 ExternalName——不代理 Pod,而是把一个 Service 名映射到一个外部 DNS 域名上。
yaml
# NodePort 示例
spec:
type: NodePort
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 可选,不写就随机分配
# LoadBalancer 示例
spec:
type: LoadBalancer
selector:
app: myapp
ports:
- port: 80
targetPort: 8080云上的生产环境用 LoadBalancer。自建机房用 NodePort + 外部 Nginx/HAProxy 或者 MetalLB(裸金属的负载均衡方案)。
03. Ingress——HTTP/HTTPS 路由
Service 是四层(传输层)的负载均衡,Ingress 是七层(应用层)的 HTTP 路由。Ingress 能根据域名和 URL 路径把请求路由到不同的 Service。
比如 example.com/api 去后端 API Service,example.com/web 去前端 Service。一个 Ingress 管理多个域名和路径。
Ingress 本身只是一个配置规则,真正干活的是 Ingress Controller——Nginx Ingress、Traefik、HAProxy 这些。你需要先部署 Ingress Controller,然后创建 Ingress 资源。
现在 K8s 也在推 Gateway API——Ingress 的下一代,功能更丰富、角色更清晰,但 Ingress 仍是主流。
yaml
# Ingress YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
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: 8004. Service 发现与 CoreDNS
K8s 集群里有个内置的 DNS 服务(CoreDNS),每个 Service 创建时自动注册一条 DNS 记录。Pod 之间通过 Service 名字就找到对方,完全不需要硬编码 IP。
DNS 名规则:服务名.命名空间.svc.cluster.local。同 Namespace 下直接用服务名就行,跨 Namespace 用 服务名.命名空间。
比如 dev 命名空间里有个叫 db 的 Service,同 Namespace 的 Pod 直接连 db。prod 里的 Pod 想连 dev 的 db 就写 db.dev。
如果 Service 是 Headless Service(clusterIP: None),DNS 不会返回虚拟 IP 而是返回所有后端 Pod 的 IP。适合需要自己控制负载均衡的场景(如数据库集群主从发现)。
yaml
# 同 Namespace 访问:直接用服务名
curl http://my-service/api
# 跨 Namespace:用 服务名.命名空间
curl http://my-service.dev.svc.cluster.local
# Headless Service
apiVersion: v1
kind: Service
metadata:
name: db-headless
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306CoreDNS 默认部署为一个 Deployment(多个副本),保证 DNS 高可用。如果 Pod 的 DNS 解析有问题,先查 CoreDNS 的 Pod 是否 Running。
05. 网络策略——NetworkPolicy
默认情况下 K8s 集群里所有 Pod 之间可以互相访问(扁平网络),这在安全上是个隐患。NetworkPolicy 像防火墙规则——控制 Pod 的出入流量。
你可以定义:允许哪些来源的流量进入 Pod(ingress),允许 Pod 的流量去哪些目的地(egress)。源和目的地可以用 Pod Selector、Namespace Selector、IP 块来定义。
注意:NetworkPolicy 是命名空间级别的资源。要让它生效,你需要安装一个支持 NetworkPolicy 的网络插件(如 Calico、Cilium、Weave Net)。Flannel 默认不支持。
yaml
# NetworkPolicy——只允许 app=frontend 的 Pod 访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080NetworkPolicy 默认是允许所有流量的。你创建第一条 deny-all 策略后,只放行你明确允许的流量。白名单模式比黑名单安全。
知识测验
第 1/5 题正确 0
Service 的第一种类型 ClusterIP 能在集群外访问吗?
下一节
下一节 ConfigMap 与 Secret