Kubernetes(K8s)已经成为容器编排的事实标准。但对于初次接触的人,它的概念体系庞大,学习曲线陡峭——你可能在还没有运行第一个 Pod 之前,就已经被 etcd、Controller Manager、Scheduler、CNI、CRI 这些词淹没了。
本文换一个思路:先动手,再理解原理。我们会从搭建一个本地集群开始,依次完成部署应用、暴露服务、滚动更新、水平扩缩容、配置管理这些最核心的实战操作,让你在完成一件件真实的事情中建立对 K8s 的直觉。
一、核心概念速览(先记住名字,边用边理解)
Kubernetes 的核心是一个声明式系统:你告诉它"我要 3 个 nginx 副本",K8s 负责让现实与你的声明保持一致,无论期间发生什么故障。
集群的两类节点
graph TD
subgraph Cluster[K8s 集群]
subgraph CP[Control Plane Master Node]
API[API Server]
ETCD[etcd]
SCH[Scheduler]
CM[Controller Manager]
end
subgraph W1[Worker Node 1]
KB1[kubelet]
KP1[kube-proxy]
RT1[container runtime]
end
subgraph W2[Worker Node 2]
KB2[kubelet]
KP2[kube-proxy]
RT2[container runtime]
end
CP --> W1
CP --> W2
end
- Control Plane:集群大脑。API Server 是所有操作的入口,etcd 存储集群所有状态,Scheduler 决定 Pod 跑在哪个节点,Controller Manager 负责保持现实符合声明
- Worker Node:实际跑容器的机器。kubelet 在每个节点上执行 Control Plane 的指令,kube-proxy 处理网络规则
最常用的 6 类资源
| 资源 | 一句话说明 | 类比 |
|---|---|---|
| Pod | K8s 最小调度单位,包含一个或多个容器 | 一组住在一起的室友,共享网络和存储 |
| Deployment | 管理无状态应用的副本数量与更新策略 | 工厂的生产线,负责维持 N 条流水线同时运行 |
| Service | 为一组 Pod 提供稳定的网络访问入口 | 前台接待员,无论后端服务器怎么换,对外电话号码不变 |
| Ingress | 集群的 HTTP 入口,基于域名/路径路由 | 大厦的门卫,根据来访目的把人引导到不同楼层 |
| ConfigMap | 存储非敏感配置数据(键值对/文件) | 应用的配置文件,可以在不重新打镜像的情况下修改 |
| Secret | 存储敏感数据(密码、Token、证书) | 保险箱,Base64 编码存储(注意:不是加密) |
二、搭建本地集群
生产环境用 kubeadm 或托管 K8s(GKE/EKS/AKS),本地学习用 minikube 或 kind(Kubernetes IN Docker)最方便。这里用 minikube。
安装 minikube 和 kubectl
# macOS
brew install minikube kubectl
# Linux(Ubuntu/Debian)
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -m 0755 kubectl /usr/local/bin/kubectl
启动集群
# 启动单节点集群(默认用 Docker 作为驱动)
minikube start
# 验证集群状态
kubectl cluster-info
# 输出:
# Kubernetes control plane is running at https://127.0.0.1:63790
# CoreDNS is running at ...
# 查看节点
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# minikube Ready control-plane 1m v1.31.0
看到 STATUS=Ready 就成功了。kubectl 是与 K8s 集群交互的命令行工具,几乎所有操作都通过它完成。
三、部署第一个应用
方法一:命令式(快速验证)
# 创建一个 nginx Deployment,运行 2 个副本
kubectl create deployment nginx --image=nginx:1.25 --replicas=2
# 查看 Deployment
kubectl get deployment nginx
# NAME READY UP-TO-DATE AVAILABLE AGE
# nginx 2/2 2 2 30s
# 查看 Pod(2 个副本自动创建)
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-7f456874f4-6x2kp 1/1 Running 0 35s
# nginx-7f456874f4-m9r8t 1/1 Running 0 35s
方法二:声明式 YAML(生产推荐)
命令式操作难以版本控制,生产环境应该用 YAML 文件描述期望状态,再通过 kubectl apply 提交。
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
kubectl apply -f nginx-deployment.yaml
# deployment.apps/nginx created(或 configured,如果已存在)
YAML 中几个关键字段:
spec.replicas:期望运行的 Pod 数量spec.selector.matchLabels:Deployment 通过标签找到它管理的 Podspec.template:Pod 模板,每个副本按此创建resources.requests/limits:CPU 和内存的请求量与限制量,建议始终设置
四、暴露服务(Service)
Pod 的 IP 是动态分配的,扩缩容时会变化。Service 提供一个稳定的访问端点,并做负载均衡。
Service 的三种常用类型
| 类型 | 适用场景 | 说明 |
|---|---|---|
| ClusterIP | 集群内部服务间通信 | 默认类型,仅集群内可访问 |
| NodePort | 本地开发/测试 | 在每个节点上开放一个端口(30000-32767),可从集群外访问 |
| LoadBalancer | 云环境生产部署 | 调用云厂商 API 创建外部负载均衡器(AWS ELB / GCP LB 等) |
# nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx # 匹配带有 app=nginx 标签的 Pod
ports:
- protocol: TCP
port: 80 # Service 对外暴露的端口
targetPort: 80 # 转发到 Pod 的端口
type: NodePort
kubectl apply -f nginx-service.yaml
kubectl get service nginx-svc
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-svc NodePort 10.108.73.142 <none> 80:31234/TCP 10s
# minikube 环境获取访问 URL
minikube service nginx-svc --url
# http://127.0.0.1:31234
curl http://127.0.0.1:31234
# <!DOCTYPE html> ... nginx 欢迎页面
五、滚动更新与回滚
K8s Deployment 默认使用滚动更新(Rolling Update)策略:先启动新版本的 Pod,等它 Ready 后再停止旧版本,保证服务不中断。
执行更新
# 更新镜像版本
kubectl set image deployment/nginx nginx=nginx:1.26
# 观察更新过程
kubectl rollout status deployment/nginx
# Waiting for deployment "nginx" rollout to finish: 1 out of 2 new replicas have been updated...
# Waiting for deployment "nginx" rollout to finish: 1 old replicas are pending termination...
# deployment "nginx" successfully rolled out
# 查看更新历史
kubectl rollout history deployment/nginx
# REVISION CHANGE-CAUSE
# 1 <none>
# 2 <none>
回滚到上一版本
# 回滚到上一个版本
kubectl rollout undo deployment/nginx
# 回滚到指定版本
kubectl rollout undo deployment/nginx --to-revision=1
# 验证当前镜像版本
kubectl get deployment nginx -o jsonpath='{.spec.template.spec.containers[0].image}'
# nginx:1.25
更新策略配置
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 更新期间最多多创建 1 个 Pod(超出 replicas 的数量)
maxUnavailable: 0 # 更新期间最多允许 0 个 Pod 不可用(保证零停机)
maxSurge: 1, maxUnavailable: 0 是最保守的零停机配置:每次先启动 1 个新 Pod,等它 Ready 后再停 1 个旧 Pod,始终保持 replicas 个 Pod 可用。
六、水平扩缩容
手动扩缩容
# 扩容到 5 个副本
kubectl scale deployment nginx --replicas=5
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-xxx-aaa 1/1 Running 0 5m
# nginx-xxx-bbb 1/1 Running 0 5m
# nginx-xxx-ccc 1/1 Running 0 10s ← 新创建
# nginx-xxx-ddd 1/1 Running 0 10s ← 新创建
# nginx-xxx-eee 1/1 Running 0 10s ← 新创建
# 缩容回 2 个
kubectl scale deployment nginx --replicas=2
HPA:基于 CPU 自动扩缩容
Horizontal Pod Autoscaler(HPA)根据 CPU 或自定义指标自动调整副本数。
# 先确保 metrics-server 已安装(minikube 内置)
minikube addons enable metrics-server
# 创建 HPA:CPU 使用率超过 50% 时扩容,最多 10 个副本
kubectl autoscale deployment nginx --cpu-percent=50 --min=2 --max=10
kubectl get hpa
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
# nginx Deployment/nginx 2%/50% 2 10 2 30s
或者用 YAML 声明(更推荐):
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
七、配置管理(ConfigMap 与 Secret)
把配置从镜像中分离出来,是云原生应用的基本原则(12-Factor App)。
ConfigMap:非敏感配置
# app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "production"
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"
# 也可以存整个文件
nginx.conf: |
server {
listen 80;
location / {
root /usr/share/nginx/html;
}
}
在 Pod 中使用 ConfigMap:
spec:
containers:
- name: app
image: myapp:1.0
env:
# 方式一:逐个引用
- name: APP_ENV
valueFrom:
configMapKeyRef:
name: app-config
key: APP_ENV
envFrom:
# 方式二:整个 ConfigMap 注入为环境变量
- configMapRef:
name: app-config
volumeMounts:
# 方式三:挂载为文件
- name: config-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: config-volume
configMap:
name: app-config
items:
- key: nginx.conf
path: default.conf
Secret:敏感数据
# 命令行创建 Secret(值会自动 Base64 编码)
kubectl create secret generic db-secret \
--from-literal=DB_HOST=mysql.default.svc.cluster.local \
--from-literal=DB_PASSWORD=supersecret123
# 在 Pod 中使用 Secret(与 ConfigMap 方式相同)
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: DB_PASSWORD
注意:Secret 默认只是 Base64 编码,不是加密。生产环境应配合 etcd 加密、Vault、或 External Secrets Operator 使用。
八、健康检查(Probe)
K8s 通过三种 Probe 判断容器状态:
- livenessProbe:容器是否还活着。失败则重启容器
- readinessProbe:容器是否准备好接收流量。失败则从 Service 的 Endpoints 中摘除
- startupProbe:容器是否完成启动(适合启动慢的应用)。未通过前不执行 liveness/readiness
spec:
containers:
- name: app
image: myapp:1.0
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /healthz # 请求这个路径,返回 2xx 则认为健康
port: 8080
initialDelaySeconds: 10 # 容器启动后等待 10s 再开始检查
periodSeconds: 10 # 每 10s 检查一次
failureThreshold: 3 # 连续失败 3 次才重启
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30 # 允许启动最多等 30 * 10s = 5 分钟
periodSeconds: 10
这三个 Probe 组合使用是最佳实践:startupProbe 保护慢启动,readinessProbe 保护流量只到就绪的 Pod,livenessProbe 自动重启卡死的容器。
九、常用 kubectl 命令速查
查看资源
# 查看所有 Pod(加 -A 看所有命名空间)
kubectl get pods
kubectl get pods -A
kubectl get pods -o wide # 显示节点和 IP
# 查看详细信息(排查问题的主要命令)
kubectl describe pod <pod-name>
kubectl describe deployment nginx
# 查看日志
kubectl logs <pod-name>
kubectl logs <pod-name> -f # 实时追踪
kubectl logs <pod-name> --previous # 查看上次崩溃的日志
# 进入容器 shell
kubectl exec -it <pod-name> -- /bin/bash
kubectl exec -it <pod-name> -- sh # 如果没有 bash
调试命令
# 端口转发(临时访问集群内服务,不用创建 Service)
kubectl port-forward pod/<pod-name> 8080:80
kubectl port-forward service/nginx-svc 8080:80
# 复制文件
kubectl cp <pod-name>:/path/to/file ./local-file
# 查看事件(Pod 异常时必看)
kubectl get events --sort-by='.lastTimestamp'
kubectl get events --field-selector reason=Failed
# 查看资源使用(需要 metrics-server)
kubectl top pods
kubectl top nodes
命名空间(Namespace)
# 查看所有命名空间
kubectl get namespaces
# 在指定命名空间下操作
kubectl get pods -n kube-system
kubectl apply -f app.yaml -n production
# 设置默认命名空间(避免每次都加 -n)
kubectl config set-context --current --namespace=production
十、完整示例:部署一个 Web 应用
把前面学到的所有内容串起来,部署一个有配置、有健康检查、能自动扩缩容的 Web 应用。
# complete-app.yaml
---
# 1. ConfigMap:应用配置
apiVersion: v1
kind: ConfigMap
metadata:
name: webapp-config
data:
APP_ENV: "production"
LOG_LEVEL: "info"
---
# 2. Deployment:应用本体
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 3
selector:
matchLabels:
app: webapp
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: nginx:1.25
ports:
- containerPort: 80
envFrom:
- configMapRef:
name: webapp-config
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
---
# 3. Service:稳定访问入口
apiVersion: v1
kind: Service
metadata:
name: webapp-svc
spec:
selector:
app: webapp
ports:
- port: 80
targetPort: 80
type: ClusterIP
---
# 4. HPA:自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: webapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: webapp
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
# 一键部署所有资源
kubectl apply -f complete-app.yaml
# 验证
kubectl get all
# NAME READY STATUS RESTARTS AGE
# pod/webapp-xxx-aaa 1/1 Running 0 1m
# pod/webapp-xxx-bbb 1/1 Running 0 1m
# pod/webapp-xxx-ccc 1/1 Running 0 1m
#
# NAME TYPE CLUSTER-IP PORT(S) AGE
# service/webapp-svc ClusterIP 10.100.10.100 80/TCP 1m
#
# NAME READY UP-TO-DATE AVAILABLE
# deployment.apps/webapp 3/3 3 3
#
# NAME REFERENCE TARGETS MINPODS MAXPODS
# horizontalpodautoscaler.autoscaling/webapp-hpa Deployment/webapp 2%/60% 3 20
十一、关键点总结
- K8s 是声明式系统:你描述期望状态,它持续将现实状态向期望状态靠拢
- Pod 是最小调度单元,但直接管理 Pod 不推荐——用 Deployment 管理无状态应用
- 标签(Label)是 K8s 内部关联的核心机制:Service 通过 selector 找 Pod,Deployment 通过 matchLabels 认领 Pod
- 滚动更新:
maxSurge: 1, maxUnavailable: 0实现零停机更新;kubectl rollout undo随时回滚 - ConfigMap/Secret 将配置与镜像解耦,是 12-Factor App 的核心实践;Secret 默认 Base64 编码不等于加密
- 三类 Probe 组合使用:startupProbe 保护慢启动,readinessProbe 控制流量,livenessProbe 自动恢复
kubectl describe和kubectl get events是排查 Pod 异常的第一工具- 生产部署:始终设置
resources.requests/limits,始终配置readinessProbe,始终用 YAML 而不是命令式操作