CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Kubernetes 入门/课时/Service 与网络
RawBlame
课时目录12 节

Kubernetes 入门

  1. 01Kubernetes 是什么
  2. 02核心概念与架构
  3. 03本地集群与 kubectl
  4. 04Pod
  5. 05Deployment 与滚动更新
  6. 06Service 与网络
  7. 07ConfigMap 与 Secret
  8. 08存储卷
  9. 09Ingress 入口
  10. 10资源配额与 HPA
  11. 11RBAC 与安全基础
  12. 12综合练习:部署 backend

Service 与网络

ClusterIP、NodePort、DNS 服务发现。

35 分钟

Service 与网络

这一课你将能做到

  1. 为 Deployment 创建 ClusterIP Service,并用 selector 稳定选中后端 Pod
  2. 说清 ClusterIP / NodePort / LoadBalancer / ExternalName 四种类型的适用场景
  3. 用 DNS 名在集群内访问服务,会用 get endpoints 定位「服务不通」类问题

为什么要学

Pod 会随时被重建,IP 跟着变;把 IP 写进任何配置都是定时炸弹。Service 用一个稳定的虚拟 IP + DNS 名把流量负载均衡到「当前健康的一组 Pod」。

对照你已经会的心智:Compose 里 platform 用 http://backend:8080 访问后端、backend 用 mysql 连库——靠的是 Compose 内置 DNS。K8s 把这件事升级成全集群标准:CoreDNS 为每个 Service 生成域名,backend 调 Redis、连 MySQL(集群外也一样有办法)都写稳定名字。面试必考「Service 有哪几种类型」「ClusterIP 的原理」。

先建立图像

其他 Pod --DNS--> backend(Service,稳定虚拟 IP 10.96.x.x)
                     │
          kube-proxy 的转发规则(iptables/IPVS)
                     │
              负载到 Endpoints 列表(当前 Ready 的 Pod IP:端口)
                     │
        ┌────────────┼────────────┐
     Pod A        Pod B        Pod C   (app=backend 且 Ready)
type作用域典型场景
ClusterIP仅集群内服务互访(默认),backend/redis/mysql
NodePort节点 IP:30000-32767本地演示、临时外部访问
LoadBalancer云厂商负载均衡器云上把服务暴露到公网/内网
ExternalNameDNS CNAME引用集群外地址(如托管 MySQL)

跟着做

步骤 1:确认有带标签的 Deployment

沿用上一课的 backend(2 副本 nginx 占位):

kubectl get deploy backend
kubectl get pods -l app=backend --show-labels

标签是 Service 的「挂钩」,app=backend 必须存在于 Pod 上。

步骤 2:写 ClusterIP Service

svc-backend.yaml:

apiVersion: v1
kind: Service
metadata:
  name: backend
spec:
  type: ClusterIP
  selector:
    app: backend
  ports:
    - name: http
      port: 80          # Service 对外提供的端口
      targetPort: 80    # 容器实际监听的端口

本站真实 backend 通常写 port: 80, targetPort: 8080:集群内其他服务统一访问 http://backend(80),Spring Boot 容器内部仍是 8080——两个端口解耦,容器改端口不用动调用方。

步骤 3:apply 并检查 Endpoints

kubectl apply -f svc-backend.yaml
kubectl get svc backend
kubectl get endpoints backend

Endpoints 应列出 2 个 Pod IP。Endpoints 为空是新手第一坑,顺序排查:selector 与 Pod 标签是否一致 → Pod 是否 Ready(readiness 失败会被摘除)。

步骤 4:集群内用 DNS 验证负载均衡

起一个临时 curl 容器打 6 次请求:

kubectl run curl --rm -it --image=curlimages/curl:8.9.1 --restart=Never -- \
  sh -c "for i in 1 2 3 4 5 6; do curl -s -o /dev/null http://backend; done"

再看两个 Pod 的访问日志分布:

kubectl logs -l app=backend --prefix --tail=3

--prefix 会标明日志来自哪个 Pod——应看到请求被分摊到两个 Pod 上,这就是 Service 内置的负载均衡。

步骤 5:本机访问(port-forward 与 NodePort)

port-forward 最适合本机调试:

kubectl port-forward svc/backend 8080:80
# 另开终端
curl -sS http://127.0.0.1:8080 | head -3

NodePort 适合演示给局域网看。改一个 NodePort 版 Service:

# svc-backend-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: backend-np
spec:
  type: NodePort
  selector:
    app: backend
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080      # 可指定,不填则随机分配
kubectl apply -f svc-backend-nodeport.yaml
minikube service backend-np --url

步骤 6:DNS 规则与集群外依赖

FQDN 公式:<服务名>.<命名空间>.svc.cluster.local。同命名空间写短名 backend 即可;跨命名空间写全名。验证:

kubectl run dns --rm -it --image=busybox:1.36 --restart=Never -- \
  nslookup backend

集群外依赖(如托管 MySQL)用 ExternalName 或直连地址:

apiVersion: v1
kind: Service
metadata:
  name: mysql-external
spec:
  type: ExternalName
  externalName: rm-xxxx.mysql.rds.aliyuncs.com

本站过渡期推荐:MySQL/Redis 留在集群外,backend 的 DB_HOST 填可达地址或这类 ExternalName——第 7、8 课展开。

