跳转至

第02章 Docker容器化

Docker容器化图

📚 章节概述

本章将深入讲解Docker容器化技术,包括Docker的核心概念、镜像管理、容器操作、网络配置、存储卷管理等。通过本章学习,你将能够熟练使用Docker进行应用容器化,为后续学习Kubernetes打下坚实基础。

🎯 学习目标

完成本章后,你将能够:

  1. 理解Docker的核心概念和架构
  2. 掌握Docker镜像的创建、管理和优化
  3. 熟练使用Docker容器进行应用部署
  4. 理解Docker网络和存储卷机制
  5. 掌握Docker Compose多容器编排
  6. 了解Docker安全最佳实践
  7. 能够编写高质量的Dockerfile

2.1 Docker概述

2.1.1 什么是Docker

Docker是一个开源的容器化平台,可以将应用程序及其依赖项打包到一个轻量级、可移植的容器中,确保应用在任何环境中都能以相同的方式运行。

Docker的核心价值

  1. 一致性
  2. 开发、测试、生产环境一致
  3. 消除"在我机器上能运行"的问题
  4. 简化环境配置

  5. 轻量级

  6. 容器共享宿主机内核
  7. 启动速度快(秒级)
  8. 资源占用少

  9. 可移植性

  10. 一次构建,到处运行
  11. 跨平台支持
  12. 云原生友好

  13. 隔离性

  14. 进程级隔离
  15. 资源限制
  16. 安全沙箱

2.1.2 Docker vs 虚拟机

特性 Docker容器 虚拟机
架构 共享宿主机内核 独立操作系统
启动时间 秒级 分钟级
资源占用 MB级别 GB级别
性能 接近原生 有损耗
隔离性 进程级 系统级
密度 高(单机数百) 低(单机数十)
适用场景 微服务、云原生 传统应用、多租户
Text Only
┌─────────────────────────────────────────────────────┐
│                    虚拟机架构                          │
├─────────────────────────────────────────────────────┤
│  应用A    │  应用B    │  应用C    │  应用D          │
├───────────┼───────────┼───────────┼─────────────────┤
│  Guest OS │  Guest OS │  Guest OS │  Guest OS       │
├───────────┼───────────┼───────────┼─────────────────┤
│           │  Hypervisor (KVM/VMware/Xen)            │
├─────────────────────────────────────────────────────┤
│                    宿主机操作系统                      │
├─────────────────────────────────────────────────────┤
│                    物理硬件                          │
└─────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────┐
│                   Docker架构                         │
├─────────────────────────────────────────────────────┤
│  应用A    │  应用B    │  应用C    │  应用D          │
├───────────┼───────────┼───────────┼─────────────────┤
│           │  Docker Engine (容器运行时)               │
├─────────────────────────────────────────────────────┤
│                    宿主机操作系统                      │
├─────────────────────────────────────────────────────┤
│                    物理硬件                          │
└─────────────────────────────────────────────────────┘

2.1.3 Docker架构

Docker采用客户端-服务器(C/S)架构,主要组件包括:

核心组件

  1. Docker Client(客户端)
  2. 用户与Docker交互的接口
  3. 通过REST API与Docker Daemon通信
  4. 命令行工具(docker CLI)

  5. Docker Daemon(守护进程)

  6. 监听Docker API请求
  7. 管理镜像、容器、网络、卷
  8. 后台运行的服务进程

  9. Docker Registry(镜像仓库)

  10. 存储和分发Docker镜像
  11. 公有仓库:Docker Hub
  12. 私有仓库:Harbor、GitLab Registry

  13. Docker Objects(Docker对象)

  14. 镜像(Image)
  15. 容器(Container)
  16. 网络(Network)
  17. 卷(Volume)
  18. 服务(Service)

工作流程

Text Only
用户命令
Docker Client
   ▼ REST API
Docker Daemon
   ├─► 镜像管理(拉取、构建、推送)
   ├─► 容器管理(创建、启动、停止)
   ├─► 网络管理(创建、连接)
   └─► 卷管理(创建、挂载)

2.2 Docker安装与配置

2.2.1 在Ubuntu上安装Docker

Bash
# 更新包索引
sudo apt-get update

# 安装依赖
sudo apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg  # |管道:将前一命令的输出作为后一命令的输入

# 添加Docker仓库
echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) 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-compose-plugin

# 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker

# 验证安装
sudo docker run hello-world

# 将当前用户添加到docker组(避免每次使用sudo)
sudo usermod -aG docker $USER

2.2.2 在CentOS/RHEL上安装Docker

Bash
# 卸载旧版本
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

# 安装依赖
sudo yum install -y yum-utils

# 添加Docker仓库
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

# 安装Docker Engine
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker

# 验证安装
sudo docker run hello-world

# 将当前用户添加到docker组
sudo usermod -aG docker $USER

2.2.3 在macOS上安装Docker

Bash
# 使用Homebrew安装
brew install --cask docker

# 或下载Docker Desktop for Mac
# https://www.docker.com/products/docker-desktop

2.2.4 在Windows上安装Docker

PowerShell
# 使用Chocolatey安装
choco install docker-desktop

# 或下载Docker Desktop for Windows
# https://www.docker.com/products/docker-desktop

# 启用WSL 2
wsl --install

2.2.5 Docker配置

Bash
# 查看Docker信息
docker info

# 查看Docker版本
docker version

# 配置Docker守护进程
sudo vim /etc/docker/daemon.json

