Kubernetes
07. Docker、Kubernetes 与云原生教程
本章从“会 docker run”推进到“理解容器和 Kubernetes 基础,并能部署一个服务”。重点是概念、命令、配置对象和排查路径。
1. Docker 基础概念
1.1 镜像和容器
镜像是只读模板,容器是镜像运行后的进程环境。
docker run --name demo-nginx -p 8080:80 nginx:alpine
这条命令做了:
- 如果本地没有
nginx:alpine,从 registry 拉取镜像。 - 创建容器。
- 启动容器中的 nginx 进程。
- 把宿主机 8080 端口映射到容器 80 端口。
删除容器不会删除镜像,删除容器也会丢失写在容器可写层里的数据。
1.2 Volume
数据库数据不能只存在容器可写层。
docker volume create pgdata
docker run --name pg \
-e POSTGRES_PASSWORD=postgres \
-v pgdata:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:16
1.3 Network
Compose 默认会创建网络,同一 Compose 项目内服务可以用服务名互相访问。
services:
api:
build: .
environment:
DB_HOST: db
db:
image: postgres:16
api 访问 db:5432,不是访问 localhost:5432。
2. Dockerfile
Go 服务多阶段构建:
FROM golang:1.23 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/api ./cmd/api
FROM gcr.io/distroless/static-debian12
COPY --from=build /out/api /api
EXPOSE 8080
ENTRYPOINT ["/api"]
Java Spring Boot 服务:
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
最佳实践:
- 使用明确 tag,不要生产使用
latest。 - 多阶段构建减少镜像体积。
- 不把密钥写进镜像。
- 应用配置运行时注入。
- 尽量非 root 用户运行。
- 定期更新基础镜像。
3. Compose:本地多容器开发
示例:
services:
api:
build: .
ports:
- "8080:8080"
environment:
DB_DSN: postgres://postgres:postgres@db:5432/payments?sslmode=disable
REDIS_ADDR: redis:6379
depends_on:
- db
- redis
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: payments
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7
volumes:
pgdata:
常用命令:
docker compose up --build
docker compose logs -f api
docker compose exec db psql -U postgres -d payments
docker compose down
docker compose down --volumes
注意:down --volumes 会删除数据卷,学习环境可以用,生产要谨慎。
4. Kubernetes 核心对象
4.1 Pod
Pod 是 Kubernetes 最小调度单元,包含一个或多个容器。不要直接长期管理裸 Pod,通常用 Deployment 管理。
4.2 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: payments-api
spec:
replicas: 2
selector:
matchLabels:
app: payments-api
template:
metadata:
labels:
app: payments-api
spec:
containers:
- name: api
image: example.com/payments-api:1.0.0
ports:
- containerPort: 8080
env:
- name: DB_DSN
valueFrom:
secretKeyRef:
name: payments-secret
key: db-dsn
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
4.3 Service
apiVersion: v1
kind: Service
metadata:
name: payments-api
spec:
selector:
app: payments-api
ports:
- port: 80
targetPort: 8080
Service 给一组 Pod 提供稳定访问入口。
4.4 Ingress
Ingress 用于 HTTP/HTTPS 入口路由。Kubernetes 文档说明 Ingress 可按规则把流量映射到不同后端,并可做 TLS 终止等。现在新能力更多进入 Gateway API,但 Ingress 仍大量存在。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: payments-api
spec:
rules:
- host: payments.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: payments-api
port:
number: 80
5. ConfigMap 与 Secret
ConfigMap 保存非敏感配置:
apiVersion: v1
kind: ConfigMap
metadata:
name: payments-config
data:
LOG_LEVEL: "info"
RISK_ENDPOINT: "http://risk-api"
Secret 保存敏感配置,但默认只是 base64 编码,不等于加密。生产要结合云厂商 KMS、External Secrets、Sealed Secrets 或平台方案。
apiVersion: v1
kind: Secret
metadata:
name: payments-secret
type: Opaque
stringData:
db-dsn: postgres://user:pass@db:5432/payments
6. Probe:健康检查
- readinessProbe:是否可以接流量。
- livenessProbe:进程是否需要重启。
- startupProbe:慢启动应用是否已经启动完成。
常见错误:
- readiness 和 liveness 用同一个重依赖检查,导致 DB 抖动时 Pod 被反复重启。
- liveness 过于敏感。
- 没有 startupProbe,慢启动 Java 应用被提前杀死。
建议:
/healthz只检查进程基本存活。/readyz检查关键依赖是否可服务。- Java/Spring 可结合 Actuator readiness/liveness。
7. 资源与扩缩容
requests 是调度依据,limits 是上限。
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "1Gi"
HPA 示例:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: payments-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: payments-api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
8. 排查命令
kubectl get pods
kubectl describe pod <pod>
kubectl logs <pod>
kubectl logs -f deployment/payments-api
kubectl exec -it <pod> -- sh
kubectl get events --sort-by=.metadata.creationTimestamp
kubectl rollout status deployment/payments-api
kubectl rollout history deployment/payments-api
kubectl rollout undo deployment/payments-api
常见问题:
ImagePullBackOff:镜像名、tag、仓库认证错误。CrashLoopBackOff:应用启动后崩溃。Pending:资源不足或调度约束不满足。- Service 无法访问:selector 不匹配或 Pod readiness 失败。
- Ingress 不通:Ingress Controller 未安装、DNS/host 不对、Service 端口错误。
9. Kubernetes 安全基础
CISA/NSA Kubernetes hardening guidance 关注误配置和集群安全。入门阶段至少做到:
- 不用 privileged 容器。
- 不用 root 用户运行应用。
- 设置 requests/limits。
- Secret 不进镜像和 Git。
- RBAC 最小权限。
- NetworkPolicy 限制东西向流量。
- 镜像来源可信并扫描。
- 控制平面和 kubeconfig 保护好。
Pod 安全上下文示例:
securityContext:
runAsNonRoot: true
runAsUser: 10001
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
10. Helm 与 Kustomize
Kustomize 适合按环境 patch:
base/
deployment.yaml
service.yaml
overlays/
dev/
prod/
Helm 适合模板化发布包:
charts/payments/
Chart.yaml
values.yaml
templates/
学习建议:
- 先写原生 YAML。
- 再用 Kustomize 管理环境差异。
- 最后学习 Helm 管理可复用 Chart。
11. 本章练习
练习 1:容器化 Go API
- 写 Dockerfile。
- 本地
docker build。 docker run暴露 8080。- 访问
/healthz。
练习 2:Compose 本地环境
- Go API。
- Postgres。
- Redis。
- 持久化 Postgres 数据。
- 用服务名访问依赖。
练习 3:部署到 Kubernetes
- Deployment。
- Service。
- ConfigMap。
- Secret。
- readiness/liveness。
- Ingress。
- 修改镜像 tag 并滚动发布。
练习 4:故障演练
- 故意配置错误镜像 tag,观察
ImagePullBackOff。 - 故意让 readiness 返回失败,观察 Service endpoints。
- 扩容 replicas 到 5,观察负载分发。
12. 本章检查清单
- 能解释 image、container、volume、network。
- 能写 Go/Java 服务 Dockerfile。
- 能用 Compose 管理 app + db + redis。
- 能写 Deployment、Service、Ingress。
- 能配置 ConfigMap、Secret、probe、resources。
- 能用 kubectl 定位常见部署问题。