知序
返回
保存草稿
发布
H1
H2
H3
1
2
3
Excalidraw 图
AI 写作
AI 优化
目录
输入内容后显示目录
Markdown
# 02 - 网络与暴露:Service 与 Ingress > 本篇目标:解决"服务怎么被访问"这件事。分两级 —— 先让**集群内部**的服务能互相访问(Service),再让**外网用户**能进来(Ingress)。 > 前置:01 篇里服务已经能被 Deployment 拉起来了,但你访问不到它。 --- ## 1. 为什么不能直接用 Pod IP  *图:Pod IP 是一次性的:重启、滚动更新、扩容、节点重建都会换 IP* ```text 问题:Pod IP 是"一次性"的 ├─ Pod 重启 → 换 IP ├─ 滚动更新 → 换 IP └─ 扩容 3 → 5 个 → 多了 2 个你不知道的 IP 所以:绝对不能把 Pod IP 写进配置或数据库。 ``` Service 就是解决这个的:它提供一个**永不变化的虚拟 IP(VIP)**,后面挂着一组随时在变的 Pod。 --- ## 2. Service 如何找到 Pod  *图:Service 通过 label selector 与 Endpoints 找到健康的 Pod* ```text ┌──────────────┐ ┌─────────────────────────────────────────┐ │ Service │ │ Endpoints / EndpointSlice │ │ ClusterIP │───────>│ (自动维护:哪些 Pod 是健康的、该转发给它) │ │ 10.96.0.10 │ │ 10.1.2.7:8080 ← Pod 1 │ │ :80 │ │ 10.1.3.9:8080 ← Pod 2 │ └──────────────┘ │ 10.1.4.2:8080 ← Pod 3 │ ▲ └─────────────────────────────────────────┘ │ 靠 label selector 匹配(app=blog-system) │ │ ← 关键:readinessProbe 没通过的 Pod 会被自动摘除 │ ┌──────┴───────┐ │ kube-proxy │ 在每个节点上写 iptables/IPVS 规则,把 VIP 流量负载均衡到真实 Pod └──────────────┘ ``` 这条链路解释了两件常被忽略的事: 1. **Service 只是"规则",不是"进程"** —— 它没有自己的容器在转发流量,真实转发是 kube-proxy 写的内核规则在做。所以 Service 本身不存在"性能瓶颈",也不存在"能承受多少 QPS"这种指标。 2. **readinessProbe 决定流量** —— 探针没过,Pod 就被从 Endpoints 里摘掉,请求不会打到它。这就是"发布时用户不会遇到 502"的原因。 --- ## 3. 四种 Service 类型  *图:Service 四种类型的演进:由内到外逐级暴露,代价各不相同* ```text ClusterIP 只有集群内部能访问 ← 默认,内部服务互访用它 │ v (需要外部访问时,往下选) NodePort 在每个节点开一个高位端口(30000-32767) │ 外网用 <节点IP>:<NodePort> 访问 │ ← 简单但有端口管理问题,适合测试 v LoadBalancer 向云厂商申请一个真实的负载均衡器(有公网 IP 和费用) │ ← 云上最省心,但每个 Service 一个 LB 很贵 v Ingress 一个 LB + 七层路由,按域名/路径分发到多个 Service ← 多服务对外暴露的标准做法,见第 5 节 ``` | 类型 | 谁能访问 | 典型用途 | 代价 | |---|---|---|---| | `ClusterIP` | 只有集群内 | 内部服务互访(应用 → 数据库) | 无 | | `NodePort` | 集群外(用节点 IP + 端口) | 本地测试、临时暴露 | 端口要自己管,且暴露了节点 | | `LoadBalancer` | 集群外(有独立公网 IP) | 单个 TCP 服务(MQ、数据库) | 云上按实例计费 | | `Ingress` | 集群外(按域名/路径) | 多个 HTTP 服务 | 需要装 Ingress Controller | --- ## 4. 给 Deployment 配一个 Service ```yaml # service.yaml apiVersion: v1 kind: Service metadata: name: blog-system spec: type: ClusterIP # 先给集群内部用 selector: app: blog-system # 必须匹配 Pod 的 labels ports: - name: http port: 80 # Service 自己的端口 targetPort: 8080 # 转发到容器的哪个端口 ``` ```bash kubectl apply -f service.yaml kubectl get svc kubectl get endpoints blog-system # 看有几个 Pod 挂上来了(关键排障命令) # 本机临时验证(不用暴露到外网) kubectl port-forward svc/blog-system 8080:80 # 然后浏览器访问 http://localhost:8080 ``` > `kubectl port-forward` 是排查问题的万能钥匙:**先确认 Service 通不通,再去查 Ingress / LB。** ### 4.1 集群内怎么互访 同一个集群里的服务,直接用 **Service 名字**当成 DNS 域名访问: ```text 同命名空间: http://blog-system:80 跨命名空间: http://blog-system.prod:80 完整域名: http://blog-system.prod.svc.cluster.local ``` 所以应用配置里的数据库地址,应该写 Service 名而不是 IP: ```properties # 不要写 IP(Pod IP 会变、数据库 Pod 也可能会迁移) spring.datasource.url=jdbc:mysql://mysql:3306/blog ``` --- ## 5. 让外部用户进来:Ingress ### 5.1 流量路径  *图:外网到 Pod 的完整链路:LB → Ingress Controller → Service → Pod* ```text 外网用户 │ https://www.example.com/api/xxx v ┌──────────────────────────────────────────────────────────────┐ │ 云负载均衡(LB) → 指向 Ingress Controller 的 Service │ └───────────────────────────┬──────────────────────────────────┘ v ┌──────────────────────────────────────────────────────────────┐ │ Ingress Controller(真正干活的进程,比如 ingress-nginx) │ │ ← 注意:Ingress 是一份"规则",Controller 才是执行者 │ │ 只创建 Ingress 资源、不装 Controller = 什么都不会发生 │ └───────────────────────────┬──────────────────────────────────┘ │ 按 host + path 匹配 ┌───────────────────┼───────────────────┐ v v v ┌───────────┐ ┌───────────┐ ┌───────────┐ │ Service A │ │ Service B │ │ Service C │ │(blog-web) │ │(blog-api) │ │(grafana) │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ v v v Pod... Pod... Pod... ``` ### 5.2 一份 Ingress ```yaml # ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: blog-ingress annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" spec: ingressClassName: nginx tls: - hosts: - www.example.com secretName: example-tls # 证书放在 Secret 里 rules: - host: www.example.com http: paths: - path: / pathType: Prefix backend: service: name: blog-system port: number: 80 ``` ```bash kubectl apply -f ingress.yaml kubectl get ingress kubectl describe ingress blog-ingress # 确认 Rules 和实际后端都挂上了 ``` ### 5.3 安装 Ingress Controller(kind 环境) ```bash kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml kubectl -n ingress-nginx wait --for=condition=Ready pod \ --selector=app.kubernetes.io/component=controller --timeout=180s ``` > 云托管集群通常在控制台点一下就有内置的 Ingress Controller(TKE 叫「Ingress 实例」,ACK 有 nginx-ingress 组件)。**先确认有没有,再决定装不装。** ### 5.4 Service 与 Ingress 怎么分工 | | Service(LoadBalancer) | Ingress | |---|---|---| | 工作层 | 四层(TCP/UDP) | 七层(HTTP/HTTPS) | | 一个需要几个云资源 | 一个 Service 一个 LB | 一个 LB 服务多个域名/路径 | | 能按域名/路径路由 | ❌ | ✅ | | HTTPS 证书管理 | 每个 LB 单独配 | 集中在 Ingress 上 | | 适合 | 单个服务、TCP 服务(数据库、MQ) | 多个 HTTP 服务对外 | > 一句话:**要暴露 HTTP 服务,优先 Ingress;只有 TCP 服务或临时调试才单开 LB / NodePort。** --- ## 6. 本篇小结 ```text Pod IP 会变 ──→ 用 Service 提供稳定 VIP │ ├─ 靠 label selector 找到 Pod ├─ 靠 readinessProbe 摘掉不健康的 Pod └─ 靠 kube-proxy 写内核规则做真实转发 集群外要访问 ──→ 优先 Ingress(七层、按域名、便宜) └─ TCP 服务才用 LoadBalancer ``` 服务现在能被访问了,但配置还硬编码在镜像里(数据库地址、密码写在 YAML 里)。 下一篇解决"配置与数据":ConfigMap、Secret、Volume。
预览
发布文章
添加摘要让读者更快了解文章内容
取消
确认发布
AI 写作助手
输入一个主题,AI 将为你生成一篇 Markdown 博客文章
AI 正在写作中...
取消
开始生成
AI 优化助手
描述你的修改需求,AI 将在原文基础上进行补充或微调
AI 正在优化中...
取消
开始优化
画布
从已有图里选
✕
图名
保存后生成 /images/excalidraw/<图名>.svg(只能用字母、数字、短横线、下划线、点)
取消
保存并插入