119 lines
5.6 KiB
Markdown
119 lines
5.6 KiB
Markdown
---
|
||
id: devops.k8s.core-objects
|
||
title: Kubernetes 基础:Pod / Deployment / Service / Ingress、配置与密钥、探针、滚动更新和扩缩容
|
||
type: lesson
|
||
domain: devops
|
||
stack: [k8s]
|
||
tags: [Kubernetes, Pod, Deployment, Service, Ingress, ConfigMap, Secret, 探针, 滚动更新, HPA, PDB, kubectl]
|
||
level: basic
|
||
prerequisites: [devops.docker.image-dockerfile]
|
||
est_hours: 3
|
||
related: [devops.k8s.scenario.agent-rollout, devops.nginx.scenario.ai-gateway-sse-canary, devops.k8s.interview]
|
||
week: [14]
|
||
order: 1
|
||
---
|
||
|
||
# Kubernetes 基础:Pod / Deployment / Service / Ingress、配置与密钥、探针、滚动更新和扩缩容
|
||
|
||
> 定位:**能读懂和修改清单、能用 kubectl 排查**,集群搭建和运维不在范围内。BOSS直聘 2026-10-23 的调研中有岗位把 K8s 列为要求或加分项。示例清单通过 kubeconform 结构校验(6 个资源全部有效)和团队规范测试(5 个测试通过),**没有在真实集群中部署**。以官方文档为准:https://kubernetes.io/zh-cn/docs/home/ 。
|
||
|
||
## 解释说明
|
||
|
||
### 核心对象
|
||
|
||
| 对象 | 作用 | 类比 |
|
||
| --- | --- | --- |
|
||
| **Pod** | 最小调度单位,一个或几个容器共享网络和存储 | 一组 `docker run` |
|
||
| **Deployment** | 声明“要几个什么样的 Pod”,负责滚动更新和回滚 | Compose 的 service + 副本数 |
|
||
| **Service** | 给一组 Pod 一个稳定的虚拟 IP / DNS 名,做负载均衡 | 内部的负载均衡器 |
|
||
| **Ingress** | 集群入口的 HTTP 路由(域名、路径、TLS) | Nginx 反向代理配置 |
|
||
| **ConfigMap / Secret** | 配置 / 敏感信息,以环境变量或文件注入 | `.env` |
|
||
| **HPA** | 按指标自动调整副本数 | — |
|
||
| **PDB** | 主动驱逐(节点维护)时至少保留多少可用 Pod | — |
|
||
| Namespace | 资源隔离和配额 | — |
|
||
|
||
**声明式**:你提交“期望状态”(YAML),控制器不断把“实际状态”调整为期望状态。Pod 挂了会被重建,而不是由你手动重启。
|
||
|
||
**标签和选择器**:Deployment、Service 通过标签选择 Pod,标签不一致是新手最常见的问题(Service 没有后端)。
|
||
|
||
### 三种探针
|
||
|
||
| 探针 | 失败的后果 | 检查什么 |
|
||
| --- | --- | --- |
|
||
| startupProbe | 启动阶段超时则重启 | 启动是否完成(给慢启动的应用留时间) |
|
||
| readinessProbe | 从 Service 的后端中摘除,不重启 | 能否处理请求(可检查关键依赖) |
|
||
| livenessProbe | 重启容器 | 进程是否卡死(**不要检查外部依赖**) |
|
||
|
||
### 滚动更新和优雅退出
|
||
|
||
- `maxSurge` / `maxUnavailable` 控制更新节奏;`kubectl rollout undo` 回滚。
|
||
- Pod 终止流程:从 Service 端点中移除 + 执行 `preStop` → 发送 SIGTERM → 等待 `terminationGracePeriodSeconds` → SIGKILL。应用要处理 SIGTERM:停止接收新请求、完成进行中的请求(AI 流式回答可能持续几十秒)。
|
||
|
||
### 常用排查命令
|
||
|
||
```bash
|
||
kubectl get pods -l app.kubernetes.io/name=agent-api -o wide
|
||
kubectl describe pod <pod> # 看事件:拉取镜像失败、探针失败、OOMKilled、调度失败
|
||
kubectl logs <pod> --previous # 看上一次崩溃前的日志
|
||
kubectl get endpoints agent-api # Service 是否有后端
|
||
kubectl rollout status deploy/agent-api
|
||
kubectl rollout undo deploy/agent-api
|
||
```
|
||
|
||
## 案例
|
||
|
||
把 AI Agent API 部署到公司的 K8s 集群:3 副本、零不可用的滚动更新、启动慢时用 startupProbe 保护、密钥由 Secret 注入、Ingress 关闭缓冲以支持 SSE、HPA 按负载扩到 10 个、PDB 保证节点维护时至少 2 个可用。
|
||
|
||
## 代码示例
|
||
|
||
清单:[examples/agent-api](examples/agent-api/)(`deployment.yaml`、`service.yaml`、`ingress.yaml`、`configmap.yaml`、`hpa.yaml`),校验结果:
|
||
|
||
```text
|
||
$ kubeconform -strict -summary *.yaml
|
||
Summary: 6 resources found in 5 files - Valid: 6, Invalid: 0, Errors: 0, Skipped: 0
|
||
$ pytest -q test_manifests.py
|
||
5 passed
|
||
```
|
||
|
||
Deployment 关键部分:
|
||
|
||
```yaml
|
||
strategy:
|
||
type: RollingUpdate
|
||
rollingUpdate: { maxSurge: 1, maxUnavailable: 0 }
|
||
template:
|
||
spec:
|
||
terminationGracePeriodSeconds: 90
|
||
containers:
|
||
- name: api
|
||
image: registry.example.com/agent-api:1.4.2
|
||
env:
|
||
- name: LLM_API_KEY
|
||
valueFrom: { secretKeyRef: { name: agent-api-secrets, key: llm-api-key } }
|
||
resources:
|
||
requests: { cpu: "250m", memory: "256Mi" }
|
||
limits: { memory: "512Mi" }
|
||
startupProbe: { httpGet: { path: /healthz, port: http }, periodSeconds: 5, failureThreshold: 24 }
|
||
readinessProbe: { httpGet: { path: /readyz, port: http }, periodSeconds: 5 }
|
||
livenessProbe: { httpGet: { path: /healthz, port: http }, periodSeconds: 10 }
|
||
```
|
||
|
||
团队规范测试([test_manifests.py](examples/agent-api/test_manifests.py))检查:选择器与标签一致、镜像固定版本、有资源和探针、密钥不明文、PDB 小于最小副本数、仓库中没有 Secret 对象。
|
||
|
||
## 易错点
|
||
|
||
- Service 选择器和 Pod 标签不一致。
|
||
- 存活探针检查数据库,数据库抖动时所有 Pod 被重启,雪上加霜。
|
||
- 没有 startupProbe,慢启动的应用被存活探针反复杀掉(CrashLoopBackOff)。
|
||
- 镜像用 `latest`,无法确定线上跑的是哪个版本,回滚也不可靠。
|
||
- 内存没有限制或限制过小(OOMKilled)。
|
||
- 应用不处理 SIGTERM,滚动更新时正在进行的流式回答被切断。
|
||
- 把 Secret 的 YAML(只是 base64,不是加密)提交到仓库。
|
||
|
||
## 面试常问
|
||
|
||
- Pod、Deployment、Service 的关系?
|
||
- 三种探针的区别?
|
||
- 滚动更新怎么做到不中断服务?
|
||
- Pod 一直 CrashLoopBackOff 怎么排查?
|