4、Docker Compose核心概念:服务、项目、配置文件结构、常用指令、与docker run的区别

在完成单容器镜像构建与运行之后,编排层成为边缘AI推理落地中承上启下的关键环节。边缘节点往往同时承载视频流接入、模型推理、结果上报、日志采集等多个进程,若继续依赖逐条 docker run 命令,不仅启动顺序难以保证,环境变量与网络配置也极易漂移。Docker Compose 通过声明式 YAML 文件将多容器组织为“项目”,以“服务”为最小调度单元,为边缘AI推理提供可版本化、可复现的部署范式。本章将围绕服务、项目、配置文件结构、常用指令以及与 docker run 的差异展开,帮助你在边缘网关或工控机上建立标准化的推理服务编排能力。

docker run 命令 docker-compose.yml Compose 项目 docker run -d --name cam1 -p 8080:8080 ai-camera docker run -d --name infer --link cam1 ai-infer docker run -d --name mqtt -v /data:/data mqtt-broker 手动管理启动顺序 手动配置网络/卷 无法版本化 services: camera: build: ./camera ports: ["8080:8080"] inference: image: ai-infer:1.2 depends_on: [camera] mqtt: image: mqtt-broker 声明式定义 可版本化/可审计 自动处理依赖 项目名: edge-ai (目录名) 网络: edge-ai_default (自动创建) 卷: edge-ai_data (命名卷) 统一生命周期 docker compose up/down 一键启停/伸缩

上图展示了从命令式 docker run 到声明式 Compose 的演进路径:左侧是分散的容器启动命令,中间是统一的 YAML 描述文件,右侧是 Compose 根据文件自动生成的项目级资源(网络、卷、服务组)。理解这一映射关系,是掌握 Compose 编排思维的第一步。

4.1 服务(Service)与项目(Project)的核心原理

服务是 Compose 中最基本的部署单元,对应一个容器镜像及其运行时配置。在边缘AI推理场景中,一个服务通常代表一个逻辑功能模块,例如 camera-grabber(视频采集)、yolo-inference(模型推理)、mqtt-publisher(结果上报)。每个服务可以指定镜像、构建上下文、环境变量、端口映射、卷挂载、资源限制、健康检查等属性。服务之间通过 depends_on 声明启动依赖,但需要注意:depends_on 仅控制启动顺序,不等待服务内部就绪,因此对于推理服务依赖数据库或消息队列的场景,需要配合健康检查或等待脚本。

项目是 Compose 对一组关联服务的逻辑封装,默认以 docker-compose.yml 所在目录名命名。项目名称决定了容器、网络、卷等资源的前缀,例如项目名为 edge-ai,则自动创建的网络名为 edge-ai_default,卷名为 edge-ai_data。这种命名隔离机制允许多个项目在同一台边缘主机上共存而不互相干扰。在边缘AI场景中,建议将同一路视频流或同一推理任务的所有服务放入一个项目,便于统一启停与日志查看。

关键理解:服务是“做什么”的定义,项目是“一组服务如何组织”的边界。在边缘节点上,一个项目通常对应一个业务单元(如“车间A的缺陷检测”),而不同业务单元之间通过项目名隔离网络和存储。

4.2 配置文件结构:docker-compose.yml 的层次化解析

Compose 文件采用 YAML 语法,顶层包含 version(现代版本已弱化,但建议保留)、services、networks、volumes、configs 等关键字段。以下是一个面向边缘AI推理的典型配置结构:

version: "3.8"
services:
  camera:
    image: edge-camera:1.0
    environment:
      - CAMERA_ID=front-gate
      - RTSP_URL=rtsp://192.168.1.64:554/stream1
    volumes:
      - ./config/camera.yaml:/app/config.yaml:ro
    restart: unless-stopped
    networks:
      - edge-net

  inference:
    image: edge-yolo:2.1
    depends_on:
      - camera
    environment:
      - MODEL_PATH=/models/yolov5s.onnx
      - DEVICE=GPU
    deploy:
      resources:
        limits:
          memory: 2G
          cpus: "2.0"
    volumes:
      - model-cache:/models/cache
    ports:
      - "8080:8080"
    networks:
      - edge-net

  mqtt:
    image: eclipse-mosquitto:2.0
    ports:
      - "1883:1883"
    volumes:
      - mqtt-data:/mosquitto/data
    networks:
      - edge-net

networks:
  edge-net:
    driver: bridge

volumes:
  model-cache:
  mqtt-data:

