如何在Kubernetes集群中使用Service公开应用?

来源:编程学习作者:灯下变量头衔:程序员
导读:本期聚焦于灯下变量创作的《如何在Kubernetes集群中使用Service公开应用?》,敬请观看详情。将应用部署到Kubernetes后,Pod的IP地址会随重建而改变,直接依赖Pod IP访问服务几乎不可行。Service对象通过标签选择器动态关联后端Pod,暴露一个稳定的虚拟IP或DNS名称,从而解耦客户端与Pod实例。本文从Service的工作机制入手,拆解ClusterIP、NodePort、LoadBalancer和ExternalName四种类型的区别及适用场景,并通过一个完整的YAML示例演示如何将Deployment中的应用公开为可访问的服务。同时介绍Service与Ingress的配合方式,以及遇到访问不通时如何从标签选择器、端口映射和网络策略等方向进行排查。掌握这些内容后,你可以根据实际环境选择合适的Service类型,快速打通集群内外流量。

在Kubernetes中,Pod的IP地址是易变的。当Deployment进行滚动更新、节点故障或Pod被驱逐时,新的Pod会分配到不同的IP。如果客户端在配置文件中写死某一个Pod的IP,一旦Pod重建,访问就会失败。Service资源正是为了解决这一稳定性问题而引入的。它通过一个稳定的虚拟IP(ClusterIP)和一个DNS名称来抽象一组Pod,客户端只需要访问Service,而不需要关心具体由哪个Pod响应。

如何在Kubernetes集群中使用Service公开应用?

Service的核心机制:标签选择器与Endpoints

Service本身并不直接运行任何进程,它只是一个逻辑抽象。它通过selector字段定义一组标签选择条件,凡是带有匹配标签的Pod都会被纳入这个Service的后端集合。例如,一个Service的selector设置为app: nginx,那么所有带有该标签的Pod都会成为它的流量目标。当Pod因扩缩容或故障发生变化时,Kubernetes会自动更新Service对应的Endpoints对象,无需人工干预。

每个Service在创建后会获得一个固定的ClusterIP,这个IP在Service的生命周期内保持不变。集群内部的DNS服务(如CoreDNS)会为Service生成一条解析记录,格式通常为服务名.命名空间.svc.cluster.local。这样一来,集群内的其他应用就可以通过这个DNS名称来访问服务,而不必关心ClusterIP的具体数值。客户端发往ClusterIP的请求会被kube-proxy组件拦截,并根据一定规则转发到后端的某个Pod。

Service的四种主要类型及适用场景

Kubernetes提供了多种Service类型,最常见的是ClusterIP、NodePort、LoadBalancer和ExternalName。默认创建的Service类型是ClusterIP,它只允许集群内部通信。如果你希望服务能够被集群外部的用户访问,就需要选择NodePort、LoadBalancer或者结合Ingress来暴露服务。下面分别说明它们的工作方式和适用场景。

ClusterIP类型是基础。它只在一个集群内部IP上暴露服务,适合用于微服务架构中服务与服务之间的调用。例如,一个订单服务需要调用用户服务,订单服务只需要知道用户服务的DNS名称,而不需要让用户服务暴露到公网。ClusterIP的优势是安全、简单,缺点是只能内网访问。

NodePort类型会在所有Node上打开同一个端口,并把该端口映射到Service的端口。用户可以通过任意节点的IP加上该端口访问服务。例如,NodePort设置为30080,那么访问http://节点IP:30080即可到达Service。NodePort的优点是无需额外的外部负载均衡器即可实现外部访问,适合本地开发、测试环境或临时演示。缺点是端口范围有限(默认30000-32767),而且需要自行处理节点故障转移。

LoadBalancer类型是在NodePort的基础上,再向云厂商申请一个外部的负载均衡器。云厂商会自动创建负载均衡器并将流量转发到节点的NodePort端口。用户只需要访问负载均衡器的外部IP或域名即可。这种类型最适合生产环境,因为云负载均衡器可以提供高可用、TLS终结等能力。但缺点是会产生额外的成本,并且强依赖云平台。

