编程开发编程开发DockerDocker 和 Docker Compose 完全指南
ZhangCurryDocker 和 Docker Compose 完全指南
在这里插入图片描述
目录
- Docker 简介
- Docker 安装
- Docker 核心概念
- Docker 基础使用
- Dockerfile 编写
- Docker Compose 简介
- Docker Compose 安装
- Docker Compose 使用
- 实战案例
- 最佳实践
- 常见问题
Docker 简介
什么是 Docker
Docker 是一个开源的容器化平台,它允许开发者将应用程序及其所有依赖项打包到一个轻量级、可移植的容器中。容器可以在任何支持 Docker 的系统上运行,确保应用在不同环境中的一致性。
Docker 的优势
- • 环境一致性: 消除”在我的机器上可以运行”的问题
- • 快速部署: 容器启动速度快,通常只需几秒钟
- • 资源隔离: 每个容器相互独立,互不影响
- • 轻量级: 相比虚拟机,容器共享主机内核,占用资源更少
- • 版本控制: 镜像可以进行版本管理
- • 可移植性: 一次构建,到处运行
Docker vs 虚拟机
| 特性 |
Docker 容器 |
虚拟机 |
| 启动时间 |
秒级 |
分钟级 |
| 磁盘占用 |
MB 级别 |
GB 级别 |
| 性能 |
接近原生 |
有性能损耗 |
| 系统支持 |
每台主机支持数千个容器 |
每台主机支持几十个虚拟机 |
| 隔离性 |
进程级隔离 |
操作系统级隔离 |
Docker 安装
Windows 安装
系统要求
- • Windows 10 64-bit: Pro, Enterprise, or Education (Build 19041 或更高)
- • 启用 WSL 2 功能
- • 启用虚拟化功能
安装步骤
- 启用 WSL 2打开 PowerShell(管理员模式):
1 2 3 4 5 6 7
| # 启用 WSL dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
# 启用虚拟机平台 dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
# 重启计算机
|
- 下载并安装 WSL 2 Linux 内核更新包访问 Microsoft WSL 2 更新页面 下载并安装
- 设置 WSL 2 为默认版本
1
| wsl --set-default-version 2
|
- 下载 Docker Desktop for Windows访问 Docker 官网 下载安装程序
- 安装 Docker Desktop
- • 双击下载的
Docker Desktop Installer.exe
- • 按照向导完成安装
- • 安装完成后重启计算机
- 验证安装打开命令行工具(CMD 或 PowerShell):
1 2
| docker --version docker run hello-world
|
macOS 安装
系统要求
安装步骤
- 下载 Docker Desktop for Mac
- • Intel 芯片: 下载 Docker Desktop for Mac (Intel chip)
- • Apple 芯片: 下载 Docker Desktop for Mac (Apple chip)
- 安装
- • 打开下载的
.dmg 文件
- • 将 Docker 图标拖到 Applications 文件夹
- • 从 Applications 文件夹启动 Docker
- 验证安装
1 2
| docker --version docker run hello-world
|
Linux 安装 (以 Ubuntu 为例)
卸载旧版本
1
| sudo apt-get remove docker docker-engine docker.io containerd runc
|
安装步骤
- 更新软件包索引
- 安装依赖包
1 2 3 4 5
| sudo apt-get install \ ca-certificates \ curl \ gnupg \ lsb-release
|
- 添加 Docker 官方 GPG 密钥
1 2
| sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
- 设置 Docker 仓库
1 2 3
| echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
- 安装 Docker Engine
1 2
| sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
- 启动 Docker 服务
1 2
| sudo systemctl start docker sudo systemctl enable docker
|
- 将当前用户添加到 docker 组(避免每次使用 sudo)
1 2
| sudo usermod -aG docker $USER newgrp docker
|
- 验证安装
1 2
| docker --version docker run hello-world
|
Docker 核心概念
镜像 (Image)
镜像是一个只读的模板,包含了运行应用所需的代码、运行时、库、环境变量和配置文件。可以把镜像理解为一个”类”,它定义了容器应该是什么样子。
特点:
容器 (Container)
容器是镜像的运行实例。如果镜像是”类”,那么容器就是”对象”。容器可以被创建、启动、停止、删除和暂停。
特点:
- • 可读写
- • 相互隔离
- • 可以连接网络
- • 可以挂载存储
仓库 (Repository)
仓库是集中存放镜像的地方。Docker Hub 是最大的公共仓库,用户也可以搭建私有仓库。
常见仓库:
数据卷 (Volume)
数据卷是容器持久化数据的机制,数据卷的生命周期独立于容器。
网络 (Network)
Docker 提供了多种网络模式,使容器之间以及容器与外部网络能够通信。
Docker 基础使用
镜像操作
搜索镜像
1 2 3 4 5
| # 从 Docker Hub 搜索镜像 docker search nginx
# 搜索并限制结果数量 docker search --limit 5 nginx
|
拉取镜像
1 2 3 4 5 6 7 8
| # 拉取最新版本 docker pull nginx
# 拉取指定版本 docker pull nginx:1.21.0
# 拉取指定架构的镜像 docker pull --platform linux/amd64 nginx
|
查看本地镜像
1 2 3 4 5 6 7 8 9 10 11
| # 列出所有镜像 docker images
# 或使用 docker image ls
# 查看镜像详细信息 docker image inspect nginx
# 查看镜像历史 docker history nginx
|
删除镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # 删除单个镜像 docker rmi nginx:1.21.0
# 删除多个镜像 docker rmi nginx:1.21.0 nginx:1.20.0
# 强制删除 docker rmi -f nginx
# 删除所有未使用的镜像 docker image prune
# 删除所有镜像 docker rmi $(docker images -q)
|
导出和导入镜像
1 2 3 4 5
| # 导出镜像为 tar 文件 docker save -o nginx.tar nginx:latest
# 从 tar 文件导入镜像 docker load -i nginx.tar
|
容器操作
创建并运行容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| # 基础运行 docker run nginx
# 后台运行 docker run -d nginx
# 指定容器名称 docker run -d --name my-nginx nginx
# 端口映射 (主机端口:容器端口) docker run -d -p 8080:80 --name my-nginx nginx
# 环境变量 docker run -d -e "ENV=production" nginx
# 挂载数据卷 docker run -d -v /host/path:/container/path nginx
# 完整示例 docker run -d \ --name my-nginx \ -p 8080:80 \ -v /usr/share/nginx/html:/usr/share/nginx/html \ -e "NGINX_HOST=example.com" \ --restart=always \ nginx:latest
|
常用参数说明:
- •
-d: 后台运行
- •
-p: 端口映射
- •
-v: 挂载数据卷
- •
-e: 设置环境变量
- •
--name: 指定容器名称
- •
--rm: 容器停止后自动删除
- •
-it: 交互式运行(分配伪终端)
- •
--restart: 重启策略 (no/always/on-failure/unless-stopped)
查看容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # 查看运行中的容器 docker ps
# 查看所有容器(包括停止的) docker ps -a
# 查看容器详细信息 docker inspect my-nginx
# 查看容器资源使用情况 docker stats my-nginx
# 查看容器进程 docker top my-nginx
|
容器日志
1 2 3 4 5 6 7 8 9 10 11
| # 查看容器日志 docker logs my-nginx
# 实时查看日志 docker logs -f my-nginx
# 查看最后 100 行日志 docker logs --tail 100 my-nginx
# 查看带时间戳的日志 docker logs -t my-nginx
|
进入容器
1 2 3 4 5 6 7 8 9 10 11
| # 使用 exec 进入容器(推荐) docker exec -it my-nginx bash
# 或使用 sh(如果容器没有 bash) docker exec -it my-nginx sh
# 以 root 用户进入 docker exec -it -u root my-nginx bash
# 在容器中执行命令 docker exec my-nginx ls /usr/share/nginx/html
|
容器控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 启动容器 docker start my-nginx
# 停止容器 docker stop my-nginx
# 重启容器 docker restart my-nginx
# 暂停容器 docker pause my-nginx
# 恢复容器 docker unpause my-nginx
# 杀死容器 docker kill my-nginx
|
删除容器
1 2 3 4 5 6 7 8 9 10 11
| # 删除已停止的容器 docker rm my-nginx
# 强制删除运行中的容器 docker rm -f my-nginx
# 删除所有停止的容器 docker container prune
# 删除所有容器 docker rm -f $(docker ps -aq)
|
容器和镜像互转
1 2 3 4 5 6 7 8
| # 将容器提交为新镜像 docker commit my-nginx my-custom-nginx:v1
# 导出容器为 tar 文件 docker export my-nginx > nginx-container.tar
# 从 tar 文件导入为镜像 cat nginx-container.tar | docker import - my-nginx:imported
|
数据卷管理
创建数据卷
1 2 3 4 5 6 7 8
| # 创建命名数据卷 docker volume create my-volume
# 查看所有数据卷 docker volume ls
# 查看数据卷详情 docker volume inspect my-volume
|
使用数据卷
1 2 3 4 5 6 7 8 9 10 11 12 13
| # 使用命名数据卷 docker run -d -v my-volume:/usr/share/nginx/html nginx
# 使用主机路径(绑定挂载) docker run -d -v /host/path:/container/path nginx
# 只读挂载 docker run -d -v my-volume:/usr/share/nginx/html:ro nginx
# 使用 --mount 语法(更明确) docker run -d \ --mount type=volume,source=my-volume,target=/usr/share/nginx/html \ nginx
|
删除数据卷
1 2 3 4 5
| # 删除指定数据卷 docker volume rm my-volume
# 删除所有未使用的数据卷 docker volume prune
|
网络管理
查看网络
1 2 3 4 5
| # 列出所有网络 docker network ls
# 查看网络详情 docker network inspect bridge
|
创建网络
1 2 3 4 5 6 7 8
| # 创建桥接网络 docker network create my-network
# 创建自定义子网的网络 docker network create --subnet=172.18.0.0/16 my-custom-network
# 创建指定驱动的网络 docker network create -d bridge my-bridge-network
|
使用网络
1 2 3 4 5 6 7 8
| # 容器连接到网络 docker run -d --name web --network my-network nginx
# 将运行中的容器连接到网络 docker network connect my-network my-nginx
# 断开容器与网络的连接 docker network disconnect my-network my-nginx
|
删除网络
1 2 3 4 5
| # 删除指定网络 docker network rm my-network
# 删除所有未使用的网络 docker network prune
|
Dockerfile 编写
什么是 Dockerfile
Dockerfile 是一个文本文件,包含了一系列指令,用于自动化构建 Docker 镜像。
Dockerfile 基本结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| # 基础镜像 FROM ubuntu:20.04
# 维护者信息 LABEL maintainer="yourname@example.com"
# 设置环境变量 ENV APP_HOME=/app \ PORT=8080
# 设置工作目录 WORKDIR $APP_HOME
# 复制文件 COPY package.json . COPY src/ ./src/
# 执行命令 RUN apt-get update && \ apt-get install -y nodejs npm && \ npm install && \ apt-get clean && \ rm -rf /var/lib/apt/lists/*
# 暴露端口 EXPOSE $PORT
# 数据卷 VOLUME ["/app/data"]
# 启动命令 CMD ["node", "src/app.js"]
|
常用指令详解
FROM - 指定基础镜像
1 2 3 4 5 6 7 8 9 10 11
| # 使用官方镜像 FROM node:16
# 使用特定版本 FROM python:3.9.7-slim
# 使用 scratch(空白镜像,最小化) FROM scratch
# 多阶段构建 FROM node:16 AS builder
|
LABEL - 添加元数据
1 2 3
| LABEL version="1.0" LABEL description="This is a web application" LABEL maintainer="developer@example.com"
|
ENV - 设置环境变量
1 2 3 4 5 6 7
| # 单个环境变量 ENV NODE_ENV=production
# 多个环境变量 ENV APP_HOME=/app \ PORT=3000 \ USER=appuser
|
WORKDIR - 设置工作目录
1 2 3 4 5 6
| # 设置工作目录(如果不存在会自动创建) WORKDIR /app
# 可以使用环境变量 ENV APP_DIR=/application WORKDIR $APP_DIR
|
COPY 和 ADD - 复制文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # COPY 基本用法 COPY package.json /app/ COPY src/ /app/src/
# 复制并重命名 COPY config.json /app/configuration.json
# ADD 可以自动解压缩 ADD archive.tar.gz /app/
# ADD 可以从 URL 下载 ADD https://example.com/file.txt /app/
# 推荐使用 COPY(更透明)
|
RUN - 执行命令
1 2 3 4 5 6 7 8 9 10 11 12 13
| # Shell 格式 RUN apt-get update
# Exec 格式 RUN ["/bin/bash", "-c", "echo hello"]
# 合并命令减少层数 RUN apt-get update && \ apt-get install -y \ python3 \ python3-pip && \ apt-get clean && \ rm -rf /var/lib/apt/lists/*
|
EXPOSE - 暴露端口
1 2 3 4 5 6 7 8 9
| # 暴露单个端口 EXPOSE 80
# 暴露多个端口 EXPOSE 80 443
# 指定协议 EXPOSE 53/udp EXPOSE 53/tcp
|
VOLUME - 创建挂载点
1 2 3 4 5
| # 单个挂载点 VOLUME /data
# 多个挂载点 VOLUME ["/var/log", "/var/db"]
|
CMD - 容器启动命令
1 2 3 4 5 6 7 8
| # Exec 格式(推荐) CMD ["nginx", "-g", "daemon off;"]
# Shell 格式 CMD npm start
# 提供默认参数给 ENTRYPOINT CMD ["--help"]
|
ENTRYPOINT - 容器入口点
1 2 3 4 5 6 7 8 9
| # Exec 格式 ENTRYPOINT ["python", "app.py"]
# 与 CMD 结合使用 ENTRYPOINT ["python", "app.py"] CMD ["--port", "8080"]
# 可以通过 docker run 覆盖 CMD 参数 # docker run myimage --port 9000
|
ARG - 构建参数
1 2 3 4 5 6 7 8 9 10
| # 定义构建参数 ARG VERSION=latest ARG BUILD_DATE
# 使用构建参数 FROM ubuntu:${VERSION} LABEL build_date=${BUILD_DATE}
# 构建时传递参数 # docker build --build-arg VERSION=20.04 --build-arg BUILD_DATE=$(date) .
|
USER - 指定运行用户
1 2 3 4 5 6
| # 创建用户并切换 RUN useradd -m -u 1000 appuser USER appuser
# 切换回 root USER root
|
HEALTHCHECK - 健康检查
1 2 3 4 5 6
| # 基本健康检查 HEALTHCHECK CMD curl -f http://localhost/ || exit 1
# 带参数的健康检查 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost/health || exit 1
|
实战示例
Node.js 应用 Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| # 多阶段构建 - 构建阶段 FROM node:16-alpine AS builder
WORKDIR /app
# 复制依赖文件 COPY package*.json ./
# 安装依赖 RUN npm ci --only=production
# 复制源代码 COPY . .
# 构建应用 RUN npm run build
# 多阶段构建 - 运行阶段 FROM node:16-alpine
# 设置环境变量 ENV NODE_ENV=production \ PORT=3000
# 创建应用用户 RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001
WORKDIR /app
# 从构建阶段复制文件 COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist COPY --from=builder --chown=nodejs:nodejs /app/package.json ./
# 切换到非 root 用户 USER nodejs
# 暴露端口 EXPOSE $PORT
# 健康检查 HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ CMD node -e "require('http').get('http://localhost:$PORT/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# 启动命令 CMD ["node", "dist/main.js"]
|
Python Flask 应用 Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| FROM python:3.9-slim
# 设置环境变量 ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ APP_HOME=/app
WORKDIR $APP_HOME
# 安装系统依赖 RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc \ postgresql-client && \ apt-get clean && \ rm -rf /var/lib/apt/lists/*
# 复制依赖文件 COPY requirements.txt .
# 安装 Python 依赖 RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码 COPY . .
# 创建非 root 用户 RUN useradd -m -u 1000 appuser && \ chown -R appuser:appuser $APP_HOME
USER appuser
EXPOSE5000
HEALTHCHECK --interval=30s --timeout=3s \ CMD python -c "import requests; requests.get('http://localhost:5000/health')"
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "app:app"]
|
Nginx 静态网站 Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| FROM nginx:alpine
# 删除默认配置 RUN rm /etc/nginx/conf.d/default.conf
# 复制自定义配置 COPY nginx.conf /etc/nginx/conf.d/
# 复制静态文件 COPY dist/ /usr/share/nginx/html/
# 设置权限 RUN chown -R nginx:nginx /usr/share/nginx/html && \ chmod -R 755 /usr/share/nginx/html
EXPOSE80
HEALTHCHECK --interval=30s --timeout=3s \ CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1
CMD ["nginx", "-g", "daemon off;"]
|
构建镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 基本构建 docker build -t myapp:latest .
# 指定 Dockerfile docker build -f Dockerfile.dev -t myapp:dev .
# 传递构建参数 docker build --build-arg VERSION=1.0 -t myapp:1.0 .
# 不使用缓存 docker build --no-cache -t myapp:latest .
# 指定平台 docker build --platform linux/amd64 -t myapp:latest .
# 查看构建历史 docker history myapp:latest
|
Dockerfile 最佳实践
- 使用 .dockerignore 文件
1 2 3 4 5 6
| node_modules npm-debug.log .git .env *.md .vscode
|
- 最小化层数 - 合并 RUN 命令
1 2 3 4 5 6 7 8 9
| # 不好的做法 RUN apt-get update RUN apt-get install -y python RUN apt-get clean
# 好的做法 RUN apt-get update && \ apt-get install -y python && \ apt-get clean
|
- 使用多阶段构建 - 减小最终镜像大小
- 利用构建缓存 - 将不常改变的指令放在前面
- 使用非 root 用户 - 提高安全性
- 明确指定版本 - 不要使用
latest 标签
Docker Compose 简介
什么是 Docker Compose
Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。使用 YAML 文件来配置应用的服务,然后使用一个命令就可以创建并启动所有服务。
Docker Compose 的优势
- • 单一配置文件: 所有服务配置集中管理
- • 一键部署: 通过一个命令启动所有服务
- • 服务编排: 自动管理服务间的依赖关系
- • 网络隔离: 自动创建独立的网络环境
- • 环境管理: 支持多环境配置
- • 开发效率: 简化开发环境的搭建
Docker Compose 安装
Windows 和 macOS
Docker Desktop 已经包含了 Docker Compose,无需单独安装。
验证安装:
Linux 安装
方法一: 使用 Docker 插件(推荐)
如果你安装的是最新版 Docker Engine,Compose 已经作为插件包含在内。
验证:
方法二: 独立安装 Compose V2
1 2 3 4 5 6 7 8 9 10
| # 下载 Compose 二进制文件 DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} mkdir -p $DOCKER_CONFIG/cli-plugins curl -SL https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
# 添加执行权限 chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
# 验证安装 docker compose version
|
方法三: 使用 pip 安装(旧版本)
1 2 3 4
| sudo pip install docker-compose
# 验证 docker-compose --version
|
Docker Compose 使用
docker-compose.yml 基本结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| version: '3.8'# Compose 文件版本
services: # 定义服务 web: image:nginx:latest ports: -"8080:80"
db: image:postgres:13 environment: POSTGRES_PASSWORD:example
networks: # 定义网络(可选) default: driver:bridge
volumes: # 定义数据卷(可选) db-data: driver: local
|
服务配置详解
image - 指定镜像
1 2 3 4 5 6
| services: web: image: nginx:latest
app: image: myregistry.com/myapp:1.0
|
build - 构建镜像
1 2 3 4 5 6 7 8 9 10 11 12
| services: web: build:.# 使用当前目录的 Dockerfile
app: build: context:./app # 构建上下文 dockerfile:Dockerfile.dev# 指定 Dockerfile args: # 构建参数 VERSION:"1.0" BUILD_ENV:production target:production # 多阶段构建的目标阶段
|
ports - 端口映射
1 2 3 4 5 6 7
| services: web: ports: - "8080:80" # HOST:CONTAINER - "443:443" - "127.0.0.1:3000:3000" # 绑定到特定 IP - "9000-9002:9000-9002" # 端口范围
|
environment - 环境变量
1 2 3 4 5 6 7 8 9 10 11
| services: db: environment: POSTGRES_USER:admin POSTGRES_PASSWORD:secret POSTGRES_DB:mydb
# 或使用数组格式 environment: -POSTGRES_USER=admin - POSTGRES_PASSWORD=secret
|
env_file - 环境变量文件
1 2 3 4 5
| services: web: env_file: - .env - .env.local
|
.env 文件内容:
1 2 3
| DATABASE_URL=postgresql://localhost/mydb API_KEY=your-api-key DEBUG=true
|
volumes - 数据卷
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| services: web: volumes: # 命名卷 -data-volume:/var/lib/mysql
# 绑定挂载 -./src:/app/src -/host/path:/container/path
# 只读挂载 -./config:/etc/config:ro
# 匿名卷 -/app/node_modules
volumes: data-volume: # 定义命名卷
|
networks - 网络配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| services: web: networks: -frontend -backend
db: networks: -backend
networks: frontend: driver:bridge backend: driver:bridge internal:true # 内部网络,不对外
|
depends_on - 依赖关系
1 2 3 4 5 6 7 8 9 10 11
| services: web: depends_on: -db -redis
db: image:postgres
redis: image: redis
|
高级依赖(等待服务健康):
1 2 3 4 5 6 7 8 9 10 11 12 13
| services: web: depends_on: db: condition:service_healthy
db: image:postgres healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval:10s timeout:5s retries: 5
|
restart - 重启策略
1 2 3 4 5 6
| services: web: restart: always # 总是重启 # restart: unless-stopped # 除非手动停止 # restart: on-failure # 失败时重启 # restart: no # 不重启(默认)
|
command - 覆盖默认命令
1 2 3 4 5 6 7 8
| services: web: image: nginx command: nginx -g 'daemon off;'
app: image: python:3.9 command: ["python", "app.py", "--port", "8000"]
|
entrypoint - 覆盖入口点
1 2 3 4 5 6
| services: web: entrypoint: /app/entrypoint.sh
app: entrypoint: ["python", "-u", "app.py"]
|
container_name - 容器名称
1 2 3
| services: web: container_name: my-web-container
|
healthcheck - 健康检查
1 2 3 4 5 6 7 8
| services: web: healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 30s timeout: 10s retries: 3 start_period: 40s
|
labels - 标签
1 2 3 4 5 6
| services: web: labels: com.example.description: "Web application" com.example.department: "IT" com.example.version: "1.0"
|
logging - 日志配置
1 2 3 4 5 6 7
| services: web: logging: driver: json-file options: max-size: "10m" max-file: "3"
|
Docker Compose 命令
启动服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 启动所有服务 docker compose up
# 后台启动 docker compose up -d
# 启动特定服务 docker compose up web db
# 重新构建并启动 docker compose up --build
# 强制重新创建容器 docker compose up --force-recreate
# 不启动依赖服务 docker compose up --no-deps web
|
停止服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # 停止所有服务 docker compose stop
# 停止特定服务 docker compose stop web
# 停止并删除容器、网络 docker compose down
# 停止并删除容器、网络、卷 docker compose down -v
# 停止并删除容器、网络、镜像 docker compose down --rmi all
|
查看服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 查看运行中的服务 docker compose ps
# 查看所有服务(包括停止的) docker compose ps -a
# 查看服务日志 docker compose logs
# 实时查看日志 docker compose logs -f
# 查看特定服务日志 docker compose logs web
# 查看最后 100 行日志 docker compose logs --tail=100
|
执行命令
1 2 3 4 5 6 7 8
| # 在运行的容器中执行命令 docker compose exec web bash
# 在新容器中运行一次性命令 docker compose run web python manage.py migrate
# 不启动依赖服务 docker compose run --no-deps web npm test
|
服务管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # 启动已存在的容器 docker compose start
# 重启服务 docker compose restart
# 暂停服务 docker compose pause
# 恢复服务 docker compose unpause
# 查看服务进程 docker compose top
|
构建和推送
1 2 3 4 5 6 7 8 9 10 11
| # 构建服务镜像 docker compose build
# 构建时不使用缓存 docker compose build --no-cache
# 并行构建 docker compose build --parallel
# 推送镜像到仓库 docker compose push
|
配置验证
1 2 3 4 5 6 7 8
| # 验证 compose 文件 docker compose config
# 查看最终配置(包含变量替换) docker compose config --services
# 查看服务列表 docker compose config --volumes
|
实战案例
案例 1: WordPress + MySQL
创建 docker-compose.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| version: '3.8'
services: db: image:mysql:8.0 container_name:wordpress-db restart:always environment: MYSQL_ROOT_PASSWORD:rootpassword MYSQL_DATABASE:wordpress MYSQL_USER:wpuser MYSQL_PASSWORD:wppassword volumes: -db-data:/var/lib/mysql networks: -wordpress-network
wordpress: depends_on: -db image:wordpress:latest container_name:wordpress-app restart:always ports: -"8080:80" environment: WORDPRESS_DB_HOST:db:3306 WORDPRESS_DB_USER:wpuser WORDPRESS_DB_PASSWORD:wppassword WORDPRESS_DB_NAME:wordpress volumes: -wordpress-data:/var/www/html networks: -wordpress-network
volumes: db-data: wordpress-data:
networks: wordpress-network: driver: bridge
|
启动:
访问: http://localhost:8080
案例 2: NGINX + Flask + PostgreSQL + Redis
项目结构:
1 2 3 4 5 6 7 8 9 10
| . ├── docker-compose.yml ├── .env ├── nginx/ │ ├── Dockerfile │ └── nginx.conf └── app/ ├── Dockerfile ├── requirements.txt └── app.py
|
docker-compose.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| version: '3.8'
services: nginx: build:./nginx container_name:nginx-proxy ports: -"80:80" depends_on: -web networks: -frontend restart:unless-stopped
web: build:./app container_name:flask-app command:gunicorn-w4-b0.0.0.0:5000app:app environment: -DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB} -REDIS_URL=redis://redis:6379/0 depends_on: db: condition:service_healthy redis: condition:service_started networks: -frontend -backend restart:unless-stopped
db: image:postgres:13-alpine container_name:postgres-db environment: POSTGRES_USER:${POSTGRES_USER} POSTGRES_PASSWORD:${POSTGRES_PASSWORD} POSTGRES_DB:${POSTGRES_DB} volumes: -postgres-data:/var/lib/postgresql/data networks: -backend healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] interval:10s timeout:5s retries:5 restart:unless-stopped
redis: image:redis:7-alpine container_name:redis-cache command:redis-server--appendonlyyes volumes: -redis-data:/data networks: -backend restart:unless-stopped
volumes: postgres-data: redis-data:
networks: frontend: driver:bridge backend: driver:bridge internal: true
|
.env 文件:
1 2 3
| POSTGRES_USER=appuser POSTGRES_PASSWORD=apppassword POSTGRES_DB=appdb
|
app/Dockerfile:
1 2 3 4 5 6 7 8 9 10 11 12
| FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:app"]
|
app/requirements.txt:
1 2 3 4
| Flask==2.3.0 gunicorn==20.1.0 psycopg2-binary==2.9.6 redis==4.5.5
|
app/app.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| from flask import Flask, jsonify import os import redis import psycopg2
app = Flask(__name__)
# Redis 连接 redis_client = redis.from_url(os.getenv('REDIS_URL', 'redis://localhost:6379/0'))
@app.route('/') defhello(): return jsonify({"message": "Hello from Flask!"})
@app.route('/health') defhealth(): return jsonify({"status": "healthy"}), 200
@app.route('/redis-test') defredis_test(): redis_client.incr('hits') hits = redis_client.get('hits').decode('utf-8') return jsonify({"hits": hits})
if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
|
nginx/Dockerfile:
1 2 3 4 5 6 7 8 9
| FROM nginx:alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
|
nginx/nginx.conf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| upstream flask_app { server web:5000; }
server { listen80; server_name localhost;
location / { proxy_pass http://flask_app; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
|
启动应用:
1
| docker compose up -d --build
|
案例 3: 微服务架构监控栈
使用 Prometheus + Grafana + Node Exporter
docker-compose.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| version: '3.8'
services: prometheus: image:prom/prometheus:latest container_name:prometheus command: -'--config.file=/etc/prometheus/prometheus.yml' -'--storage.tsdb.path=/prometheus' ports: -"9090:9090" volumes: -./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml -prometheus-data:/prometheus networks: -monitoring restart:unless-stopped
grafana: image:grafana/grafana:latest container_name:grafana ports: -"3000:3000" environment: -GF_SECURITY_ADMIN_PASSWORD=admin -GF_USERS_ALLOW_SIGN_UP=false volumes: -grafana-data:/var/lib/grafana depends_on: -prometheus networks: -monitoring restart:unless-stopped
node-exporter: image:prom/node-exporter:latest container_name:node-exporter ports: -"9100:9100" networks: -monitoring restart:unless-stopped
volumes: prometheus-data: grafana-data:
networks: monitoring: driver: bridge
|
prometheus/prometheus.yml:
1 2 3 4 5 6 7 8 9 10 11 12
| global: scrape_interval:15s evaluation_interval:15s
scrape_configs: -job_name:'prometheus' static_configs: -targets: ['localhost:9090']
-job_name:'node-exporter' static_configs: -targets: ['node-exporter:9100']
|
案例 4: 开发环境配置
使用不同的 compose 文件管理多环境:
docker-compose.yml (基础配置):
1 2 3 4 5 6 7 8 9 10 11 12
| version: '3.8'
services: web: build:. environment: -NODE_ENV=production networks: -app-network
networks: app-network:
|
docker-compose.dev.yml (开发环境覆盖):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| version: '3.8'
services: web: build: target:development environment: -NODE_ENV=development -DEBUG=true volumes: -./src:/app/src ports: -"3000:3000" command:npmrun dev
|
docker-compose.prod.yml (生产环境覆盖):
1 2 3 4 5 6 7 8 9 10
| version: '3.8'
services: web: build: target:production environment: -NODE_ENV=production restart:always command:npm start
|
使用:
1 2 3 4 5
| # 开发环境 docker compose -f docker-compose.yml -f docker-compose.dev.yml up
# 生产环境 docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
最佳实践
1. 镜像优化
使用轻量级基础镜像
1 2 3
| # 优先使用 Alpine 版本 FROM node:16-alpine FROM python:3.9-slim
|
多阶段构建
1 2 3 4 5 6 7 8 9 10 11 12 13
| # 构建阶段 FROM node:16 AS builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build
# 运行阶段 FROM node:16-alpine WORKDIR /app COPY --from=builder /app/dist ./dist CMD ["node", "dist/main.js"]
|
最小化层数
1 2 3 4 5
| # 合并 RUN 命令 RUN apt-get update && \ apt-get install -y package1 package2 && \ apt-get clean && \ rm -rf /var/lib/apt/lists/*
|
2. 安全实践
使用非 root 用户
1 2 3
| RUN addgroup -g 1001 -S appgroup && \ adduser -S appuser -u 1001 -G appgroup USER appuser
|
不在镜像中存储敏感信息
1 2 3 4 5
| # 使用环境变量 services: app: env_file: - .env.local
|
扫描镜像漏洞
1 2 3 4 5
| # 使用 Docker Scan docker scan myimage:latest
# 使用 Trivy trivy image myimage:latest
|
3. 性能优化
利用构建缓存
1 2 3 4 5 6
| # 先复制依赖文件 COPY package.json package-lock.json ./ RUN npm install
# 再复制源代码 COPY . .
|
使用 .dockerignore
1 2 3 4 5
| node_modules .git .env *.md test/
|
并行构建
1
| docker compose build --parallel
|
4. 开发效率
使用卷进行热重载
1 2 3 4 5
| services: web: volumes: - ./src:/app/src command: npm run dev
|
使用命名卷持久化数据
1 2 3
| volumes: db-data: driver: local
|
5. 日志管理
限制日志大小
1 2 3 4 5 6 7
| services: web: logging: driver: json-file options: max-size: "10m" max-file: "3"
|
6. 健康检查
配置健康检查
1 2 3 4 5 6 7 8
| services: web: healthcheck: test: ["CMD", "curl", "-f", "http://localhost/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s
|
7. 资源限制
限制容器资源使用
1 2 3 4 5 6 7 8 9 10
| services: web: deploy: resources: limits: cpus: '0.50' memory: 512M reservations: cpus: '0.25' memory: 256M
|
常见问题
1. 容器无法启动
检查日志
1 2
| docker logs <container-id> docker compose logs
|
检查容器状态
1 2
| docker ps -a docker inspect <container-id>
|
2. 端口已被占用
查找占用端口的进程
1 2 3 4 5
| # Windows netstat -ano | findstr :8080
# Linux/Mac lsof -i :8080
|
更改映射端口
1 2
| ports: - "8081:80" # 使用不同的主机端口
|
3. 数据持久化问题
使用命名卷
1 2 3 4 5
| volumes: my-data:/var/lib/data
volumes: my-data:
|
查看卷内容
1 2
| docker volume inspect my-data docker run --rm -v my-data:/data alpine ls /data
|
4. 网络连接问题
检查容器网络
1 2
| docker network ls docker network inspect <network-name>
|
容器间通信
1 2 3 4 5 6 7
| # 使用服务名作为主机名 services: web: environment: - DATABASE_URL=postgresql://db:5432/mydb db: image: postgres
|
5. 镜像拉取缓慢
配置镜像加速器
编辑 /etc/docker/daemon.json:
1 2 3 4 5 6
| { "registry-mirrors": [ "https://mirror.ccs.tencentyun.com", "https://docker.mirrors.ustc.edu.cn" ] }
|
重启 Docker:
1
| sudo systemctl restart docker
|
6. 容器时间不同步
设置时区
1 2 3 4 5 6
| services: web: environment: - TZ=Asia/Shanghai volumes: - /etc/localtime:/etc/localtime:ro
|
7. 权限问题
设置文件权限
1 2
| RUN chown -R appuser:appuser /app USER appuser
|
挂载卷权限
1 2
| volumes: - ./data:/app/data:rw # 读写权限
|
8. 清理无用资源
清理停止的容器
清理无用镜像
1 2
| docker image prune docker image prune -a # 删除所有未使用的镜像
|
清理无用卷
一键清理
1 2
| docker system prune docker system prune -a --volumes # 全部清理
|
总结
Docker 和 Docker Compose 是现代应用开发和部署的重要工具。通过本文,你应该掌握了:
- Docker 基础
- • 安装和配置
- • 镜像和容器管理
- • 数据卷和网络配置
- • Dockerfile 编写
- Docker Compose
- • 安装和配置
- • docker-compose.yml 编写
- • 多容器应用编排
- • 多环境管理
- 实战应用
- • Web 应用部署
- • 微服务架构
- • 开发环境配置
- 最佳实践
继续实践和探索,你将能够更熟练地使用 Docker 和 Docker Compose 来简化开发、测试和部署流程。
参考资源
- • Docker 官方文档
- • Docker Hub
- • Docker Compose 文档
- • Dockerfile 最佳实践
- • Docker 安全最佳实践
最后更新时间: 2025-11-04