> 技术文档 > 【Docker-Day 14】Docker Compose深度解析

【Docker-Day 14】Docker Compose深度解析


Langchain系列文章目录

01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来

Python系列文章目录

PyTorch系列文章目录

机器学习系列文章目录

深度学习系列文章目录

Java系列文章目录

JavaScript系列文章目录

Python系列文章目录

Go语言系列文章目录

Docker系列文章目录

01-【Docker-Day 1】告别部署噩梦:为什么说 Docker 是每个开发者的必备技能?
02-【Docker-Day 2】从零开始:手把手教你在 Windows、macOS 和 Linux 上安装 Docker
03-【Docker-Day 3】深入浅出:彻底搞懂 Docker 的三大核心基石——镜像、容器与仓库
04-【Docker-Day 4】从创建到删除:一文精通 Docker 容器核心操作命令
05-【Docker-Day 5】玩转 Docker 镜像:search, pull, tag, rmi 四大金刚命令详解
06-【Docker-Day 6】从零到一:精通 Dockerfile 核心指令 (FROM, WORKDIR, COPY, RUN)
07-【Docker-Day 7】揭秘 Dockerfile 启动指令:CMD、ENTRYPOINT、ENV、ARG 与 EXPOSE 详解
08-【Docker-Day 8】高手进阶:构建更小、更快、更安全的 Docker 镜像
09-【Docker-Day 9】实战终极指南:手把手教你将 Node.js 应用容器化
10-【Docker-Day 10】容器的“持久化”记忆:深入解析 Docker 数据卷 (Volume)
11-【Docker-Day 11】Docker 绑定挂载 (Bind Mount) 实战:本地代码如何与容器实时同步?
12-【Docker-Day 12】揭秘容器网络:深入理解 Docker Bridge 模式与端口映射
13-【Docker-Day 13】超越默认Bridge:精通Docker Host、None与自定义网络模式
14-【Docker-Day 14】Docker Compose深度解析


文章目录

  • Langchain系列文章目录
  • Python系列文章目录
  • PyTorch系列文章目录
  • 机器学习系列文章目录
  • 深度学习系列文章目录
  • Java系列文章目录
  • JavaScript系列文章目录
  • Python系列文章目录
  • Go语言系列文章目录
  • Docker系列文章目录
  • 摘要
  • 一、为什么需要 Docker Compose?
    • 1.1 单容器应用的局限性
    • 1.2 手动管理的噩梦
    • 1.3 Docker Compose 的诞生:化繁为简
  • 二、Docker Compose 核心概念与安装
    • 2.1 核心概念解析
    • 2.2 安装 Docker Compose
  • 三、`docker-compose.yml` 文件详解
    • 3.1 文件结构概览
    • 3.2 `services` 配置项剖析
    • 3.3 一个简单的示例
  • 四、Docker Compose 常用命令
    • 4.1 启动与构建
    • 4.2 查看与管理
    • 4.3 停止与清理
    • 4.4 命令总结表格
  • 五、实战演练:编排一个简单的 Web 应用
    • 5.1 场景描述
    • 5.2 项目结构
    • 5.3 编写应用代码
        • (1) `requirements.txt`
        • (2) `app.py`
        • (3) `Dockerfile` (用于构建 `web` 服务)
    • 5.4 编写 `docker-compose.yml`
    • 5.5 一键启动与验证
  • 六、总结

摘要

在现代软件开发中,一个应用通常由多个相互协作的服务构成,例如 Web 服务器、数据库、缓存和消息队列。手动管理这些分散的容器不仅繁琐、易错,而且难以复现和共享。本文是 Docker 入门系列的第 14 篇,将深入探讨 Docker 生态中的编排神器——Docker Compose。我们将从“为什么需要 Docker Compose”出发,系统解析其核心概念、docker-compose.yml 文件的编写范式,并通过一个完整的实战案例,手把手教你如何使用 Docker Compose 定义和运行一个多容器应用,真正实现“一键启动,一键销毁”的高效开发与部署流程。


一、为什么需要 Docker Compose?

在我们掌握了如何运行单个 Docker 容器后,很快就会遇到一个现实问题:绝大多数真实世界的应用程序都不是孤立存在的。一个典型的 Web 应用可能包含前端服务、后端 API、数据库和缓存服务。如果这些服务都分别容器化,我们该如何管理它们呢?

1.1 单容器应用的局限性

想象一下,我们正在开发一个 WordPress 网站。它至少需要两个核心组件:

  • WordPress 服务:运行 PHP 代码的 Web 服务器。
  • MySQL 服务:用于存储文章、用户等数据的数据库。

这两个服务必须在同一个网络中,以便 WordPress 能够连接到 MySQL。如果只使用 docker run,我们将面临一系列挑战。

