Docker与Kubernetes容器化部署完全教程
关键词:Docker, Kubernetes, 容器化, DevOps, 云原生, 部署
本教程从零开始,带你掌握 Docker 容器化技术与 Kubernetes 集群编排的核心知识,最终能够独立完成生产级应用的容器化部署。
目录
- 容器化技术概述
- Docker 基础与安装
- Docker 镜像构建
- Docker Compose 多容器编排
- Kubernetes 核心概念
- kubectl 命令实战
- Helm 包管理器
- 集群部署与运维
- CI/CD 集成
- 总结与最佳实践
1. 容器化技术概述
1.1 什么是容器化
容器化是一种轻量级的虚拟化技术,它将应用程序及其所有依赖项(库、配置文件、运行时环境)打包到一个独立的、可移植的单元中——即容器。与传统虚拟机不同,容器共享宿主机的操作系统内核,因此更加轻量、启动更快。
容器 vs 虚拟机的核心区别:
| 特性 | 容器 | 虚拟机 |
|---|---|---|
| 启动速度 | 秒级 | 分钟级 |
| 资源占用 | MB 级别 | GB 级别 |
| 隔离级别 | 进程级 | 系统级 |
| 运行密度 | 单机可运行数百个 | 单机通常数十个 |
1.2 为什么需要容器化
- 环境一致性:开发、测试、生产环境完全一致,告别"在我机器上能跑"
- 快速部署:镜像一次构建,随处运行
- 资源高效:比虚拟机节省大量系统资源
- 微服务友好:每个服务独立容器,互不干扰
- 版本控制:镜像版本化管理,支持快速回滚
2. Docker 基础与安装
2.1 安装 Docker
Ubuntu/Debian 系统安装:
# 更新包索引
sudo apt-get update
# 安装依赖
sudo apt-get install -y ca-certificates curl gnupg
# 添加 Docker 官方 GPG 密钥
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# 添加 Docker 仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 将当前用户添加到 docker 组(免 sudo)
sudo usermod -aG docker $USER
newgrp docker
# 验证安装
docker --version
docker run hello-world
macOS / Windows:直接下载安装 Docker Desktop,图形化界面管理更方便。
2.2 Docker 基本操作
# 拉取镜像
docker pull nginx:latest
# 查看本地镜像
docker images
# 运行容器
docker run -d --name my-nginx -p 8080:80 nginx:latest
# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
# 停止容器
docker stop my-nginx
# 删除容器
docker rm my-nginx
# 删除镜像
docker rmi nginx:latest
# 查看容器日志
docker logs my-nginx
# 进入容器内部
docker exec -it my-nginx /bin/bash
2.3 Docker 数据管理
容器是临时的,数据持久化需要使用卷(Volume)或绑定挂载(Bind Mount):
# 创建命名卷
docker volume create my-data
# 使用命名卷运行容器
docker run -d --name my-app -v my-data:/app/data nginx:latest
# 使用绑定挂载(将宿主机目录映射到容器)
docker run -d --name my-app -v /host/path:/container/path nginx:latest
# 查看所有卷
docker volume ls
# 删除未使用的卷
docker volume prune
3. Docker 镜像构建
3.1 Dockerfile 基础
Dockerfile 是一个文本文件,包含了一系列构建镜像的指令。以下是一个 Node.js 应用的 Dockerfile 示例:
# 基础镜像
FROM node:20-alpine
# 设置工作目录
WORKDIR /app
# 复制依赖文件(利用缓存层优化)
COPY package.json package-lock.json ./
# 安装依赖
RUN npm ci --only=production
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 3000
# 设置环境变量
ENV NODE_ENV=production
# 启动命令
CMD ["node", "server.js"]
3.2 多阶段构建
多阶段构建可以显著减小最终镜像的体积:
# === 构建阶段 ===
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# === 生产阶段 ===
FROM node:20-alpine AS production
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY --from=builder /app/dist ./dist
# 非 root 用户运行
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
USER appuser
EXPOSE 3000
CMD ["node", "dist/server.js"]
3.3 Dockerfile 最佳实践
# ✅ 使用精简基础镜像
FROM node:20-alpine
# ✅ 合并 RUN 指令减少层数
RUN apk add --no-cache git && \
npm install -g typescript && \
npm cache clean --force
# ✅ 使用 .dockerignore 排除不需要的文件
# .dockerignore 文件内容:
# node_modules
# .git
# *.md
# .env
# ✅ 使用 COPY --chown 设置文件权限
COPY --chown=appuser:appgroup . .
# ✅ 使用 HEALTHCHECK 检查容器健康状态
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
3.4 构建与推送镜像
# 构建镜像
docker build -t my-app:1.0.0 .
# 标记镜像(用于推送到仓库)
docker tag my-app:1.0.0 registry.example.com/my-app:1.0.0
# 推送到私有仓库
docker push registry.example.com/my-app:1.0.0
# 使用 BuildKit 加速构建
DOCKER_BUILDKIT=1 docker build -t my-app:1.0.0 .
4. Docker Compose 多容器编排
4.1 基础配置
Docker Compose 用于定义和运行多容器应用。以下是一个典型的 Web 应用配置:
# docker-compose.yml
version: "3.9"
services:
# Web 应用
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
networks:
- app-network
# PostgreSQL 数据库
db:
image: postgres:16-alpine
volumes:
- postgres-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
environment:
POSTGRES_DB: myapp
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
# Redis 缓存
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
command: redis-server --appendonly yes
networks:
- app-network
# Nginx 反向代理
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- web
networks:
- app-network
volumes:
postgres-data:
redis-data:
networks:
app-network:
driver: bridge
4.2 Compose 常用命令
# 启动所有服务(后台运行)
docker compose up -d
# 查看服务状态
docker compose ps
# 查看日志
docker compose logs -f web
# 停止并删除所有资源
docker compose down
# 停止并删除所有资源(包括数据卷)
docker compose down -v
# 重新构建镜像并启动
docker compose up -d --build
# 扩展服务实例数
docker compose up -d --scale web=3
# 执行一次性命令
docker compose exec web npm run migrate
4.3 环境分离
为不同环境创建独立的 Compose 文件:
# docker-compose.prod.yml
version: "3.9"
services:
web:
image: registry.example.com/my-app:1.0.0
deploy:
replicas: 3
resources:
limits:
cpus: "0.5"
memory: 512M
reservations:
cpus: "0.25"
memory: 256M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# 使用生产配置启动
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
5. Kubernetes 核心概念
5.1 为什么需要 Kubernetes
Docker Compose 适合单机部署,当应用规模扩大到多台服务器时,就需要 Kubernetes(K8s)来进行集群编排:
- 自动调度:自动将容器分配到合适的节点
- 自我修复:容器崩溃后自动重启、替换
- 水平扩展:根据负载自动增减容器数量
- 服务发现与负载均衡:自动分配网络流量
- 滚动更新与回滚:零停机部署
5.2 核心资源对象
Pod —— 最小部署单元:
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-app
labels:
app: my-app
version: v1
spec:
containers:
- name: my-app
image: my-app:1.0.0
ports:
- containerPort: 3000
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
Deployment —— 管理 Pod 的副本集:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: my-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app:1.0.0
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
Service —— 为 Pod 提供稳定的网络访问:
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: ClusterIP
Ingress —— 对外暴露 HTTP/HTTPS 路由:
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
5.3 其他重要资源
# ConfigMap - 存储非敏感配置
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "production"
LOG_LEVEL: "info"
config.json: |
{
"apiUrl": "https://api.example.com",
"features": { "darkMode": true }
}
---
# Secret - 存储敏感信息
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
database-url: cG9zdGdyZXNxbDovL3VzZXI6cGFzc0Bob3N0OjU0MzIvZGI= # base64 编码
api-key: c2VjcmV0LWFwaS1rZXk=
---
# Namespace - 资源隔离
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
env: production
6. kubectl 命令实战
6.1 集群管理
# 查看集群信息
kubectl cluster-info
# 查看节点状态
kubectl get nodes
# 查看节点详细信息
kubectl describe node <node-name>
6.2 资源操作
# 应用配置文件
kubectl apply -f deployment.yaml
# 查看所有资源
kubectl get all -n production
# 查看 Pod 详情
kubectl describe pod <pod-name> -n production
# 查看 Pod 日志
kubectl logs <pod-name> -n production -f
# 进入 Pod
kubectl exec -it <pod-name> -n production -- /bin/sh
# 端口转发(本地调试)
kubectl port-forward svc/my-app-service 8080:80 -n production
# 查看资源使用情况
kubectl top pods -n production
kubectl top nodes
6.3 扩容与更新
# 手动扩容
kubectl scale deployment my-app --replicas=5 -n production
# 滚动更新镜像
kubectl set image deployment/my-app my-app=my-app:2.0.0 -n production
# 查看更新状态
kubectl rollout status deployment/my-app -n production
# 查看更新历史
kubectl rollout history deployment/my-app -n production
# 回滚到上一版本
kubectl rollout undo deployment/my-app -n production
# 回滚到指定版本
kubectl rollout undo deployment/my-app --to-revision=2 -n production
6.4 调试技巧
# 查看事件(排查问题的关键)
kubectl get events -n production --sort-by=.metadata.creationTimestamp
# 以 YAML 格式查看资源
kubectl get deployment my-app -n production -o yaml
# 以 JSON 格式查看并过滤字段
kubectl get pods -n production -o jsonpath='{.items[*].status.podIP}'
# 临时运行一个调试 Pod
kubectl run debug --image=busybox -it --rm --restart=Never -- /bin/sh
# 查看资源配额
kubectl describe resourcequota -n production
7. Helm 包管理器
7.1 Helm 基础
Helm 是 Kubernetes 的包管理器,将相关资源打包成 Chart,方便复用和分发。
# 安装 Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 添加常用仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# 搜索 Chart
helm search repo nginx
# 安装 Chart
helm install my-nginx bitnami/nginx -n web --create-namespace
# 查看已安装的 Release
helm list -A
# 升级
helm upgrade my-nginx bitnami/nginx -n web --set replicaCount=3
# 回滚
helm rollback my-nginx 1 -n web
# 卸载
helm uninstall my-nginx -n web
7.2 创建自定义 Chart
# 创建 Chart 骨架
helm create my-app
# 目录结构
my-app/
├── Chart.yaml # Chart 元信息
├── values.yaml # 默认配置值
├── charts/ # 依赖的子 Chart
├── templates/ # K8s 资源模板
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── hpa.yaml
│ ├── _helpers.tpl
│ └── tests/
└── .helmignore
values.yaml 自定义配置:
replicaCount: 3
image:
repository: registry.example.com/my-app
tag: "1.0.0"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: nginx
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: myapp-tls
hosts:
- myapp.example.com
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
# 使用自定义值安装
helm install my-app ./my-app -f custom-values.yaml -n production
# 打包分发
helm package my-app
8. 集群部署与运维
8.1 使用 kubeadm 搭建集群
# === Master 节点 ===
# 关闭 swap
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
# 安装 kubeadm、kubelet、kubectl
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
# 初始化集群
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=<master-ip>
# 配置 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 安装网络插件(Calico)
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
# === Worker 节点 ===
# 使用 kubeadm init 输出的 join 命令
sudo kubeadm join <master-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
8.2 资源监控
# 安装 Metrics Server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 安装 Prometheus + Grafana(监控栈)
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install monitoring prometheus-community/kube-prometheus-stack -n monitoring --create-namespace
# 查看 Grafana 仪表板
kubectl port-forward svc/monitoring-grafana 3000:80 -n monitoring
8.3 日志管理
# 部署 EFK(Elasticsearch + Fluentd + Kibana)日志栈
helm repo add elastic https://helm.elastic.co
# 安装 Elasticsearch
helm install elasticsearch elastic/elasticsearch -n logging --create-namespace
# 安装 Kibana
helm install kibana elastic/kibana -n logging
# Fluentd 作为 DaemonSet 在每个节点收集日志
kubectl apply -f fluentd-daemonset.yaml
8.4 备份与恢复
# 使用 Velero 备份集群
velero backup create full-backup --include-namespaces production
# 查看备份状态
velero backup describe full-backup
# 恢复
velero restore create --from-backup full-backup
# 定时备份(每日凌晨 2 点)
velero schedule create daily-backup --schedule="0 2 * * *" --include-namespaces production
9. CI/CD 集成
9.1 GitHub Actions 工作流
# .github/workflows/deploy.yml
name: Build and Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
needs: build-and-push
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v3
- name: Configure kubeconfig
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBECONFIG }}" | base64 -d > $HOME/.kube/config
- name: Deploy to Kubernetes
run: |
kubectl set image deployment/my-app \
my-app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
-n production
kubectl rollout status deployment/my-app -n production --timeout=120s
- name: Verify deployment
run: |
kubectl get pods -n production -l app=my-app
9.2 GitLab CI 配置示例
# .gitlab-ci.yml
stages:
- test
- build
- deploy
variables:
DOCKER_IMAGE: registry.example.com/my-app
test:
stage: test
image: node:20-alpine
script:
- npm ci
- npm run test
- npm run lint
build:
stage: build
image: docker:24
services:
- docker:24-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA .
- docker tag $DOCKER_IMAGE:$CI_COMMIT_SHA $DOCKER_IMAGE:latest
- docker push $DOCKER_IMAGE:$CI_COMMIT_SHA
- docker push $DOCKER_IMAGE:latest
deploy:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/my-app my-app=$DOCKER_IMAGE:$CI_COMMIT_SHA -n production
- kubectl rollout status deployment/my-app -n production
only:
- main
environment:
name: production
10. 总结与最佳实践
10.1 镜像安全
- 使用最小基础镜像(Alpine、Distroless)
- 不要在镜像中硬编码密钥,使用 Secret 管理
- 定期扫描镜像漏洞:
trivy image my-app:1.0.0 - 使用非 root 用户运行容器
10.2 集群安全
- 启用 RBAC(基于角色的访问控制)
- 使用 Network Policy 限制 Pod 间通信
- 定期更新 Kubernetes 版本
- 启用审计日志
10.3 资源管理
- 始终为容器设置资源请求(requests)和限制(limits)
- 使用 HPA(水平 Pod 自动扩缩容)应对流量波动
- 使用 PDB(Pod 中断预算)确保高可用
- 定期清理未使用的资源
10.4 可观测性
- 指标:Prometheus + Grafana 监控集群和应用指标
- 日志:EFK/Loki 收集和查询日志
- 链路追踪:Jaeger/Zipkin 追踪请求链路
- 告警:Alertmanager 配置关键告警规则
10.5 推荐学习路径
- 先在本地使用 Docker Desktop 自带的 Kubernetes 练习
- 使用 Minikube 搭建本地集群深入学习
- 在云服务商(阿里云 ACK、腾讯云 TKE、AWS EKS)上部署生产集群
- 学习服务网格(Istio)实现更高级的流量管理
- 探索 GitOps 工具(ArgoCD/Flux)实现声明式部署
结语:容器化与 Kubernetes 已经成为现代应用部署的标准。掌握这些技术不仅能提升开发效率,更是向云原生架构迈进的关键一步。从 Docker 单容器开始,逐步过渡到 Kubernetes 集群编排,你会发现运维工作变得前所未有的高效和可靠。