本文同步发布在我的博客之中:一文入门 Docker Compose - Lynn的小站
前言
借助 Docker,您可将容器当做轻巧、模块化的虚拟机来使用。同时,您还将获得高度灵活性,实现对容器的高效创建、部署及复制,并在环境之间迁移它们,从而有助于您针对云来优化应用。
——《什么是 Docker?》
Docker Compose is a tool for running multi-container applications on Docker defined using the Compose file format. A Compose file is used to define how one or more containers that make up your application are configured. Once you have a Compose file, you can create and start your application with a single command:
docker compose up。——《Docker Compose 官方介绍》
简单来说,Docker可以让我们把一个项目的所有依赖环境配置好,我们可以快速的运行起来,而无需处理环境的依赖问题;
而某个项目需要用到诸如数据库、Redis等其他项目的时候,使用Docker Compose可以将所有的项目和项目依赖通过一个yml完全配置好,我们只需要通过一行命令就可以快速启动这个项目。
Compose 使用的三个步骤:
- 使用 Dockerfile 定义应用程序的环境。
- 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
- 最后,执行 docker-compose up 命令来启动并运行整个应用程序。
——《Docker Compose - 菜鸟教程》
安装 Docker Compose
这部分,我们在这里仅介绍Linux的安装步骤,Windows和MacOS已经在Docker Desktop之中内置了Docker Compose的功能,如果你有其他特殊的需求,也可以参考官方文档。
基本上来说,只需要这两条命令即可:
sudo curl -L "https://github.com/docker/compose/releases/download/<版本号>/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
如果你使用的是Ubuntu系统,那么安装的步骤则会变得更为简单:
sudo apt install docker-compose
在安装完成后,我们可以通过下面的命令检查是否安装成功
docker compose --version
配置文件
接下来,我们聊聊配置文件,也就是Docker Compose的核心部分,在这里我们设计了两个服务,一种为源文件构造,另一种是拉取现有的镜像部署。
# compose.yml
services: # 定义服务
web: # Web 应用
build: ./app # 使用 ./app 目录下的 Dockerfile 构建镜像
command: flask run --host=0.0.0.0 --port=5000 # 启动 Flask 应用
ports:
- "8000:5000" # 本机8000端口映射到容器5000端口
environment:
# 数据库连接URL,这里通过服务名 db 连接 Postgres
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
depends_on:
db:
condition: service_healthy # 等待数据库健康检查通过再启动
db: # 数据库服务(PostgreSQL)
image: postgres:16 # 使用官方 Postgres 16 镜像
restart: unless-stopped # 意外退出时自动重启
environment:
POSTGRES_USER: postgres # 数据库用户名
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} # 从 .env 文件读取密码
POSTGRES_DB: ${POSTGRES_DB} # 默认数据库名
volumes:
- db_data:/var/lib/postgresql/data # 数据持久化,保存到数据卷 db_data 之中
healthcheck: # 健康检查,保证数据库可用
test: ["CMD-SHELL", "pg_isready -U postgres -d ${POSTGRES_DB}"]
interval: 5s
timeout: 3s
retries: 10
volumes: # 定义数据卷
db_data: # PostgreSQL 的数据卷
Service - Web服务(从源文件构造)
我们以Web服务为例,这里我们设计了一个Python Flask项目作为示例:
web: # Web 应用服务(Flask 示例)
build: ./app # 使用 ./app 目录下的 Dockerfile 构建镜像
command: flask run --host=0.0.0.0 --port=5000 # 启动 Flask 应用
ports:
- "8000:5000" # 本机8000端口映射到容器5000端口
environment:
# 数据库连接URL,这里通过服务名 db 连接 Postgres
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
depends_on:
db:
condition: service_healthy # 等待数据库健康检查通过再启动
- build:指定构建镜像的目录(./app 里需要有 Dockerfile)。
- command:覆盖容器启动命令,这里用flask启动了一个允许所有IP访问的,端口为5000的服务端。
[!warning]
这里应该允许所有IP访问(0.0.0.0),而不是只允许本地访问(127.0.0.1),否则会导致无法从外部连接到容器。
- ports:端口映射,本机 8000 → 容器 5000。
- env_file:从 .env 文件读取环境变量。
- environment:额外定义的环境变量,在这里我们设置了数据库地址。
- depends_on:表示依赖关系,这里web服务要等到db服务通过了健康检查,才会启动。
Services - db服务(拉取现有的镜像)
db: # 数据库服务(PostgreSQL)
image: postgres:16 # 使用官方 Postgres 16 镜像
restart: unless-stopped # 意外退出时自动重启
environment:
POSTGRES_USER: postgres # 数据库用户名
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} # 从 .env 文件读取密码
POSTGRES_DB: ${POSTGRES_DB} # 默认数据库名
volumes:
- db_data:/var/lib/postgresql/data # 数据持久化,保存到卷 db_data
healthcheck: # 健康检查,保证数据库可用
test: ["CMD-SHELL", "pg_isready -U postgres -d ${POSTGRES_DB}"]
interval: 5s
timeout: 3s
retries: 10
- image:使用构建好的镜像。这里我们固定了版本为16,如果使用latest可能会导致新旧版本的兼容性导致问题。
- restart:容器异常退出后会自动重启。
- environment:POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB 仅在第一次初始化数据目录时生效。之后数据由卷持久化,再改这些变量不会重置已有库。
- volumes:用 命名卷(db_data)作为文件的存储,后面说映射到容器内的存储目录。
- healthcheck:
- CMD-SHELL:表示这条命令会在容器的 shell 里执行(相当于 bash -c)。
- pg_isready:这是 PostgreSQL 自带的一个小工具,用来检测数据库是否可以连接。
- -U postgres:指定用 postgres 这个用户去检测。
- -d ${POSTGRES_DB}:指定要检测的数据库名字(这里我们使用的是变量,会从 .env 文件读取同名的环境变量值)。
数据卷
在 Docker Compose 中,数据卷的定义通常放在最底部的 volumes 字段中。我们可以为每个服务定义一个或多个数据卷,以便在容器之间共享数据或持久化数据。
数据卷无需我们关心文件在机器的存放位置,Docker 会自动处理,而且数据卷也可以方便的在不同的容器之间共享。
volumes:
db_data: # PostgreSQL 的数据卷
而实际上大多数情况是,一些项目需要大家git clone下来,在仓库的路径进行操作,如果我们希望直接把这个目录挂载到容器中,可以在 volumes 中进行配置。
web:
volumes:
- ./app:/app
上面的配置将宿主机的 ./app 目录挂载到容器的 /app 目录中,这样我们就可以在宿主机上直接修改代码,而容器内的应用会直接使用这个路径里的内容,同步改变的内容。
常用的命令
| 命令 | 作用 | 备注 |
|---|---|---|
| docker compose up -d | 后台启动所有服务 | -d 表示 detached 模式,不占用当前终端 |
| docker compose down | 停止并清理容器、网络 | 数据卷默认保留,如果需要一起清理,可以使用docker compose down -v |
| docker compose ps | 查看当前服务运行状态 | 类似 docker ps,但只显示 Compose 管理的容器 |
| docker compose logs -f | 查看日志(实时刷新) | -f 类似 tail -f,适合调试 |
| docker compose exec <服务名> bash | 进入容器内部 | 比如:docker compose exec web bash 进入 web 容器 |
[!tip]
如果只想启动单个服务,可以用
docker compose up -d web来启动。
迁移Docker项目到Docker Compose
接下来我们来尝试一下把现有的Docker项目迁移到Docker Compose,
说白了,其实就是把我们使用的各种参数转换成配置文件中的每一个字段,并且填写进去。
这里附上一份简单的转换表:
| docker run | Compose 字段 | 示例 |
|---|---|---|
| –name app | container_name | container_name: app |
| -p 8080:80 | ports | ports: [“8080:80”] |
| -v host:ctr[:ro] | volumes | volumes: [“app_data:/var/lib/app”] 或 [“./cfg:/etc/app:ro”] |
| -e KEY=VAL | environment / .env | environment: [“KEY=${KEY}”] |
| –env-file .env | env_file | env_file: .env |
| –restart unless-stopped | restart | restart: unless-stopped |
| –network mynet | networks | networks: [“mynet”] |
| –health-cmd … | healthcheck.test | `test: [“CMD-SHELL”,“curl -f http://localhost/health |
| –cpus/–memory | deploy.resources(本地用 deploy 限制有限) | deploy: { resources: { limits: { cpus: “1.0”, memory: “512M”} } } |
| –dns/–add-host | dns / extra_hosts | extra_hosts: [“db.local:10.0.0.5”] |
| –log-driver | logging.driver | logging: { driver: “json-file” } |
我们来看一个示例:
docker run -d --name db \
-p 5432:5432 \
-v pgdata:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=devpassword \
-e POSTGRES_DB=mydb \
--restart unless-stopped \
postgres:16
让我们转换成docker compose的配置文件,便得到了如下结果:
services:
db:
image: postgres:16
container_name: db
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL","pg_isready -U postgres -d ${POSTGRES_DB}"]
interval: 5s
timeout: 3s
retries: 10
ports:
- "5432:5432"
restart: unless-stopped
volumes:
pgdata:
上面我们使用了一些环境变量,在这里我们可以有两种方式使用他们,第一种便是直接写入到配置文件之中,也就是:
environment:
POSTGRES_PASSWORD: devpassword
POSTGRES_DB: mydb
但是这样的话,我们如果把这个配置文件分享给其他人用,或者是上传到Github仓库的时候,那就不是很安全了,所以我们还有第二种方式,也就是上面我使用的方式,我们新建一个.env文件来存储这些变量的值。
.env(与 yml 同目录):
POSTGRES_PASSWORD=devpassword
POSTGRES_DB=mydb
个人技巧
更新镜像以始终保持最新
在使用LobeChat的时候,我希望保持镜像的最新以体验最新的功能,所以在官方脚本的参考下设计了一个更完善的脚本:
此处脚本因为使用了AI进行优化,所以不放出原文,大家可以点击链接查看。
如果需要适配其他服务,只需要修改WORK_DIR和IMAGE_REPO的内容即可,同时IMAGE_TAG可以匹配不同TAG,方便使用。
后记
这篇文章只是简单聊了聊Docker Compose的安装、配置文件和常用命令,并没有涉及到一些更深层的内容和配置,以及容器内部连接等内容,如果想要了解更多,你可以参考官方文档和现有的教程,也可以在下面留言,如果有时间也会写一下文章介绍给大家。