K8s 系列 | 第 5 天:Service 与网络基础:ClusterIP、NodePort、LoadBalancer 详解


title: K8s 系列 | 第 5 天:Service 与网络基础:ClusterIP、NodePort、LoadBalancer 详解
tags:
– Kubernetes
– K8s系列
– DevOps
– Service
– 网络
– 容器编排
– ClusterIP
– NodePort
– LoadBalancer


K8s 系列 | 第 5 天:Service 与网络基础:ClusterIP、NodePort、LoadBalancer 详解

第 5 / 30 天


一、引言

在前四天的学习中,我们已经掌握了 K8s 的核心概念(第1天)、集群搭建(第2天)、Pod 生命周期管理(第3天)以及 Deployment 声明式部署(第4天)。我们能够运行 Pod 并通过 Deployment 管理副本,但这些 Pod 的 IP 地址是动态分配的——Pod 重启、滚动更新、节点故障都会导致 IP 变化。那么,如何让客户端稳定访问一组动态变化的 Pod?

答案是 Service。Service 是 Kubernetes 中网络抽象的核心层,它为 Pod 提供稳定的访问入口和负载均衡能力。今天我们将深入解析三种最常用的 Service 类型:ClusterIP、NodePort 和 LoadBalancer,并通过实战带你掌握 K8s 服务暴露的全貌。


二、核心概念:Service 的工作原理

2.1 为什么需要 Service?

Pod 是非永久性的资源,它们可以被创建、销毁、调度到不同节点。每个 Pod 获得一个集群内 IP(Cluster IP),但这个 IP 在 Pod 重建后会变化。Service 通过 Selector(标签选择器) 动态匹配一组 Pod,并提供一个固定的虚拟 IP(VIP) 和 DNS 名称,流量到达 VIP 后由 kube-proxy 转发到后端 Pod。

2.2 Service 的三大要素

要素 说明
Cluster IP Service 在集群内部的虚拟 IP,固定不变
Port 映射 port(Service 端口)→ targetPort(Pod 容器端口)→ nodePort(节点端口,仅 NodePort 类型)
Endpoints 匹配到标签的 Pod IP:Port 列表,由 Endpoint Controller 自动维护

2.3 Service 流量转发机制

kube-proxy 支持三种模式(按演进顺序):

  • userspace 模式(已弃用):用户态代理,性能差
  • iptables 模式(默认):利用 Linux iptables NAT 规则,随机转发,无健康检查
  • IPVS 模式(推荐生产):基于内核 IPVS,支持多种调度算法(rr、wrr、lc 等),性能更高
# 检查当前集群 kube-proxy 模式
kubectl get configmap kube-proxy -n kube-system -o yaml | grep mode

三、准备工作:部署一个示例应用

我们先部署一个 Nginx Deployment 作为测试目标:

# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-demo
  labels:
    app: nginx-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-demo
  template:
    metadata:
      labels:
        app: nginx-demo
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
# 应用 Deployment
kubectl apply -f nginx-deployment.yaml

# 确认三个 Pod 都 Running
kubectl get pods -l app=nginx-demo -o wide

四、ClusterIP:集群内部访问(默认类型)

ClusterIP 是 Service 的默认类型,只能在集群内部访问。它分配一个虚拟 IP(Cluster IP),同集群内的 Pod 可以通过这个 IP 或 DNS 名称访问 Service。

4.1 创建 ClusterIP Service

# svc-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-clusterip
spec:
  selector:
    app: nginx-demo
  ports:
  - protocol: TCP
    port: 80          # Service 端口
    targetPort: 80    # Pod 容器端口
  type: ClusterIP
# 创建 Service
kubectl apply -f svc-clusterip.yaml

# 查看 Service 详情
kubectl get svc nginx-clusterip

# 查看自动生成的 Endpoints
kubectl get endpoints nginx-clusterip

4.2 验证 ClusterIP 可达性

# 在集群内任意 Pod 中测试 Service 可达性
kubectl run test-pod --image=busybox -it --rm --restart=Never -- wget -qO- http://nginx-clusterip:80

