前后端一把拉起:Docker Compose 编排告别手动起服务

举报
海是岛思念的泪 发表于 2026/10/16 21:37:22 2026/10/16
【摘要】 用 Docker Compose 编排多容器前后端小项目:services 定义、服务名互通(compose 内置 DNS)、depends_on 定序、卷持久化,一条 up 全起。讲清 depends_on 只管启动不管就绪、反代写服务名不写 localhost、端口/密码等坑。

一、背景:手动起服务,环境一换就抓瞎
本文把"多容器小项目"用 compose 编排讲透:服务怎么定义、容器间怎么互通、数据怎么持久化、常见坑。它和 27 篇是递进——27 讲"怎么把单个服务容器化",这篇讲"多个服务怎么一起管"。

二、一个典型的多服务 compose

假设项目有前端、后端、再加一个数据库(演示用):

services:
  db:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: "devpass"
      MYSQL_DATABASE: "app"
    volumes:
      - db-data:/var/lib/mysql        # 数据持久化
    ports: ["3306:3306"]

  backend:
    build: ./backend
    environment:
      DB_HOST: db                       # 用服务名当主机名
    depends_on: [db]
    ports: ["3000:3000"]

  frontend:
    build: ./frontend
    depends_on: [backend]
    ports: ["8080:80"]
    # 前端 Nginx 反代 /api -> http://backend:3000

volumes:
  db-data:

三个 services:db / backend / frontend。depends_on 表达启动顺序(先 db、再 backend、再 frontend)。容器间通信用服务名当主机名——backend 连数据库填 DB_HOST: db、compose 内置 DNS 把 db 解析到 db 容器,不用写 IP。volumes 把 MySQL 数据目录挂到命名卷 db-data,容器重建数据不丢。前端 Nginx 反代 backend:3000(服务名),和 27 篇一致。

三、为什么用服务名就能互通

手动 docker run 多个容器时,容器 IP 是随机的、重启还变,互相连极麻烦。Compose 给同一文件里的服务建了一个用户自定义网络,服务名就是这个网络里的主机名。所以 backend 容器里 mysql -h db 能连上 db 容器,frontend 的 Nginx proxy_pass http://backend:3000 也能解析——全靠 compose 的网络和 DNS,你不用管 IP、不用 --link。这是 compose 相比裸 docker run 最大的省心事之一。

四、数据持久化:卷是关键

容器本身是"用完可弃"的,里面写的任何东西容器一删就没。数据库、用户上传这类要留的数据,必须用**卷(volume)或绑定挂载(bind mount)**挂出来:

  • volumes: db-data:/var/lib/mysql:命名卷,由 Docker 管理,适合数据库数据;
  • ./uploads:/app/uploads:绑定挂载,把宿主机目录挂进容器,适合开发时实时看文件、或用户上传要落到宿主机。

演示里 db 用命名卷,重启 compose down 后数据还在(down 默认不清卷;down -v 才连卷一起删,慎用)。不挂卷的容器(如 frontend 静态文件,构建进镜像的)重启就重置,那是预期。关键数据务必挂卷,否则"容器一重建、库空了"。

五、常用命令与开发流程

docker compose up -d --build     # 构建并后台启动全部
docker compose ps                # 看各服务状态
docker compose logs backend      # 看某个服务日志
docker compose down              # 停止并删容器(默认留卷)
docker compose restart backend   # 只重启后端

up -d --build 一次起全部,-d 后台、--build 重新构建镜像(改了代码要加)。logs <服务> 单独看某服务日志,排查哪挂了。down 停服,down -v 才删卷(清数据)。开发时改代码 → up --build 或 restart,流程固定、不用记一堆 run 参数。具体命令以 Docker 官方文档为准。

六、几个容易踩的坑

第一,depends_on 只管启动顺序、不管就绪。backend depends_on: [db] 只保证"db 容器先启动",不保证"MySQL 已经能接受连接"。如果 backend 起来立刻连 db,可能连不上(MySQL 还在初始化)。生产要解决"等待就绪"(如 backend 加重连逻辑、或用 depends_on 的 condition: service_healthy 健康检查,以文档为准),别假设 depends_on 等于"依赖已可用"。

第二,端口冲突。宿主机 3306/3000/8080 若本机已占用(如本机已跑着 MySQL),compose 映射会失败。开发环境常用不同宿主机端口(如 3307:3306),或确保本机没占。端口映射 宿主机:容器,冲突的是宿主机侧。

第三,.env 与密码。compose 里 MYSQL_ROOT_PASSWORD: "devpass" 明文写在文件里、还提交了仓库,是隐患。用 .env 文件 + ${DB_PASS} 引用、.env 不提交,或接密钥管理。开发用弱密码可接受,生产务必走环境变量/凭据,别硬编码。

第四,构建上下文与 .dockerignore。每个 build: ./backend 把该目录作构建上下文,务必在子目录放 .dockerignore 排除 node_modules/.git,否则构建慢、还可能把本机依赖带进镜像导致跨平台跑不起来(见 27 篇)。

第五,前端反代地址。前端容器里反代填的是服务名 backend:3000(容器内网络),不是 localhost——localhost 在 frontend 容器里指的是 frontend 自己,连不到 backend。这个"容器内 localhost ≠ 宿主机 localhost"的坑,新手必踩一次。

七、小结

Docker Compose 把"多容器小项目"从一堆 docker run 参数变成一份 docker-compose.yml:服务定义、用服务名互通(compose 内置网络 DNS)、depends_on 定顺序、卷做数据持久化,一条 up 全起。重点是——容器间用服务名当主机名(不是 localhost/IP)、关键数据挂卷(命名卷/绑定挂载)、depends_on 只管启动顺序不管就绪(就绪要靠重连或健康检查)。端口冲突、明文密码、反代写 localhost 是三个高频坑。Docker Compose 语法与命令以官方文档为准。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。