# 示例配置
{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "data-root": "/var/lib/docker",
  "insecure-registries": [],
  "debug": false,
  "experimental": false
}

# 重启Docker服务
sudo systemctl restart docker

2.3 Docker镜像管理

2.3.1 镜像基本操作

Bash
# 搜索镜像
docker search nginx
docker search --filter=stars=100 nginx

# 拉取镜像
docker pull nginx:latest
docker pull nginx:1.27
docker pull nginx@sha256:abc123...

# 查看本地镜像
docker images
docker images --digests
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

# 删除镜像
docker rmi nginx:latest
docker rmi -f $(docker images -q)  # 删除所有镜像

# 查看镜像详情
docker inspect nginx:latest

# 查看镜像历史
docker history nginx:latest

# 导出镜像
docker save -o nginx.tar nginx:latest

# 导入镜像
docker load -i nginx.tar

2.3.2 构建镜像

Dockerfile基础

Docker
# 基础镜像
FROM python:3.12-slim

# 维护者信息
LABEL maintainer="devops@example.com"

# 设置工作目录
WORKDIR /app

# 复制依赖文件
COPY requirements.txt .

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 8000

# 设置环境变量
ENV PYTHONUNBUFFERED=1
ENV APP_ENV=production

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

# 启动命令
CMD ["python", "app.py"]

构建命令

Bash
# 基本构建
docker build -t myapp:1.0 .

# 指定Dockerfile路径
docker build -f Dockerfile.prod -t myapp:prod .

# 构建时传递参数
docker build --build-arg APP_VERSION=1.0 -t myapp:latest .

# 多阶段构建
docker build --target builder -t myapp:builder .

# 使用构建缓存
docker build --cache-from myapp:latest -t myapp:new .

# 查看构建历史
docker history myapp:latest

# 查看构建信息
docker inspect myapp:latest

2.3.3 Dockerfile最佳实践

1. 选择合适的基础镜像

Docker
# ✅ 推荐:使用官方镜像
FROM python:3.12-slim

# ❌ 不推荐:使用非官方镜像
FROM my-custom-python:3.12

# ✅ 推荐:使用特定版本
FROM python:3.12.8-slim

# ❌ 不推荐:使用latest标签
FROM python:latest

2. 利用构建缓存

Docker
# ✅ 推荐:先复制依赖文件,再安装
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

# ❌ 不推荐:一次性复制所有文件
COPY . .
RUN pip install -r requirements.txt

3. 减少镜像层数

