k8sday10服务发现(1/2)
目录
Service(svc)
一、概念区分
1、Service
2、Endpoint / EndpointSlice
3、kube-proxy
4、Pod
5、总结
二、配置文件
1、举例
2、不同类型的Service
①、ClusterIP
②、NodePort
③、LoadBalancer
④、ExternalName
⑤、选型总结
3、Service匹配
4、常见命令
三、访问集群内部服务
四、访问集群外部静态 IP
五、访问集群外部域名
六、访问服务
1、确保 Service 已选中 Pod
2、进入某个容器
3、在容器里访问 Service
4、退出容器
Service(svc)
实现集群内部网络的调用,主控东西流量(横向流量),如对同一个集群中的节点进行互相访问。其本质是一条存储在 etcd 中的逻辑记录,没有任何进程在监听这个 IP,真正让它“生效”的是 kube-proxy。
一、概念区分
组件 | 角色 |
---|---|
Service | 稳定的入口(如ClusterIP:80),定义了要暴露的Pod标签(selector)和端口映射(ports)。 |
Endpoint (老版本) EndpointSlice(新版本) | Service的后端列表(自动生成),存储了匹配selector 的Pod的IP+Port(如10.244.1.5:80 )。如果Service的selector 没有匹配到Pod,Endpoint会是空的。 |
kube-proxy | 运行在每个节点上的网络代理,负责:- 监控Service和Endpoint的变化;- 配置节点上的网络规则(如iptables/ipvs);- 将Service的请求负载均衡到后端Pod。 |
Pod | 实际提供服务的容器(如nginx),通过containerPort 暴露端口(如80)。 |
API Server | 集群的中央枢纽,存储和管理所有资源对象的状态。 |
ContainerPort | 容器内部的监听端口,是服务暴露的最终端口(定义在yaml文件中)。 |
1、Service
就是给一组 Pod 提供一个“不变的入口”,解耦调用方与 Pod 生命周期。
2、Endpoint / EndpointSlice
Service 选中哪些 Pod,kube-controller-manager 就自动为 Service 生成同名的 Endpoints(老版本)或 EndpointSlice(新版本,性能好),同名的Endpoints或 EndpointSlice内容就是 PodIP:ContainerPort。
3、kube-proxy
部署:以 DaemonSet 或裸进程方式跑在每个节点上。当观察到watch Service/EndpointSlice 变化等,会生成配置规则【iptables(默认)或 ipvs(性能好)或 nftables(未来)或 userspace(已废弃)】,实现 NodePort/ExternalIP/LoadBalancer 的南北向流量入口,可做负载均衡等
4、Pod
最终流量目的地;Pod 的 IP 是集群私网地址,生命周期短。
5、总结
Service 是“虚拟入口”,EndpointSlice 是“后端列表”,Pod 是“实际进程”,kube-proxy 是“在每个节点上把虚拟入口和后端列表翻译成内核转发规则的守护进程”。
二、配置文件
1、举例
以下提供一个简易的service的YAML文件,会话亲和性、拓扑感知、健康检查等等有需要自行添加:
# 文件名:nginx-service1.yamlapiVersion: v1 # Service的API版本(固定为v1)kind: Service # 资源类型为Servicemetadata: # 元数据name: nginx-service1 # Service的名称(唯一标识)labels: # Service的标签(用于筛选)app: nginx # 标签(自定义)spec: # 规约(期望状态)type: ClusterIP # Service类型(ClusterIP/NodePort/LoadBalancer/ExternalName)selector: # 关键!用于选择要暴露的Pod(通过标签匹配)app: nginx-deployment1 # 匹配label为"app: nginx-deployment1"的Podports: # 端口映射规则(可配置多个)- name: http # 端口名称(可选,用于区分多个端口)protocol: TCP # 协议(TCP/UDP/SCTP,默认TCP)port: 80 # Service暴露的端口(集群内部访问用)targetPort: 80 # Pod中容器的端口(Service转发的目标端口)# nodePort: 30080 # 仅NodePort类型需要,暴露到节点的端口(范围30000-32767)
2、不同类型的Service
类型 | 用途 | 示例配置 |
---|---|---|
ClusterIP | 集群内部访问(默认) | type: ClusterIP |
NodePort | 暴露到节点的端口(外部可访问) | type: NodePort + nodePort: 30080 (节点IP:30080访问) |
LoadBalancer | 结合云厂商负载均衡器(如AWS ELB、阿里云SLB),外部可访问 | type: LoadBalancer (云厂商会自动创建负载均衡器) |
ExternalName | 映射到外部域名(如example.com ) | type: ExternalName + externalName: example.com (访问Service等于访问外部域名) |
①、ClusterIP
当需要service仅在集群内部被访问,或作为其他service的后端,即可选择ClusterIP
-
优点:简单高效,无需暴露到外部,可自动 DNS 解析
-
缺点:无法直接从集群外访问
-
特殊变体:Headless=
type: ClusterIP
+clusterIP: None
②、NodePort
需要临时从外部访问集群内服务(如开发测试环境),即可选择NodePort(在 ClusterIP 基础上,会额外给每个节点开一个nodePort: 30000-32767 之间的端口),可通过NodePort和nodePort二者配合暴露端口(只有四层负载),效率较低
-
优点:不依赖云厂商,所有节点自动开放端口,可通过任意节点IP访问
-
缺点:需手动管理节点IP和端口,端口有限(端口范围 30000-32767),节点 IP 可能变化,需自行处理高可用(多节点负载均衡)
③、LoadBalancer
需要云厂商提供的负载均衡器(自动分配公网IP、健康检查等),生产环境需要稳定、高可用的外部访问(如公有云部署),即可选择LoadBalancer
-
优点:自动向云厂商 API 申请一个外部负载均衡器(ELB/NLB/SLB)来创建,支持 SSL 终止、流量监控等高级功能
-
缺点:依赖云厂商,可能产生费用,私有化部署需额外插件
④、ExternalName
将 Kubernetes 服务映射到集群外的域名(如旧系统、第三方API),统一集群内外服务,即可选择ExternalName
-
优点:无需维护 Pod 或 Endpoint,可让不同命名空间/集群共享外部服务,无需手动改代码
-
缺点:不支持端口映射或负载均衡
⑤、选型总结
Ⅰ、默认选择,只在集群内部通信 ——>ClusterIP
Ⅱ、临时外部访问或兼容旧系统,裸机调试 ——>NodePort
Ⅲ、生产环境云部署,公有云生产 ——>LoadBalancer
Ⅳ、集成外部服务,指向外部域名 ——>ExternalName
3、Service匹配
同一组 Pod可以被 任意多个 Service 选中,确定服务看 Service 的 Selector 与 Pod 的 labels 是否匹配。任何最终会产生 Pod 并携带 labels 的资源,都可以成为 Service 的后端。
Service 永远只看 Pod 的 labels,不看 Deployment、StatefulSet 等控制器的 labels;控制器 selector
也只是用来“挑 Pod”,与 Service 无关。
资源类型 | 是否直接产生 Pod | 典型场景/说明 |
---|---|---|
Deployment | ✅ | 最常用的无状态服务 |
ReplicaSet | ✅ | Deployment 的下层实现,也可以单独使用 |
StatefulSet | ✅ | 需要稳定网络标识、持久卷的有状态服务 |
DaemonSet | ✅ | 每个节点跑一个 Pod |
Job / CronJob | ✅ | 一次性 / 定时任务产生的 Pod |
ReplicationController | ✅ | 早期资源,已不推荐使用 |
Pod | ✅ | 裸 Pod(不推荐,缺少自愈能力) |
ReplicaSet(由 Deployment 管理) | ✅ | 理解层级即可 |
我给出我的Service服务来解释匹配, 例如:
要想使下面的nginx-service1服务也有与之匹配的Pod,只需重新生成一个Pod,内部配置labels:nginx-deployment1或者修改这个service的selector,使之等于当前已有Pod的labels。
4、常见命令
# 1、创建/更新# 用 expose 快速生成 Servicekubectl expose deploy nginx --name=nginx-svc --port=80 --target-port=80# 2、指定 Service类型kubectl expose deploy nginx --name=nginx-np --type=<你要指定的类型> --port=80 --target-port=80# 3、从 YAML 文件创建/更新kubectl apply -f <你的配置文件名># 4、查看kubectl get svc # 极简列表kubectl get svc -o wide # 带 selectorkubectl describe svc nginx-svc # 详细信息kubectl get endpoints nginx-svc # 看后端 PodIP:Port# 5、调试访问# 集群内临时 Pod 测试kubectl run tmp-$RANDOM --rm -it --image=curlimages/curl -- curl http://nginx-svc# kubectl run tmp-$RANDOM 创建一个名字随机的 Pod(如 tmp-28471),避免重名。# --rm 容器退出后自动删除 Pod,不留下垃圾。# -it 交互模式(-i 保持 stdin,-t 分配伪终端),让你能在 Pod 里敲命令。# --image=curlimages/curl 使用超轻量的镜像 curlimages/curl,里面只有 curl 二进制,启动快。# -- curl http://nginx-svc 容器启动后立刻执行 curl http://nginx-svc,请求集群内的 Service。# 端口转发到本地(无需 ingress)kubectl port-forward svc/nginx-svc 8080:80# 浏览器访问 http://localhost:8080# 6、修改# 在线编辑(当然也可以直接出去使用外部编辑器编辑yaml文件)kubectl edit svc nginx-svc# 快速改 selectorkubectl patch svc nginx-svc -p '{"spec":{"selector":{"app":"new-label"}}}'# 7、删除service以及其yaml配置文件kubectl delete svc nginx-svckubectl delete -f nginx-svc.yaml
三、访问集群内部服务
-
用 ClusterIP / Headless
二、配置文件中给出的例子就可适配集群内部的访问
当然我可以再给出一个极简的yaml配置文件
apiVersion: v1kind: Servicemetadata:name: nginxspec:type: ClusterIP # 默认selector:app: nginx # 匹配 Pod labelports:- port: 80targetPort: 80
浏览器 / 其他 Pod
│
│① DNS解析
▼
ClusterIP
│
│② kube-proxy DNAT
▼
Pod
四、访问集群外部静态 IP
-
Service(无 selector) + Endpoints
给出一份极简的yaml配置文件,其实就是分为两个写,确保二者的name相同即可
# Service(无 selector)---apiVersion: v1kind: Service # 声明资源类型是Servicemetadata:name: db # 集群内域名就是 db.default.svc.cluster.localspec:type: ClusterIP ports:- port: 3306targetPort: 3306# Endpoints---apiVersion: v1kind: Endpoints # 声明资源类型是Endpointsmetadata:name: db # 与 Service 的 name 同名subsets:- addresses:- ip: 203.0.113.10 # 外部你要访问的服务的实际 IP# 注意203.0.113.10是你自己手动输入的要访问的外部IPports:- port: 3306
k8s内部服务
│
│
▼
Service
│
│
▼
Endpoints
│
│
▼
外部你要访问的ip
五、访问集群外部域名
-
ExternalName
只给出一份极简的yaml配置文件,其实只是把你的Service的类型修改为ExternalName
apiVersion: v1kind: Servicemetadata:name: api-partnerspec:type: ExternalName # 只用修改type类型,再加上外部你要访问的域名即可externalName: api.partner.com # 任何公网域名
k8s内部服务
│
│
▼
Service
│
│
▼
外部你要访问的域名
六、访问服务
本部分主要演示在实现了三、四、五的配置文件后,如何访问服务
以下以一个nginx的集群内部服务访问为例
1、确保 Service 已选中 Pod
# 查看已有Servicekubectl get svc# 查看详细信息kubectl describe svc <你自己的Service名称>kubectl get endpoints <你的Pod名称># 这个会输出和你service中相同的endpoints
2、进入某个容器
kubectl exec -it deployment/nginx -- /bin/sh# deployment/nginx可替换为你自己要进入的容器
3、在容器里访问 Service
# 用 Service 名称(推荐)curl http://nginx# 或使用你的内部域名curl http://nginx.default.svc.cluster.local# 用 ClusterIP(同样有效)curl http://10.96.0.123
如果容器镜像没有 curl,可以换成 wget 等等
4、退出容器
exit
ExternalName / 无 selector + Endpoints 的外部 Service 同样适用,只要 DNS/CoreDNS 已同步
ExternalName 和 Service+Endpoints 方式:容器内用 Service 名 就能访问外部服务