Kubernetes 入门指南:从容器到集群编排
Kubernetes(简称 K8s)已成为云原生时代的基础设施标准。本文将带你从零开始理解 Kubernetes 的核心概念,掌握集群部署和应用编排的实战技能。
一、为什么需要 Kubernetes?
在微服务架构下,管理成百上千个容器变得极其复杂。Kubernetes 提供了:
- 自动部署和回滚:声明式配置,自动达成期望状态
- 服务发现和负载均衡:容器 IP 变化无需关心
- 自动扩缩容:根据 CPU/内存或自定义指标自动伸缩
- 自我修复:容器失败自动重启,节点故障自动迁移
- 密钥和配置管理:敏感信息与代码分离
二、核心概念解析
2.1 架构概览
┌─────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
├─────────────────────────────────────────────────────────┤
│ Control Plane (控制平面) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ API Server │ │ Scheduler │ │ Controller │ │
│ │ │ │ │ │ Manager │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ etcd │ │ Cloud │ │
│ │ (存储) │ │ Controller │ │
│ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ Worker Nodes (工作节点) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │
│ │ │ kubelet │ │ │ │ kubelet │ │ │ │ kubelet │ │ │
│ │ ├──────────┤ │ │ ├──────────┤ │ │ ├──────────┤ │ │
│ │ │ Pod │ │ │ │ Pod │ │ │ │ Pod │ │ │
│ │ │ ┌──────┐ │ │ │ │ ┌──────┐ │ │ │ │ ┌──────┐ │ │ │
│ │ │ │Container│││ │ │ │Container│││ │ │ │Container│││ │
│ │ │ └──────┘ │ │ │ │ └──────┘ │ │ │ │ └──────┘ │ │ │
│ │ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
2.2 核心组件
控制平面组件
- API Server:集群的统一入口,所有操作都通过它
- etcd:分布式键值存储,保存集群所有状态
- Scheduler:决定 Pod 调度到哪个节点
- Controller Manager:运行各种控制器,维护集群状态
节点组件
- kubelet:节点代理,管理 Pod 生命周期
- kube-proxy:网络代理,实现 Service 负载均衡
- 容器运行时:Docker、containerd 等
2.3 工作负载资源
Pod - 最小调度单元
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.24
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Deployment - 无状态应用
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
spec:
replicas: 3 # 期望副本数
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.24
ports:
- containerPort: 80
# 健康检查
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5
StatefulSet - 有状态应用
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: "mysql"
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
DaemonSet - 每节点运行
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
containers:
- name: node-exporter
image: prom/node-exporter:latest
ports:
- containerPort: 9100
# 宿主机网络
hostNetwork: true
hostPID: true
Job/CronJob - 批处理任务
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup-job
spec:
schedule: "0 2 * * *" # 每天凌晨 2 点
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: backup-tool:latest
env:
- name: DB_HOST
value: "mysql.default.svc"
restartPolicy: OnFailure
三、服务发现与网络
3.1 Service 类型
# ClusterIP - 集群内部访问(默认)
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
type: ClusterIP
# NodePort - 通过节点端口暴露
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 30080 # 30000-32767
type: NodePort
# LoadBalancer - 云厂商负载均衡
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
type: LoadBalancer
# Headless Service - 直接访问 Pod IP
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
selector:
app: mysql
clusterIP: None # 关键配置
ports:
- port: 3306
3.2 Ingress - HTTP/HTTPS 路由
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- app.example.com
secretName: app-tls-secret
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
四、配置与存储管理
4.1 ConfigMap - 非敏感配置
# 创建 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_URL: "mysql://localhost:3306/app"
LOG_LEVEL: "info"
# 也可以从文件创建
# kubectl create configmap app-config --from-file=config.properties
# 使用 ConfigMap
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
template:
spec:
containers:
- name: app
image: myapp:latest
# 方式 1:环境变量
envFrom:
- configMapRef:
name: app-config
# 方式 2:挂载为文件
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
4.2 Secret - 敏感信息
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData: # 明文写入,自动 base64 编码
username: admin
password: SuperSecret123!
# 使用 Secret
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
template:
spec:
containers:
- name: app
image: myapp:latest
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASS
valueFrom:
secretKeyRef:
name: db-secret
key: password
4.3 PersistentVolume - 持久化存储
# PV - 集群中的存储资源
apiVersion: v1
kind: PersistentVolume
metadata:
name: data-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: "/mnt/data"
# PVC - 存储申请
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
# 在 Pod 中使用
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: data-volume
mountPath: /data
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: data-pvc
五、实战:部署一个完整应用
5.1 应用架构
前端 (React) → Ingress → Service → Deployment (3 副本)
↓
后端 (Node.js) → Service → Deployment (3 副本)
↓
数据库 (MySQL) → Service → StatefulSet (1 副本) + PVC
5.2 完整部署清单
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: myapp
# mysql-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
namespace: myapp
type: Opaque
stringData:
root-password: "MySecureRootPass123!"
app-password: "MyAppPass456!"
# mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
namespace: myapp
spec:
serviceName: mysql
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
- name: MYSQL_DATABASE
value: "myapp"
- name: MYSQL_USER
value: "appuser"
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: app-password
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
livenessProbe:
exec:
command: ["mysqladmin", "ping", "-h", "localhost"]
initialDelaySeconds: 30
periodSeconds: 10
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
# mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: myapp
spec:
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
clusterIP: None # Headless Service
# backend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: myapp
spec:
replicas: 3
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: myapp/backend:1.0
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
value: "mysql://appuser:MyAppPass456!@mysql:3306/myapp"
- name: NODE_ENV
value: "production"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
# backend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: myapp
spec:
selector:
app: backend
ports:
- port: 3000
targetPort: 3000
type: ClusterIP
# frontend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: myapp
spec:
replicas: 3
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: myapp/frontend:1.0
ports:
- containerPort: 80
env:
- name: API_URL
value: "http://backend:3000"
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "200m"
# frontend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: myapp
spec:
selector:
app: frontend
ports:
- port: 80
targetPort: 80
type: ClusterIP
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
namespace: myapp
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: backend
port:
number: 3000
5.3 部署命令
# 创建命名空间
kubectl apply -f namespace.yaml
# 按顺序部署(依赖关系)
kubectl apply -f mysql-secret.yaml
kubectl apply -f mysql-statefulset.yaml
kubectl apply -f mysql-service.yaml
# 等待 MySQL 就绪
kubectl wait statefulset/mysql --for=condition=Ready --timeout=300s -n myapp
# 部署后端和前端
kubectl apply -f backend-deployment.yaml
kubectl apply -f backend-service.yaml
kubectl apply -f frontend-deployment.yaml
kubectl apply -f frontend-service.yaml
kubectl apply -f ingress.yaml
# 验证部署
kubectl get all -n myapp
kubectl get pods -n myapp -w # 实时监控
六、常用运维命令
# 查看资源
kubectl get pods -n myapp
kubectl get deployments -n myapp
kubectl get services -n myapp
kubectl get ingress -n myapp
# 查看详细信息
kubectl describe pod -n myapp
kubectl logs -n myapp
kubectl logs -n myapp -f # 实时日志
kubectl logs -n myapp -c # 多容器
# 进入容器
kubectl exec -it -n myapp -- /bin/bash
# 扩缩容
kubectl scale deployment/backend --replicas=5 -n myapp
# 滚动更新
kubectl set image deployment/backend backend=myapp/backend:2.0 -n myapp
kubectl rollout status deployment/backend -n myapp
kubectl rollout undo deployment/backend -n myapp # 回滚
# 资源使用
kubectl top pods -n myapp
kubectl top nodes
# 故障排查
kubectl get events -n myapp --sort-by='.lastTimestamp'
七、最佳实践
7.1 资源管理
- 始终设置 requests 和 limits
- 使用 LimitRange 和 ResourceQuota 限制命名空间资源
- 监控实际使用情况,合理调整
7.2 健康检查
- 配置 livenessProbe 检测容器是否存活
- 配置 readinessProbe 检测容器是否就绪
- 配置 startupProbe 用于慢启动应用
7.3 安全
- 使用最小权限原则(RBAC)
- Secret 加密存储(启用 Encryption at Rest)
- 使用 NetworkPolicy 限制网络访问
- 定期更新镜像,扫描漏洞
7.4 高可用
- 多副本部署(至少 2-3 个)
- 使用 PodDisruptionBudget 防止同时下线
- 跨可用区部署节点
- 使用亲和性/反亲和性调度
总结
Kubernetes 学习曲线陡峭,但掌握后将获得强大的容器编排能力。建议学习路径:
- 基础概念:Pod、Deployment、Service
- 实践部署:在本地用 minikube/kind 搭建环境
- 深入理解:网络、存储、调度原理
- 生产实践:监控、日志、安全、CI/CD
- 生态工具:Helm、Operator、Service Mesh
记住:Kubernetes 不是银弹,适合复杂场景。简单应用可能用 Docker Swarm 或云服务更合适。选择合适的工具,解决合适的问题。
文章评论