Docker/Kubernetes 实战:从入门到生产级部署

一篇帮助开发者理解容器化技术并掌握生产级部署实践的完整指南。


目录


一、为什么需要容器化

1.1 传统部署的痛点

在容器技术普及之前,应用部署面临着诸多挑战:

问题表现影响
环境不一致「在我本地能跑」开发、测试、生产环境差异导致 Bug
依赖冲突项目 A 需要 Node 16,项目 B 需要 Node 18同一服务器无法共存
资源隔离差一个应用占满资源,连累其他应用服务不稳定
部署效率低手动安装依赖、配置环境发布周期长,容易出错
可移植性差迁移到新服务器需要重新配置扩展困难

1.2 容器化如何解决这些问题

Docker 提供了「一次构建,到处运行」的能力:

┌─────────────────────────────────────────────────────────┐
│                    容器化架构                            │
├─────────────────────────────────────────────────────────┤
│  应用代码 + 运行环境 + 依赖库 + 配置 = 容器镜像          │
│                                                         │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                 │
│  │ 容器 A  │  │ 容器 B  │  │ 容器 C  │                 │
│  │ Node 18 │  │ Python  │  │ Java 17 │                 │
│  └─────────┘  └─────────┘  └─────────┘                 │
│  ─────────────────────────────────────                  │
│              Docker 引擎 (容器运行时)                    │
│  ─────────────────────────────────────                  │
│              操作系统 (Linux/Windows/macOS)              │
└─────────────────────────────────────────────────────────┘

Kubernetes 则在 Docker 之上提供了大规模容器编排能力:

  • 自动化部署:声明式配置,自动创建和管理容器
  • 弹性伸缩:根据负载自动扩缩容
  • 自愈能力:容器崩溃自动重启,节点故障自动迁移
  • 服务发现:内置 DNS 和负载均衡
  • 滚动更新:零停机部署

1.3 Docker 与 Kubernetes 的定位

技术定位核心能力适用场景
Docker容器运行时构建、运行、分发容器单机部署、开发环境
Kubernetes容器编排平台多节点管理、调度、自愈生产集群、大规模部署

一句话总结:Docker 解决「如何打包和运行一个应用」,Kubernetes 解决「如何管理成百上千个容器」。


二、Docker 实战基础

2.1 安装与环境准备

Linux (Ubuntu/Debian)
# 更新包索引
sudo apt-get update

# 安装依赖
sudo apt-get install 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

# 添加仓库
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
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 验证安装
docker --version
# Docker version 24.0.7, build afdd53b

# 启动并设置开机自启
sudo systemctl enable --now docker

# 将当前用户加入 docker 组(免 sudo)
sudo usermod -aG docker $USER
# 注销重新登录后生效
macOS / Windows

下载安装 Docker Desktop,图形化安装即可。

安装后验证:

docker run hello-world
# 成功输出:Hello from Docker! This message shows that your installation appears to be working correctly.

2.2 Docker 核心概念

镜像(Image)

镜像是容器的「蓝图」,包含运行应用所需的一切:代码、运行时、库、配置。

# 查看本地镜像
docker images

# 拉取镜像
docker pull nginx:latest
docker pull node:18-alpine  # 推荐 alpine 版本,体积小

# 搜索镜像
docker search redis

# 删除镜像
docker rmi nginx:latest
容器(Container)

容器是镜像的「运行实例」。

# 运行容器
docker run -d --name my-nginx -p 8080:80 nginx:latest
# -d: 后台运行
# --name: 容器名称
# -p: 端口映射(宿主机:容器)

# 查看运行中的容器
docker ps

# 查看所有容器(包括已停止)
docker ps -a

# 进入容器
docker exec -it my-nginx /bin/bash

# 查看容器日志
docker logs my-nginx
docker logs -f my-nginx  # 实时追踪

# 停止/启动/重启容器
docker stop my-nginx
docker start my-nginx
docker restart my-nginx

# 删除容器
docker rm my-nginx
docker rm -f my-nginx  # 强制删除运行中的容器
仓库(Registry)

仓库是存放镜像的地方,类似代码仓库。

  • Docker Hub:官方公共仓库(hub.docker.com)
  • 私有仓库:Harbor、Nexus、阿里云容器镜像服务
