145 lines
4.7 KiB
Markdown
145 lines
4.7 KiB
Markdown
|
|
---
|
|||
|
|
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 是服务端发现模式的代表
|