该配置中,camera 服务负责拉取 RTSP 视频流,inference 服务执行 YOLO 推理并通过 8080 端口提供 HTTP API,mqtt 服务作为消息总线接收推理结果。三个服务共享 edge-net 网络,通过服务名互相访问(例如 http://inference:8080),无需关心 IP 地址变化。

配置层级关键字段边缘AI场景说明
顶层version, services, networks, volumes定义项目全局资源
服务级image/build, environment, volumes, ports定义单个容器的运行参数
依赖级depends_on, healthcheck, restart控制启动顺序与故障恢复
资源级deploy.resources.limits限制推理服务的内存/CPU占用
网络级networks, aliases, driver定义服务间通信方式

4.3 常用指令:从启动到排障的完整操作链

Compose 指令覆盖了项目全生命周期。在边缘AI推理的日常运维中,以下指令使用频率最高:

  • docker compose up -d:后台启动所有服务,首次执行会构建镜像并创建网络/卷。
  • docker compose ps:查看项目内所有服务的运行状态、端口映射、健康状态。
  • docker compose logs -f inference:跟踪指定服务的日志输出,用于排查推理异常。
  • docker compose exec inference bash:进入运行中的容器,执行调试命令(如查看模型加载日志)。
  • docker compose down:停止并删除所有服务容器,但默认保留卷数据。
  • docker compose down -v:连同命名卷一起删除,慎用于生产环境。
  • docker compose config:校验配置文件语法并输出最终生效的配置。
经验提醒:在边缘节点上执行 docker compose up -d 后,建议立即执行 docker compose ps 确认所有服务进入 Up 状态。若某个服务反复重启,使用 docker compose logs --tail=50 <service> 查看最近50行日志,通常能快速定位镜像拉取失败、端口冲突或环境变量缺失等问题。

4.4 与 docker run 的对比:从命令到声明式

docker run 是单容器操作的命令式工具,而 Compose 是面向多容器协作的声明式工具。两者并非替代关系,而是抽象层次不同。下表从多个维度进行对比:

对比维度docker rundocker compose
操作对象单个容器一组服务(项目)
配置方式命令行参数,易遗漏YAML 文件,可版本化
网络管理需手动创建/连接网络自动创建项目网络
启动顺序手动控制,易出错depends_on 自动排序
扩展性不支持服务伸缩支持 docker compose up --scale
适用场景临时调试、单容器运行边缘AI多模块协同、生产部署

在边缘AI推理中,docker run 适合快速验证单个模型镜像是否正常,而 Compose 适合将采集、推理、上报、监控等模块打包为可交付的解决方案。例如,当需要将推理服务部署到10台边缘网关时,只需复制 docker-compose.yml 并修改环境变量即可,无需逐台执行长串命令。

4.5 案例拆解:边缘视频流推理服务的 Compose 编排

某工厂部署了一套边缘AI安全帽检测系统,边缘网关配置为 8 核 CPU、16GB 内存、无 GPU。初始阶段使用 docker run 启动三个容器:视频拉流(ffmpeg)、推理(TensorFlow Lite)、结果上报(MQTT)。运行一周后暴露三个问题:

  1. 网关重启后需手动按顺序启动容器,且经常忘记先启动 MQTT 导致推理服务报错。
  2. 三个容器使用默认 bridge 网络,IP 地址不固定,推理服务无法稳定连接视频拉流容器。
  3. 日志分散在三个容器中,排查问题需要分别执行 docker logs。

改用 Compose 后,编写 docker-compose.yml 将三个服务纳入同一项目,并增加健康检查与资源限制。关键配置如下:

services:
  video-grabber:
    image: ffmpeg-rtsp:latest
    command: ["-i", "rtsp://admin:pass@192.168.1.20:554/stream", "-f", "mpegts", "tcp://inference:5000"]
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "pgrep", "ffmpeg"]
      interval: 30s
      timeout: 5s
      retries: 3

  inference:
    image: tflite-detector:2.0
    depends_on:
      video-grabber:
        condition: service_healthy
    environment:
      - MODEL=/models/helmet.tflite
      - CONF_THRESH=0.5
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: "4"
    ports:
      - "8080:8080"
    restart: unless-stopped

  mqtt-broker:
    image: eclipse-mosquitto:2.0
    ports:
      - "1883:1883"
    restart: unless-stopped

改造后,网关重启时只需执行 docker compose up -d,Compose 会先启动 MQTT 和视频拉流,待视频拉流健康检查通过后再启动推理服务。同时,三个容器自动加入同一网络,通过服务名 inference 和 video-grabber 互相访问,彻底解决了 IP 漂移问题。日志可通过 docker compose logs -f 统一查看,排障效率显著提升。

风险提示:在边缘设备上使用 depends_on 的 condition: service_healthy 时,务必确保健康检查命令在容器内可用(如 pgrep 需要 procps 包)。若基础镜像未包含该命令,健康检查会一直失败,导致后续服务无法启动。建议在 Dockerfile 中显式安装或改用 curl 探测 HTTP 端点。

4.6 常见误区与总结复盘

在 Compose 编排边缘AI服务时,以下误区需要特别警惕:

  • 误区一:将 depends_on 当作服务就绪等待。实际上它只保证启动顺序,不保证服务可用。对于推理服务依赖模型加载完成的场景,应使用健康检查或应用层重试机制。
  • 误区二:在 docker-compose.yml 中硬编码 IP 地址。边缘网络环境多变,应使用服务名进行服务间通信,由 Compose 内置 DNS 解析。
  • 误区三:忽略 restart 策略。边缘网关可能频繁断电重启,未设置 restart: unless-stopped 的服务在重启后不会自动恢复,导致推理链路中断。
  • 误区四:将所有数据都放入容器可写层。推理模型、日志、配置应通过卷挂载持久化,否则容器重建后数据丢失。