# 登录仓库
docker login

# 给镜像打标签
docker tag my-app:latest my-registry.com/my-app:v1.0

# 推送镜像
docker push my-registry.com/my-app:v1.0

# 从私有仓库拉取
docker pull my-registry.com/my-app:v1.0

2.3 Dockerfile 编写规范

Dockerfile 是构建镜像的「脚本」,定义了如何从基础镜像创建自定义镜像。

基础示例:Node.js 应用
# syntax=docker/dockerfile:1

# 指定基础镜像
FROM node:18-alpine

# 设置工作目录
WORKDIR /app

# 复制依赖清单(利用缓存层)
COPY package*.json ./

# 安装依赖
RUN npm ci --only=production

# 复制应用代码
COPY . .

# 暴露端口(仅声明,实际映射需 -p)
EXPOSE 3000

# 设置环境变量
ENV NODE_ENV=production

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

# 启动命令
CMD ["node", "server.js"]
关键指令详解
指令作用最佳实践
FROM指定基础镜像使用官方镜像,优先 alpine 版本
WORKDIR设置工作目录使用绝对路径,自动创建
COPY复制文件先复制依赖清单,再复制代码(利用缓存)
RUN执行命令合并多条命令减少层数
ENV设置环境变量敏感信息不要硬编码
EXPOSE声明端口仅文档作用,方便阅读
CMD容器启动命令使用 JSON 数组格式
ENTRYPOINT入口点配合 CMD 实现灵活启动
多阶段构建优化

多阶段构建可以将构建环境和运行环境分离,大幅减小镜像体积。

#syntax=docker/dockerfile:1

# ===== 构建阶段 =====
FROM node:18-alpine AS builder

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build

# ===== 运行阶段 =====
FROM nginx:alpine

# 从构建阶段复制产物
COPY --from=builder /app/dist /usr/share/nginx/html

# 复制 nginx 配置
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

效果对比

阶段镜像大小说明
单阶段~800MB包含完整 Node.js + 构建工具
多阶段~25MB仅 Nginx + 静态文件
Dockerfile 最佳实践清单
  • 使用明确的镜像版本标签(避免 latest
  • 使用 .dockerignore 排除无关文件
  • 合并 RUN 命令,减少镜像层数
  • 不要在镜像中存储敏感信息
  • 使用非 root 用户运行应用
  • 合理利用缓存,将不常变化的指令放前面

示例 .dockerignore

node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
README.md
.env
coverage
.nyc_output

2.4 Docker Compose 编排

当应用由多个服务组成时,Docker Compose 可以通过一个 YAML 文件定义和管理所有服务。

完整示例:前后端分离应用
# docker-compose.yml
version: '3.8'

services:
  # 前端服务
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
      target: production
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - app-network
    restart: unless-stopped

  # 后端 API 服务
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:password@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - app-network
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  # PostgreSQL 数据库
  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=myapp
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    networks:
      - app-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  # Redis 缓存
  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis-data:/data
    networks:
      - app-network
    restart: unless-stopped

networks:
  app-network:
    driver: bridge

volumes:
  postgres-data:
  redis-data:
常用命令
# 启动所有服务(后台运行)
docker compose up -d

# 查看服务状态
docker compose ps

# 查看日志
docker compose logs
docker compose logs -f backend  # 实时追踪特定服务

# 重新构建并启动
docker compose up -d --build

# 停止所有服务
docker compose down

# 停止并删除数据卷
docker compose down -v

# 扩展服务(运行多个实例)
docker compose up -d --scale backend=3

2.5 实战案例:部署一个完整的 Web 应用

项目结构
my-webapp/
├── backend/
│   ├── Dockerfile
│   ├── package.json
│   └── src/
│       └── server.js
├── frontend/
│   ├── Dockerfile
│   ├── nginx.conf
│   └── src/
│       └── ...
├── docker-compose.yml
└── .env
后端 Dockerfile
# backend/Dockerfile
FROM node:18-alpine

WORKDIR /app

# 安装 dumb-init(正确处理信号)
RUN apk add --no-cache dumb-init

COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

COPY src/ ./src/

# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

USER nodejs

EXPOSE 3000

ENV NODE_ENV=production

ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "src/server.js"]
构建和推送镜像
# 构建镜像
docker build -t my-webapp-backend:v1.0 ./backend

