3.3 服务发现
3.3.1 Service <东西流量 : 服务内部>
在学习service前,先说说为什么需要service,核心原因是pod的问题
- 动态 IP:Pod 的 IP 地址不是固定的。当 Pod 重启、迁移或扩缩容时,IP 会变化。
- 多个副本:一个 Deployment 可能有多个 Pod 副本,每个都有不同的 IP。
- 健康检查:如何知道哪个 Pod 是健康的,可以接收流量?
如果没有service,每次 Pod 变化,你都需要手动更新所有依赖它的应用配置,这在动态的 Kubernetes 环境中完全不可行。
Service作用:
- 稳定的虚拟 IP(ClusterIP):客户端只需要记住这个 IP
- 负载均衡:将请求均匀分发到后端的健康 Pod
- 服务发现:通过 DNS 名称访问服务
- 会话保持:可选地将同一客户端的请求转发到同一 Pod
3.3.1.1 Service 工作原理
- Service 的整体结构 : 本身不转发流量,他只是规则的制定者,真正干活的是节点上的网络组件

3.3.1.2 核心组件
-
kube-proxy : 流量的实际的指挥者
- 主要有 iptables 模式, ipvs 模式, userspace 模式(已被废弃)
- 不是传统意义上的代理,不直接转发数据包,核心工作是:
-
endpoints 控制器 ; Pod 的追踪器
-

-
kubectl get endpoints my-service -o yaml # 查看 Service 的 Endpoints
-
编写 Service 配置文件时,不指定 Selecter 属性,不会创建默认的 endPoints
# 输出示例:如果 `endpoints` 输出为空,说明没有符合 `Pod` 的 `Service` 的 `Selecter` apiVersion: v1 kind: Endpoints metadata: name: my-service # 与 SVC 一致 namespace: default # 与 SVC 一致 subsets: - addresses: - ip: 10.244.1.10 nodeName: node1 targetRef: kind: Pod name: web-pod-1 - ip: 10.244.1.11 nodeName: node1 targetRef: kind: Pod name: web-pod-2 ports: - port: 8080 protocol: TCP
-
-
coreDNS : 服务的电话本 : coreDNS 为 Service 提供 DNS 解析
-

# 在 Pod 中测试 DNS kubectl run -it --rm --image=busybox dns-test -- /bin/sh # 查询完整域名 nslookup my-service.default.svc.cluster.local # 查询同一命名空间内的服务(简写) nslookup my-service # 查询不同命名空间 nslookup my-service.other-namespace # 对于 Headless Service(clusterIP: None) nslookup headless-service # 返回所有 Pod IP,而不是 Service IP
-
3.3.1.3 Service 类型
ClusterIP: 集群内部服务IP,只能在内部使用,默认
示例 : 指定为 ClusterIP
apiVersion: v1
kind: Service
metadata:
name: backend-api
spec:
type: ClusterIP # 可省略,默认就是 ClusterIP
selector:
app: backend
ports:
- port: 80 # Service 对外的端口
targetPort: 8080 # Pod 监听的端口
protocol: TCP
%% 可以通过下面方式访问 %%
# 方式1:使用 DNS 名称(推荐)
# 在同一命名空间内
curl http://backend-api
# 在不同命名空间
curl http://backend-api.dev.svc.cluster.local
# 方式2:使用 ClusterIP
# 先获取 ClusterIP
kubectl get svc backend-api
# NAME TYPE CLUSTER-IP PORT(S)
# backend-api ClusterIP 10.96.123.456 80/TCP
curl http://10.96.123.456
| 场景 | 说明 | 示例 |
|---|---|---|
| 微服务间通信 | 服务之间内部调用 | 前端调用用户服务 |
| 数据库访问 | 应用访问数据库 | Web应用访问 MySQL |
| 内部API | 不对外暴露的API | 监控API、管理API |
| 缓存访问 | 访问Redis/Memcached | 应用访问Redis缓存 |
ExternalName: ExternalName 是一种特殊的 Service,它没有 selector,也不创建 Endpoints,而是返回一个 DNS CNAME 记录,将 Service 名称重定向到外部域名。
示例 : ExternalName
apiVersion: v1
kind: Service
metadata:
name: external-database
spec:
type: ExternalName
externalName: database.company.com # 外部服务地址
集群内部访问: http://external-database.default.svc
↓
DNS 解析时返回 CNAME 记录
↓
实际解析到: database.company.com
↓
访问外部服务
| 场景 | 说明 | 示例 |
|---|---|---|
| 访问外部数据库 | 迁移过程中访问云数据库 | AWS RDS, Cloud SQL |
| 第三方API | 访问外部 SaaS 服务 | Stripe, SendGrid API |
| 混合云架构 | 访问本地数据中心服务 | 本地 Oracle 数据库 |
| 逐步迁移 | 从外部服务迁移到内部 | 临时重定向 |
NodePort: 节点端口服务,在每一个节点打开一个固定端口(30000~32767),外部可以通过任意节点的 IP:NodePort 访问服务
示例:指定为 NodePort
apiVersion: v1
kind: Service
metadata:
name: web-app
spec:
type: NodePort
%% nodeport可以指定流量路径:
- Cluster:流量可能跨节点,丢失真实客户端IP
- Local:保留客户端IP,但要求节点上有 Pod(否则连接失败)
%%
externalTrafficPolicy: Local # 或者Cluster(默认的流量路径是cluster)
selector:
app: web
ports:
- port: 80 # Service 端口(集群内部用)
targetPort: 8080 # Pod 端口
nodePort: 31080 # 节点端口(可选,不指定则随机分配)
# 1. 查看分配的 NodePort
kubectl get svc web-app
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# web-app NodePort 10.96.123.456 <none> 80:31080/TCP
# ↑节点端口
# 2. 通过节点IP访问(假设节点IP是 192.168.1.100)
curl http://192.168.1.100:31080
curl http://192.168.1.101:31080 # 另一个节点也可以
| 场景 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 开发测试 | 快速验证服务 | 简单,无需额外配置 | 端口范围有限 |
| 演示环境 | 给客户演示 | 直接访问,无需域名 | 需要知道节点IP |
| 没有云负载均衡器 | 本地/裸机集群 | 不依赖云服务 | 需要外部负载均衡 |
| 临时外部访问 | 临时暴露服务 | 快速启用 | 生产环境不推荐 |
LoadBalancer: LoadBalancer 是 NodePort 的升级版,它会自动创建云厂商的负载均衡器(如 AWS ELB、GCP Load Balancer、Azure LB),并提供外部 IP 或 DNS 名称。
3.3.2 Ingress <南北流量>

