Docker与Kubernetes容器化部署完全教程

教程简介

全面讲解Docker容器化技术与Kubernetes编排系统的核心概念与实战部署,涵盖Docker镜像构建、Dockerfile编写、Docker Compose多容器编排、Kubernetes核心概念(Pod/Service/Deployment/Ingress)、kubectl命令实战、Helm包管理、集群部署与运维、CI/CD集成等核心内容。

Docker与Kubernetes容器化部署完全教程

关键词:Docker, Kubernetes, 容器化, DevOps, 云原生, 部署

本教程从零开始,带你掌握 Docker 容器化技术与 Kubernetes 集群编排的核心知识,最终能够独立完成生产级应用的容器化部署。


目录

  1. 容器化技术概述
  2. Docker 基础与安装
  3. Docker 镜像构建
  4. Docker Compose 多容器编排
  5. Kubernetes 核心概念
  6. kubectl 命令实战
  7. Helm 包管理器
  8. 集群部署与运维
  9. CI/CD 集成
  10. 总结与最佳实践

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 推荐学习路径

  1. 先在本地使用 Docker Desktop 自带的 Kubernetes 练习
  2. 使用 Minikube 搭建本地集群深入学习
  3. 在云服务商(阿里云 ACK、腾讯云 TKE、AWS EKS)上部署生产集群
  4. 学习服务网格(Istio)实现更高级的流量管理
  5. 探索 GitOps 工具(ArgoCD/Flux)实现声明式部署

结语:容器化与 Kubernetes 已经成为现代应用部署的标准。掌握这些技术不仅能提升开发效率,更是向云原生架构迈进的关键一步。从 Docker 单容器开始,逐步过渡到 Kubernetes 集群编排,你会发现运维工作变得前所未有的高效和可靠。

内容声明

本文内容为AI技术学习教程,仅供学习参考。如涉及技术问题,欢迎通过 xurj005@163.com 与我们交流。

目录