# 本地测试运行
docker run -d -p 3000:3000 --name backend-test my-webapp-backend:v1.0

# 测试通过后打标签推送到仓库
docker tag my-webapp-backend:v1.0 registry.example.com/my-webapp-backend:v1.0
docker push registry.example.com/my-webapp-backend:v1.0

三、Kubernetes 实战进阶

3.1 核心概念解析

Pod(最小部署单元)

Pod 是 Kubernetes 中最小的可部署单元,一个 Pod 可以包含一个或多个紧密关联的容器。

# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-app
  labels:
    app: my-app
    tier: frontend
spec:
  containers:
  - name: app
    image: nginx:1.25-alpine
    ports:
    - containerPort: 80
    resources:
      requests:
        memory: "64Mi"
        cpu: "50m"
      limits:
        memory: "128Mi"
        cpu: "100m"
    livenessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 10
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 5
Deployment(控制器)

Deployment 管理 Pod 的副本数量,提供滚动更新和回滚能力。

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
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: app
        image: my-app:v1.0
        ports:
        - containerPort: 3000
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        env:
        - name: NODE_ENV
          value: "production"
        - name: DB_HOST
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: db-host
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: db-password
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 15
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5
Service(服务发现)

Service 为 Pod 提供稳定的访问入口。

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  selector:
    app: my-app
  ports:
  - port: 80        # Service 端口
    targetPort: 3000 # Pod 端口
    protocol: TCP
  type: ClusterIP  # 内部访问
---
# NodePort 类型(可从集群外部访问)
apiVersion: v1
kind: Service
metadata:
  name: my-app-nodeport
spec:
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 3000
    nodePort: 30080  # 范围: 30000-32767
  type: NodePort
ConfigMap 和 Secret(配置管理)
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  db-host: "postgres-service"
  db-port: "5432"
  cache-ttl: "3600"
  app.properties: |
    feature.flag.a=true
    feature.flag.b=false
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
stringData:
  db-password: "your-secure-password"
  api-key: "your-api-key"
  tls.crt: |
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----
Ingress(入站流量管理)
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.example.com
    secretName: api-tls-secret
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app-service
            port:
              number: 80

3.2 本地开发环境搭建

使用 Kind (Kubernetes in Docker)
# 安装 kind
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 --name my-cluster

# 查看集群
kubectl cluster-info --context kind-my-cluster

# 加载本地镜像到集群(无需推送仓库)
kind load docker-image my-app:v1.0 --name my-cluster

# 删除集群
kind delete cluster --name my-cluster
使用 Minikube
# 安装 minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# 启动集群
minikube start --cpus=4 --memory=8192

# 启用插件
minikube addons enable ingress
minikube addons enable metrics-server
minikube addons enable dashboard

# 访问 Dashboard
minikube dashboard

# 停止/删除集群
minikube stop
minikube delete

3.3 部署应用实践

# 创建命名空间
kubectl create namespace myapp

# 应用配置
kubectl apply -f configmap.yaml -n myapp
kubectl apply -f secret.yaml -n myapp

# 部署应用
kubectl apply -f deployment.yaml -n myapp
kubectl apply -f service.yaml -n myapp
kubectl apply -f ingress.yaml -n myapp

# 查看部署状态
kubectl get all -n myapp

# 查看 Pod 详情
kubectl describe pod <pod-name> -n myapp

# 查看日志
kubectl logs -f deployment/my-app -n myapp

# 进入容器
kubectl exec -it <pod-name> -n myapp -- /bin/sh

# 端口转发(本地调试)
kubectl port-forward svc/my-app-service 8080:80 -n myapp

3.4 自动扩缩容(HPA)

# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
# 应用 HPA
kubectl apply -f hpa.yaml -n myapp

# 查看 HPA 状态
kubectl get hpa -n myapp

四、生产级最佳实践

4.1 镜像安全与优化