讲清楚要点

  1. Service 的「稳定」稳定的是名字和虚拟 IP,不是某个 Pod:后端 Pod 全挂时 Service 还在,但 Endpoints 为空——「服务存在」≠「有可用后端」。
  2. selector + readiness 双重门控 Endpoints:标签不匹配、Pod 未 Ready,都会让 Endpoints 空,表现为 curl 连接被拒/超时。
  3. ClusterIP 原理(面试必背):Service 的虚拟 IP 不是某台机器上的网卡,由 kube-proxy 在每个节点写 iptables/IPVS 规则,把目标为虚拟 IP 的流量 DNAT 到真实 Pod IP——所以它天然负载均衡,且不需要「Service 进程」。
  4. port 与 targetPort 解耦:port 是调用方视角,targetPort 是容器视角;规范化做法给 port 命名(name: http)。
  5. NodePort 是逃生门不是生产方案:端口范围受限(30000-32767)、无 TLS、无路由;生产对外用 LoadBalancer + Ingress(第 9 课)。
  6. 本站多服务的约定:每个 Deployment 配一个同名 Service(backend、platform、redis…),调用方只认名字,谁都不许写 Pod IP。

你可能会懵的地方

  • Service 是一个容器/进程吗? 不是。它是 API 对象 + 全节点的转发规则,没有任何「Service 容器」在跑。故障时别去找「Service 的日志」,去看 Endpoints 和 Pod。

  • headless Service 是什么? clusterIP: None 的 Service:不做虚拟 IP 与负载均衡,DNS 直接解析出所有 Pod IP。适合客户端自己做均衡的场景(数据库主从发现、gRPC),以及 StatefulSet 的稳定网络标识。

  • sessionAffinity 能做会话保持吗? 能:sessionAffinity: ClientIP 让同一来源 IP 固定打到同一 Pod。但更好的做法是应用无状态化(会话放 Redis),别依赖 IP 亲和。

  • Service 和 Compose 服务名心智差在哪? 思想一致(名字代替 IP),但 K8s 额外提供跨节点负载均衡、readiness 门控、命名空间作用域与统一 FQDN 规则——从「联通」升级到「健康地联通」。

  • 为什么 curl Service 时好时坏? 典型原因是部分 Pod 未 Ready 或探针路径错误:Endpoints 里混着坏实例。get endpoints 配合逐个 Pod 的 logs 对账。

错法对照

错法问题正解
selector 写错或漏标签Endpoints 空,连接拒绝get endpoints + --show-labels 对账
port/targetPort 语义写反转发到不存在的端口port=服务端口,targetPort=容器端口
应用配置写死 Pod IPPod 重建即断一律写 Service DNS 名
生产长期裸 NodePort无 TLS 难管理、端口混乱Ingress/LB 收口
跨命名空间仍用短名解析失败或解析错对象用 svc.ns.svc.cluster.local

卡点急救

  1. Endpoints 为空:三步走——kubectl get endpoints <名> 确认;kubectl get pods -l app=backend --show-labels 核对标签;kubectl get pods 看 READY 是否 1/1(readiness 问题回上一课)。
  2. NodePort 访问不通:先 minikube service <名> --url 拿对地址;再 curl 节点 IP:端口 验证;云服务器需检查安全组放行 30000-32767。
  3. DNS 解析失败(nslookup 不出名字):确认调用方与 Service 同命名空间或用了 FQDN;查 CoreDNS 是否正常:kubectl get pods -n kube-system -l k8s-app=kube-dns。

面试常问

  • Service 有哪几种类型?分别什么场景? ClusterIP(默认):集群内互访,虚拟 IP + DNS;NodePort:在每个节点开 30000-32767 端口映射到 Service,适合测试暴露;LoadBalancer:在云厂商创建外部负载均衡器指向 NodePort,是生产暴露的基座;ExternalName:返回 DNS CNAME,用于引用集群外服务。生产实践通常是 LoadBalancer 承载 Ingress Controller,再由 Ingress 按域名/路径分发。

  • ClusterIP 的实现原理? 用户创建 Service 时 API Server 分配虚拟 IP 并写入 etcd;kube-proxy 监听变化,在每个节点生成 iptables(或 IPVS)规则,把发往虚拟 IP 的流量按概率 DNAT 到 Endpoints 里的健康 Pod。特点:虚拟 IP 不绑定任何网卡、不需要进程监听、天然具备负载均衡与容错(Pod 挂掉被摘出 Endpoints 即不再命中)。IPVS 模式适合大规模集群,规则查找更高效并支持更多调度算法。

  • Endpoints 是什么时候更新的? EndpointSlice(新版本拆分对象)由 EndpointSlice 控制器维护:selector 匹配的 Pod 且 readiness 通过才会进入;Pod 创建、删除、Ready 状态翻转都会实时增删条目。所以「Service 通不通」的第一手证据永远是 kubectl get endpoints——它直接反映「当前有哪些可用后端」。

自测三问

  1. Service 的「稳定」到底稳定的是什么?不保证什么?
  2. Endpoints 为空时,你的排查顺序是什么?
  3. 本站 platform 容器内访问 backend,URL 的主机名应该写什么?

小结一句话

Service 用标签选中「当前 Ready 的 Pod」,提供稳定 DNS 与负载均衡,让应用彻底告别 Pod IP——下一课把配置和密钥从镜像里拆出去,交给 ConfigMap 与 Secret。

延伸

  • Service
  • DNS for Services and Pods
  • 下一课预告:ConfigMap 与 Secret——把 SPRING_PROFILES_ACTIVE、DB_HOST、密码从镜像里外置出来。
加载本节练习…
← 上一课Deployment 与滚动更新下一课 →ConfigMap 与 Secret