Docker 和 Docker Compose 完全指南

Docker 和 Docker Compose 完全指南

在这里插入图片描述在这里插入图片描述

目录

    1. Docker 简介
    1. Docker 安装
    1. Docker 核心概念
    1. Docker 基础使用
    1. Dockerfile 编写
    1. Docker Compose 简介
    1. Docker Compose 安装
    1. Docker Compose 使用
    1. 实战案例
    1. 最佳实践
    1. 常见问题

Docker 简介

什么是 Docker

Docker 是一个开源的容器化平台,它允许开发者将应用程序及其所有依赖项打包到一个轻量级、可移植的容器中。容器可以在任何支持 Docker 的系统上运行,确保应用在不同环境中的一致性。

Docker 的优势

  • 环境一致性: 消除”在我的机器上可以运行”的问题
  • 快速部署: 容器启动速度快,通常只需几秒钟
  • 资源隔离: 每个容器相互独立,互不影响
  • 轻量级: 相比虚拟机,容器共享主机内核,占用资源更少
  • 版本控制: 镜像可以进行版本管理
  • 可移植性: 一次构建,到处运行

Docker vs 虚拟机

特性 Docker 容器 虚拟机
启动时间 秒级 分钟级
磁盘占用 MB 级别 GB 级别
性能 接近原生 有性能损耗
系统支持 每台主机支持数千个容器 每台主机支持几十个虚拟机
隔离性 进程级隔离 操作系统级隔离

Docker 安装

Windows 安装

系统要求

  • • Windows 10 64-bit: Pro, Enterprise, or Education (Build 19041 或更高)
  • • 启用 WSL 2 功能
  • • 启用虚拟化功能

安装步骤

    1. 启用 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

    # 重启计算机
    1. 下载并安装 WSL 2 Linux 内核更新包访问 Microsoft WSL 2 更新页面 下载并安装
    1. 设置 WSL 2 为默认版本
    1
    wsl --set-default-version 2
    1. 下载 Docker Desktop for Windows访问 Docker 官网 下载安装程序
    1. 安装 Docker Desktop
    • • 双击下载的 Docker Desktop Installer.exe
    • • 按照向导完成安装
    • • 安装完成后重启计算机
    1. 验证安装打开命令行工具(CMD 或 PowerShell):
    1
    2
    docker --version
    docker run hello-world

macOS 安装

系统要求

  • • macOS 10.15 或更高版本

安装步骤

    1. 下载 Docker Desktop for Mac
    • • Intel 芯片: 下载 Docker Desktop for Mac (Intel chip)
    • • Apple 芯片: 下载 Docker Desktop for Mac (Apple chip)
    1. 安装
    • • 打开下载的 .dmg 文件
    • • 将 Docker 图标拖到 Applications 文件夹
    • • 从 Applications 文件夹启动 Docker
    1. 验证安装
    1
    2
    docker --version
    docker run hello-world

Linux 安装 (以 Ubuntu 为例)

卸载旧版本

1
sudo apt-get remove docker docker-engine docker.io containerd runc

安装步骤

    1. 更新软件包索引
    1
    sudo apt-get update
    1. 安装依赖包
    1
    2
    3
    4
    5
    sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
    1. 添加 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
    1. 设置 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
    1. 安装 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
    1. 启动 Docker 服务
    1
    2
    sudo systemctl start docker
    sudo systemctl enable docker
    1. 将当前用户添加到 docker 组(避免每次使用 sudo)
    1
    2
    sudo usermod -aG docker $USER
    newgrp docker
    1. 验证安装
    1
    2
    docker --version
    docker run hello-world

Docker 核心概念

镜像 (Image)

镜像是一个只读的模板,包含了运行应用所需的代码、运行时、库、环境变量和配置文件。可以把镜像理解为一个”类”,它定义了容器应该是什么样子。

特点:

  • • 分层存储
  • • 只读
  • • 可以被共享和重用

容器 (Container)

容器是镜像的运行实例。如果镜像是”类”,那么容器就是”对象”。容器可以被创建、启动、停止、删除和暂停。

特点:

  • • 可读写
  • • 相互隔离
  • • 可以连接网络
  • • 可以挂载存储

仓库 (Repository)

仓库是集中存放镜像的地方。Docker Hub 是最大的公共仓库,用户也可以搭建私有仓库。

常见仓库:

  • • Docker Hub: https://hub.docker.com/
  • • 阿里云镜像仓库
  • • 腾讯云镜像仓库
  • • Harbor(企业私有仓库)

数据卷 (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 最佳实践

    1. 使用 .dockerignore 文件
    1
    2
    3
    4
    5
    6
    node_modules
    npm-debug.log
    .git
    .env
    *.md
    .vscode
    1. 最小化层数 - 合并 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
    1. 使用多阶段构建 - 减小最终镜像大小
    1. 利用构建缓存 - 将不常改变的指令放在前面
    1. 使用非 root 用户 - 提高安全性
    1. 明确指定版本 - 不要使用 latest 标签

Docker Compose 简介

什么是 Docker Compose

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。使用 YAML 文件来配置应用的服务,然后使用一个命令就可以创建并启动所有服务。

Docker Compose 的优势

  • 单一配置文件: 所有服务配置集中管理
  • 一键部署: 通过一个命令启动所有服务
  • 服务编排: 自动管理服务间的依赖关系
  • 网络隔离: 自动创建独立的网络环境
  • 环境管理: 支持多环境配置
  • 开发效率: 简化开发环境的搭建

Docker Compose 安装

Windows 和 macOS

Docker Desktop 已经包含了 Docker Compose,无需单独安装。

验证安装:

1
docker compose version

Linux 安装

方法一: 使用 Docker 插件(推荐)

如果你安装的是最新版 Docker Engine,Compose 已经作为插件包含在内。

验证:

1
docker compose version

方法二: 独立安装 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

启动:

1
docker compose up -d

访问: 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
docker container prune

清理无用镜像

1
2
docker image prune
docker image prune -a # 删除所有未使用的镜像

清理无用卷

1
docker volume prune

一键清理

1
2
docker system prune
docker system prune -a --volumes # 全部清理

总结

Docker 和 Docker Compose 是现代应用开发和部署的重要工具。通过本文,你应该掌握了:

    1. Docker 基础
    • • 安装和配置
    • • 镜像和容器管理
    • • 数据卷和网络配置
    • • Dockerfile 编写
    1. Docker Compose
    • • 安装和配置
    • • docker-compose.yml 编写
    • • 多容器应用编排
    • • 多环境管理
    1. 实战应用
    • • Web 应用部署
    • • 微服务架构
    • • 开发环境配置
    1. 最佳实践
    • • 镜像优化
    • • 安全加固
    • • 性能调优

继续实践和探索,你将能够更熟练地使用 Docker 和 Docker Compose 来简化开发、测试和部署流程。


参考资源

  • • Docker 官方文档
  • • Docker Hub
  • • Docker Compose 文档
  • • Dockerfile 最佳实践
  • • Docker 安全最佳实践

最后更新时间: 2025-11-04