Docker
# ✅ 推荐:合并RUN指令
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        curl \
        git \
        vim && \
    rm -rf /var/lib/apt/lists/*

# ❌ 不推荐:多个RUN指令
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN apt-get install -y vim

4. 多阶段构建

Docker
# 构建阶段
FROM golang:1.23 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o app .

# 运行阶段
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/app .
EXPOSE 8080
CMD ["./app"]

5. 最小化镜像大小

Docker
# ✅ 推荐:使用alpine
FROM python:3.12-alpine

# ✅ 推荐:清理缓存
RUN pip install --no-cache-dir -r requirements.txt && \
    rm -rf /root/.cache

# ✅ 推荐:使用多阶段构建
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

2.3.4 镜像优化实战

示例:优化Python应用镜像

优化前:

Docker
FROM python:3.12
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

优化后:

Docker
# 多阶段构建
FROM python:3.12-slim AS builder

# 安装构建依赖
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        gcc \
        g++ \
        make && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /app

# 复制依赖文件
COPY requirements.txt .

# 安装Python依赖
RUN pip install --no-cache-dir --user -r requirements.txt

# 运行阶段
FROM python:3.12-slim

# 安装运行时依赖
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        curl \
        ca-certificates && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /app

# 从构建阶段复制依赖
COPY --from=builder /root/.local /root/.local

# 复制应用代码
COPY . .

# 设置PATH
ENV PATH=/root/.local/bin:$PATH

# 创建非root用户
RUN useradd -m -u 1000 appuser && \
    chown -R appuser:appuser /app
USER appuser

# 暴露端口
EXPOSE 8000

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

# 启动命令
CMD ["python", "app.py"]

优化效果: - 镜像大小:从900MB降至150MB - 安全性:使用非root用户运行 - 性能:利用构建缓存,加快构建速度 - 可维护性:清晰的多阶段构建结构

2.4 Docker容器管理

2.4.1 容器基本操作

Bash
# 运行容器
docker run nginx
docker run -d --name mynginx nginx
docker run -d -p 8080:80 --name mynginx nginx
docker run -d -p 8080:80 -v /data:/data --name mynginx nginx

# 查看运行中的容器
docker ps
docker ps -a  # 查看所有容器
docker ps -q  # 只显示容器ID

# 查看容器详情
docker inspect mynginx

# 查看容器日志
docker logs mynginx
docker logs -f mynginx  # 跟踪日志
docker logs --tail 100 mynginx  # 查看最后100行
docker logs --since 2024-01-01 mynginx  # 查看指定时间后的日志

# 停止容器
docker stop mynginx
docker stop $(docker ps -q)  # 停止所有容器

# 启动容器
docker start mynginx

# 重启容器
docker restart mynginx

# 删除容器
docker rm mynginx
docker rm -f mynginx  # 强制删除运行中的容器
docker rm -f $(docker ps -aq)  # 删除所有容器

# 进入容器
docker exec -it mynginx /bin/bash
docker exec -it mynginx /bin/sh

# 在容器中执行命令
docker exec mynginx ls -la
docker exec mynginx nginx -t

2.4.2 容器资源限制

Bash
# 限制CPU使用
docker run -d --cpus="1.5" nginx  # 限制使用1.5个CPU
docker run -d --cpuset-cpus="0,1" nginx  # 绑定到CPU 0和1
docker run -d --cpu-shares=512 nginx  # CPU权重(相对值)

# 限制内存使用
docker run -d --memory="512m" nginx  # 限制内存512MB
docker run -d --memory="1g" --memory-swap="2g" nginx  # 限制内存和swap

# 限制磁盘IO
docker run -d --device-read-bps /dev/sda:1mb nginx  # 限制读速度
docker run -d --device-write-bps /dev/sda:1mb nginx  # 限制写速度

# 查看容器资源使用
docker stats
docker stats mynginx
docker stats --no-stream  # 不持续更新

2.4.3 容器生命周期管理

Python
import docker
import time

class ContainerManager:
    """Docker容器管理类"""

    def __init__(self):
        self.client = docker.from_env()

    def create_container(self, image_name, container_name, **kwargs):
        """创建容器"""
        try:
            container = self.client.containers.run(
                image_name,
                name=container_name,
                detach=True,
                **kwargs
            )
            print(f"容器创建成功: {container_name}")
            return container
        except Exception as e:
            print(f"容器创建失败: {e}")
            return None

    def start_container(self, container_name):
        """启动容器"""
        try:
            container = self.client.containers.get(container_name)
            container.start()
            print(f"容器启动成功: {container_name}")
            return True
        except Exception as e:
            print(f"容器启动失败: {e}")
            return False

    def stop_container(self, container_name, timeout=10):
        """停止容器"""
        try:
            container = self.client.containers.get(container_name)
            container.stop(timeout=timeout)
            print(f"容器停止成功: {container_name}")
            return True
        except Exception as e:
            print(f"容器停止失败: {e}")
            return False

    def restart_container(self, container_name, timeout=10):
        """重启容器"""
        try:
            container = self.client.containers.get(container_name)
            container.restart(timeout=timeout)
            print(f"容器重启成功: {container_name}")
            return True
        except Exception as e:
            print(f"容器重启失败: {e}")
            return False

    def remove_container(self, container_name, force=False):
        """删除容器"""
        try:
            container = self.client.containers.get(container_name)
            container.remove(force=force)
            print(f"容器删除成功: {container_name}")
            return True
        except Exception as e:
            print(f"容器删除失败: {e}")
            return False

    def get_container_logs(self, container_name, tail=100):
        """获取容器日志"""
        try:
            container = self.client.containers.get(container_name)
            logs = container.logs(tail=tail)
            print(f"容器 {container_name} 日志:")
            print(logs.decode('utf-8'))
            return logs
        except Exception as e:
            print(f"获取日志失败: {e}")
            return None

    def get_container_stats(self, container_name):
        """获取容器统计信息"""
        try:
            container = self.client.containers.get(container_name)
            stats = container.stats(stream=False)

            print(f"容器 {container_name} 统计信息:")
            print(f"  CPU使用率: {self._calculate_cpu_percent(stats)}%")
            print(f"  内存使用: {stats['memory_stats']['usage'] / 1024 / 1024:.2f} MB")
            print(f"  网络接收: {stats['networks']['eth0']['rx_bytes'] / 1024:.2f} KB")
            print(f"  网络发送: {stats['networks']['eth0']['tx_bytes'] / 1024:.2f} KB")

            return stats
        except Exception as e:
            print(f"获取统计信息失败: {e}")
            return None

    def _calculate_cpu_percent(self, stats):
        """计算CPU使用率"""
        cpu_delta = stats['cpu_stats']['cpu_usage']['total_usage'] - \
                   stats['precpu_stats']['cpu_usage']['total_usage']
        system_delta = stats['cpu_stats']['system_cpu_usage'] - \
                      stats['precpu_stats']['system_cpu_usage']

        if system_delta > 0 and cpu_delta > 0:
            # cgroup v2 环境下 percpu_usage 可能为 None,需做兼容处理
            percpu_usage = stats['cpu_stats']['cpu_usage'].get('percpu_usage') or []
            num_cpus = len(percpu_usage) if percpu_usage else 1
            return (cpu_delta / system_delta) * num_cpus * 100.0
        return 0.0

    def list_containers(self, all=False):
        """列出容器"""
        containers = self.client.containers.list(all=all)

        print("容器列表:")
        print("-" * 80)
        print(f"{'容器ID':<15} {'名称':<20} {'状态':<15} {'镜像'}")
        print("-" * 80)

        for container in containers:
            print(f"{container.id[:12]:<15} {container.name:<20} {container.status:<15} {container.image.tags[0]}")  # 切片操作:[start:end:step]提取子序列

        return containers

    def exec_command(self, container_name, command):
        """在容器中执行命令"""
        try:
            container = self.client.containers.get(container_name)
            result = container.exec_run(command)
            print(f"命令执行结果:")
            print(result.output.decode('utf-8'))
            return result
        except Exception as e:
            print(f"命令执行失败: {e}")
            return None

# 使用示例
if __name__ == '__main__':
    manager = ContainerManager()

    # 创建容器
    container = manager.create_container(
        'nginx:latest',
        'my-nginx',
        ports={'80/tcp': 8080},
        environment={'ENV': 'production'}
    )

    time.sleep(2)

    # 列出容器
    manager.list_containers()

    # 获取日志
    manager.get_container_logs('my-nginx')

    # 获取统计信息
    manager.get_container_stats('my-nginx')

    # 停止容器
    manager.stop_container('my-nginx')

    # 删除容器
    manager.remove_container('my-nginx')

2.5 Docker网络

2.5.1 网络模式

Docker提供多种网络模式:

1. Bridge模式(默认)

Bash
# 创建bridge网络
docker network create my-bridge

# 使用bridge网络运行容器
docker run -d --name web1 --network my-bridge nginx
docker run -d --name web2 --network my-bridge nginx

# 容器间通过容器名通信
docker exec web1 ping web2

2. Host模式

Bash
# 使用host网络(共享宿主机网络)
docker run -d --name web --network host nginx

# 注意:端口冲突风险

3. None模式

Bash
# 无网络(完全隔离)
docker run -d --name web --network none nginx

4. Container模式

Bash
# 共享另一个容器的网络
docker run -d --name web1 nginx
docker run -d --name web2 --network container:web1 nginx

5. 自定义网络

Bash
# 创建自定义bridge网络
docker network create \
  --driver bridge \
  --subnet 172.20.0.0/16 \
  --ip-range 172.20.10.0/24 \
  --gateway 172.20.10.1 \
  my-custom-network

# 查看网络详情
docker network inspect my-custom-network

# 连接容器到网络
docker network connect my-custom-network web1
docker network connect my-custom-network web2

# 断开容器网络
docker network disconnect my-custom-network web1

# 删除网络
docker network rm my-custom-network

2.5.2 网络实战

示例:微服务网络架构

Python
import docker
import time

class NetworkManager:
    """Docker网络管理类"""

    def __init__(self):
        self.client = docker.from_env()
        self.networks = {}  # 存储已创建的网络对象

    def create_network(self, network_name, subnet=None, gateway=None):
        """创建网络"""
        try:
            ipam_config = None
            if subnet and gateway:
                ipam_config = docker.types.IPAMConfig(
                    pool_configs=[
                        docker.types.IPAMPool(
                            subnet=subnet,
                            gateway=gateway
                        )
                    ]
                )

            network = self.client.networks.create(
                network_name,
                driver='bridge',
                ipam=ipam_config
            )
            self.networks[network_name] = network
            print(f"网络创建成功: {network_name}")
            return network
        except Exception as e:
            print(f"网络创建失败: {e}")
            return None

    def deploy_microservices(self):
        """部署微服务架构"""

        # 1. 创建网络
        frontend_network = self.create_network('frontend-network', '172.20.0.0/16', '172.20.0.1')
        backend_network = self.create_network('backend-network', '172.21.0.0/16', '172.21.0.1')

        time.sleep(1)

        # 2. 部署数据库
        # ⚠️ 安全警告:以下代码示例包含硬编码密码,仅用于演示目的。
        # 在生产环境中,请务必使用环境变量或密钥管理服务来存储敏感信息。
        db = self.client.containers.run(
            'mysql:8.4',
            name='mysql-db',
            environment={
                'MYSQL_ROOT_PASSWORD': 'rootpassword',
                'MYSQL_DATABASE': 'appdb',
                'MYSQL_USER': 'appuser',
                'MYSQL_PASSWORD': 'apppassword'
            },
            network='backend-network',
            detach=True
        )
        print(f"数据库容器启动: {db.name}")

        # 3. 部署Redis缓存
        redis = self.client.containers.run(
            'redis:alpine',
            name='redis-cache',
            network='backend-network',
            detach=True
        )
        print(f"Redis容器启动: {redis.name}")

        # 4. 部署后端API
        backend = self.client.containers.run(
            'python:3.12-slim',
            name='backend-api',
            command='python -m http.server 8000',
            environment={
                'DB_HOST': 'mysql-db',
                'REDIS_HOST': 'redis-cache',
                'DB_PASSWORD': 'apppassword'
            },
            ports={'8000/tcp': 8000},
            network='backend-network',
            detach=True
        )
        # containers.run() 只支持 network 参数(单个网络),
        # 多网络需在启动后通过 connect() 追加
        self.networks['frontend-network'].connect(backend)
        print(f"后端API容器启动: {backend.name}")

        # 5. 部署前端
        frontend = self.client.containers.run(
            'nginx:alpine',
            name='frontend-web',
            ports={'80/tcp': 80},
            network='frontend-network',
            detach=True
        )
        print(f"前端容器启动: {frontend.name}")

        # 6. 等待容器启动
        time.sleep(5)

        # 7. 测试网络连通性
        print("\n测试网络连通性:")

        # 后端连接数据库
        result = backend.exec_run('ping -c 2 mysql-db')
        print(f"后端 -> 数据库: {'成功' if result.exit_code == 0 else '失败'}")

        # 后端连接Redis
        result = backend.exec_run('ping -c 2 redis-cache')
        print(f"后端 -> Redis: {'成功' if result.exit_code == 0 else '失败'}")

        # 前端连接后端
        result = frontend.exec_run('ping -c 2 backend-api')
        print(f"前端 -> 后端: {'成功' if result.exit_code == 0 else '失败'}")

        return {
            'db': db,
            'redis': redis,
            'backend': backend,
            'frontend': frontend
        }

# 使用示例
if __name__ == '__main__':
    manager = NetworkManager()
    services = manager.deploy_microservices()

    print("\n微服务部署完成!")
    print("访问地址: http://localhost")

2.6 Docker存储卷

2.6.1 卷类型

1. Docker Volume(推荐)

Bash
# 创建卷
docker volume create my-volume

# 查看卷
docker volume ls
docker volume inspect my-volume

# 使用卷
docker run -d --name web -v my-volume:/data nginx

# 删除卷
docker volume rm my-volume
docker volume prune  # 删除未使用的卷

2. Bind Mount(绑定挂载)

Bash
# 挂载宿主机目录
docker run -d --name web -v /host/path:/container/path nginx

# 挂载单个文件
docker run -d --name web -v /host/file.txt:/container/file.txt nginx

# 只读挂载
docker run -d --name web -v /host/path:/container/path:ro nginx

3. Tmpfs(临时文件系统)

Bash
# 使用tmpfs(数据存储在内存中,容器删除后丢失)
docker run -d --name web --tmpfs /tmp nginx

2.6.2 数据持久化实战

示例:数据库数据持久化

Python
import docker
import time

class VolumeManager:
    """Docker卷管理类"""

    def __init__(self):
        self.client = docker.from_env()

    def create_volume(self, volume_name, driver='local', **kwargs):  # *args接收任意位置参数;**kwargs接收任意关键字参数
        """创建卷"""
        try:
            volume = self.client.volumes.create(
                name=volume_name,
                driver=driver,
                driver_opts=kwargs
            )
            print(f"卷创建成功: {volume_name}")
            return volume
        except Exception as e:
            print(f"卷创建失败: {e}")
            return None

    def deploy_persistent_database(self):
        """部署持久化数据库"""

        # 1. 创建数据卷
        mysql_data = self.create_volume('mysql-data')
        mysql_logs = self.create_volume('mysql-logs')

        # 2. 创建配置卷
        mysql_config = self.create_volume('mysql-config')

        # 3. 部署MySQL
        # ⚠️ 安全警告:以下代码示例包含硬编码密码,仅用于演示目的。
        # 在生产环境中,请务必使用环境变量或密钥管理服务来存储敏感信息。
        mysql = self.client.containers.run(
            'mysql:8.4',
            name='mysql-server',
            environment={
                'MYSQL_ROOT_PASSWORD': 'rootpassword',
                'MYSQL_DATABASE': 'appdb',
                'MYSQL_USER': 'appuser',
                'MYSQL_PASSWORD': 'apppassword'
            },
            volumes={
                'mysql-data': {'bind': '/var/lib/mysql', 'mode': 'rw'},
                'mysql-logs': {'bind': '/var/log/mysql', 'mode': 'rw'},
                'mysql-config': {'bind': '/etc/mysql/conf.d', 'mode': 'ro'}
            },
            ports={'3306/tcp': 3306},
            detach=True
        )
        print(f"MySQL容器启动: {mysql.name}")

        # 4. 等待MySQL启动
        time.sleep(10)

        # 5. 测试数据库连接
        test_container = self.client.containers.run(
            'mysql:8.4',
            command='mysql -hmysql-server -uappuser -papppassword -e "SHOW DATABASES;"',
            network='host',
            remove=True
        )

        print("数据库连接测试:")
        print(test_container.logs().decode('utf-8'))

        # 6. 创建测试数据
        create_table = """
        CREATE TABLE IF NOT EXISTS users (
            id INT AUTO_INCREMENT PRIMARY KEY,
            name VARCHAR(100),
            email VARCHAR(100),
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        );
        """

        insert_data = """
        INSERT INTO users (name, email) VALUES
        ('Alice', 'alice@example.com'),
        ('Bob', 'bob@example.com'),
        ('Charlie', 'charlie@example.com');
        """

        # 执行SQL
        self.client.containers.run(
            'mysql:8.4',
            command=f'mysql -hmysql-server -uappuser -papppassword appdb -e "{create_table}"',
            network='host',
            remove=True
        )

        self.client.containers.run(
            'mysql:8.4',
            command=f'mysql -hmysql-server -uappuser -papppassword appdb -e "{insert_data}"',
            network='host',
            remove=True
        )

        # 7. 查询数据
        query_result = self.client.containers.run(
            'mysql:8.4',
            command='mysql -hmysql-server -uappuser -papppassword appdb -e "SELECT * FROM users;"',
            network='host',
            remove=True
        )

        print("\n查询结果:")
        print(query_result.logs().decode('utf-8'))

        # 8. 备份数据
        backup_container = self.client.containers.run(
            'mysql:8.4',
            command='mysqldump -hmysql-server -uroot -prootpassword appdb > /backup/appdb_backup.sql',
            volumes={
                '/tmp/backup': {'bind': '/backup', 'mode': 'rw'}
            },
            network='host',
            detach=True
        )

        print("\n数据备份完成")

        return mysql

    def backup_volume(self, volume_name, backup_path):
        """备份卷"""
        try:
            # 创建临时容器挂载卷
            backup_container = self.client.containers.run(
                'alpine',
                command=f'tar czf /backup/{volume_name}.tar.gz /data',
                volumes={
                    volume_name: {'bind': '/data', 'mode': 'ro'},
                    backup_path: {'bind': '/backup', 'mode': 'rw'}
                },
                remove=True
            )

            print(f"卷 {volume_name} 备份成功: {backup_path}/{volume_name}.tar.gz")
            return True
        except Exception as e:
            print(f"卷备份失败: {e}")
            return False

    def restore_volume(self, volume_name, backup_path):
        """恢复卷"""
        try:
            # 创建临时容器恢复卷
            restore_container = self.client.containers.run(
                'alpine',
                command=f'tar xzf /backup/{volume_name}.tar.gz -C /data',
                volumes={
                    volume_name: {'bind': '/data', 'mode': 'rw'},
                    backup_path: {'bind': '/backup', 'mode': 'ro'}
                },
                remove=True
            )

            print(f"卷 {volume_name} 恢复成功")
            return True
        except Exception as e:
            print(f"卷恢复失败: {e}")
            return False

# 使用示例
if __name__ == '__main__':
    manager = VolumeManager()

    # 部署持久化数据库
    mysql = manager.deploy_persistent_database()

    # 备份卷
    manager.backup_volume('mysql-data', '/tmp/backup')

    print("\n数据持久化部署完成!")

2.7 Docker Compose

2.7.1 Docker Compose基础

Docker Compose用于定义和运行多容器Docker应用。

docker-compose.yml示例

YAML
# Docker Compose V2 无需 version 字段
services:
  # Web服务
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - app
    networks:
      - frontend
    restart: unless-stopped

  # 应用服务
  app:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=mysql://user:password@db:3306/appdb
      - REDIS_URL=redis://redis:6379/0
    volumes:
      - ./app:/app              # ⚠️ 开发环境专用:bind mount 源代码用于热重载。生产环境应在 Dockerfile 中使用 COPY 将代码打包进镜像。
      - app-data:/app/data
    depends_on:
      - db
      - redis
    networks:
      - frontend
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # 数据库服务
  # ⚠️ 安全警告:以下配置包含硬编码密码,仅用于演示目的。
  # 在生产环境中,请务必使用环境变量或密钥管理服务来存储敏感信息。
  db:
    image: mysql:8.4
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: appdb
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    volumes:
      - db-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    networks:
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Redis缓存
  redis:
    image: redis:alpine
    command: redis-server --appendonly yes
    volumes:
      - redis-data:/data
    networks:
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  # 监控服务
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
    networks:
      - backend
    restart: unless-stopped

  # 日志服务
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.5.0
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - es-data:/usr/share/elasticsearch/data
    networks:
      - backend
    restart: unless-stopped

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

volumes:
  db-data:
    driver: local
  redis-data:
    driver: local
  app-data:
    driver: local
  prometheus-data:
    driver: local
  es-data:
    driver: local

2.7.2 Docker Compose命令

注意: Docker Compose V2 使用 docker compose(空格分隔),旧版 docker-compose(连字符)已于 2023 年从 Docker Desktop 中移除。

Bash
# 启动服务
docker compose up
docker compose up -d  # 后台运行
docker compose up -d --build  # 重新构建并启动

# 停止服务
docker compose stop
docker compose down  # 停止并删除容器、网络
docker compose down -v  # 同时删除卷

# 查看服务状态
docker compose ps
docker compose logs
docker compose logs -f web  # 跟踪web服务日志

# 重启服务
docker compose restart
docker compose restart web

# 查看服务资源使用
docker compose top

# 执行命令
docker compose exec web bash
docker compose exec app python manage.py migrate

# 扩缩容
docker compose up -d --scale app=3

# 查看配置
docker compose config

# 拉取镜像
docker compose pull

# 构建镜像
docker compose build
docker compose build --no-cache web

2.7.3 完整实战项目

项目结构

Text Only
my-project/
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
├── nginx.conf
├── init.sql
├── prometheus.yml
├── app/
│   ├── __init__.py
│   ├── main.py
│   ├── models.py
│   └── utils.py
├── html/
│   └── index.html
└── data/
    └── .gitkeep

docker-compose.yml

YAML
services:  # services定义各个服务容器
  # Nginx反向代理
  nginx:
    image: nginx:alpine
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./html:/usr/share/nginx/html:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - app
    networks:
      - frontend
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Flask应用
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: flask-app
    environment:
      - FLASK_ENV=production
      - DATABASE_URL=mysql://appuser:apppassword@db:3306/appdb
      - REDIS_URL=redis://redis:6379/0
      - SECRET_KEY=${SECRET_KEY:-your-secret-key}
    volumes:
      - ./app:/app              # ⚠️ 开发环境专用:bind mount 源代码用于热重载。生产环境应在 Dockerfile 中使用 COPY 将代码打包进镜像。
      - app-data:/app/data
      - app-logs:/app/logs
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - frontend
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

  # MySQL数据库
  # ⚠️ 安全警告:以下配置包含硬编码密码,仅用于演示目的。
  # 在生产环境中,请务必使用环境变量或密钥管理服务来存储敏感信息。
  db:
    # ⚠️ 使用 mysql:8.0 以兼容 mysql_native_password 认证插件。
    # MySQL 8.4+ 已移除该插件,默认使用 caching_sha2_password。
    # 若使用 mysql:8.4+,请删除下方 --default-authentication-plugin 行。
    image: mysql:8.0
    container_name: mysql-db
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-rootpassword}
      MYSQL_DATABASE: appdb
      MYSQL_USER: appuser
      MYSQL_PASSWORD: ${MYSQL_PASSWORD:-apppassword}
    volumes:
      - db-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
      - db-logs:/var/log/mysql
    networks:
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-rootpassword}"]
      interval: 10s
      timeout: 5s
      retries: 5
    command:
      - --default-authentication-plugin=mysql_native_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci

  # Redis缓存
  redis:
    image: redis:7-alpine
    container_name: redis-cache
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-redispassword}
    volumes:
      - redis-data:/data
    networks:
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-redispassword}", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Prometheus监控
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'
    networks:
      - backend
    restart: unless-stopped

  # Grafana可视化
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin}
      - GF_INSTALL_PLUGINS=redis-datasource
    volumes:
      - grafana-data:/var/lib/grafana
      - grafana-logs:/var/log/grafana
    depends_on:
      - prometheus
    networks:
      - backend
    restart: unless-stopped

networks:
  frontend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.21.0.0/16

volumes:
  db-data:
    driver: local
  db-logs:
    driver: local
  redis-data:
    driver: local
  app-data:
    driver: local
  app-logs:
    driver: local
  prometheus-data:
    driver: local
  grafana-data:
    driver: local
  grafana-logs:
    driver: local

Dockerfile

Docker
# 构建阶段
FROM python:3.12-slim AS builder

# 安装构建依赖
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        gcc \
        g++ \
        make && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /app  # WORKDIR设置工作目录

# 复制依赖文件
COPY requirements.txt .

# 安装Python依赖
RUN pip install --no-cache-dir --user -r requirements.txt

# 运行阶段
FROM python:3.12-slim

# 安装运行时依赖
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        curl \
        ca-certificates \
        netcat-openbsd && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /app

# 从构建阶段复制依赖
COPY --from=builder /root/.local /root/.local

# 复制应用代码
COPY app/ ./app/

# 设置PATH
ENV PATH=/root/.local/bin:$PATH

# 创建非root用户
RUN useradd -m -u 1000 appuser && \
    mkdir -p /app/data /app/logs && \
    chown -R appuser:appuser /app

USER appuser

# 暴露端口
EXPOSE 5000  # EXPOSE声明容器监听的端口

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:5000/health || exit 1  # CMD容器启动时执行的默认命令

# 启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "--timeout", "120", "app.main:app"]

app/main.py

Python
from flask import Flask, jsonify, request
from flask_cors import CORS
import redis
import pymysql
import logging
from datetime import datetime
import os

app = Flask(__name__)
CORS(app)

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# 数据库连接
def get_db_connection():
    """获取数据库连接"""
    try:  # try/except捕获异常
        connection = pymysql.connect(
            host=os.getenv('DB_HOST', 'db'),
            user=os.getenv('DB_USER', 'appuser'),
            password=os.getenv('DB_PASSWORD', 'apppassword'),
            database=os.getenv('DB_NAME', 'appdb'),
            cursorclass=pymysql.cursors.DictCursor
        )
        return connection
    except Exception as e:
        logger.error(f"数据库连接失败: {e}")
        return None

# Redis连接
def get_redis_connection():
    """获取Redis连接"""
    try:
        r = redis.Redis(
            host=os.getenv('REDIS_HOST', 'redis'),
            port=int(os.getenv('REDIS_PORT', 6379)),
            password=os.getenv('REDIS_PASSWORD', 'redispassword'),
            decode_responses=True
        )
        return r
    except Exception as e:
        logger.error(f"Redis连接失败: {e}")
        return None

@app.route('/')
def index():
    """首页"""
    return jsonify({
        'message': 'Welcome to Flask App',
        'timestamp': datetime.now().isoformat(),
        'status': 'running'
    })

@app.route('/health')
def health():
    """健康检查"""
    # 检查数据库连接
    db_status = 'ok'
    try:
        conn = get_db_connection()
        if conn:
            conn.close()
        else:
            db_status = 'error'
    except:
        db_status = 'error'

    # 检查Redis连接
    redis_status = 'ok'
    try:
        r = get_redis_connection()
        if r:
            r.ping()
        else:
            redis_status = 'error'
    except:
        redis_status = 'error'

    return jsonify({
        'status': 'healthy',
        'database': db_status,
        'redis': redis_status,
        'timestamp': datetime.now().isoformat()
    })

@app.route('/api/users', methods=['GET', 'POST'])
def users():
    """用户API"""
    if request.method == 'GET':
        # 尝试从缓存获取
        r = get_redis_connection()
        cache_key = 'users:list'

        if r:
            cached = r.get(cache_key)
            if cached:
                logger.info("从缓存获取用户列表")
                return jsonify({'source': 'cache', 'data': cached})

        # 从数据库获取
        conn = get_db_connection()
        if not conn:
            return jsonify({'error': 'Database connection failed'}), 500

        try:
            with conn.cursor() as cursor:
                cursor.execute('SELECT * FROM users')
                users = cursor.fetchall()

            # 缓存结果
            if r:
                r.setex(cache_key, 300, str(users))  # 缓存5分钟

            return jsonify({'source': 'database', 'data': users})
        finally:
            conn.close()

    elif request.method == 'POST':
        data = request.json
        conn = get_db_connection()
        if not conn:
            return jsonify({'error': 'Database connection failed'}), 500

        try:
            with conn.cursor() as cursor:
                sql = "INSERT INTO users (name, email) VALUES (%s, %s)"
                cursor.execute(sql, (data['name'], data['email']))
            conn.commit()

            # 清除缓存
            r = get_redis_connection()
            if r:
                r.delete('users:list')

            return jsonify({'message': 'User created successfully'}), 201
        except Exception as e:
            conn.rollback()
            return jsonify({'error': str(e)}), 500
        finally:
            conn.close()

@app.route('/api/stats')
def stats():
    """统计信息"""
    r = get_redis_connection()
    if not r:
        return jsonify({'error': 'Redis connection failed'}), 500

    # 增加访问计数
    r.incr('stats:visits')

    # 获取统计信息
    visits = r.get('stats:visits')

    return jsonify({
        'visits': visits,
        'timestamp': datetime.now().isoformat()
    })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)

启动脚本

Bash
#!/bin/bash

# 启动脚本

echo "启动应用..."

# 创建必要的目录
mkdir -p data logs ssl

# 生成自签名SSL证书(如果不存在)
if [ ! -f ssl/cert.pem ]; then  # 条件测试:-f文件存在 -d目录存在 -z空字符串
    openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
        -keyout ssl/key.pem \
        -out ssl/cert.pem \
        -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=localhost"
    echo "SSL证书生成完成"
fi

# 构建并启动服务
docker compose up -d --build

# 等待服务启动
echo "等待服务启动..."
sleep 10

# 检查服务状态
docker compose ps

echo "应用启动完成!"
echo "访问地址:"
echo "  HTTP:  http://localhost"
echo "  HTTPS: https://localhost"
echo "  Grafana: http://localhost:3000"
echo "  Prometheus: http://localhost:9090"

2.8 Docker安全最佳实践

2.8.1 镜像安全

Docker
# ✅ 使用官方镜像
FROM python:3.12-slim  # FROM指定基础镜像

# ✅ 使用特定版本
FROM python:3.12.8-slim

# ✅ 使用非root用户
RUN useradd -m -u 1000 appuser  # RUN在构建时执行命令
USER appuser

# ✅ 最小化镜像
FROM alpine:latest

# ✅ 扫描镜像漏洞(Docker Desktop 4.17+ 使用 docker scout 替代已弃用的 docker scan)
docker scout cves myimage:latest

# ✅ 使用多阶段构建
FROM golang:1.23 AS builder
...
FROM alpine:latest
COPY --from=builder /app /app  # COPY将文件复制到镜像中

2.8.2 容器安全

Bash
# ✅ 使用只读文件系统
docker run --read-only --tmpfs /tmp nginx

# ✅ 限制容器权限
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE nginx

# ✅ 使用用户命名空间
docker run --userns-remap default nginx

# ✅ 设置资源限制
docker run --memory="512m" --cpus="1.0" nginx

# ✅ 使用seccomp配置
docker run --security-opt seccomp=default.json nginx

# ✅ 使用AppArmor配置
docker run --security-opt apparmor=docker-default nginx

2.8.3 网络安全

Bash
# ✅ 使用自定义网络
docker network create --driver bridge my-network

# ✅ 限制容器间通信
docker network create --driver bridge --internal internal-network

# ✅ 使用TLS加密(注意:docker daemon 命令已移除,使用 dockerd)
dockerd --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem

2.9 练习题

基础题

  1. 选择题
  2. Docker和虚拟机的主要区别是什么?

    • A. Docker需要完整的操作系统
    • B. Docker共享宿主机内核
    • C. Docker启动速度慢
    • D. Docker资源占用多
  3. 简答题

  4. 解释Docker的镜像、容器、仓库的概念。
  5. 说明Dockerfile中FROM、RUN、CMD、ENTRYPOINT的区别。

进阶题

  1. 实践题
  2. 编写一个Dockerfile,构建一个Flask应用镜像。
  3. 使用Docker Compose部署一个包含Web应用、数据库、Redis的完整应用。

  4. 设计题

  5. 设计一个多阶段构建的Dockerfile,优化镜像大小。
  6. 设计一个生产级的Docker Compose配置,包括监控、日志、健康检查。

答案

1. 选择题答案

  1. B(Docker共享宿主机内核,这是与虚拟机的主要区别)

2. 简答题答案

镜像、容器、仓库的概念: - 镜像:只读的模板,包含运行应用所需的所有内容 - 容器:镜像的运行实例,可以启动、停止、删除 - 仓库:存储和分发镜像的地方,如Docker Hub

FROM、RUN、CMD、ENTRYPOINT的区别: - FROM:指定基础镜像 - RUN:在构建时执行命令 - CMD:容器启动时执行的默认命令 - ENTRYPOINT:容器启动时执行的入口点,CMD会作为参数传递

3. 实践题答案

参见2.7.3节的完整实战项目。

4. 设计题答案

参见2.3.4节和2.7.3节的示例。

2.10 面试准备

大厂面试题

字节跳动

  1. 解释Docker的Cgroups和Namespace机制。
  2. 如何优化Docker镜像大小?
  3. Docker和Kubernetes的区别是什么?
  4. 如何保证Docker容器的安全?

腾讯

  1. Docker的网络模式有哪些?
  2. 如何实现Docker容器间的通信?
  3. Docker数据持久化的方案有哪些?
  4. 如何监控Docker容器?

阿里云

  1. Dockerfile的最佳实践是什么?
  2. 如何排查Docker容器问题?
  3. Docker Compose的使用场景是什么?
  4. 如何实现Docker的高可用部署?

📚 参考资料

🎯 本章小结

本章深入讲解了Docker容器化技术,包括:

  1. Docker的核心概念和架构
  2. Docker镜像的创建、管理和优化
  3. Docker容器的操作和资源管理
  4. Docker网络和存储卷机制
  5. Docker Compose多容器编排
  6. Docker安全最佳实践
  7. 完整的实战项目案例

通过本章学习,你掌握了Docker的核心技术,能够熟练使用Docker进行应用容器化。下一章将深入学习Kubernetes容器编排技术。