安全检查清单
项目要求检查方法
基础镜像使用官方镜像,指定版本标签docker images 检查
镜像扫描扫描漏洞docker scout cves my-app:v1.0
非 root 运行容器使用非特权用户Dockerfile 中设置 USER
最小化镜像仅包含必要组件使用 alpine/distroless
敏感信息不在镜像中存储密钥使用 Secret/ConfigMap
镜像优化技巧
# 优化示例
# 1. 使用最小化基础镜像
FROM gcr.io/distroless/nodejs18-debian11

# 2. 多阶段构建
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# 3. 最终镜像仅包含必要文件
FROM gcr.io/distroless/nodejs18-debian11
COPY --from=builder /app/dist /app
COPY --from=builder /app/node_modules /app/node_modules
CMD ["server.js"]

4.2 资源限制与配额

# namespace 资源配额
apiVersion: v1
kind: ResourceQuota
metadata:
  name: app-quota
  namespace: myapp
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    pods: "50"
    services: "10"
---
# Pod 的限制范围(LimitRange)
apiVersion: v1
kind: LimitRange
metadata:
  name: app-limits
  namespace: myapp
spec:
  limits:
  - type: Container
    default:
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:
      cpu: "100m"
      memory: "128Mi"
    max:
      cpu: "2"
      memory: "2Gi"
    min:
      cpu: "50m"
      memory: "64Mi"

4.3 日志与监控

日志架构
┌─────────┐     ┌──────────┐     ┌─────────────┐
│  Pods   │────▶│ Fluentd  │────▶│ Elasticsearch│
└─────────┘     │/Fluentbit│     └─────────────┘
                └──────────┘            │
                                        ▼
                                  ┌──────────┐
                                  │  Kibana  │
                                  └──────────┘
Prometheus + Grafana 监控
# Prometheus ServiceMonitor 示例
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: my-app-monitor
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: my-app
  endpoints:
  - port: metrics
    interval: 30s
    path: /metrics

五、常见问题排查

5.1 镜像构建问题

问题原因解决方案
构建超时网络问题或镜像过大使用国内镜像源,优化 Dockerfile
依赖安装失败网络或源不可用更换 npm/pip 源,使用缓存
权限错误COPY 的文件权限问题在 Dockerfile 中设置正确权限
# 调试构建过程
docker build --progress=plain --no-cache -t my-app:v1.0 .

# 查看镜像层
docker history my-app:v1.0

5.2 容器启动失败

# 查看 Pod 状态
kubectl get pods -n myapp
kubectl describe pod <pod-name> -n myapp

# 查看容器日志
kubectl logs <pod-name> -n myapp
kubectl logs <pod-name> -c <container-name> -n myapp  # 多容器场景

# 查看事件
kubectl get events -n myapp --sort-by='.lastTimestamp'

常见状态说明

状态说明排查方向
ImagePullBackOff镜像拉取失败检查镜像名、仓库认证、网络
CrashLoopBackOff容器反复崩溃查看日志,检查启动命令
Pending无法调度检查资源请求、节点状态
OOMKilled内存超限增加内存限制或优化代码

5.3 网络与存储问题

# 测试服务连通性
kubectl run test --image=busybox --rm -it --restart=Never -- nslookup my-app-service.myapp.svc.cluster.local

# 查看服务端点
kubectl get endpoints my-app-service -n myapp

# 查看 PVC 状态
kubectl get pvc -n myapp
kubectl describe pvc <pvc-name> -n myapp

六、总结

本文从容器化基础概念出发,系统讲解了 Docker 和 Kubernetes 的核心知识和实战技巧:

核心要点回顾

  1. Docker 解决应用打包和单机运行问题,核心概念是镜像、容器、仓库
  2. Kubernetes 解决大规模容器编排问题,核心概念是 Pod、Deployment、Service
  3. 生产实践 关注镜像安全、资源限制、日志监控、自动扩缩容
  4. 问题排查 掌握 kubectl describekubectl logsdocker logs 等关键命令

学习路径建议

Docker 基础 → Docker Compose → Kubernetes 核心概念 → 本地实践 → 生产部署

下一步学习方向

  • Helm 包管理
  • GitOps(ArgoCD)
  • 服务网格(Istio)
  • 云原生安全

如果本文对你有帮助,欢迎点赞收藏!有问题欢迎在评论区讨论。

更多推荐