3.3.2.1 Ingress Controller
ngress Controller 是负责处理 Ingress 请求的组件。
Kubernetes 提供了多种 Ingress Controller,可以根据需要选择。以下是常用的 Ingress Controller:
- Nginx Ingress Controller:基于 Nginx 的 Ingress Controller,功能强大,易于配置。
- HAProxy Ingress Controller:基于 HAProxy 的 Ingress Controller,性能优异,适用于高并发场景。
- Contour Ingress Controller:基于 Envoy 的 Ingress Controller,功能丰富,适用于多云场景。
常规来说,我们一般使用nginx ingress, 先下载对应yaml文件 - [[https://gitee.com/mirrors/ingress-nginx\](https://gitee.com/mirrors/ingress-nginx\)]
对于大多数国内用户,如果你的Kubernetes集群是搭建在:
-
阿里云、腾讯云、华为云等公有云上 → 应选择
cloud目录下的deploy.yaml。 -
公司内部机房或家用服务器上 → 应选择
baremetal目录下的deploy.yaml。替换镜像
将文件中的 registry.k8s.io 镜像替换为国内源
使用sed命令一键替换(推荐)
sed -i 's|registry.k8s.io/ingress-nginx/|registry.aliyuncs.com/google_containers/|g' deploy.yaml
修改
hostNetwork : true
dnsPolicy : ClusterFirstWithHostwork
kind : DeamonSet
nodeSelecter
ingress : "true" # 增加选择器
admissionWebhooks
enabled : "false" # 关闭证书校验
Service
type : ClusterIP # 从云服务改成内部部署
kubectl apply -f deploy.yaml
3.3.2.2 创建 Ingress 规则
定义了外部访问的路由规则,以下是一个将特定域名流量转发到上面创建的 nginx-service 的示例
apiVersion: networking.k8s.io/v1 # Kubernetes API版本,v1是当前稳定版本
kind: Ingress # 资源类型:Ingress
metadata:
name: example-ingress # Ingress资源的名称,在命名空间中必须唯一
spec:
rules:
- host: "demo.yourdomain.com" # 规则1:基于域名的虚拟主机
# - host: "api.yourdomain.com" # 规则2:可以添加多个规则
http:
paths:
- pathType: Prefix # 前缀匹配
path: "/"
backend:
service:
name: nginx-service # # Service资源名称,必须在同一命名空间
port:
number: 80 # # Service端口(或使用 name: "http" 引用端口名称)
pathType - 路径匹配模式(v1 API 关键字段):
| 类型 | 匹配规则 | 示例 path: "/api" |
优先级 |
|---|---|---|---|
Exact |
精确匹配,区分大小写 | 匹配 /api,不匹配 /api/ 或 /api/v1 |
高 |
Prefix |
前缀匹配,按路径元素分隔 | 匹配 /api,/api/v1,不匹配 /apis |
中 |
ImplementationSpecific |
由 Ingress Controller 决定 | 取决于实现,通常同 Prefix |
低 |
