k8s-服务发布基础
目录
Service的定义
核心定义
Service 的类型
关键组件与机制
工作流程示例
高级特性
Service工作原理
核心工作原理
标签选择器(Label Selector)
Endpoints 对象
网络代理与负载均衡(kube-proxy)
userspace 模式(已淘汰)
iptables 模式(默认)
IPVS 模式(推荐高性能场景)
Service 类型与流量路由
ClusterIP(默认)
NodePort
LoadBalancer
ExternalName
Service的定义
在 Kubernetes(K8s)中,Service 是一个核心抽象资源,用于为一组具有相同功能的 Pod 提供稳定的网络访问入口,并实现服务发现、负载均衡和抽象隔离。
核心定义
- 逻辑抽象层:Service 将一组动态变化的 Pod(通过标签选择器匹配)抽象为一个逻辑服务单元,客户端无需关心后端 Pod 的具体数量、IP 地址或位置。
- 稳定访问入口:为 Pod 分配一个固定的 ClusterIP(虚拟 IP),该 IP 在 Service 生命周期内不变,即使后端 Pod 重建或扩缩容。
- 负载均衡:自动将客户端请求分发到匹配的 Pod,支持轮询(默认)、随机、会话保持等策略。
Service 的类型
根据网络访问方式,Service 分为以下四种类型:
类型 | 访问范围 | 适用场景 |
---|---|---|
ClusterIP | 仅集群内部访问(默认) | 内部服务间通信(如微服务调用、数据库访问)。 |
NodePort | 集群外部通过节点 IP+端口访问 | 开发测试或临时暴露服务(需手动指定节点端口,范围通常为 30000-32767)。 |
LoadBalancer | 外部负载均衡器(云环境) | 生产环境暴露服务,自动创建云厂商的负载均衡器(如 AWS ALB、GCP Load Balancer)。 |
ExternalName | 通过 DNS CNAME 映射外部服务 | 访问集群外部服务(如数据库、第三方 API),无需在集群内运行 Pod。 |
关键组件与机制
- 标签选择器(Label Selector):
- 通过
spec.selector
字段匹配 Pod 的标签(如app: nginx
),动态关联后端 Pod。 - 示例:
apiVersion: v1 kind: Service metadata:name: nginx-service spec:selector:app: nginx # 匹配所有标签为 app=nginx 的 Podports:- protocol: TCPport: 80 # Service 暴露的端口targetPort: 80 # Pod 的容器端口
- Endpoints 对象:
- K8s 自动为每个 Service 创建同名的 Endpoints 资源,记录当前匹配的 Pod IP 和端口。
- 通过
kubectl get endpoints nginx-service
可查看实时关联的 Pod。
- ClusterIP:
- 虚拟 IP,仅在集群内路由有效,由 kube-proxy 通过 iptables/IPVS 实现。
- 客户端访问
ClusterIP:Port
时,请求会被转发到后端 Pod。
- DNS 解析:
- 集群内服务可通过
<service-name>.<namespace>.svc.cluster.local
域名访问(如nginx-service.default.svc.cluster.local
)。 - 简化配置,避免硬编码 IP。
- 集群内服务可通过
- 通过
工作流程示例
- 创建 Deployment:部署 3 个 Nginx Pod,标签为
app=nginx
。 - 创建 Service:
apiVersion: v1 kind: Service metadata:name: nginx-service spec:selector:app: nginxports:- protocol: TCPport: 80targetPort: 80
- 访问服务:
- 集群内其他 Pod 可通过
nginx-service:80
或其 ClusterIP 访问。 - 若为 NodePort 类型,外部可通过
http://<节点IP>:<节点端口>
访问。
- 集群内其他 Pod 可通过
高级特性
- 会话保持(Session Affinity):
- 通过
sessionAffinity: ClientIP
确保同一客户端请求始终路由到同一 Pod。
- 通过
- 外部流量策略:
externalTrafficPolicy: Local
保留客户端源 IP,避免经过 NAT 丢失信息(仅 NodePort/LoadBalancer 有效)。
- 无头服务(Headless Service):
- 设置
clusterIP: None
,不分配 ClusterIP,直接返回 Pod IP 列表(适用于 StatefulSet 或需要直接访问 Pod 的场景)。
- 设置
Service工作原理
Kubernetes(K8s)中的 Service 通过抽象一组动态变化的 Pod,提供稳定的网络访问入口和负载均衡能力。其工作原理涉及 标签选择、Endpoint 管理、网络代理(kube-proxy)和负载均衡 等核心机制。
核心工作原理
标签选择器(Label Selector)
- 作用:Service 通过
spec.selector
字段匹配一组 Pod 的标签(如app=nginx
),动态关联后端 Pod。 - 动态性:当匹配的 Pod 数量或 IP 变化时(如扩容、重建),Service 会自动更新关联的 Endpoint,无需手动干预。
- 示例:
apiVersion: v1 kind: Service metadata:name: nginx-service spec:selector:app: nginx # 匹配所有标签为 app=nginx 的 Podports:- protocol: TCPport: 80 # Service 暴露的端口targetPort: 80 # Pod 的容器端口
Endpoints 对象
- 自动生成:K8s 为每个 Service 创建一个同名的 Endpoints 资源(如
nginx-service
),记录当前匹配的 Pod IP 和端口。 - 实时更新:当 Pod 状态变化(如新增、删除、IP 变更),Endpoints 会同步更新,确保流量始终路由到健康的 Pod。
- 查看 Endpoints:
kubectl get endpoints nginx-service
输出实例:
NAME ENDPOINTS AGE
nginx-service 10.244.1.3:80,10.244.2.5:80 5m
网络代理与负载均衡(kube-proxy)
kube-proxy 是运行在每个节点上的网络代理,负责实现 Service 的负载均衡和流量转发。它支持三种工作模式:
userspace 模式(已淘汰)
- 原理:kube-proxy 作为用户态进程,通过 iptables 捕获 Service 的 ClusterIP 流量,然后转发到后端 Pod。
- 缺点:性能较差(上下文切换开销大),已逐渐被弃用。
iptables 模式(默认)
- 原理:
- kube-proxy 监听 Service 和 Endpoint 的变化,动态生成 iptables 规则。
- 当客户端访问 Service 的 ClusterIP 时,iptables 随机选择一个后端 Pod IP,并将请求转发过去。
- 特点:
- 纯内核态转发,性能较高。
- 支持基本的轮询负载均衡。
- 无法处理会话保持(需通过
sessionAffinity: ClientIP
实现)。
- 查看 iptables 规则:
kubectl get svc nginx-service -o yaml # 获取 ClusterIP iptables -t nat -L | grep <ClusterIP>
IPVS 模式(推荐高性能场景)
- 原理:
- kube-proxy 调用 Linux 内核的 IPVS 模块(基于哈希表的负载均衡器)。
- IPVS 支持多种负载均衡算法(如轮询、加权轮询、最少连接等),性能优于 iptables。
- 启用方式:
- 修改 kube-proxy 启动参数:
--proxy-mode=ipvs
。 - 确保节点已加载 IPVS 内核模块(如
ip_vs_rr
,ip_vs_wrr
)。
- 修改 kube-proxy 启动参数:
- 查看 IPVS 规则:
ipvsadm -Ln
Service 类型与流量路由
根据访问范围,Service 分为四种类型,其流量路由方式如下:
ClusterIP(默认)
- 访问范围:仅集群内部。
- 路由过程:
- 客户端访问
nginx-service:80
或 ClusterIP。 - kube-proxy 通过 iptables/IPVS 将请求转发到匹配的 Pod。
- 客户端访问
- 适用场景:内部服务间通信(如微服务调用)。
ClusterIP实例:
apiVersion: v1
kind: Service
metadata:name: my-service # 服务名称namespace: default # 命名空间(可选)labels:app: my-app # 服务标签
spec:type: ClusterIP # 指定为ClusterIP类型(默认可省略)selector:app: my-app # 匹配Pod的标签ports:- protocol: TCP # 协议类型(TCP/UDP)port: 80 # 服务暴露的端口(集群内部访问)targetPort: 8080 # 后端Pod的端口
NodePort
- 访问范围:外部通过节点 IP + 端口访问。
- 路由过程:
- 客户端访问
<节点IP>:<NodePort>
(如192.168.1.100:30080
)。 - 节点上的 iptables/IPVS 将请求转发到 Service 的 ClusterIP,再路由到 Pod。
- 客户端访问
- 特点:
- NodePort 范围默认 30000-32767。
- 外部流量需手动配置负载均衡器(如 Nginx)分发到多个节点。
NodePort实例:
apiVersion: v1
kind: Service
metadata:name: my-nodeport-servicenamespace: defaultlabels:app: my-app
spec:type: NodePort # 指定为NodePort类型selector:app: my-app # 匹配Pod的标签ports:- protocol: TCPport: 80 # 服务内部端口(供集群内部访问)targetPort: 8080 # 后端Pod的端口nodePort: 30080 # 节点上暴露的端口(可选,默认自动分配30000-32767)
LoadBalancer
- 访问范围:外部通过云厂商负载均衡器访问。
- 路由过程:
- 创建 Service 时指定
type: LoadBalancer
。 - 云控制器(Cloud Controller Manager)自动创建外部负载均衡器(如 AWS ALB)。
- 外部流量通过负载均衡器分发到节点,再路由到 Pod。
- 创建 Service 时指定
- 适用场景:生产环境暴露服务。
loadBalancer实例:
apiVersion: v1
kind: Service
metadata:name: my-loadbalancer-servicenamespace: defaultlabels:app: my-appannotations:# 可选:云服务商特定的注解(如AWS、GKE)service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:type: LoadBalancer # 指定为LoadBalancer类型selector:app: my-app # 匹配Pod的标签ports:- protocol: TCPport: 80 # 服务暴露的端口(负载均衡器端口)targetPort: 8080 # 后端Pod的端口nodePort: 30080 # 可选:自动分配的NodePort(LoadBalancer依赖NodePort实现)externalTrafficPolicy: Cluster # 可选:Cluster(默认)或Local
ExternalName
- 访问范围:通过 DNS CNAME 映射外部服务。
- 路由过程:
- 客户端访问 Service 的 DNS 名称(如
my-db.default.svc.cluster.local
)。 - DNS 解析返回外部服务的 CNAME(如
mysql.example.com
)。
- 客户端访问 Service 的 DNS 名称(如
- 适用场景:访问集群外部数据库或 API。
创建101命名空间所需要的yaml文件
[root@k8s-master opt]# cat myapp01.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: myapp01namespace: test01
spec:replicas: 1selector: #标签选择器matchLabels: #匹配的标签为app: myapp01release: canarytemplate:metadata:labels:app: myapp01 #和上面的myapp要匹配release: canaryspec:containers:- name: myappimage: ikubernetes/myapp:v1ports:- name: http01containerPort: 80
[root@k8s-master opt]# cat myapp-svc-extername01.yaml
kind: Service
apiVersion: v1
metadata:name: myapp-svcname02namespace: test01
spec:type: ExternalNameexternalName: myapp-svc02.test02.svc.cluster.local
[root@k8s-master opt]# cat myapp-svc-headless01.yaml
apiVersion: v1
kind: Service
metadata:name: myapp-svc01namespace: test01
spec:selector:app: myapp01 #挑选的pod还是myapp01。一个pod可以有多个servicerelease: canaryclusterIP: None #None表示是无头serviceports:- port: 39320 #service ip中的端口targetPort: 80 #容器ip中的端口
创建102命名空间所需要的yaml文件
[root@k8s-master opt]# cat myapp-svc-headless02.yaml
apiVersion: v1
kind: Service
metadata:name: myapp-svc02namespace: test02
spec:selector:app: myapp02 #挑选的pod还是myapp。一个pod可以有多个servicerelease: canaryclusterIP: None #None表示是无头serviceports:- port: 39320 #service ip中的端口targetPort: 80 #容器ip中的端口
[root@k8s-master opt]# cat myapp-svc-extername02.yaml
kind: Service
apiVersion: v1
metadata:name: myapp-svcname01namespace: test02
spec:type: ExternalNameexternalName: myapp-svc01.test01.svc.cluster.local
[root@k8s-master opt]# cat myapp02.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: myapp02namespace: test02
spec:replicas: 1selector: #标签选择器matchLabels: #匹配的标签为app: myapp02release: canarytemplate:metadata:labels:app: myapp02 #和上面的myapp要匹配release: canaryspec:containers:- name: myapp02image: ikubernetes/myapp:v1ports:- name: http02containerPort: 80
验证:
##查看test01容器的ip地址
[root@k8s-master opt]# ku get pods -n test01 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp01-696c886d6b-bbvrn 1/1 Running 0 30m 10.244.36.80 k8s-node1 <none> <none>##登陆到test02命名空间的容器,访问test01容器的ip
[root@k8s-master opt]# ku exec -it myapp02-55ffcd5f64-xmgq8 -n test02 -- sh
/ # ping 10.244.36.80
PING 10.244.36.80 (10.244.36.80): 56 data bytes
64 bytes from 10.244.36.80: seq=0 ttl=63 time=0.059 ms
64 bytes from 10.244.36.80: seq=1 ttl=63 time=0.121 ms