FAQ-18:在 Ubuntu 上安装 Docker Compose
预计阅读时间:14 分钟
📖 目录
问题速查表
| 问题 | 解决章节 |
|---|---|
| 随 Docker Engine 一起安装 Compose 插件(推荐) | 前提条件:安装 Docker Engine |
| 旧版独立二进制安装方式 | 方式二:独立安装 Docker Compose(旧版方式) |
| docker: command not found | 错误一:docker: command not found |
| permission denied while trying to connect to the Docker daemon socket | 错误二:Got permission denied while trying to connect to the Docker daemon socket |
| Cannot connect to the Docker daemon | 错误三:Cannot connect to the Docker daemon at unix:///var/run/docker.sock |
| docker compose up 报端口占用 | 错误四:docker compose up 报端口占用 |
Docker Compose 用于定义和运行多容器 Docker 应用。通过一个 YAML 文件,你可以声明式地配置所有服务、网络和存储卷,然后用一条命令启动整个应用栈。无论是搭建本地开发环境、运行数据库+缓存+Web 服务的组合,还是部署微服务架构,Docker Compose 都是不可或缺的工具。本文涵盖完整的安装流程、版本管理、常见错误排查和最佳实践。
安装方法
前提条件:安装 Docker Engine
Docker Compose 是 Docker Engine 的插件,需要先安装 Docker Engine。
# 移除旧版本(如果存在)
sudo apt remove docker docker-engine docker.io containerd runc
# 安装依赖
sudo apt update
sudo apt install -y ca-certificates curl gnupg
# 添加 Docker 官方 GPG 密钥
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# 添加 Docker 官方仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 更新包索引
sudo apt update
# 安装 Docker Engine + Compose 插件(二合一)
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 将当前用户加入 docker 组(避免每次 sudo)
sudo usermod -aG docker $USER
# 重新登录后生效,或在当前 shell 立即生效
newgrp docker
方式二:独立安装 Docker Compose(旧版方式)
如果你使用的是旧版 Docker Engine 或需要特定版本的 Compose,可以通过 GitHub Releases 下载独立二进制。
# 下载最新版本(以 v2.27.1 为例)
sudo curl -L "https://github.com/docker/compose/releases/download/v2.27.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose
# 验证
docker-compose --version
注意:独立安装的 docker-compose(带连字符)和插件版的 docker compose(空格)是两种调用方式。新项目推荐使用插件版。
方式三:通过 pip 安装(Python 版,已不推荐)
Docker Compose 最初是用 Python 编写的,可以通过 pip 安装。但此方式现已不推荐,仅作为备选方案列出。
# 安装 pip(如果尚未安装)
sudo apt install -y python3-pip
# 安装 Docker Compose
pip3 install docker-compose
# 验证
docker-compose --version
版本管理
Docker Compose 随 Docker Engine 一起更新,通过 APT 安装时会自动获取最新版本。如需锁定版本或手动更新:
# 查看当前版本
docker compose version
# 查看可用版本
apt list -a docker-compose-plugin
# 安装特定版本
sudo apt install -y docker-compose-plugin=2.27.1-1~ubuntu.24.04~noble
# 锁定版本,防止自动更新
sudo apt-mark hold docker-compose-plugin
# 解除锁定
sudo apt-mark unhold docker-compose-plugin
# 更新到最新版本
sudo apt update
sudo apt install -y --only-upgrade docker-compose-plugin
compose.yaml vs docker-compose.yml:Compose V2(插件版)同时识别 compose.yaml、compose.yml、docker-compose.yml 三个文件名,推荐使用 compose.yaml(官方新标准)。旧版独立二进制(docker-compose)只认 docker-compose.yml,迁移时注意。
Compose 常用命令速查
docker compose up -d # 后台启动全部服务(-d 守护)
docker compose ps # 查看服务状态
docker compose logs -f web # 跟踪某服务日志
docker compose logs --tail=100 # 最近 100 行
docker compose exec web bash # 进入运行中容器执行命令
docker compose build # 重新构建镜像
docker compose pull # 拉取最新镜像
docker compose down # 停止并删除容器/网络
docker compose down -v # 连同数据卷一起删除(危险!)
docker compose restart web # 重启单个服务
docker compose config # 校验并展开 compose 文件(排错神器)
docker compose top # 查看各服务进程
依赖与启动顺序:compose 的 depends_on 只保证启动顺序,不保证服务"就绪"(如数据库还没接受连接 Web 就启动了)。生产环境应配合 healthcheck + condition: service_healthy(Compose V2)解决。
常见错误
错误一:docker: command not found
Docker 没有正确安装,或者当前用户不在 docker 组中:
# 检查 Docker 是否安装
which docker
docker --version
# 检查用户是否在 docker 组
groups $USER | grep docker
# 如果不在,加入 docker 组
sudo usermod -aG docker $USER
# 立即生效(无需重新登录)
newgrp docker
错误二:Got permission denied while trying to connect to the Docker daemon socket
Docker 守护进程未运行,或当前用户权限不足:
# 检查 Docker 守护进程状态
systemctl status docker
# 如果未运行,启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
# 确认 docker 组权限
sudo usermod -aG docker $USER
newgrp docker
错误三:Cannot connect to the Docker daemon at unix:///var/run/docker.sock
Docker 服务没有启动,或者配置文件有问题:
# 启动 Docker 服务
sudo systemctl start docker
# 查看 Docker 日志排查原因
sudo journalctl -u docker --no-pager -n 50
# 如果是 socket 文件权限问题:把用户加入 docker 组并重新登录
# (不要 chmod 666 /var/run/docker.sock——等于把 root 权限开放给所有本地用户)
sudo usermod -aG docker $USER
错误四:docker compose up 报端口占用
目标端口已被其他进程占用:
# 查看占用端口的进程
sudo ss -tlnp | grep :8080
# 停止占用进程,或修改 compose.yml 中的端口映射
# 例如将 "8080:80" 改为 "9090:80"
真实案例
案例 A:docker compose 报 unknown command
用户运行 docker compose version 报错 docker: 'compose' is not a docker command,但手册里明明有这条命令。
# 报错
docker: 'compose' is not a docker command.
See 'docker --help'
# 排查:compose 是插件,需确认插件包已安装
docker compose version # 失败
ls /usr/libexec/docker/cli-plugins/ # 目录为空或不存在
# 修复:安装 compose 插件
sudo apt install -y docker-compose-plugin
# 验证
docker compose version # Docker Compose version v2.27.1
根因:旧版 Docker 安装(如用 get.docker.com 脚本但版本过旧)未带 compose 插件,或插件目录缺失;修复:装 docker-compose-plugin;验证:docker compose version 输出版本号。
案例 B:compose 文件 YAML 缩进错误
# 报错
services.web.ports must be a list
services.web.environment must be a mapping
yaml: line 12: mapping values are not allowed in this context
# 错误写法(ports 少了两个空格,缩进到 web 同级)
services:
web:
image: nginx
ports: # ← 错:与 web 同级了,实际应缩进到 image 同级
- "8080:80"
# 正确写法
services:
web:
image: nginx
ports:
- "8080:80"
# 用 config 命令校验(推荐先跑再 up)
docker compose config # 无输出=语法正确;有错误会标出行号
根因:YAML 缩进敏感,端口/环境变量等键必须与服务名同级缩进;预防:编辑器开启 YAML 对齐提示,提交前 docker compose config 校验,CI 中可加 docker compose config --quiet 步骤。
案例 C:容器间通信失败——用 localhost 而非服务名
现象:Web 容器连接数据库容器报 Connection refused,compose.yml 中配置了 links 但仍然失败。
# Web 容器内测试
$ docker exec web curl -s db:5432
curl: (7) Failed to connect to db port 5432: Connection refused
# 错误写法:用 localhost 连接数据库
DATABASE_URL=postgres://localhost:5432/mydb
# 正确写法:用 compose 服务名连接
DATABASE_URL=postgres://db:5432/mydb
根因:Docker Compose 创建的网络中,每个容器可以通过服务名作为 DNS 名称互相访问。localhost 指向容器自身,不是数据库容器。
修复:连接其他容器时使用 compose.yml 中定义的服务名(如 db、redis)而非 localhost。用 docker compose exec web ping db 验证 DNS 解析。
验证安装
# 检查版本
docker --version
docker compose version
# 创建测试目录
mkdir ~/compose-test && cd ~/compose-test
# 创建 compose.yml
cat > compose.yml << 'YAMLEOF'
services:
web:
image: nginx:alpine
ports:
- "8080:80"
YAMLEOF
# 启动服务
docker compose up -d
# 查看运行状态
docker compose ps
# 访问测试
curl http://localhost:8080
# 查看日志
docker compose logs web
# 停止并清理
docker compose down
# 清理测试目录
cd ~ && rm -rf ~/compose-test
案例 D:docker compose down -v 误删生产数据
用户执行 docker compose down -v 清理环境,结果把生产数据库的数据卷也删了,数据全部丢失。
# 危险命令
docker compose down -v # -v 会删除所有 named volumes!
# 排查:查看哪些卷会被删除
docker compose down --dry-run 2>&1 | grep volume
# 或
docker volume ls | grep myproject
# 已删除的卷无法恢复!只能从备份恢复
# 预防措施:使用 docker compose down(不带 -v)
docker compose down # 只删除容器和网络,保留数据卷
# 生产环境备份策略
# 方案一:定期导出数据库
docker exec db pg_dump -U postgres mydb > backup_$(date +%Y%m%d).sql
# 方案二:使用 Docker 卷备份工具
docker run --rm -v myproject_db-data:/data -v $(pwd)/backups:/backup \
alpine tar czf /backup/db-data-$(date +%Y%m%d).tar.gz -C /data .
# 方案三:使用 docker volume inspect 确认卷存在
docker volume inspect myproject_db-data
根因:docker compose down -v 会删除所有 named volumes,包括数据库数据卷;教训:生产环境永远不要使用 -v 参数,定期备份数据卷。
案例 E:docker compose build 失败——COPY 指令找不到文件
Dockerfile 中的 COPY . . 在构建时找不到预期文件,导致构建失败。
# 报错
#8 [2/3] COPY . .
#9 ERROR: failed to solve: failed to compute cache key:
# "/package.json" not found: not found
# 排查:检查 .dockerignore 是否排除了必要文件
cat .dockerignore
# node_modules ← 可能排除了 package.json?检查是否有通配规则
# 检查构建上下文(docker compose build 时的目录)
ls -la package.json
# 文件存在
# 问题:.dockerignore 规则过于宽泛
cat .dockerignore
# * ← 排除了所有文件!
# !src/ ← 只允许 src 目录
# 漏了 !package.json 和 !package-lock.json
# 修复 .dockerignore
cat > .dockerignore << 'EOF'
.git
node_modules
*.md
.env
.env.*
# 不要排除 package.json 和 package-lock.json
EOF
# 验证
docker compose build --no-cache web
根因:.dockerignore 规则排除了构建所需的文件(如 package.json);修复:检查并修正 .dockerignore 规则,确保构建所需文件不被排除;预防:编写 .dockerignore 时明确列出不需要的文件,而非用 * 通配排除所有。
案例 F:docker compose exec 报 "no container found"
执行 docker compose exec web bash 报错 no container found for web_1,但 docker compose ps 显示服务在运行。
# 报错
Error: No container found for web_1
# 排查:docker compose ps 看到的是旧容器
docker compose ps
# NAME STATUS PORTS
# web_1 running 0.0.0.0:8080->80/tcp
# 但容器 ID 可能与 compose 预期不匹配
# 检查容器是否真的在运行
docker ps | grep web
# 可能没有匹配的容器
# 原因:容器在 compose down 后又手动 docker run 启动了
# 或者 compose.yml 修改了服务名导致不匹配
# 修复:重建服务
docker compose up -d --force-recreate web
docker compose exec web bash # 成功
# 如果是服务名变更
docker compose down
docker compose up -d # 使用新的 compose.yml
根因:compose 管理的容器与实际运行的容器不匹配(可能是手动操作或配置变更导致);修复:docker compose up -d --force-recreate 强制重建容器。
版本管理详解
Docker Compose V1 vs V2 对比
# V1(旧版,已废弃)
# 命令:docker-compose(带连字符)
# 语言:Python
# 安装:独立二进制或 pip
# 已于 2023 年 6 月停止维护
# V2(当前版本)
# 命令:docker compose(空格,作为 Docker CLI 插件)
# 语言:Go
# 安装:随 Docker Engine 一起安装
# 检查当前版本
docker compose version # V2
docker-compose --version # V1(如果存在)
# V1 → V2 迁移
# 1. 安装 V2 插件
sudo apt install -y docker-compose-plugin
# 2. 替换脚本中的命令
# 旧:docker-compose up -d
# 新:docker compose up -d
# 3. 更新 CI/CD 脚本
# 旧:docker-compose -f prod.yml up -d
# 新:docker compose -f prod.yml up -d
# 4. 如果使用 V1 的 .env 文件,V2 兼容
# 但 V2 推荐使用 compose.yml 而非 docker-compose.yml
compose.yaml 版本声明
# V2 不再需要 version 字段(已废弃)
# 旧写法(V1 兼容)
# version: "3.8"
services:
web:
image: nginx
# 新写法(V2 推荐,省略 version)
services:
web:
image: nginx
# compose 文件 schema 校验
docker compose config # 无输出=语法正确
docker compose config --quiet # 静默模式,只检查语法
# 多文件合并(环境区分)
# 基础配置
cat > compose.yml << 'EOF'
services:
web:
image: nginx
db:
image: postgres:16
EOF
# 开发环境覆盖
cat > compose.override.yml << 'EOF'
services:
web:
volumes:
- ./src:/usr/share/nginx/html
ports:
- "8080:80"
EOF
# 生产环境覆盖
cat > compose.prod.yml << 'EOF'
services:
web:
restart: always
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
EOF
# 启动
docker compose up -d # 开发(自动合并 override)
docker compose -f compose.yml -f compose.prod.yml up -d # 生产
环境变量管理最佳实践
# 方案一:.env 文件(推荐)
cat > .env << 'EOF'
POSTGRES_PASSWORD=secretpassword
POSTGRES_DB=myapp
REDIS_PASSWORD=redissecret
EOF
# compose.yml 中引用
cat > compose.yml << 'EOF'
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- db-data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
EOF
# 方案二:env_file 指定文件
cat > compose.yml << 'EOF'
services:
db:
image: postgres:16
env_file:
- ./config/db.env
EOF
# 方案三:Docker secrets(生产环境推荐)
cat > compose.yml << 'EOF'
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
EOF
# 重要:.env 和 secrets 文件加入 .gitignore
echo ".env" >> .gitignore
echo "secrets/" >> .gitignore
echo "*.env" >> .gitignore
故障排查决策树
当 Docker Compose 出现问题时,按以下流程排查:
问题:docker: command not found
├── which docker 有输出?
│ ├── 是 → 检查用户权限:groups $USER | grep docker
│ │ ├── 有 docker 组 → 检查 Docker 守护进程:systemctl status docker
│ │ └── 无 docker 组 → sudo usermod -aG docker $USER && newgrp docker
│ └── 否 → Docker 未安装
│ └── 安装:curl -fsSL https://get.docker.com | sh
问题:docker compose 报 unknown command
├── docker compose version 有输出?
│ ├── 有 → 命令正确,检查拼写
│ └── 无 → compose 插件未安装
│ └── sudo apt install -y docker-compose-plugin
问题:permission denied 连接 Docker daemon
├── Docker 守护进程运行中?systemctl status docker
│ ├── 未运行 → sudo systemctl start docker
│ └── 运行中 → 检查 docker 组
│ ├── 用户在 docker 组 → 检查 /var/run/docker.sock 权限
│ └── 不在 → sudo usermod -aG docker $USER && newgrp docker
问题:Cannot connect to Docker daemon
├── 检查 Docker 服务状态:systemctl status docker
│ ├── 未运行 → sudo systemctl start docker
│ └── 运行中 → 查看日志:journalctl -u docker --no-pager -n 50
├── 检查 daemon.json 配置
│ └── cat /etc/docker/daemon.json
├── 检查磁盘空间:df -h
│ └── 空间不足 → docker system prune -a
└── 检查内核版本:uname -r
└── 内核过旧 → 升级内核
问题:docker compose up 报端口占用
├── ss -tlnp | grep :
│ ├── 有进程占用 → 停止占用进程或修改 compose.yml 端口映射
│ └── 无进程 → 可能是 TIME_WAIT 状态
│ └── 等待或修改为其他端口
└── docker compose ps 检查服务状态
问题:容器启动后立即退出
├── docker compose logs 查看日志
├── 检查 Dockerfile 中的 CMD/ENTRYPOINT
├── 检查环境变量是否正确
├── 检查挂载的文件/目录是否存在
└── docker compose up --abort-on-container-exit 查看退出码
问题:镜像拉取失败
├── 检查网络:docker pull hello-world
│ ├── 成功 → 镜像名/标签错误
│ └── 失败 → 配置镜像加速器
│ └── /etc/docker/daemon.json 添加 registry-mirrors
├── 检查 Docker Hub 限制
│ └── 登录:docker login
└── 使用国内镜像仓库
└── 阿里云/腾讯云容器镜像服务
生产环境配置建议
- 使用 compose.yml + compose.prod.yml 分离配置:基础配置放
compose.yml,生产覆盖放compose.prod.yml,通过-f参数合并加载。 - 设置 restart: always:生产服务应设置自动重启策略,容器崩溃后自动恢复。
- 配置日志轮转:默认 JSON 文件日志驱动会无限增长,需配置
max-size和max-file限制日志大小。 - 使用 healthcheck 确保服务就绪:
depends_on只保证启动顺序,不保证服务就绪。配合healthcheck+condition: service_healthy解决。 - 数据持久化使用 named volumes:数据库等有状态服务必须使用 named volumes,不要使用 bind mount。
- 限制容器资源:使用
deploy.resources.limits限制 CPU 和内存,防止某个容器耗尽宿主机资源。 - 定期更新基础镜像:使用
docker compose pull拉取最新镜像,配合docker compose up -d --force-recreate更新服务。 - 使用 docker compose profiles 区分环境:开发工具(如调试器、数据库 GUI)放在 dev profile,生产环境只启动必要服务。
最佳实践
- 使用 compose.yml 而非 docker-compose.yml:Docker Compose V2 默认识别
compose.yml,旧版的docker-compose.yml仍然支持,但新项目建议使用新命名。 - 使用 .env 文件管理环境变量:将敏感信息(如数据库密码)放在
.env文件中,并加入.gitignore,避免提交到版本库。 - 善用 docker compose profiles:通过 profiles 区分开发环境和生产环境的服务,只启动需要的服务。
- 定期清理无用容器和镜像:
docker system prune -a可以清理所有停止的容器、无用的网络和悬空镜像,释放磁盘空间。 - 使用 depends_on 管理启动顺序:在多服务场景中,用
depends_on确保数据库等基础设施先于应用启动。
延伸阅读
- 3.1:Docker 容器入门 Docker 容器入门——镜像、容器、Dockerfile
- 5.2:Docker 生产实践 Docker 生产实践——多阶段构建、健康检查
- 6.2:Kubernetes 入门 Kubernetes 入门——从 Compose 迁移到 K8s
案例 G:docker compose profiles 未启用导致服务未启动
现象:compose.yml 中定义了 profiles,执行 docker compose up -d 后某些服务未启动:
# compose.yml
services:
web:
image: nginx
ports:
- "8080:80"
debug:
image: busybox
profiles:
- debug
# 启动后检查
$ docker compose ps
NAME STATUS PORTS
web_1 running 0.0.0.0:8080->80/tcp
# debug 服务未启动
根因:Docker Compose V2 的 profiles 功能允许按环境区分服务。未指定 profile 的服务会自动启动,但指定了 profile 的服务需要显式启用。
修复:
# 启用 debug profile
docker compose --profile debug up -d
# 或在 .env 文件中配置默认 profile
echo "COMPOSE_PROFILES=debug" >> .env
docker compose up -d
# 查看所有服务(包括未启动的)
docker compose ps -a
预防:在 compose.yml 中为可选服务添加 profiles 注释说明。团队文档中记录各环境需要启用的 profiles。
↑ 回到顶部