This commit is contained in:
2026-05-24 11:42:38 +08:00
commit 30d312ac35
521 changed files with 146481 additions and 0 deletions
@@ -0,0 +1,144 @@
---
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<br/>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 <name>` 确认 Service 存在且有 ClusterIP
> 2. `kubectl get endpoints <name>` 检查 Endpoint 列表是否为空
> 3. Endpoint 为空 → 检查 selector 标签是否匹配 Pod
> 4. Endpoint 有值但 curl 不通 → 进入 Pod `curl <ClusterIP>:<port>` 验证
> 5. ClusterIP 通但外部不通 → 检查 Ingress / LoadBalancer 配置
## 关联笔记
- [[../01-核心概念与Deployment]] — Deployment 通过 selector 与 Service 关联
- [[../02-配置管理]] — Service 的端点配置不直接涉及 ConfigMap/Secret
- [[../04-扩缩容与有状态应用]] — Headless Service + StatefulSet 配合
- [[../hhs/MS/02-服务治理/04-服务发现]] — K8s Service 是服务端发现模式的代表