# 也可以使用 DNS 完整名称
kubectl run test-pod2 --image=busybox -it --rm --restart=Never -- wget -qO- http://nginx-clusterip.default.svc.cluster.local:80

4.3 关键特性

  • Cluster IP 固定不变:只要 Service 存在,IP 就不会变化
  • DNS 自动注册:格式为 <service-name>.<namespace>.svc.cluster.local
  • 内部负载均衡:kube-proxy 自动将流量分发到后端多个 Pod

五、NodePort:外部流量接入基础

NodePort 在 ClusterIP 基础上,在每个 Node 上开放一个静态端口(范围 30000-32767),外部可以通过 任意节点IP:NodePort 访问 Service。

5.1 创建 NodePort Service

# svc-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
spec:
  selector:
    app: nginx-demo
  ports:
  - protocol: TCP
    port: 80           # Service Cluster IP 端口
    targetPort: 80     # Pod 容器端口
    nodePort: 30080    # 节点端口(可选,不指定则随机分配)
  type: NodePort
# 创建 NodePort Service
kubectl apply -f svc-nodeport.yaml

# 查看 NodePort 端口分配
kubectl get svc nginx-nodeport

# 查看节点 IP
kubectl get nodes -o wide

5.2 验证外部访问

# 从集群外部(例如宿主机或另一台机器)访问
# 假设节点 IP 为 192.168.1.100
curl http://192.168.1.100:30080

# 任何节点的同一端口都能访问(kube-proxy 负责转发)
curl http://192.168.1.101:30080

5.3 NodePort 的局限性

问题 说明
端口范围受限 仅 30000-32767,难以用于 80/443 标准端口
节点 IP 变化 节点宕机或新增时,外部需要感知变化
缺少健康检查 单点流量打到故障节点时才会转发到正常 Pod
安全风险 每个 Node 都暴露端口,攻击面扩大

适用场景:开发测试环境、演示、小型服务暴露,或作为 LoadBalancer/Ingress 的底层实现。


六、LoadBalancer:云原生外部暴露

LoadBalancer 是 NodePort 的扩展,它在 NodePort 基础上调用云平台(AWS、GCP、Azure、阿里云等)的负载均衡器 API,自动创建一个外部 LB 并将流量导入集群。

6.1 创建 LoadBalancer Service

# svc-loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-lb
spec:
  selector:
    app: nginx-demo
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: LoadBalancer
# 创建 LoadBalancer Service
kubectl apply -f svc-loadbalancer.yaml

# 查看外部 IP(EXTERNAL-IP 列)
kubectl get svc nginx-lb

# 等待 EXTERNAL-IP 分配后
curl http://<EXTERNAL-IP>:80

6.2 本地环境(无云 LB)的解决方案:MetalLB

如果你在裸金属或本地集群(如 kubeadm、minikube、k3s)中,没有云平台的 LB 支持,可以使用 MetalLB 实现类似功能:

# 安装 MetalLB(Layer2 模式)
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.8/config/manifests/metallb-native.yaml

# 创建 IP 地址池(需与集群网络在同一子网)
cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.200-192.168.1.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2-advertise
  namespace: metallb-system
EOF

# 创建 LoadBalancer Service 后即可获得外部 IP
kubectl get svc nginx-lb

七、三种 Service 类型对比总结

特性 ClusterIP NodePort LoadBalancer
访问范围 集群内部 集群内外(节点IP:NPort) 集群内外(LB IP)
端口 自定义 30000-32767 自定义
负载均衡 kube-proxy kube-proxy 云 LB + kube-proxy
成本 免费 免费 云资源计费
适合场景 内部微服务通信 开发测试、调试 生产对外暴露
外部 IP 节点 IP 云 LB IP
配置复杂度 最低 中(依赖云平台)

关键理解:NodePort = ClusterIP + 节点端口映射,LoadBalancer = NodePort + 云 LB 集成。三者是层层叠加的关系。


八、生产实战:Service 配置要点

8.1 Session 保持(Session Affinity)

需要将同一个客户端的请求始终转发到同一个 Pod 时,配置 sessionAffinity

apiVersion: v1
kind: Service
metadata:
  name: nginx-sticky
