Kubernetes 服务发布基础学习
一、Service 概述
(一)Service 的定义
Service 是 Kubernetes 中的一种抽象概念,用于定义一组 Pod 以及访问这组 Pod 的策略。其核心作用是将一组 Pod 封装为一个虚拟服务,并为客户端提供统一的入口,从而实现服务的负载均衡、服务发现与暴露等功能。
具体而言,Service 为提供服务的 Pod 抽象出一个稳定的网络访问地址(通常是 DNS 域名格式的服务名称),客户端应用可通过该地址访问服务,且网络访问方式与传统方式一致。同时,Service 具备负载均衡器的功能,能将客户端请求分发到后端各个 Pod 上。
(二)Service 的重要性
在 Kubernetes 实现微服务架构的过程中,Service 是核心资源。它不仅为客户端提供了稳定的访问地址(域名或 IP 地址)和负载均衡功能,还能屏蔽后端 Endpoint 的变化,使得构建高可用和可扩展的应用程序成为可能。
二、Service 工作原理
(一)基本原理
由于 Pod 的 IP 地址是动态变化的,无法直接通过 Pod 的 IP 地址进行访问,Service 应运而生。它为一组 Pod 创建一个虚拟的 IP 地址,客户端通过该 IP 地址访问时,请求会被负载均衡到其中一个 Pod 上。
Service 的实现依赖于 kube-proxy 和 CoreDNS 组件:
kube-proxy:在每个节点上监听 Service 的变化,一旦 Service 发生变化,便更新本地的 iptables 规则,实现流量的转发和负载均衡。
CoreDNS:作为 Kubernetes 集群中的 DNS 解析服务,将 Service 的虚拟 IP 地址注册其中,使客户端可通过 Service 名称访问虚拟 IP 地址。
通过在 Service 定义中使用 spec.selector 字段指定属于该 Service 的 Pod 标签,可将请求负载均衡到这些 Pod 上。
(二)负载均衡机制
当 Service 对象在 Kubernetes 集群中定义后,集群内的客户端应用可通过服务 IP 访问 Pod 提供的服务,而从服务 IP 到后端 Pod 的负载均衡由每个节点上的 kube-proxy 代理实现。kube-proxy 的代理模式主要有以下几种:
- userspace 模式
- 初期的 kube-proxy 是一个真实的 TCP/UDP 代理。当 Pod 以 ClusterIP 方式访问 Service 时,流量会被本机的 iptables 转发到 kube-proxy 进程,再由其转发到后端 Pod。
- 具体过程为:kube-proxy 为每个 Service 在节点上打开一个随机代理端口,建立 iptables 规则将 ClusterIP 的请求重定向到该端口,然后由 kube-proxy 转发到后端 Pod。
- 由于存在内核态到用户态的切换,开销较大,该模式已被废弃。
- iptables 模式
- 从 Kubernetes 1.2 版本开始,iptables 模式成为默认模式。此时 kube-proxy 不再负责转发数据包,而是通过 API Server 的 Watch 接口实时跟踪 Service 和 Endpoint 的变更信息,并更新对应的 iptables 规则。客户端的请求流量通过 iptables 的 NAT 机制直接路由到目标 Pod。
- 该模式下不存在内核态到用户态的切换,效率显著提高。但随着 Service 数量的增加,iptables 规则不断增多,会导致内核负担加重。
- ipvs 模式
- 从 Kubernetes 1.8 版本开始引入 ipvs 模式,它基于 netfilter 实现,专门用于高性能负载均衡,使用高效的 Hash 表数据结构,允许几乎无限的规模扩张。
- ipvs 提供了多种负载均衡算法,如 rr(轮训)、lc(最小连接数)、df(目标哈希)、sh(源哈希)、sed(预计延迟最短)、nq(从不排队)等。
- ipvs 使用 ipset 存储 iptables 规则,查找时类似 Hash 表查找,时间复杂度为 O (1),而 iptables 的时间复杂度为 O (n),因此 ipvs 模式性能更优。若操作系统未启用 IPVS 内核模块,kube-proxy 会自动切换为 iptables 模式;若启用了,则运行在 ipvs 模式。可通过命令
lsmod | grep ip_vs
查看系统是否开启了 ipvs 模块。
- kernelspace 模式
- 这是 Windows Server 上的代理模式,文档中未作详细介绍。
三、Service 的四种类型
Kubernetes 支持四种 Service 类型,分别适用于不同的应用场景:
(一)ClusterIP
- 特点:这是最常用的 Service 类型,为 Pod 提供一个虚拟的 IP 地址,其他 Pod 可通过该虚拟 IP 地址访问该 Service,Kubernetes 会自动将请求路由到相应的 Pod。
- 使用场景:适用于集群内部的服务通信,例如连接前端服务和后端服务,供内部其他服务使用。
- 示例:通过
kubectl expose deployment webapp
命令或 YAML 文件可创建 ClusterIP 类型的 Service。创建后,系统会分配一个虚拟 IP 地址,客户端可通过该 IP 地址和端口号访问 Service,请求会被自动负载分发到后端的 Pod。
(二)NodePort
- 特点:将 Pod 公开为集群中所有节点上的某个端口,当外部请求到达任何一个节点上的该端口时,Kubernetes 会将请求路由到相应的 Pod。它会创建一个 ClusterIP,并将指定的端口映射到每个节点上的相同端口。
- 使用场景:当需要从外部访问集群中的服务时,可通过节点的 IP 地址和映射的端口进行访问,适用于开发和测试环境。
- 示例:在 YAML 文件中设置
type: NodePort
和nodePort: 30008
等参数可创建 NodePort 类型的 Service。创建后,可在 Windows 宿主机上通过浏览器访问http://节点IP:30008
来测试服务。
(三)LoadBalancer
- 特点:使用云提供商的负载均衡器将请求路由到后端 Pod,Kubernetes 会自动创建和配置负载均衡器,并将其绑定到 Service 上。
- 使用场景:适用于需要将流量从外部负载均衡器分发到集群内部的服务,例如在生产环境中暴露 Web 应用程序。
- 示例:在 YAML 文件中设置
type: LoadBalancer
等参数可创建 LoadBalancer 类型的 Service。创建后,云服务商会在 Service 定义中补充 LoadBalancer 的 IP 地址,客户端可通过该 IP 地址和端口号访问服务。
(四)ExternalName
- 特点:允许 Service 通过返回 CNAME 记录来引用集群外部的服务,它没有 ClusterIP、NodePort 或 LoadBalancer。
- 使用场景:适用于需要将 Kubernetes 内部的服务与集群外的现有服务进行关联,例如连接到外部的数据库或其他资源。此外,还可用于实现两个不同命名空间中的 Pod 通过 Service 名称进行通信。
- 示例:通过在 YAML 文件中设置
type: ExternalName
和externalName
字段指定外部服务的地址(如域名或 IP)可创建 ExternalName 类型的 Service。创建后,集群内客户端应用可通过访问该 Service 来访问外部服务。
四、生成用于测试 Service 的 Deployment
在应用 Service 概念之前,需先创建一个提供 Web 服务的 Pod 集合,以方便对各种 Service 进行验证。以下是创建过程:
(一)编辑 Deployment YAML 文件
apiVersion: apps/v1
kind: Deployment
metadata:name: webapp
spec:replicas: 2 # Pod的副本数selector: # 目标Pod的标签选择器matchLabels: # 需要匹配的标签app: webapp # 对应目标Pod的标签名称template: # 自动创建新Pod副本的模板metadata:labels: # 定义Pod的标签app: webapp # 标签值为app:webappspec:containers:- name: webappimage: kubeguide/tomcat-app:v1ports:- name: httpcontainerPort: 8080protocol: TCP
(二)创建 Deployment
使用命令kubectl create -f webapp-deployment.yaml
创建 Deployment。
(三)查看 Pod 创建情况
通过kubectl get pod
命令可查看 Pod 的创建状态,确保 Pod 处于 Running 状态。
(四)查看 Pod 的 IP 地址
使用kubectl get pods -l app=webapp -o wide
命令可查看各个 Pod 的 IP 地址。
(五)访问 Pod 地址
通过curl Pod IP:8080
命令可访问 Pod 提供的服务,验证 Pod 是否正常工作。
五、Service 的创建
(一)创建 ClusterIP 类型 Service
- 通过 expose 命令创建
- 执行
kubectl expose deployment webapp
命令暴露端口。 - 查看创建的 Service:
kubectl get svc
,系统会分配一个虚拟 IP 地址。 - 访问测试:
curl 虚拟IP:8080
,请求会被负载分发到后端 Pod。 - 删除 Service:
kubectl delete service webapp
。
- 执行
- 使用 YAML 文件创建编辑 YAML 文件:
apiVersion: v1
kind: Service
metadata:name: webapp
spec:ports:- protocol: TCPport: 8080targetPort: 8080selector:app: webapp
创建服务:kubectl create -f webapp-service.yaml
。
查看并访问测试:kubectl get svc
获取虚拟 IP,然后curl 虚拟IP:8080
。
查看 EndPoint 列表:kubectl describe svc webapp
可查看后端的 EndPoint(Pod 的 IP 和端口)。
查看 EndPoint 资源对象:kubectl get endpoints
。
删除 Service:kubectl delete -f webapp-service.yaml
或kubectl delete service webapp
。
(二)创建 NodePort 类型的 Service
- 创建 Service 文件
apiVersion: v1
kind: Service
metadata:name: webapp
spec:type: NodePortports:- port: 8080targetPort: 8080nodePort: 30008selector:app: webapp
创建 Service:kubectl create -f webapp-svc-nodeport.yaml
。
查看创建的 Service:kubectl get svc
,可见 NodePort 类型及端口映射信息。
测试访问:在 Windows 宿主机上通过浏览器访问http://节点IP:30008
。
删除 Service:kubectl delete -f webapp-svc-nodeport.yaml
。
(三)创建 LoadBalancer 类型的 Service
- 编写 YAML 文件
apiVersion: v1
kind: Service
metadata:name: webappnamespace: defaultlabels:app: webapp
spec:type: LoadBalancerports:- port: 8080targetPort: httpprotocol: TCPname: httpnodePort: 31771 # 可选,系统会自动指定selector:app: webapp
创建 Service:kubectl create -f webapp-svc-loadbalancer.yaml
。
查看创建结果:kubectl get svc
,External-IP 初始为<pending>,待云提供商分配后会显示具体 IP。
访问测试:通过负载均衡器的 IP 和端口访问服务。
删除 Service:kubectl delete -f webapp-svc-loadbalancer.yaml
。
(四)创建 ExternalName 类型的 Service
以两个不同命名空间中的 Pod 通信为例:
创建两个命名空间:kubectl create namespace test01
和kubectl create namespace test02
。
- 在 test01 命名空间创建 Pod 和相关 Service
- 创建 Pod 的 Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:name: myapp01namespace: test01
spec:replicas: 1selector:matchLabels:app: myapp01release: canarytemplate:metadata:labels:app: myapp01release: canaryspec:containers:- name: myappimage: ikubernetes/myapp:v1ports:- name: http01containerPort: 80
创建无头 Service
apiVersion: v1
kind: Service
metadata:name: myapp-svc01namespace: test01
spec:selector:app: myapp01release: canaryclusterIP: None # 无头Serviceports:- port: 39320targetPort: 80
创建 ExternalName Service:
kind: Service
apiVersion: v1
metadata:name: myapp-svcname02namespace: test01
spec:type: ExternalNameexternalName: myapp-svc02.test02.svc.cluster.local
- 在 test02 命名空间创建 Pod 和相关 Service
- 类似地,创建 myapp02 的 Deployment、无头 Service 和 ExternalName Service,注意命名空间和引用的服务名称。
- 验证 Pod 间的通信
- 通过
kubectl exec
进入 Pod,使用nslookup
和ping
命令验证是否可通过 Service 名称解析到对方 Pod 的 IP 地址,实现跨命名空间通信。
- 通过
六、Service 的其他应用
(一)Service 的多端口设置
当容器应用提供多个端口服务时,可在 Service 定义中设置多个端口号:
创建 Service 文件
apiVersion: v1
kind: Service
metadata:name: webapp
spec:ports:- port: 8080targetPort: 8080name: webprotocol: TCP- port: 8005targetPort: 8005name: managementprotocol: TCPselector:app: webapp
- 创建 Service:
kubectl create -f service-multiple-ports.yaml
。 - 查看 EndPoint 列表和 Service 信息:
kubectl describe svc webapp
和kubectl get svc webapp
。 - 删除 Service:
kubectl delete -f webapp-service.yaml
或kubectl delete service webapp
。
(二)Kubernetes 服务发现
服务发现机制用于客户端获知后端服务的访问地址,主要有以下两种方式:
- 基于环境变量的服务发现
- 当 Pod 部署到节点后,节点上的 kubelet 会在 Pod 内部设置一组基于活跃 Service 生成的环境变量。
- 使用该方式时,需先创建 Service,再创建 Pod。Pod 运行时,系统会自动为其容器注入所有有效 Service 的信息,包括服务 IP、端口号、协议等。
- 客户端应用可根据 Service 相关环境变量的命名规则,从环境变量中获取目标服务的地址。例如,通过
kubectl exec -it Pod名称 -- env
命令可查看 Pod 中的环境变量。
- 基于 DNS 的服务发现
- Kubernetes 新版默认使用 CoreDNS 作为集群内部 DNS,一般 CoreDNS 的 Service 地址为 Service 网段的低 10 个地址(如 10.96.0.10),端口为 53。
- DNS 服务器监听 Kubernetes 创建的 Service,并为每个 Service 添加一组 DNS 记录,集群中的 Pod 可通过内部 DNS 解析到 Service 的 ClusterIP。
- 例如,创建一个含 nslookup 命令的容器,通过
kubectl exec -it 容器名称 -- nslookup Service名称
可测试 DNS 解析。
七、案例练习
(一)案例一:创建 LoadBalancer 类型的 Nginx 服务
- YAML 文件
apiVersion: v1
kind: Service
metadata:name: mynginxnamespace: defaultlabels:app: mynginx
spec:type: LoadBalancerports:- port: 80targetPort: httpprotocol: TCPname: httpselector:app: mynginxapiVersion: apps/v1
kind: Deployment
metadata:name: mynginx-deploymentnamespace: defaultlabels:app: mynginx
spec:replicas: 2selector:matchLabels:app: mynginxtemplate:metadata:labels:app: mynginxspec:containers:- name: mynginximage: nginx:1.7.9ports:- name: httpcontainerPort: 80protocol: TCP
- 创建服务和 Deployment:
kubectl create -f nginx-service.yaml
。
(二)案例二:创建 NodePort 类型的 Tomcat 服务
- YAML 文件
apiVersion: v1
kind: Service
metadata:name: webapp
spec:type: NodePortports:- port: 8080targetPort: 8080nodePort: 30008selector:app: webappapiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:replicas: 2selector:matchLabels:app: webapptemplate:metadata:labels:app: webappspec:containers:- name: webappimage: kubeguide/tomcat-app:v1ports:- name: httpcontainerPort: 8080protocol: TCP
- 创建服务和 Deployment:
kubectl create -f tomcat-service.yaml
。
八、本章总结
本章全面介绍了 Kubernetes 中 Service 的核心知识,包括概念、工作原理、类型、创建方法及相关应用:
- Service 的核心作用:作为 Pod 的抽象,为其提供稳定的访问入口,实现负载均衡、服务发现与暴露,是 Kubernetes 微服务架构的核心。
- 工作原理关键组件:kube-proxy 负责流量转发和负载均衡规则更新,CoreDNS 实现 Service 的 DNS 解析。
- 四种 Service 类型特点与场景:
- ClusterIP:集群内部通信。
- NodePort:外部通过节点端口访问。
- LoadBalancer:结合云服务商负载均衡器。
- ExternalName:关联集群外部服务。
- 服务发现机制:基于环境变量和 DNS,使客户端能便捷获取服务地址。
- 实践应用:通过 Deployment 配合不同类型 Service 的创建与配置案例,掌握了 Service 在实际场景中的运用