You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用docker-compose从源码构建多服务并生成单一镜像?

问题描述

我正在为名为controller的Python/Django应用创建多个容器,希望Django、Celery(worker、beat、flower)这些服务基于单一镜像运行,而非多个。当前docker-compose.yml从源码构建两个服务,生成两个独立镜像。应用包含5个服务:Django项目、Celery(worker、beat、flower)以及Redis。

我尝试把redis服务的image: controller-redis改成image: controller,虽然生成了单一镜像,但多数服务启动失败,提示文件未找到:

错误日志

$ docker-compose logs -f
controller-celery_beat-1    | /usr/local/bin/docker-entrypoint.sh: 24: exec: /start-celerybeat: not found
controller-django-1         | /usr/local/bin/docker-entrypoint.sh: 24: exec: /start: not found
controller-flower-1         | /usr/local/bin/docker-entrypoint.sh: 24: exec: /start-flower: not found
[...]
controller-celery_worker-1  | /usr/local/bin/docker-entrypoint.sh: 24: exec: /start-celeryworker: not found

容器状态

$ docker-compose ps
NAME                         COMMAND                  SERVICE             STATUS              PORTS
controller-celery_beat-1     "docker-entrypoint.s…"   celery_beat         exited (127)        
controller-celery_worker-1   "docker-entrypoint.s…"   celery_worker       exited (127)        
controller-django-1          "docker-entrypoint.s…"   django              exited (127)        
controller-flower-1          "docker-entrypoint.s…"   flower              exited (127)        
controller-redis-1           "docker-entrypoint.s…"   redis               running             6378-6379/tcp
错误原因

你错误地将Redis服务的镜像设置为和Django服务相同的controller,但Redis的Dockerfile是基于官方Redis镜像构建的,这个镜像里根本没有/start、/start-celeryworker等启动脚本——这些脚本只存在于基于Python镜像构建的Django镜像中。当Redis服务构建时,它覆盖了原来的controller镜像,导致其他依赖该镜像的服务找不到启动脚本,从而启动失败。

另外,Celery相关服务的volumes配置有误:- .:/app:/controller是错误的挂载方式,会把本地目录同时挂载到容器的/app和/controller,导致目录结构混乱;同时depends_on里写的controller是镜像名,不是服务名,应该依赖django服务。

正确配置方案

Redis是独立的数据库服务,不能和Python/Django服务共用同一个镜像(两者基础镜像完全不同,运行环境、依赖都不一样)。正确的做法是:让Django、Celery worker/beat/flower共用基于Python构建的controller镜像,Redis服务使用独立的镜像(可以是官方Redis镜像,也可以用你自定义的Redis Dockerfile构建独立镜像)。

修改后的docker-compose.yml

version: '3.8'

services:
  django:
    build:
      context: .
      dockerfile: ./compose/local/django/Dockerfile
    image: controller
    command: /start
    volumes:
      - .:/app
    ports:
      - "8001:8001"
    env_file:
      - controller/.env
    depends_on:
      - redis
    networks:
      - mynetwork

  redis:
    # 方案1:直接使用官方Redis镜像,不需要自己构建
    # image: redis:latest
    # 方案2:保留你自定义的Redis Dockerfile,构建独立镜像
    build:
      context: .
      dockerfile: ./compose/local/redis/Dockerfile
    image: controller-redis
    expose:
      - "6378"
    networks:
      - mynetwork

  celery_worker:
    image: controller
    command: /start-celeryworker
    volumes:
      - .:/app  # 修正挂载路径,和Django服务一致
    env_file:
      - controller/.env
    depends_on:
      - redis
      - django  # 修正为服务名,不是镜像名
    networks:
      - mynetwork

  celery_beat:
    image: controller
    command: /start-celerybeat
    volumes:
      - .:/app
    env_file:
      - controller/.env
    depends_on:
      - redis
      - django
    networks:
      - mynetwork

  flower:
    image: controller
    command: /start-flower
    volumes:
      - .:/app
    env_file:
      - controller/.env
    depends_on:
      - redis
      - django
    networks:
      - mynetwork

networks:
  mynetwork:
    name: mynetwork

关键修改点说明

  1. Redis服务恢复独立镜像:要么用官方Redis镜像,要么保留自定义Dockerfile构建独立的controller-redis镜像,避免覆盖Django的controller镜像。
  2. 修正Celery服务的挂载路径:把错误的- .:/app:/controller改成- .:/app,和Django服务保持一致,确保容器内的/app目录正确映射本地项目文件。
  3. 修正依赖配置:将depends_on中的controller改为服务名django,确保Celery服务在Django服务启动后再尝试启动。
验证方法

执行以下命令重新构建并启动服务:

# 先清理旧镜像和容器
docker-compose down -v
# 重新构建并启动
docker-compose up --build

此时Django、Celery worker/beat/flower都会基于同一个controller镜像启动,Redis则使用独立镜像,所有服务应该能正常运行。

内容的提问来源于stack exchange,提问作者Florent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 04:30:30