ExternalName类型较为特殊,它不直接转发流量到Pod,而是为Service提供一个CNAME记录,将服务名映射到集群外部的某个DNS名称。例如,当集群内的应用需要访问一个外部数据库时,可以通过ExternalName将内部服务名指向该数据库的域名。这种类型没有ClusterIP,也没有端口转发,仅做DNS别名。

实战:创建Service公开应用

下面通过一个完整的示例来演示如何将一个Nginx应用通过Service公开。首先创建一个Deployment,确保Pod带有app: nginx标签。然后创建一个NodePort类型的Service,让外部流量可以通过节点端口访问。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80

上面的Deployment会创建3个Nginx Pod副本,每个Pod都带有app: nginx标签。接下来定义Service,使用相同的selector来关联这些Pod,并将容器的80端口映射到Service的80端口。为了外部访问,设置type为NodePort。

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30080

在这个Service定义中,port是Service暴露的端口,其他服务或外部流量通过这个端口访问;targetPort是后端Pod上实际监听的端口,对应容器内的80端口;nodePort是每个节点上打开的端口,范围为30000到32767。如果省略nodePort,Kubernetes会自动分配一个。执行kubectl apply -f service.yaml后,可以使用kubectl get svc nginx-service查看Service的详细信息,其中会列出ClusterIP、NodePort和端口映射。

验证服务是否正常工作,可以在集群外通过任意节点的IP访问http://192.168.1.100:30080(假设节点IP为192.168.1.100)。如果浏览器显示Nginx欢迎页,说明Service已经成功将外部流量转发到了后端的某个Pod。此时即使你删除其中一个Pod,Deployment会重新创建一个新的Pod,Service仍然能够正常转发,因为标签匹配会自动更新Endpoints。

Service与Ingress的配合

虽然NodePort和LoadBalancer能够让服务被外部访问,但如果集群中运行了多个HTTP服务,每个服务都使用一个独立的NodePort或负载均衡器会带来管理上的负担。Ingress资源的作用是在七层(HTTP/HTTPS)上进行路由,它可以根据请求的域名和路径将流量分发到不同的Service。例如,api.ippipp.com的流量路由到API服务,web.ippipp.com路由到前端服务。

使用Ingress时,底层通常仍然需要一个LoadBalancer类型的Service来接收外部流量,或者使用Ingress Controller(如Nginx Ingress Controller)直接监听节点的端口。Ingress本身不直接取代Service,而是站在Service之上进行更精细的流量控制。在Ingress的规则中,通过backend.service.name引用目标Service的名称和端口。因此,创建Ingress之前,需要确保对应的Service已经是ClusterIP类型或NodePort类型,并且selector正确匹配Pod。

一个典型的Ingress规则如下所示,它将nginx.ippipp.com的请求转发到名为nginx-service的Service的80端口。注意,Ingress Controller需要根据实际环境进行部署,且域名解析需要指向Ingress Controller的入口地址。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  rules:
  - host: nginx.ippipp.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

排错指南:Service访问不通的常见原因

在实际使用中,Service无法正常转发流量是最常见的问题之一。排查时可以从以下几个方向入手。首先检查Service的selector是否与Pod的labels完全匹配。可以使用kubectl get endpoints 服务名查看Endpoints中是否列出了后端Pod的IP和端口。如果Endpoints为空,说明selector没有匹配到任何Pod,此时需要对比Service的selector和Pod的labels是否一致,包括键名和值的大小写。

其次,检查端口映射是否正确。porttargetPortnodePort三者之间的关系容易被误解。如果Service的targetPort写错,即使Endpoints存在,转发也会失败。在Pod内部,可以使用kubectl exec进入容器,通过curl访问Service的ClusterIP和端口,快速验证Service的转发链路是否正常。

另外,网络策略(NetworkPolicy)也可能阻止流量到达Pod。默认情况下,Kubernetes集群内的网络策略是允许所有流量的,但如果集群管理员配置了默认拒绝规则,就需要显式放行相关流量。最后,如果使用的是NodePort类型,还要确认节点防火墙或安全组是否放行了对应的端口范围。在云环境中,LoadBalancer的配置错误也可能导致外部访问失败,此时应检查云控制台的负载均衡器状态。

Kubernetes Service服务发现负载均衡修改时间:2026-08-26 19:29:35

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。