【一起来学kubernetes】24、Service使用详解
Kubernetes 中的 Service 是用于暴露应用服务的核心抽象,为 Pod 提供稳定的访问入口、负载均衡和服务发现机制。Service在Kubernetes中代表了一组Pod的逻辑集合,通过创建一个Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并将请求负载分发到后端的各个容器应用上。
一、Service 的核心作用
-
服务发现
- 为一组动态变化的 Pod(通过标签选择器)提供固定的访问地址(IP/DNS)。
- 客户端无需关心 Pod 的具体位置和数量。
-
负载均衡
- 将请求均匀分发到后端 Pod,支持多种负载均衡策略(如轮询、会话保持等)。
-
抽象网络访问
- 屏蔽 Pod 的动态变化(扩缩容、重启、迁移),对外提供稳定的服务入口。
二、Service 的类型
Kubernetes 支持多种 Service 类型,适用于不同场景:
类型 | 说明 | 适用场景 |
---|---|---|
ClusterIP | 默认类型,为 Service 分配集群内部的虚拟 IP(仅集群内可访问)。 | 内部服务通信(如微服务间调用) |
NodePort | 在每个节点上开放一个固定端口(默认范围 30000-32767),通过 节点IP:端口 访问。 | 允许外部通过节点 IP 访问服务 |
LoadBalancer | 集成云厂商的负载均衡器(如 AWS ALB、GCP LB),自动分配外部 IP。 | 公有云环境下的外部服务暴露 |
ExternalName | 将 Service 映射到外部 DNS 名称(如数据库域名),实现外部服务代理。 | 代理集群外服务(如云数据库) |
Headless | 无 ClusterIP,直接返回 Pod IP 列表(需设置 clusterIP: None )。 | 有状态服务(如 StatefulSet 的 DNS 记录) |
三、Service 的架构与关键组件
1. 核心概念
-
Label Selector
通过标签(如app: web
)选择后端 Pod。只有匹配标签的 Pod 会被 Service 纳入负载均衡池。 -
Endpoints
Service 的后端 Pod IP 列表,自动维护(由 Endpoints Controller 管理)。 -
kube-proxy
负责实现 Service 的负载均衡规则,支持以下模式: -
iptables(默认):通过 iptables 规则转发流量。
-
IPVS:基于内核的 IP Virtual Server,性能更高。
-
userspace(已弃用):用户态代理,性能较差。
2. 流量转发流程
- 客户端访问 Service 的 ClusterIP 或 DNS 名称。
- kube-proxy 根据 Service 规则将请求转发到后端 Pod。
- 请求到达 Pod 后由应用处理。
四、Service 的 YAML 示例
1. ClusterIP 类型
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: ClusterIP
selector:
app: web # 选择标签为 app=web 的 Pod
ports:
- protocol: TCP
port: 80 # Service 暴露的端口
targetPort: 80 # Pod 监听的端口
2. NodePort 类型
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 31000 # 手动指定节点端口(可选)
3. LoadBalancer类型
-
. 定义YAML文件:
首先,你需要定义一个YAML文件来描述Service的属性。以下是一个示例YAML文件,用于创建一个LoadBalancer类型的Service:apiVersion: v1 kind: Service metadata: name: my-loadbalancer-service spec: selector: app: my-app ports: - protocol: TCP port: 80 targetPort: 8080 type: LoadBalancer
在这个示例中:
apiVersion
指定了Kubernetes API的版本。kind
指定了资源类型为Service。metadata.name
指定了Service的名称。spec.selector
用于选择哪些Pod将被此Service暴露。这里选择的是标签为app: my-app
的Pod。spec.ports
定义了Service监听的端口以及目标Pod的端口。这里Service监听的端口是80,目标Pod的端口是8080。spec.type
指定了Service的类型为LoadBalancer。
-
. 应用YAML文件:
使用kubectl apply命令将YAML文件应用到Kubernetes集群中:kubectl apply -f my-loadbalancer-service.yaml
-
. 等待外部IP分配:
LoadBalancer类型的Service是异步创建的。创建后,Kubernetes会请求云提供商创建一个外部负载均衡器,并将流量路由到后端Pod。这个过程可能需要一些时间。你可以使用kubectl get service命令查看Service的状态,并等待EXTERNAL-IP列显示一个有效的IP地址:kubectl get service my-loadbalancer-service
一旦EXTERNAL-IP列显示了一个IP地址,就意味着外部负载均衡器已经创建成功,你可以通过这个IP地址访问你的Service。
4. ExternalName类型
在Kubernetes(k8s)中,创建一个ExternalName类型的Service可以让你将集群内部的服务通过DNS CNAME机制映射到一个外部域名上。这样,集群内部的Pod就可以通过内部服务名访问外部服务,而无需知道外部服务的真实域名。以下是创建ExternalName类型Service的步骤:
- 定义YAML文件
首先,你需要定义一个YAML文件来描述Service的属性。以下是一个示例YAML文件,用于创建一个ExternalName类型的Service:
apiVersion: v1
kind: Service
metadata:
name: my-externalname-service
namespace: default # 或者你指定的其他命名空间
spec:
type: ExternalName
externalName: www.example.com # 外部服务的域名
在这个示例中:
apiVersion
指定了Kubernetes API的版本。kind
指定了资源类型为Service。metadata.name
指定了Service的名称。metadata.namespace
指定了Service所在的命名空间(可选,默认为default)。spec.type
指定了Service的类型为ExternalName。spec.externalName
指定了外部服务的域名。
- 应用YAML文件
使用kubectl apply命令将YAML文件应用到Kubernetes集群中:
kubectl apply -f my-externalname-service.yaml
- 验证Service
创建完成后,你可以使用kubectl get service命令查看Service的状态:
kubectl get service my-externalname-service -n default # 如果指定了命名空间,则加上-n参数
你应该会看到类似以下的输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-externalname-service ExternalName <none> www.example.com <none> <age>
此时,Service已经成功创建,并且已经通过DNS CNAME机制映射到了外部域名www.example.com
上。
- 访问外部服务
在集群内部的Pod中,你可以通过以下方式访问外部服务:
curl http://my-externalname-service.default.svc.cluster.local # 如果指定了命名空间,则使用对应的命名空间名;否则,默认使用default
或者,如果你没有指定命名空间或者使用的是默认命名空间,并且DNS配置正确,你也可以直接通过以下方式访问:
curl http://my-externalname-service
这样,你就可以通过内部服务名my-externalname-service
来访问外部服务www.example.com
了。
- 注意事项
- DNS解析:确保集群内部的DNS配置正确,能够解析
my-externalname-service.default.svc.cluster.local
(或你指定的命名空间名)到外部域名www.example.com
。 - 安全性:访问外部服务时,请注意安全性问题,如SSL/TLS证书验证、身份验证和授权等。
- 可用性:ExternalName类型的Service不依赖于Kubernetes集群内部的负载均衡器或代理,因此外部服务的可用性将直接影响集群内部Pod的访问。
五、Service 的生命周期管理
1. 创建与验证
# 创建 Service
kubectl apply -f service.yaml
# 查看 Service 状态
kubectl get svc web-service
# 查看关联的 Endpoints
kubectl get endpoints web-service
# 通过 DNS 访问(集群内)
curl http://web-service.default.svc.cluster.local
2. 更新与删除
# 更新 Service(如修改端口)
kubectl edit svc web-service
# 删除 Service
kubectl delete svc web-service
六、典型应用场景
-
微服务间通信
通过 ClusterIP 实现服务间的内部调用(如前端调用后端 API)。 -
数据库服务暴露
使用 ClusterIP 或 Headless Service 暴露数据库实例(如 MySQL Pod)。 -
外部流量接入
结合 LoadBalancer 或 NodePort 暴露 Web 服务到公网。 -
灰度发布
通过多个 Service 和标签选择器实现流量分流。
七、注意事项与最佳实践
-
命名规范
Service 名称需符合 DNS 命名规则(小写字母、数字、-
)。 -
标签管理
确保 Pod 的标签与 Service 的selector
严格匹配。 -
避免使用短 DNS
集群内访问 Service 时,使用完整 DNS 名称(如web-service.default.svc.cluster.local
)。 -
会话保持
若需会话保持(Session Affinity),配置sessionAffinity: ClientIP
。 -
监控与调试
• 检查 Endpoints 是否包含预期 Pod:kubectl describe svc <service-name>
• 查看 kube-proxy 日志:kubectl logs -n kube-system <kube-proxy-pod>
八、与其他资源的对比
资源 | 作用 | 与 Service 的关系 |
---|---|---|
Ingress | 管理 HTTP/HTTPS 路由,提供域名和 TLS 支持 | Service 的上一层代理,需绑定后端 Service |
EndpointSlice | 替代 Endpoints,支持大规模集群的分片管理 | Service 的后端地址集合的扩展实现 |
ExternalName | 代理外部服务 | 一种特殊类型的 Service |
九、常见问题
-
Q: ClusterIP 无法访问?
A: 检查 Pod 是否正常运行、标签是否匹配、kube-proxy 是否正常工作。 -
Q: NodePort 端口不通?
A: 检查节点防火墙规则、kube-proxy 是否监听端口、Pod 是否就绪。 -
Q: DNS 解析失败?
A: 检查 CoreDNS 是否运行正常、Service 名称是否合法。 -
Q: 如何实现跨命名空间访问?
A: 使用完整的 DNS 名称(如web-service.other-ns.svc.cluster.local
)。
十、总结
Service 是 Kubernetes 中实现服务暴露和负载均衡的核心机制,通过 ClusterIP、NodePort、LoadBalancer 等类型满足不同场景需求。理解其工作原理和配置方法,是构建稳定、可扩展的云原生应用的关键步骤。
十一、拓展
【一起来学kubernetes】23、Namespace使用详解
【一起来学kubernetes】10、CoreDNS的作用原理与Pod间的调用
【一起来学kubernetes】12、k8s中的Endpoint详解