1.2 手动管理的噩梦

如果坚持使用基础的 docker 命令来管理这个 WordPress 应用,我们的操作流程可能会是这样的:

  1. 创建网络:首先,需要手动创建一个 Docker 网络,以确保两个容器可以互相通信。
    docker network create wordpress-net
  2. 启动 MySQL 容器:编写一条长长的 docker run 命令来启动数据库,需要指定网络、挂载数据卷以持久化数据、设置环境变量等。
    docker run -d --name mysql-db \\ --network wordpress-net \\ -v db_data:/var/lib/mysql \\ -e MYSQL_ROOT_PASSWORD=my-secret-pw \\ -e MYSQL_DATABASE=wordpress \\ mysql:5.7
  3. 启动 WordPress 容器:再编写另一条复杂的命令来启动 WordPress,需要链接到同一个网络、映射端口到主机、并配置环境变量指向刚刚创建的数据库。
    docker run -d --name wordpress-app \\ --network wordpress-net \\ -p 8080:80 \\ -e WORDPRESS_DB_HOST=mysql-db \\ -e WORDPRESS_DB_PASSWORD=my-secret-pw \\ -e WORDPRESS_DB_NAME=wordpress \\ wordpress

这个过程存在显而易见的痛点:

  • 命令冗长且易错:每条命令都包含大量参数,容易输错,且难以记忆。
  • 管理困难:启动、停止、重启或删除整个应用需要对多个容器分别执行命令。
  • 依赖关系不明确:WordPress 依赖于 MySQL,必须先启动数据库。这种启动顺序需要手动保证。
  • 环境难以复制:如果新同事想在自己机器上搭建同样的环境,他必须重复以上所有步骤,并确保所有参数完全一致,效率极低。

1.3 Docker Compose 的诞生:化繁为简

为了解决上述问题,Docker Compose 应运而生。它是一个用于定义和运行多容器 Docker 应用程序的工具。

核心思想:使用一个 YAML 文件(docker-compose.yml)来配置应用的所有服务,然后使用一条命令,就可以根据配置创建并启动所有服务。

这就像从手写乐谱的每个音符(单个 docker run),升级为拥有一份完整的交响乐总谱(docker-compose.yml 文件),而你,作为指挥家,只需一个手势(docker compose up),就能让整个乐队(所有容器)和谐地演奏起来。

二、Docker Compose 核心概念与安装

在深入学习如何编写 YAML 文件之前,我们先来了解 Docker Compose 的几个基本概念和安装方法。

2.1 核心概念解析

  • 服务 (Service):一个服务代表一个应用容器的配置。它定义了该容器应使用哪个镜像、如何构建、需要映射哪些端口、依赖哪些其他服务等。在 docker-compose.yml 文件中,我们定义的每一个顶级键就是一个服务。例如,web 服务和 db 服务。
  • 项目 (Project):一个项目是由一个 docker-compose.yml 文件定义的整个应用,它包含了多个服务。Docker Compose 会为每个项目创建一个独立的环境,包括默认的网络。项目名称通常是其所在目录的名称。
  • 网络 (Network):Docker Compose 会为每个项目自动创建一个默认的 bridge 网络。该项目下的所有服务都会连接到这个网络中。最妙的是,在这个网络内部,每个服务都可以通过其服务名作为主机名直接访问其他服务。例如,web 服务可以直接通过 ping db 来连接到数据库服务,而无需关心其容器 IP 地址。

2.2 安装 Docker Compose

Docker Compose 的安装非常简单,因为它现在已经作为 Docker 的一个插件集成到了 Docker Engine 中。

  • 对于 Windows 和 macOS 用户
    如果你安装了 Docker Desktop,那么 Docker Compose 已经内置好了,无需额外安装。
  • 对于 Linux 用户
    Docker Compose 现在以 docker-compose-plugin 的形式提供。你可以使用系统的包管理器进行安装。例如,在 Ubuntu/Debian 上:
    sudo apt-get updatesudo apt-get install docker-compose-plugin

    在 CentOS/Fedora 上,通常通过设置 Docker 的官方仓库后使用 dnfyum 安装。

安装完成后,可以通过以下命令验证:

docker compose version

注意:你可能在旧的教程或项目中看到 docker-compose(带连字符)的命令。这是 V1 版本的独立二进制文件。现在官方推荐使用 docker compose(无连字符)命令,它是 V2 版本,作为 Docker CLI 的一个插件,提供了更好的集成和性能。

三、docker-compose.yml 文件详解

docker-compose.yml 是 Docker Compose 的灵魂,它使用 YAML 语法来描述一个多容器应用的完整架构。

