k8sday10服务发现(1/2)

目录

Service(svc)

一、概念区分

1、Service

[2、Endpoint / EndpointSlice](#2、Endpoint / EndpointSlice)

3、kube-proxy

4、Pod

5、总结

二、配置文件

1、举例

2、不同类型的Service

①、ClusterIP

②、NodePort

③、LoadBalancer

④、ExternalName

⑤、选型总结

3、Service匹配

4、常见命令

三、访问集群内部服务

[四、访问集群外部静态 IP](#四、访问集群外部静态 IP)

五、访问集群外部域名

六、访问服务

[1、确保 Service 已选中 Pod](#1、确保 Service 已选中 Pod)

2、进入某个容器

[3、在容器里访问 Service](#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.yaml
  apiVersion: v1         # Service的API版本(固定为v1)
  kind: Service          # 资源类型为Service
  metadata:              # 元数据
    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"的Pod
    ports:               # 端口映射规则(可配置多个)
    - 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、常见命令
bash 复制代码
 # 1、创建/更新
  # 用 expose 快速生成 Service
  kubectl 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         # 带 selector
  kubectl 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
  # 快速改 selector
  kubectl patch svc nginx-svc -p '{"spec":{"selector":{"app":"new-label"}}}'
  ​
  # 7、删除service以及其yaml配置文件
  kubectl delete svc nginx-svc
  kubectl delete -f nginx-svc.yaml

三、访问集群内部服务

  • ClusterIP / Headless

二、配置文件中给出的例子就可适配集群内部的访问

当然我可以再给出一个极简的yaml配置文件

bash 复制代码
apiVersion: v1
  kind: Service
  metadata:
    name: nginx
  spec:
    type: ClusterIP        # 默认
    selector:
      app: nginx           # 匹配 Pod label
    ports:
    - port: 80
      targetPort: 80

浏览器 / 其他 Pod

│① DNS解析

ClusterIP

│② kube-proxy DNAT

Pod

四、访问集群外部静态 IP

  • Service(无 selector) + Endpoints

给出一份极简的yaml配置文件,其实就是分为两个写,确保二者的name相同即可

bash 复制代码
 # Service(无 selector)
  ---
  apiVersion: v1
  kind: Service          # 声明资源类型是Service
  metadata:
    name: db              # 集群内域名就是 db.default.svc.cluster.local
  spec:
    type: ClusterIP     
    ports:
    - port: 3306
      targetPort: 3306
      
  # Endpoints
  ---
  apiVersion: v1
  kind: Endpoints        # 声明资源类型是Endpoints
  metadata:
    name: db              # 与 Service 的 name 同名
  subsets:
  - addresses:
    - ip: 203.0.113.10    # 外部你要访问的服务的实际 IP
    # 注意203.0.113.10是你自己手动输入的要访问的外部IP
    ports:
    - port: 3306

k8s内部服务

Service

Endpoints

外部你要访问的ip

五、访问集群外部域名

  • ExternalName

只给出一份极简的yaml配置文件,其实只是把你的Service的类型修改为ExternalName

bash 复制代码
  apiVersion: v1
  kind: Service
  metadata:
    name: api-partner
  spec:
    type: ExternalName              # 只用修改type类型,再加上外部你要访问的域名即可
    externalName: api.partner.com   # 任何公网域名

k8s内部服务

Service

外部你要访问的域名

六、访问服务

本部分主要演示在实现了三、四、五的配置文件后,如何访问服务

以下以一个nginx的集群内部服务访问为例

1、确保 Service 已选中 Pod
bash 复制代码
# 查看已有Service
  kubectl get svc
  # 查看详细信息
  kubectl describe svc <你自己的Service名称>
  kubectl get endpoints <你的Pod名称>
  # 这个会输出和你service中相同的endpoints
2、进入某个容器
bash 复制代码
  kubectl exec -it deployment/nginx -- /bin/sh
  # deployment/nginx可替换为你自己要进入的容器
3、在容器里访问 Service
bash 复制代码
  # 用 Service 名称(推荐)
  curl http://nginx
  # 或使用你的内部域名
  curl http://nginx.default.svc.cluster.local
  ​
  # 用 ClusterIP(同样有效)
  curl http://10.96.0.123

如果容器镜像没有 curl,可以换成 wget 等等

4、退出容器
bash 复制代码
  exit

ExternalName / 无 selector + Endpoints 的外部 Service 同样适用,只要 DNS/CoreDNS 已同步

ExternalNameService+Endpoints 方式:容器内用 Service 名 就能访问外部服务