Kubernetes Service 详解:稳定访问端点的核心机制
在 Kubernetes 集群中,Pod 是最小的部署单元,但它的 IP 地址是动态变化的。当一个 Pod 被销毁并由控制器(如 Deployment)重新创建时,新的 Pod 会获得一个新的 IP 地址。这对需要访问这些 Pod 的前端应用或其他服务来说是个问题——它们无法依赖一个固定的 IP 来通信。为了解决这个问题,Kubernetes 引入了 Service 资源。
什么是 Service?
Service 定义了一组 Pod 的稳定访问入口。它通过标签选择器(Label Selector)找到匹配的 Pod 集合,并将流量负载均衡到这些 Pod 上。Service 的 IP 地址(ClusterIP)在生命周期内保持不变,从而实现了前端应用与后端 Pod 的解耦。
ReplicaSet 或 Deployment 等控制器负责维护 Pod 的副本数量,确保服务的高可用性。而 Service 则负责提供固定的网络端点。
实战:创建 Nginx 服务并暴露为 Service
首先,创建一个 Nginx Deployment:
kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80 --replicas=1
查看 Pod:
kubectl get pod | grep nginx
输出示例:
nginx-deploy-84cbfc56b6-7v59n 1/1 Running 0 4m1s
直接访问 Pod IP:
curl 172.20.0.64
你会看到 Nginx 的欢迎页面。但如果删除这个 Pod,Deployment 会重新创建一个,新的 Pod IP 会不同。为了解决这个问题,创建一个 Service:
kubectl expose deployment nginx-deploy --name=nginx --port=80 --target-port=80 --protocol=TCP
查看 Service:
kubectl get svc | grep nginx
输出示例:
nginx ClusterIP 10.68.23.129 <none> 80/TCP 18s
现在访问 Service IP:
curl 10.68.23.129
即使 Pod 被重建,这个 IP 仍然有效,因为 Service 会自动将流量转发到新的 Pod。
Service 的 DNS 解析
如果集群安装了 CoreDNS,Service 可以通过 DNS 名称访问。默认的 DNS 格式为 <service-name>.<namespace>.svc.cluster.local。例如,创建一个 BusyBox 客户端来测试:
kubectl run client --image=busybox --replicas=1 -it --restart=Never
在容器内执行:
wget -O - -q http://nginx:80
你可以看到与直接访问 IP 相同的结果。这意味着客户端可以通过 Service 名称(如 nginx)来访问,而不需要知道具体的 IP 地址。
深入理解 Service 的工作原理
Service 本质上是通过 iptables 或 IPVS 规则实现的。当你创建一个 Service 时,Kubernetes 会在每个节点上配置相应的规则,将发往 Service IP 的流量转发到后端的 Pod。我们可以查看 Service 关联的端点:
kubectl describe svc nginx
输出中的 Endpoints 字段显示了当前后端的 Pod IP 列表。标签选择器 Selector 决定了哪些 Pod 会被纳入 Service 的后端。
动态扩容与负载均衡
创建一个新的 Deployment:
kubectl run myapp --image=ikubernetes/myapp:v1 --replicas=2
查看 Pod 信息:
kubectl get pod -o wide | grep myapp
然后为它创建 Service:
kubectl expose deployment myapp --name=myapp --port=80
现在,从客户端访问这个 Service:
wget -O - -q myapp
使用循环测试负载均衡:
while true; do wget -O - -q myapp/hostname.html; sleep 1; done
你会看到请求被均匀地分发到两个 Pod 上:
myapp-9b4987d5-tcg4p
myapp-9b4987d5-jngkk
验证 Service 的底层实现
Service IP 无法 ping 通,因为它不是真实的网络接口,而是 iptables 规则。我们可以查看节点上的 NAT 规则:
iptables -vnL -t nat
输出中包含了 KUBE-SERVICES 链,其中定义了所有 Service 的转发规则。
外部访问:NodePort 类型
默认的 ClusterIP 只能在集群内部访问。如果希望外部用户访问,可以将 Service 类型改为 NodePort:
kubectl edit svc myapp
将 spec.type 从 ClusterIP 改为 NodePort,Kubernetes 会自动在节点上开放一个端口(范围 30000-32767),外部可以通过 <节点IP>:<NodePort> 访问。