3.1 文件结构概览

一个典型的 docker-compose.yml 文件结构如下:

# 顶层键定义了Compose文件的版本规范,现在已是可选的# version: \"3.8\" # 定义所有的服务services: # 服务1:例如一个web服务器 web: # ... 服务的具体配置 ... # 服务2:例如一个数据库 database: # ... 服务的具体配置 ...# (可选)定义自定义网络networks: # ... 网络配置 ...# (可选)定义数据卷volumes: # ... 数据卷配置 ...

最核心的部分是 services,它包含了应用的所有组件。

3.2 services 配置项剖析

services 键下,我们可以为每个服务定义一系列配置。以下是一些最常用的指令:

指令 描述 示例 image 指定服务使用的镜像。如果本地没有,Compose 会尝试从 Docker Hub 拉取。 image: \"nginx:latest\" build 指定用于构建镜像的 Dockerfile 路径。 build: .build: ./webapp container_name 指定一个自定义的容器名称,而不是由 Compose 自动生成。 container_name: my-web-server ports 映射端口。格式为 \"主机端口:容器端口\"ports: - \"8080:80\" volumes 挂载数据卷或绑定挂载。 volumes: - db-data:/var/lib/mysql environment 设置环境变量。可以是键值对或数组。 environment: - MYSQL_ROOT_PASSWORD=secret depends_on 定义服务间的启动依赖关系。 depends_on: - database networks 将服务连接到指定的网络。 networks: - my-app-net command 覆盖容器启动时执行的默认命令。 command: [\"redis-server\", \"--appendonly\", \"yes\"] restart 定义容器的重启策略,如 no, always, on-failurerestart: always

3.3 一个简单的示例

让我们来看一个只包含 Redis 服务的简单 docker-compose.yml 文件,以熟悉其语法:

docker-compose.yml

services: # 定义一个名为 \"cache\" 的服务 cache: # 使用官方的 redis:alpine 镜像 image: \"redis:alpine\" # 给容器取一个固定的名字 container_name: my-redis-cache # 将主机的 6379 端口映射到容器的 6379 端口 ports: - \"6379:6379\" # 挂载一个名为 \"redis-data\" 的数据卷到容器的 /data 目录 volumes: - redis-data:/data # 设置重启策略为总是重启 restart: always# 在文件末尾定义顶层 volumes,让 Compose 管理这个数据卷volumes: redis-data:

有了这个文件,我们不再需要记住任何 docker run 参数。

四、Docker Compose 常用命令

掌握了 YAML 文件的编写,接下来就是学习如何使用 docker compose 命令来“指挥”我们的应用。所有命令都需要在包含 docker-compose.yml 文件的目录中执行。

4.1 启动与构建

  • docker compose up
    这是最核心的命令,它会一次性创建并启动所有服务。

    # 在前台启动,日志会直接输出到终端docker compose up# 使用 -d (detached) 参数在后台启动docker compose up -d
  • docker compose up --build
    如果你的服务配置中使用了 build 指令(即通过 Dockerfile 构建),此命令会在启动容器前强制重新构建镜像。

    docker compose up -d --build

4.2 查看与管理

  • docker compose ps
    列出当前项目中所有容器的状态。
    docker compose ps
  • docker compose logs
    查看服务的日志输出。
    # 查看所有服务的日志docker compose logs# 持续跟踪日志 (-f, follow)docker compose logs -f# 只看特定服务的日志docker compose logs -f web
  • docker compose exec
    在一个正在运行的服务(容器)中执行命令,非常适合用于调试。
    # 在名为 web 的服务中启动一个交互式 shelldocker compose exec web sh

4.3 停止与清理

  • docker compose stop
    停止正在运行的服务,但不会删除它们。可以通过 docker compose start 重新启动。
  • docker compose down
    这是 up 的逆操作。它会停止并移除项目中的所有容器和网络。
    docker compose down

    如果还想删除在 volumes 中定义的数据卷,需要加上 -v 参数。

    # 彻底清理,包括数据卷docker compose down -v

4.4 命令总结表格

命令 主要作用 docker compose up [-d] 创建并启动所有服务(-d 后台运行) docker compose down [-v] 停止并移除容器、网络(-v 移除数据卷) docker compose ps 查看项目中所有容器的状态 docker compose logs [-f] [service] 查看服务日志(-f 持续跟踪) docker compose exec 在指定服务中执行命令 docker compose build [service] 构建或重新构建服务的镜像 docker compose pull [service] 拉取服务所需的镜像 docker compose start/stop/restart [service] 启动/停止/重启服务

五、实战演练:编排一个简单的 Web 应用

