Kubernetes容器编排实战:从入门到部署完整应用¶
学习目标¶
完成本教程后,你将能够:
- 理解Kubernetes的核心架构和设计理念
- 掌握Kubernetes集群的安装和配置
- 熟练使用kubectl命令行工具
- 创建和管理Pod、Deployment、Service等核心资源
- 理解Kubernetes的网络和存储机制
- 使用ConfigMap和Secret管理配置
- 实现应用的滚动更新和回滚
- 配置自动扩缩容和健康检查
- 部署完整的微服务应用到K8s集群
前置要求¶
在开始本教程之前,你需要:
知识要求: - 熟悉Docker容器技术(必须先学习Docker容器技术入门) - 了解Linux基本命令 - 理解基本的网络概念 - 了解YAML配置文件格式
技能要求: - 能够使用命令行工具 - 会编写Dockerfile - 了解容器化应用的基本概念 - 熟悉基本的应用部署流程
硬件要求: - 64位操作系统(Linux、macOS、Windows) - 至少8GB内存(推荐16GB) - 至少40GB可用磁盘空间 - 支持虚拟化的CPU
概述¶
Kubernetes(简称K8s)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用。它最初由Google设计,现在由Cloud Native Computing Foundation(CNCF)维护。
为什么需要Kubernetes?
当你有大量容器需要管理时,手动操作Docker会变得非常困难: - 如何在多台服务器上部署容器? - 如何实现负载均衡和服务发现? - 如何处理容器故障和自动恢复? - 如何实现零停机更新? - 如何管理配置和密钥?
Kubernetes解决了这些问题,提供了: - 自动化部署和回滚:声明式配置,自动管理应用状态 - 服务发现和负载均衡:自动分配IP和DNS,内置负载均衡 - 存储编排:自动挂载存储系统 - 自我修复:自动重启失败的容器,替换和重新调度 - 密钥和配置管理:安全地存储和管理敏感信息 - 水平扩展:通过命令或自动扩展应用
Kubernetes在物联网和嵌入式领域的应用: - 边缘计算节点的应用编排 - 物联网平台的微服务部署 - 数据处理管道的自动化管理 - 多租户物联网应用的隔离和管理
什么是Kubernetes¶
Kubernetes核心概念¶
1. 集群架构¶
Kubernetes集群由控制平面(Control Plane)和工作节点(Worker Nodes)组成:
Kubernetes集群架构:
┌─────────────────────────────────────────────────────────┐
│ Control Plane │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ API Server │ │ Scheduler │ │ Controller │ │
│ │ │ │ │ │ Manager │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ etcd (集群数据存储) │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
│ │ │
┌───────▼────────┐ ┌───────▼────────┐ ┌──────▼─────────┐
│ Worker Node 1 │ │ Worker Node 2 │ │ Worker Node 3 │
│ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │
│ │ kubelet │ │ │ │ kubelet │ │ │ │ kubelet │ │
│ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │
│ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │
│ │kube-proxy│ │ │ │kube-proxy│ │ │ │kube-proxy│ │
│ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │
│ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │
│ │Container │ │ │ │Container │ │ │ │Container │ │
│ │ Runtime │ │ │ │ Runtime │ │ │ │ Runtime │ │
│ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │
│ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │
│ │ Pods │ │ │ │ Pods │ │ │ │ Pods │ │
│ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │
└────────────────┘ └────────────────┘ └────────────────┘
控制平面组件: - API Server:集群的前端,所有操作都通过它 - etcd:分布式键值存储,保存集群所有数据 - Scheduler:负责将Pod调度到合适的节点 - Controller Manager:运行控制器进程,维护集群状态
工作节点组件: - kubelet:节点代理,确保容器在Pod中运行 - kube-proxy:网络代理,维护网络规则 - Container Runtime:容器运行时(Docker、containerd等)
2. 核心资源对象¶
Pod: - Kubernetes中最小的部署单元 - 包含一个或多个容器 - 共享网络和存储 - 同一Pod中的容器总是被调度到同一节点
Pod结构:
┌─────────────────────────────┐
│ Pod │
│ ┌─────────┐ ┌─────────┐ │
│ │Container│ │Container│ │
│ │ A │ │ B │ │
│ └─────────┘ └─────────┘ │
│ ┌─────────────────────┐ │
│ │ Shared Network │ │
│ │ (localhost) │ │
│ └─────────────────────┘ │
│ ┌─────────────────────┐ │
│ │ Shared Volumes │ │
│ └─────────────────────┘ │
└─────────────────────────────┘
Deployment: - 管理Pod的副本数量 - 支持滚动更新和回滚 - 确保指定数量的Pod始终运行
Service: - 为Pod提供稳定的网络端点 - 实现负载均衡 - 服务发现
ConfigMap和Secret: - ConfigMap:存储非敏感配置 - Secret:存储敏感信息(密码、密钥等)
Namespace: - 虚拟集群,用于资源隔离 - 多租户环境的逻辑分组
3. Kubernetes工作流程¶
应用部署流程:
1. 用户提交配置
kubectl apply -f deployment.yaml
│
▼
2. API Server接收请求
验证和存储到etcd
│
▼
3. Controller Manager检测到新的Deployment
创建ReplicaSet
│
▼
4. Scheduler选择合适的节点
将Pod调度到节点
│
▼
5. kubelet在节点上创建容器
启动应用
│
▼
6. kube-proxy配置网络规则
实现服务访问
准备工作¶
系统要求¶
开发环境(单节点集群): - CPU:2核心或更多 - 内存:4GB或更多 - 磁盘:20GB可用空间
生产环境(多节点集群): - 控制平面:4核心、8GB内存 - 工作节点:2核心、4GB内存(每个节点) - 网络:节点间可以互相通信
安装Kubernetes¶
我们将介绍几种常用的安装方式:
方式1:Minikube(推荐用于学习)¶
Minikube在本地运行单节点Kubernetes集群,非常适合学习和开发。
安装Minikube:
# Linux
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# macOS
brew install minikube
# Windows (使用PowerShell管理员权限)
choco install minikube
启动Minikube:
# 启动集群
minikube start
# 指定资源
minikube start --cpus=4 --memory=8192
# 指定容器运行时
minikube start --driver=docker
# 查看状态
minikube status
# 停止集群
minikube stop
# 删除集群
minikube delete
方式2:Kind(Kubernetes in Docker)¶
Kind在Docker容器中运行Kubernetes集群,轻量且快速。
# 安装Kind
# Linux/macOS
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
# 创建集群
kind create cluster
# 创建多节点集群
kind create cluster --config kind-config.yaml
# 删除集群
kind delete cluster
kind-config.yaml示例:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
方式3:Docker Desktop(Windows/macOS)¶
Docker Desktop内置Kubernetes支持:
- 打开Docker Desktop设置
- 进入Kubernetes选项卡
- 勾选"Enable Kubernetes"
- 点击"Apply & Restart"
安装kubectl¶
kubectl是Kubernetes的命令行工具。
# Linux
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# macOS
brew install kubectl
# Windows (PowerShell管理员权限)
choco install kubernetes-cli
# 验证安装
kubectl version --client
# 查看集群信息
kubectl cluster-info
# 查看节点
kubectl get nodes
配置kubectl自动补全¶
# Bash
echo 'source <(kubectl completion bash)' >>~/.bashrc
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
# Zsh
echo 'source <(kubectl completion zsh)' >>~/.zshrc
echo 'alias k=kubectl' >>~/.zshrc
步骤1:kubectl基本命令¶
1.1 查看集群信息¶
# 查看集群信息
kubectl cluster-info
# 查看节点
kubectl get nodes
# 查看节点详细信息
kubectl describe node <node-name>
# 查看所有命名空间
kubectl get namespaces
# 查看当前上下文
kubectl config current-context
# 查看所有上下文
kubectl config get-contexts
1.2 资源操作命令¶
# 查看资源(get)
kubectl get pods # 查看Pod
kubectl get deployments # 查看Deployment
kubectl get services # 查看Service
kubectl get all # 查看所有资源
# 查看详细信息(describe)
kubectl describe pod <pod-name>
kubectl describe deployment <deployment-name>
# 查看日志(logs)
kubectl logs <pod-name>
kubectl logs <pod-name> -f # 实时查看
kubectl logs <pod-name> -c <container-name> # 多容器Pod
# 执行命令(exec)
kubectl exec <pod-name> -- ls /app
kubectl exec -it <pod-name> -- bash # 进入容器
# 端口转发(port-forward)
kubectl port-forward <pod-name> 8080:80
# 删除资源(delete)
kubectl delete pod <pod-name>
kubectl delete deployment <deployment-name>
kubectl delete -f deployment.yaml
1.3 常用选项¶
# 指定命名空间
kubectl get pods -n kube-system
# 查看所有命名空间
kubectl get pods --all-namespaces
kubectl get pods -A
# 输出格式
kubectl get pods -o wide # 更多信息
kubectl get pods -o yaml # YAML格式
kubectl get pods -o json # JSON格式
# 标签选择器
kubectl get pods -l app=nginx
kubectl get pods -l 'env in (prod,staging)'
# 监听变化
kubectl get pods --watch
kubectl get pods -w
步骤2:Pod管理¶
2.1 创建第一个Pod¶
创建 nginx-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
部署Pod:
# 创建Pod
kubectl apply -f nginx-pod.yaml
# 查看Pod
kubectl get pods
# 查看Pod详细信息
kubectl describe pod nginx-pod
# 查看Pod日志
kubectl logs nginx-pod
# 进入Pod
kubectl exec -it nginx-pod -- bash
# 删除Pod
kubectl delete pod nginx-pod
2.2 多容器Pod¶
创建 multi-container-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: multi-container-pod
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: content-generator
image: busybox
command: ["/bin/sh"]
args:
- -c
- >
while true; do
echo "Hello from Kubernetes! $(date)" > /data/index.html;
sleep 10;
done
volumeMounts:
- name: shared-data
mountPath: /data
volumes:
- name: shared-data
emptyDir: {}
测试多容器Pod:
# 创建Pod
kubectl apply -f multi-container-pod.yaml
# 查看Pod状态
kubectl get pod multi-container-pod
# 查看特定容器的日志
kubectl logs multi-container-pod -c content-generator
# 端口转发测试
kubectl port-forward multi-container-pod 8080:80
# 在另一个终端测试
curl http://localhost:8080
2.3 Pod生命周期¶
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-pod
spec:
containers:
- name: app
image: nginx:1.21
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo 'Container started' > /tmp/started"]
preStop:
exec:
command: ["/bin/sh", "-c", "nginx -s quit; while killall -0 nginx; do sleep 1; done"]
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 3
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
探针类型: - livenessProbe:检查容器是否存活,失败则重启 - readinessProbe:检查容器是否就绪,失败则不接收流量 - startupProbe:检查容器是否启动完成
步骤3:Deployment管理¶
3.1 创建Deployment¶
Deployment是管理Pod的推荐方式,提供声明式更新和回滚功能。
创建 nginx-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
部署和管理:
# 创建Deployment
kubectl apply -f nginx-deployment.yaml
# 查看Deployment
kubectl get deployments
# 查看ReplicaSet
kubectl get replicasets
# 查看Pod
kubectl get pods
# 查看详细信息
kubectl describe deployment nginx-deployment
# 查看部署状态
kubectl rollout status deployment/nginx-deployment
3.2 扩缩容¶
# 手动扩容
kubectl scale deployment nginx-deployment --replicas=5
# 查看扩容结果
kubectl get pods
# 缩容
kubectl scale deployment nginx-deployment --replicas=2
# 自动扩缩容(HPA)
kubectl autoscale deployment nginx-deployment --min=2 --max=10 --cpu-percent=80
# 查看HPA
kubectl get hpa
3.3 滚动更新¶
# 更新镜像
kubectl set image deployment/nginx-deployment nginx=nginx:1.22
# 查看更新状态
kubectl rollout status deployment/nginx-deployment
# 查看更新历史
kubectl rollout history deployment/nginx-deployment
# 查看特定版本详情
kubectl rollout history deployment/nginx-deployment --revision=2
# 回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment
# 回滚到特定版本
kubectl rollout undo deployment/nginx-deployment --to-revision=1
# 暂停更新
kubectl rollout pause deployment/nginx-deployment
# 恢复更新
kubectl rollout resume deployment/nginx-deployment
3.4 更新策略¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 更新时最多可以超出期望副本数的数量
maxUnavailable: 1 # 更新时最多可以不可用的副本数
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
更新策略类型: - RollingUpdate(默认):逐步替换旧Pod - Recreate:先删除所有旧Pod,再创建新Pod
步骤4:Service服务¶
4.1 ClusterIP Service¶
ClusterIP是默认的Service类型,只能在集群内部访问。
创建 nginx-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: ClusterIP
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
部署和测试:
# 创建Service
kubectl apply -f nginx-service.yaml
# 查看Service
kubectl get services
kubectl get svc
# 查看Service详细信息
kubectl describe service nginx-service
# 查看Endpoints
kubectl get endpoints nginx-service
# 测试Service(在集群内)
kubectl run test-pod --image=busybox --rm -it -- wget -O- nginx-service
4.2 NodePort Service¶
NodePort在每个节点上开放一个端口,可以从集群外部访问。
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport
spec:
type: NodePort
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080 # 可选,范围30000-32767
访问NodePort Service:
# 创建Service
kubectl apply -f nginx-nodeport.yaml
# 查看Service
kubectl get svc nginx-nodeport
# 获取节点IP
kubectl get nodes -o wide
# 访问服务(Minikube)
minikube service nginx-nodeport --url
# 浏览器访问
# http://<node-ip>:30080
4.3 LoadBalancer Service¶
LoadBalancer类型在云环境中创建外部负载均衡器。
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
注意:LoadBalancer类型需要云提供商支持(AWS、GCP、Azure等)。在Minikube中可以使用minikube tunnel模拟。
4.4 Headless Service¶
Headless Service不分配ClusterIP,用于直接访问Pod。
apiVersion: v1
kind: Service
metadata:
name: nginx-headless
spec:
clusterIP: None # Headless Service
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
步骤5:配置管理¶
5.1 ConfigMap¶
ConfigMap用于存储非敏感的配置数据。
创建ConfigMap:
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
database_url: "postgresql://db:5432/myapp"
log_level: "info"
config.json: |
{
"server": {
"port": 8080,
"host": "0.0.0.0"
},
"features": {
"cache": true,
"debug": false
}
}
使用ConfigMap:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
# 方式1:环境变量
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: database_url
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: log_level
# 方式2:挂载为文件
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
命令行创建ConfigMap:
# 从字面值创建
kubectl create configmap app-config \
--from-literal=database_url=postgresql://db:5432/myapp \
--from-literal=log_level=info
# 从文件创建
kubectl create configmap app-config --from-file=config.json
# 从目录创建
kubectl create configmap app-config --from-file=./config/
# 查看ConfigMap
kubectl get configmap
kubectl describe configmap app-config
kubectl get configmap app-config -o yaml
5.2 Secret¶
Secret用于存储敏感信息,如密码、密钥等。
创建Secret:
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
# Base64编码的值
username: YWRtaW4= # admin
password: cGFzc3dvcmQxMjM= # password123
使用Secret:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: app-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: password
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: app-secret
命令行创建Secret:
# 从字面值创建
kubectl create secret generic app-secret \
--from-literal=username=admin \
--from-literal=password=password123
# 从文件创建
kubectl create secret generic app-secret \
--from-file=username.txt \
--from-file=password.txt
# 创建Docker registry secret
kubectl create secret docker-registry regcred \
--docker-server=<registry-server> \
--docker-username=<username> \
--docker-password=<password> \
--docker-email=<email>
# 查看Secret
kubectl get secrets
kubectl describe secret app-secret
# Base64编码/解码
echo -n 'admin' | base64 # 编码
echo 'YWRtaW4=' | base64 -d # 解码
步骤6:存储管理¶
6.1 Volume类型¶
Kubernetes支持多种Volume类型:
emptyDir:临时存储,Pod删除时数据丢失
apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: cache
mountPath: /cache
volumes:
- name: cache
emptyDir: {}
hostPath:挂载主机目录
configMap和secret:前面已介绍
6.2 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC)¶
创建PersistentVolume:
# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /mnt/data
创建PersistentVolumeClaim:
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
storageClassName: manual
在Pod中使用PVC:
apiVersion: v1
kind: Pod
metadata:
name: pvc-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: storage
mountPath: /usr/share/nginx/html
volumes:
- name: storage
persistentVolumeClaim:
claimName: my-pvc
管理PV和PVC:
# 创建PV和PVC
kubectl apply -f pv.yaml
kubectl apply -f pvc.yaml
# 查看PV
kubectl get pv
# 查看PVC
kubectl get pvc
# 查看PVC详情
kubectl describe pvc my-pvc
# 删除PVC
kubectl delete pvc my-pvc
6.3 StorageClass¶
StorageClass提供动态存储供应。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-storage
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
fsType: ext4
使用StorageClass的PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-storage
resources:
requests:
storage: 10Gi
步骤7:命名空间和资源配额¶
7.1 Namespace¶
Namespace用于资源隔离和多租户管理。
# 查看命名空间
kubectl get namespaces
# 创建命名空间
kubectl create namespace dev
kubectl create namespace prod
# 使用YAML创建
kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: staging
EOF
# 在特定命名空间创建资源
kubectl apply -f deployment.yaml -n dev
# 设置默认命名空间
kubectl config set-context --current --namespace=dev
# 删除命名空间
kubectl delete namespace dev
7.2 ResourceQuota¶
限制命名空间的资源使用。
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: dev
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
pods: "50"
services: "10"
persistentvolumeclaims: "10"
# 创建ResourceQuota
kubectl apply -f resource-quota.yaml
# 查看配额
kubectl get resourcequota -n dev
kubectl describe resourcequota dev-quota -n dev
7.3 LimitRange¶
设置Pod和容器的默认资源限制。
apiVersion: v1
kind: LimitRange
metadata:
name: dev-limits
namespace: dev
spec:
limits:
- max:
cpu: "2"
memory: 2Gi
min:
cpu: "100m"
memory: 128Mi
default:
cpu: "500m"
memory: 512Mi
defaultRequest:
cpu: "250m"
memory: 256Mi
type: Container
步骤8:部署完整应用¶
让我们部署一个完整的Web应用栈(前端 + 后端 + 数据库)。
8.1 项目结构¶
k8s-app/
├── namespace.yaml
├── database/
│ ├── postgres-pvc.yaml
│ ├── postgres-deployment.yaml
│ └── postgres-service.yaml
├── backend/
│ ├── backend-configmap.yaml
│ ├── backend-secret.yaml
│ ├── backend-deployment.yaml
│ └── backend-service.yaml
└── frontend/
├── frontend-deployment.yaml
└── frontend-service.yaml
8.2 创建命名空间¶
8.3 部署数据库¶
PVC:
# database/postgres-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
namespace: myapp
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
Deployment:
# database/postgres-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: myapp
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:14
env:
- name: POSTGRES_DB
value: myapp
- name: POSTGRES_USER
value: appuser
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: postgres-pvc
Service:
# database/postgres-service.yaml
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: myapp
spec:
selector:
app: postgres
ports:
- protocol: TCP
port: 5432
targetPort: 5432
8.4 部署后端¶
Secret:
# backend/backend-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: myapp
type: Opaque
stringData:
password: "mypassword123"
ConfigMap:
# backend/backend-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-config
namespace: myapp
data:
DATABASE_HOST: "postgres"
DATABASE_PORT: "5432"
DATABASE_NAME: "myapp"
LOG_LEVEL: "info"
Deployment:
# backend/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: 8080
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: backend-config
key: DATABASE_HOST
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: backend-config
key: DATABASE_PORT
- name: DATABASE_NAME
valueFrom:
configMapKeyRef:
name: backend-config
key: DATABASE_NAME
- name: DATABASE_USER
value: "appuser"
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
Service:
# backend/backend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: myapp
spec:
selector:
app: backend
ports:
- protocol: TCP
port: 8080
targetPort: 8080
8.5 部署前端¶
Deployment:
# frontend/frontend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: myapp
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: myapp/frontend:1.0
ports:
- containerPort: 80
env:
- name: BACKEND_URL
value: "http://backend:8080"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
Service:
# frontend/frontend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: myapp
spec:
type: NodePort
selector:
app: frontend
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
8.6 部署应用¶
# 创建命名空间
kubectl apply -f namespace.yaml
# 部署数据库
kubectl apply -f database/
# 部署后端
kubectl apply -f backend/
# 部署前端
kubectl apply -f frontend/
# 查看所有资源
kubectl get all -n myapp
# 查看Pod状态
kubectl get pods -n myapp
# 查看Service
kubectl get svc -n myapp
# 访问应用(Minikube)
minikube service frontend -n myapp --url
# 查看日志
kubectl logs -f deployment/backend -n myapp
步骤9:Ingress控制器¶
Ingress提供HTTP和HTTPS路由到集群内服务。
9.1 安装Ingress Controller¶
# Minikube启用Ingress
minikube addons enable ingress
# 或使用Nginx Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml
# 查看Ingress Controller
kubectl get pods -n ingress-nginx
9.2 创建Ingress¶
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
namespace: myapp
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: backend
port:
number: 8080
配置和测试:
# 创建Ingress
kubectl apply -f ingress.yaml
# 查看Ingress
kubectl get ingress -n myapp
# 配置hosts文件
# Linux/macOS: /etc/hosts
# Windows: C:\Windows\System32\drivers\etc\hosts
# 添加:
# <minikube-ip> myapp.local
# 获取Minikube IP
minikube ip
# 测试访问
curl http://myapp.local
curl http://myapp.local/api/health
9.3 TLS/HTTPS配置¶
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
namespace: myapp
type: kubernetes.io/tls
data:
tls.crt: <base64-encoded-cert>
tls.key: <base64-encoded-key>
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress-tls
namespace: myapp
spec:
tls:
- hosts:
- myapp.local
secretName: tls-secret
rules:
- host: myapp.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
步骤10:监控和日志¶
10.1 查看资源使用¶
# 查看节点资源使用
kubectl top nodes
# 查看Pod资源使用
kubectl top pods -n myapp
# 查看特定Pod的资源使用
kubectl top pod <pod-name> -n myapp
10.2 查看日志¶
# 查看Pod日志
kubectl logs <pod-name> -n myapp
# 实时查看日志
kubectl logs -f <pod-name> -n myapp
# 查看多容器Pod的特定容器日志
kubectl logs <pod-name> -c <container-name> -n myapp
# 查看之前容器的日志
kubectl logs <pod-name> --previous -n myapp
# 查看最近的日志
kubectl logs <pod-name> --tail=100 -n myapp
# 查看带时间戳的日志
kubectl logs <pod-name> --timestamps -n myapp
10.3 事件查看¶
# 查看所有事件
kubectl get events -n myapp
# 按时间排序
kubectl get events -n myapp --sort-by='.lastTimestamp'
# 监听事件
kubectl get events -n myapp --watch
故障排除¶
问题1:Pod一直处于Pending状态¶
现象:
可能原因: 1. 资源不足(CPU、内存) 2. PVC未绑定 3. 节点选择器不匹配
解决方法:
# 查看Pod详情
kubectl describe pod my-pod
# 检查事件
kubectl get events --sort-by='.lastTimestamp'
# 检查节点资源
kubectl top nodes
# 检查PVC状态
kubectl get pvc
# 临时解决:降低资源请求
# 编辑deployment,减少resources.requests
问题2:Pod一直重启¶
现象:
可能原因: 1. 应用启动失败 2. 健康检查失败 3. 配置错误
解决方法:
# 查看日志
kubectl logs my-pod
kubectl logs my-pod --previous # 查看上次运行的日志
# 查看Pod详情
kubectl describe pod my-pod
# 进入容器调试
kubectl exec -it my-pod -- sh
# 检查健康检查配置
kubectl get pod my-pod -o yaml | grep -A 10 livenessProbe
问题3:Service无法访问¶
现象: 无法通过Service访问Pod
解决方法:
# 检查Service
kubectl get svc
kubectl describe svc my-service
# 检查Endpoints
kubectl get endpoints my-service
# 检查Pod标签
kubectl get pods --show-labels
# 检查Service选择器
kubectl get svc my-service -o yaml | grep -A 5 selector
# 测试Pod直接访问
kubectl run test --image=busybox --rm -it -- wget -O- <pod-ip>:80
问题4:镜像拉取失败¶
现象:
解决方法:
# 查看详细错误
kubectl describe pod my-pod
# 检查镜像名称
kubectl get pod my-pod -o yaml | grep image:
# 使用imagePullSecrets
kubectl create secret docker-registry regcred \
--docker-server=<registry> \
--docker-username=<username> \
--docker-password=<password>
# 在Pod中使用
spec:
imagePullSecrets:
- name: regcred
问题5:PVC无法绑定¶
现象:
kubectl get pvc
# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
# my-pvc Pending standard 5m
解决方法:
# 查看PVC详情
kubectl describe pvc my-pvc
# 检查PV
kubectl get pv
# 检查StorageClass
kubectl get storageclass
# 手动创建PV(如果需要)
# 或使用动态供应
最佳实践¶
1. 资源管理¶
# ✅ 好的做法:始终设置资源请求和限制
spec:
containers:
- name: app
image: myapp:1.0
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
# ❌ 不好的做法:不设置资源限制
spec:
containers:
- name: app
image: myapp:1.0
# 没有resources配置
2. 健康检查¶
# ✅ 好的做法:配置健康检查
spec:
containers:
- name: app
image: myapp:1.0
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
# ❌ 不好的做法:不配置健康检查
3. 标签和选择器¶
# ✅ 好的做法:使用有意义的标签
metadata:
labels:
app: myapp
component: backend
version: v1.0
environment: production
# ❌ 不好的做法:标签不清晰
metadata:
labels:
name: pod1
4. 配置管理¶
# ✅ 好的做法:使用ConfigMap和Secret
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: database_url
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: password
# ❌ 不好的做法:硬编码配置
env:
- name: DATABASE_URL
value: "postgresql://db:5432/myapp"
- name: DATABASE_PASSWORD
value: "password123" # 不要这样做!
5. 镜像管理¶
# ✅ 好的做法:使用特定版本标签
spec:
containers:
- name: app
image: myapp:1.2.3
imagePullPolicy: IfNotPresent
# ❌ 不好的做法:使用latest标签
spec:
containers:
- name: app
image: myapp:latest # 避免使用latest
6. 命名空间隔离¶
# ✅ 好的做法:使用命名空间隔离环境
kubectl create namespace dev
kubectl create namespace staging
kubectl create namespace prod
# 在特定命名空间部署
kubectl apply -f app.yaml -n dev
# ❌ 不好的做法:所有资源都在default命名空间
7. 滚动更新策略¶
# ✅ 好的做法:配置合理的更新策略
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # 确保服务不中断
# ❌ 不好的做法:使用Recreate策略(除非必要)
spec:
strategy:
type: Recreate # 会导致服务中断
8. 安全实践¶
# ✅ 好的做法:使用非root用户
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: app
image: myapp:1.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
# ❌ 不好的做法:以root用户运行
总结¶
通过本教程,你已经学习了Kubernetes容器编排的核心内容:
核心要点回顾¶
Kubernetes架构: - ✅ 控制平面:API Server、Scheduler、Controller Manager、etcd - ✅ 工作节点:kubelet、kube-proxy、Container Runtime - ✅ 核心资源:Pod、Deployment、Service、ConfigMap、Secret
基本操作: - ✅ kubectl命令:get、describe、logs、exec、apply、delete - ✅ Pod管理:创建、查看、调试、删除 - ✅ Deployment:部署、扩缩容、滚动更新、回滚 - ✅ Service:ClusterIP、NodePort、LoadBalancer
高级功能: - ✅ 配置管理:ConfigMap、Secret - ✅ 存储管理:Volume、PV、PVC、StorageClass - ✅ 命名空间:资源隔离、ResourceQuota、LimitRange - ✅ Ingress:HTTP路由、TLS配置
实践项目: - ✅ 部署完整的三层应用(前端+后端+数据库) - ✅ 配置服务发现和负载均衡 - ✅ 实现滚动更新和健康检查 - ✅ 配置Ingress和域名访问
实践成果¶
完成本教程后,你应该能够: 1. 搭建和管理Kubernetes集群 2. 使用kubectl进行日常操作 3. 部署和管理容器化应用 4. 配置服务发现和负载均衡 5. 实现应用的自动化运维 6. 解决常见的Kubernetes问题
下一步学习建议¶
- 深入学习
- Helm包管理器
- Kubernetes Operator
- 服务网格(Istio、Linkerd)
-
GitOps(ArgoCD、Flux)
-
实践项目
- 部署微服务应用
- 实现CI/CD流程
- 配置监控和告警
-
实现多集群管理
-
进阶主题
- 集群安全加固
- 性能优化
- 灾难恢复
- 多云部署
进阶挑战¶
尝试以下挑战来巩固学习:
挑战1:部署有状态应用(45分钟)¶
任务: 1. 使用StatefulSet部署MongoDB集群 2. 配置持久化存储 3. 实现数据备份和恢复 4. 配置Headless Service
提示: - 使用StatefulSet而不是Deployment - 配置volumeClaimTemplates - 使用init容器进行初始化
挑战2:实现蓝绿部署(30分钟)¶
任务: 1. 部署应用的两个版本(蓝色和绿色) 2. 使用Service切换流量 3. 验证新版本后完全切换 4. 实现快速回滚
目标: - 零停机部署 - 快速回滚能力
挑战3:搭建物联网数据处理平台(90分钟)¶
任务: 1. 部署MQTT Broker(Mosquitto) 2. 部署数据处理服务(Python/Node.js) 3. 部署时序数据库(InfluxDB) 4. 部署可视化服务(Grafana) 5. 配置Ingress访问
要求: - 所有服务使用Deployment - 配置持久化存储 - 实现服务间通信 - 配置资源限制 - 实现健康检查
常见问题¶
Q1: Kubernetes和Docker Swarm有什么区别?¶
A: 主要区别:
| 特性 | Kubernetes | Docker Swarm |
|---|---|---|
| 复杂度 | 较高 | 较低 |
| 功能 | 非常丰富 | 基础功能 |
| 社区 | 非常活跃 | 较小 |
| 学习曲线 | 陡峭 | 平缓 |
| 生产就绪 | 是 | 是 |
| 生态系统 | 庞大 | 有限 |
Kubernetes功能更强大,适合大规模生产环境;Docker Swarm更简单,适合小型项目。
Q2: 什么时候使用Deployment,什么时候使用StatefulSet?¶
A:
使用Deployment: - 无状态应用 - 可以随意替换的Pod - 不需要稳定的网络标识 - 例如:Web服务器、API服务
使用StatefulSet: - 有状态应用 - 需要稳定的网络标识 - 需要持久化存储 - 需要有序部署和扩展 - 例如:数据库、消息队列、分布式系统
Q3: 如何选择Service类型?¶
A:
ClusterIP(默认): - 只需要集群内部访问 - 通过Ingress暴露服务
NodePort: - 需要从集群外部访问 - 开发和测试环境 - 不需要负载均衡器
LoadBalancer: - 生产环境 - 需要云提供商的负载均衡器 - 需要固定的外部IP
Headless: - 需要直接访问Pod - 有状态应用 - 服务发现
Q4: 如何调试Pod启动失败?¶
A: 按以下步骤排查:
# 1. 查看Pod状态
kubectl get pods
# 2. 查看Pod详情和事件
kubectl describe pod <pod-name>
# 3. 查看容器日志
kubectl logs <pod-name>
kubectl logs <pod-name> --previous # 查看上次运行的日志
# 4. 进入容器调试(如果容器在运行)
kubectl exec -it <pod-name> -- sh
# 5. 查看集群事件
kubectl get events --sort-by='.lastTimestamp'
# 6. 检查资源配置
kubectl get pod <pod-name> -o yaml
Q5: 如何实现零停机部署?¶
A:
-
使用滚动更新:
-
配置就绪探针:
-
优雅关闭:
-
足够的副本数:
Q6: 如何在Kubernetes中管理密钥?¶
A:
方法1:使用Secret(基础):
方法2:使用外部密钥管理(推荐): - HashiCorp Vault - AWS Secrets Manager - Azure Key Vault - Google Secret Manager
方法3:使用Sealed Secrets: - 加密Secret后存储在Git - 集群中自动解密
最佳实践: - 不要将Secret提交到Git - 使用RBAC限制访问 - 定期轮换密钥 - 使用外部密钥管理系统
延伸阅读¶
推荐资源¶
官方文档: - Kubernetes官方文档 - Kubernetes中文文档 - kubectl命令参考
在线教程: - Kubernetes官方教程 - Katacoda Kubernetes课程 - Play with Kubernetes
书籍推荐: - 《Kubernetes权威指南》- 龚正等 - 《Kubernetes in Action》- Marko Lukša - 《深入剖析Kubernetes》- 张磊
视频课程: - Kubernetes官方YouTube频道 - CNCF YouTube频道 - 极客时间《深入剖析Kubernetes》
相关技术¶
容器编排: - Docker Swarm - Docker原生编排 - Nomad - HashiCorp的编排工具 - Rancher - Kubernetes管理平台
服务网格: - Istio - 功能最丰富的服务网格 - Linkerd - 轻量级服务网格 - Consul Connect - HashiCorp的服务网格
包管理: - Helm - Kubernetes包管理器 - Kustomize - Kubernetes配置管理 - Operator Framework - 自定义控制器
CI/CD: - ArgoCD - GitOps持续交付 - Flux - GitOps工具 - Tekton - Kubernetes原生CI/CD
监控和日志: - Prometheus - 监控系统 - Grafana - 可视化平台 - ELK/EFK Stack - 日志分析 - Jaeger - 分布式追踪
参考资料¶
- Kubernetes官方文档 - https://kubernetes.io/docs/
- Kubernetes最佳实践 - https://kubernetes.io/docs/concepts/configuration/overview/
- kubectl命令参考 - https://kubernetes.io/docs/reference/kubectl/
- Kubernetes API参考 - https://kubernetes.io/docs/reference/kubernetes-api/
- CNCF云原生技术栈 - https://landscape.cncf.io/
反馈与支持: - 如果你在学习过程中遇到问题,欢迎在评论区留言 - 发现文档错误或有改进建议,请提交Issue - 想要分享你的Kubernetes实践经验,欢迎投稿
下一步学习: - Serverless无服务器架构 - 学习函数计算 - 云原生应用开发 - 构建云原生应用 - 微服务架构设计 - 学习微服务 - 消息队列应用 - 学习异步通信
版权声明: 本文采用 CC BY-NC-SA 4.0 许可协议,欢迎分享和改编,但请注明出处。