当多个容器需要协同:用 Docker Compose 一键拉起整个应用


当多个容器需要协同:用 Docker Compose 一键拉起整个应用

前面几篇我们聊了 Docker 的基础、Dockerfile 的写法、pm2 在容器里的应用,可以说已经能熟练地把单个应用打包成镜像并跑起来了。但在实际开发中,一个完整的应用往往不止一个服务——前端可能需要一个 Nginx 容器来 serve 静态文件,后端可能需要一个 Node 容器跑 API,再加上数据库 MySQL 或 Redis,甚至还有消息队列。如果每次都要手动敲 docker run 启动这几个容器,还得操心网络怎么连通、数据卷怎么挂载、启动顺序怎么保证,那可就太折腾了。

这时候就该 Docker Compose 登场了。它就是一个“一键启动全家桶”的工具,让你用一个 YAML 文件描述整个应用的服务、网络、数据卷,然后一个命令就能把所有容器拉起来。今天我们就来聊聊 Docker Compose 怎么用,以及它如何让多容器环境的管理变得轻松愉快。

Docker Compose 是什么?

Docker Compose 是 Docker 官方推出的容器编排工具,专门用来定义和运行多个容器的应用。你只需要写一个 docker-compose.yml 文件,在里面声明有哪些服务(比如 web、db、redis),每个服务用哪个镜像、暴露哪些端口、挂载哪些卷、依赖哪些其他服务,然后执行 docker-compose up,Compose 就会按照依赖顺序启动所有容器,并自动创建一个默认的网络让它们可以互相通信。

它最适合用在开发环境测试环境,也能用于单机的生产环境(虽然生产环境更推荐用 Kubernetes 做集群编排,但 Compose 在简单场景下完全够用)。

安装与准备

如果你已经安装了 Docker Desktop(Windows/Mac),Compose 是自带的,直接在终端输入 docker-compose --version 就能看到版本。Linux 用户可能需要单独安装,但也很简单,去官网下二进制文件就行。

我们假设现在要搭建一个简单的应用:一个 Node.js 写的 Web 服务,加上一个 Redis 来做缓存。两个服务各跑一个容器,Node 服务需要把代码挂载到容器里方便开发时热更新,Redis 需要把数据持久化到宿主机。

写一个 docker-compose.yml 文件

在项目根目录新建一个文件,名字必须是 docker-compose.yml(或 .yaml)。内容如下:

version: '3.8'

services:
  web:
    build: .                     # 使用当前目录的 Dockerfile 构建镜像
    ports:
      - "3000:3000"               # 宿主机 3000 映射到容器 3000
    volumes:
      - .:/app                    # 挂载当前目录到容器 /app,实现代码热更新
      - /app/node_modules          # 匿名卷,避免覆盖容器内的 node_modules
    environment:
      - NODE_ENV=development
      - REDIS_HOST=redis           # 服务名就是 hostname,Compose 会自动做 DNS 解析
    depends_on:
      - redis                      # 确保 redis 先启动

  redis:
    image: redis:alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data            # 使用命名卷持久化数据

volumes:
  redis_data:                       # 声明一个命名卷

解释一下关键部分:

  • version:指定 Compose 文件格式的版本,一般用最新的 '3.8''3'
  • services:定义要启动的服务。每个服务都是一个容器。

    • web:我们的 Node 应用。

      • build: .:告诉 Compose 用当前目录下的 Dockerfile 构建镜像,而不是直接拉取现成镜像。这样适合开发时频繁修改代码。
      • ports:端口映射,和 docker run -p 一样。
      • volumes:卷挂载。这里把当前目录挂载到容器的 /app,这样本地修改代码容器内立即生效,不用重新构建。同时专门加了一个 /app/node_modules 的匿名卷,防止本地的 node_modules(可能没有或不同平台)覆盖掉容器里安装好的依赖。
      • environment:环境变量,可以在 Node 里通过 process.env.REDIS_HOST 拿到 Redis 的地址。注意这里直接写了 redis,因为 Compose 会为每个服务创建一个可解析的 hostname,服务名就是 hostname。
      • depends_on:指定依赖关系,确保 redis 服务先启动。
    • redis:缓存服务。

      • image:直接使用官方 Redis 镜像。
      • volumes:使用命名卷 redis_data 挂载到 /data,Redis 的数据就会持久化到卷里,不会因为容器删除而丢失。
  • volumes:在顶层声明命名卷,这样 Compose 会帮我们创建和管理这个卷。

启动和常用命令

在项目目录下执行:

docker-compose up

Compose 就会开始构建 web 镜像(如果本地没有)、拉取 redis 镜像,然后启动两个容器,并把日志输出到当前终端。如果你想在后台运行,加个 -d 参数:

docker-compose up -d

其他常用命令:

  • docker-compose down:停止并删除所有容器、网络,但不会删除卷(除非加 -v)。
  • docker-compose logs -f:查看所有服务的日志,-f 表示持续跟踪。
  • docker-compose exec web sh:在运行中的 web 容器里执行命令(比如进入容器调试)。
  • docker-compose ps:列出当前项目相关的容器状态。
  • docker-compose build:只构建镜像,不启动容器。

网络是怎么工作的?

当你执行 up 时,Compose 会自动创建一个默认的网络(名字通常是 项目名_default),并把所有服务都加入到这个网络里。这样服务之间就可以通过服务名直接通信,比如 Node 代码里连接 Redis 的 host 直接写 redis 就行。完全不用手动 --link 或者配置复杂的网络。

如果你想自定义网络,也可以在 networks 顶层定义,然后在每个服务的 networks 里指定,但默认网络已经足够满足大多数需求。

与 Docker 命令行的对比

如果不使用 Compose,你需要依次执行:

docker network create myapp
docker run -d --name redis --network myapp -v redis_data:/data redis:alpine
docker build -t myapp .
docker run -d --name web --network myapp -p 3000:3000 -v .:/app -v /app/node_modules -e REDIS_HOST=redis myapp

而且停止时还要一个个 docker stopdocker rm,删除卷也要单独处理。用 Compose,只需要一个 docker-compose down。当项目变大、服务变多时,这种简化的优势会更明显。

开发环境与生产环境的配置差异

通常我们会为不同环境准备不同的 Compose 文件,或者使用 extendsprofiles。一个常见的做法是:开发环境用 docker-compose.yml,生产环境用 docker-compose.prod.yml,启动时通过 -f 指定:

docker-compose -f docker-compose.prod.yml up -d

生产环境的配置可能没有代码挂载,而是使用构建好的镜像,并加上重启策略等。

Compose 的局限

Docker Compose 非常强大,但它只能管理单台 Docker 主机上的容器。如果你需要在多台服务器上部署容器、实现自动伸缩、滚动更新,就需要用到更高级的编排工具,比如 Docker Swarm(也是 Docker 原生)或 Kubernetes。不过对于中小型项目、开发测试环境,Compose 已经足够好用。

小结

Docker Compose 是 Docker 生态里的一把利器,它把多容器的管理变得像单容器一样简单。通过一个 YAML 文件,你可以清晰地描述整个应用架构,然后用几个命令控制整个生命周期。结合之前学的 Dockerfile、数据卷、环境变量等知识,现在你完全可以构建出复杂的多服务应用了。

声明:麋鹿与鲸鱼|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 当多个容器需要协同:用 Docker Compose 一键拉起整个应用


Carpe Diem and Do what I like