理论结合实践是最好的学习方式。让我们来构建一个简单的 Web 应用,它包含一个 Python Flask 后端和一个 Redis 数据库,用于计算网页的访问次数。

5.1 场景描述

  • web 服务:一个用 Flask 编写的简单网页,每次刷新都会连接 Redis,使一个计数器加一,并显示当前计数值。
  • redis 服务:一个 Redis 数据库,用于存储访问次数。

这个例子能清晰地展示服务间如何通过服务名进行通信。

5.2 项目结构

首先,创建如下的目录和文件结构:

/my-visit-counter├── app.py├── requirements.txt├── Dockerfile└── docker-compose.yml

5.3 编写应用代码

(1) requirements.txt
flaskredis
(2) app.py
from flask import Flaskfrom redis import Redisimport osapp = Flask(__name__)# 注意:这里的主机名 \'redis\' 正是 docker-compose.yml 中定义的服务名!# Docker Compose 会自动处理 DNS 解析,将 \'redis\' 指向 Redis 容器的 IP。redis = Redis(host=\'redis\', port=6379)@app.route(\'/\')def hello(): count = redis.incr(\'hits\') return f\'Hello from Docker! I have been seen {count} times.\\n\'if __name__ == \"__main__\": app.run(host=\"0.0.0.0\", port=5000, debug=True)
(3) Dockerfile (用于构建 web 服务)
# 使用官方 Python 镜像作为基础FROM python:3.9-slim# 设置工作目录WORKDIR /app# 复制依赖文件COPY requirements.txt .# 安装依赖RUN pip install --no-cache-dir -r requirements.txt# 复制应用代码COPY . .# 容器启动时执行的命令CMD [\"python\", \"app.py\"]

5.4 编写 docker-compose.yml

这是整个编排的核心。

services: # 定义 Web 服务 web: # 使用当前目录下的 Dockerfile 进行构建 build: . # 将主机的 8000 端口映射到容器的 5000 端口 ports: - \"8000:5000\" # 显式声明 web 服务依赖于 redis 服务 # 这能保证 redis 会在 web 之前启动 depends_on: - redis # 定义 Redis 服务 redis: # 直接使用官方 Redis 镜像 image: \"redis:alpine\"

这个配置文件的精髓在于:

  1. 服务发现web 服务通过主机名 redis 就能找到 redis 服务。
  2. 依赖管理depends_on 确保了启动顺序的正确性。

5.5 一键启动与验证

现在,所有准备工作都已完成。在 my-visit-counter 目录下,执行:

docker compose up -d

Compose 会自动:

  1. 读取 docker-compose.yml 文件。
  2. web 服务构建 Docker 镜像。
  3. 拉取 redis 镜像。
  4. 创建一个名为 my-visit-counter_default 的网络。
  5. 启动 redis 容器并加入网络。
  6. 启动 web 容器并加入网络。

你可以用 docker compose ps 查看状态:

NAME COMMAND  SERVICE STATUS  PORTSmy-visit-counter-redis-1 \"docker-entrypoint.s…\" redis  running 6379/tcpmy-visit-counter-web-1 \"python app.py\" web  running 0.0.0.0:8000->5000/tcp

现在,打开浏览器访问 http://localhost:8000。你应该能看到 “Hello from Docker! I have been seen 1 times.”。每次刷新页面,计数器都会增加。

最后,当你完成实验后,只需一条命令即可清理所有资源:

docker compose down

六、总结

通过本文的学习,我们完成了从手动管理单个容器到使用 Docker Compose 优雅编排多容器应用的跨越。现在,让我们对核心知识点进行回顾:

  1. 核心价值:Docker Compose 旨在解决多容器应用管理的复杂性,通过一个 docker-compose.yml 配置文件,实现了对整个应用栈的声明式定义一键式管理,极大地提升了开发、测试和部署的效率与一致性。
  2. 核心组件:Compose 的世界由服务 (Service)项目 (Project)网络 (Network) 构成。每个服务是一个容器配置,所有服务共同组成一个项目,并默认共享一个隔离的网络环境。
  3. YAML 文件是蓝图docker-compose.yml 文件是应用架构的“总设计图”。我们通过 image, build, ports, volumes, environment, depends_on 等指令精确描述每个服务的行为和它们之间的关系。
  4. 服务发现是关键:Compose 最强大的特性之一是其内置的服务发现机制。在同一个 Compose 项目中,任何服务都可以通过其服务名作为主机名直接访问到另一个服务,这大大简化了容器间的通信配置。
  5. 命令集是工具箱:以 docker compose updocker compose down 为核心的命令集,为我们提供了完整的应用生命周期管理能力,包括启动、停止、查看日志、执行命令和彻底清理,让复杂操作变得简单直观。