--- tags: [kubernetes, service, ingress, networking, service-discovery] create time: 2026-05-18 00:30 --- # K8s 网络与服务发现 — Service 与 Ingress ## 概述 Kubernetes 的网络模型解决了容器 IP 频繁变动的问题。Service 提供**稳定的服务发现入口**,Ingress 提供**L7 HTTP 路由能力**。本文将梳理核心概念、典型模式和常见问题。 ## Service 类型 | 类型 | 特点 | 使用场景 | |------|------|---------| | **ClusterIP** | 集群内 IP,外部不可访问 | 默认,内部服务间调用 | | **NodePort** | 在每个 Node 上开端口 | 调试、临时访问 | | **LoadBalancer** | 云厂商分配公网 IP | 对外暴露的服务 | | **ExternalName** | CNAME 到外部域名 | 对接外部系统 | ### ClusterIP Service — 服务发现的载体 ```yaml apiVersion: v1 kind: Service metadata: name: order-service spec: selector: app: order # 匹配带此 label 的 Pod ports: - port: 80 # Service 端口(对外暴露) targetPort: 8080 # 容器实际监听端口 protocol: TCP type: ClusterIP ``` 调用方只需 `http://order-service:80`,K8s 通过 iptables/IPVS 自动实现负载均衡。 > [!question] Service 是怎么做到负载均衡的? > > 每个 Node 上的 kube-proxy 会监控 Service 的变动,自动生成 iptables 规则或 IPVS 虚拟服务器配置。当请求发往 ClusterIP 时,内核将其 DNAT 到后端 Pod IP 之一,负载均衡算法默认是 round-robin。K8s 1.14+ 推荐使用 IPVS 模式(`kube-proxy --proxy-mode=ipvs`),性能更高且支持更多算法。 ## Ingress — HTTP/HTTPS 路由 ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: main-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: api.example.com http: paths: - path: /orders pathType: Prefix backend: service: name: order-service port: number: 80 - path: /users pathType: Prefix backend: service: name: user-service port: number: 80 ``` > [!info] Ingress Controller 是什么? > > Ingress 只是一个 API 对象,真正的 HTTP 路由由 Ingress Controller(如 NGINX、Traefik、Envoy)执行。安装后会在集群中运行一个 LoadBalancer 类型的 Pod 集群,监听 Ingress 资源变化并生成对应配置。 ### 常见 Ingress Annotation(NGINX 为例) | Annotation | 用途 | 示例值 | |------------|------|--------| | `rewrite-target` | URL 重写 | `/` | | `ssl-redirect` | 强制 HTTPS | `"true"` | | `rate-limit` | 限流 | `100` | | `whitelist-source-range` | IP 白名单 | `10.0.0.0/8` | | `client-max-body-size` | 上传文件大小限制 | `50m` | ## Headless Service — 无头服务 Headless Service (`ClusterIP: None`) 不分配虚拟 IP,而是返回所有匹配 Pod 的真实 IP。这是 StatefulSet 的灵魂搭档: ```yaml apiVersion: v1 kind: Service metadata: name: mysql-headless spec: clusterIP: None # 关键:不分配 ClusterIP selector: app: mysql ports: - port: 3306 ``` 通过 DNS 可以直接访问单个 Pod: - `mysql-cluster-0.mysql-headless.production.svc.cluster.local:3306` - `mysql-cluster-1.mysql-headless.production.svc.cluster.local:3306` ## K8s 网络模型总结 ```mermaid flowchart LR EXT["外部流量"] --> INGRESS["Ingress Controller"] INGRESS --> SVC_A["order-service:80"] INGRESS --> SVC_B["user-service:80"] SVC_A --> Pod1["order-pod-1\n10.244.1.5:8080"] SVC_A --> Pod2["order-pod-2\n10.244.2.3:8080"] SVC_B --> Pod3["user-pod-1\n10.244.1.8:3000"] Pod1 -->|DNS解析| COREDNS["CoreDNS
svc.cluster.local"] style EXT fill:#e3f2fd style INGRESS fill:#fff3e0 style SVC_A fill:#e8f5e9 style SVC_B fill:#fce4ec ``` > [!tip] 调试技巧:Service 不通怎么办? > > 1. `kubectl get svc ` 确认 Service 存在且有 ClusterIP > 2. `kubectl get endpoints ` 检查 Endpoint 列表是否为空 > 3. Endpoint 为空 → 检查 selector 标签是否匹配 Pod > 4. Endpoint 有值但 curl 不通 → 进入 Pod `curl :` 验证 > 5. ClusterIP 通但外部不通 → 检查 Ingress / LoadBalancer 配置 ## 关联笔记 - [[../01-核心概念与Deployment]] — Deployment 通过 selector 与 Service 关联 - [[../02-配置管理]] — Service 的端点配置不直接涉及 ConfigMap/Secret - [[../04-扩缩容与有状态应用]] — Headless Service + StatefulSet 配合 - [[../hhs/MS/02-服务治理/04-服务发现]] — K8s Service 是服务端发现模式的代表