spec:
  selector:
    app: nginx-demo
  ports:
  - port: 80
    targetPort: 80
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800  # 会话保持时间,默认 10800s(3小时)
  type: ClusterIP

8.2 自定义 Endpoints(外部服务接入)

如果后端服务不在 K8s 内(如外部数据库),可以手动管理 Endpoints:

# 创建不带 Selector 的 Service
apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  ports:
  - port: 3306
    targetPort: 3306
---
# 手动指定 Endpoints
apiVersion: v1
kind: Endpoints
metadata:
  name: external-db
subsets:
- addresses:
  - ip: 192.168.100.50
  ports:
  - port: 3306
# 验证 Endpoints
kubectl get endpoints external-db
# 集群内 Pod 即可通过 svc 名称访问外部数据库
kubectl run test-db --image=mysql:8.0 -it --rm -- mysql -h external-db -u root -p

8.3 多端口 Service

当 Pod 暴露多个端口时,需要为每个端口命名:

apiVersion: v1
kind: Service
metadata:
  name: multi-port-svc
spec:
  selector:
    app: my-app
  ports:
  - name: http
    port: 80
    targetPort: 8080
  - name: metrics
    port: 9090
    targetPort: 9090
  type: ClusterIP

8.4 ExternalName Service(DNS 别名转发)

将 Service 映射到集群外的 DNS 名称,无需 Cluster IP:

apiVersion: v1
kind: Service
metadata:
  name: external-api
spec:
  type: ExternalName
  externalName: api.example.com
# 集群内通过 svc DNS 访问,实际解析为 api.example.com
kubectl run test --image=busybox -it --rm -- nslookup external-api

九、常见问题(FAQ)

Q1:为什么我访问 NodePort 时连接被拒绝?

排查步骤

# 1. 确认 Service 已创建
kubectl get svc

# 2. 确认 Endpoints 不为空(有匹配的 Pod)
kubectl get endpoints nginx-nodeport

# 3. 检查防火墙是否放行了 nodePort 端口
iptables -L INPUT -n | grep 30080

# 4. 确认 kube-proxy 运行正常
kubectl get pod -n kube-system -l k8s-app=kube-proxy

Q2:LoadBalancer 的 EXTERNAL-IP 一直显示 <pending>

  • 在云平台:检查 LB 配额是否用尽、IAM 权限是否正确
  • 在本地集群:确认 MetalLB(或其他 LB 方案)已正确安装且 IP 池配置无误

Q3:Service 的 Cluster IP 能固定吗?

可以,在 Service spec 中指定 clusterIP 字段(需在网络规划的范围内):

apiVersion: v1
kind: Service
metadata:
  name: fixed-ip-svc
spec:
  clusterIP: 10.96.0.100  # 需在 service-cluster-ip-range 范围内
  selector:
    app: my-app
  ports:
  - port: 80

Q4:如何调试 Service 流量转发?

# 查看 iptables 规则(kube-proxy iptables 模式)
iptables-save -t nat | grep nginx-clusterip

# 使用 tcpdump 抓包确认流量去向
kubectl exec -it <pod-name> -- tcpdump -i eth0 port 80

# 检查 kube-proxy 日志
kubectl logs -n kube-system -l k8s-app=kube-proxy --tail=50

十、总结

今天我们系统学习了 K8s Service 的三种核心类型:

  1. ClusterIP —— 集群内部微服务通信的标准方式,通过 DNS 名称实现服务发现
  2. NodePort —— 最简单的集群外部暴露方案,适合开发测试环境
  3. LoadBalancer —— 生产环境的对外暴露方案,云原生集成 LB

掌握 Service 是理解 K8s 网络的基石。实际工作中,ClusterIP + Ingress 的组合是最常见的生产环境架构模式(NodePort 通常不直接暴露给外部,而是作为 Ingress Controller 的底层支撑)。


📖 系列目录


🔮 下期预告

第 6 天:Namespace 与资源配额:多租户隔离基础

当你的集群中运行着多个团队、多个项目的应用时,如何实现资源隔离、权限管理和配额限制?下期我们将深入 Namespace、ResourceQuota 与 LimitRange,掌握 K8s 多租户的基础设施。


本系列文章持续更新中,欢迎收藏关注!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容