Docker Compose中三个Python容器脚本运行混淆问题排查
问题描述
目录结构:
python_tools/ ├─ scriptA/ │ ├─ main.py │ └─ requirements.txt ├─ scriptB/ │ ├─ main.py │ └─ requirements.txt ├─ scriptC/ │ ├─ main.py │ └─ requirements.txt ├─ logs/ │ ├─ scriptA/ │ ├─ scriptB/ │ └─ scriptC/ ├─ docker-compose.yml ├─ Dockerfile.scriptA ├─ Dockerfile.scriptB └─ Dockerfile.scriptC
原docker-compose.yml配置:
version: "3.1" services: scriptA: image: python:3.9 volumes: - ./python_tools/logs/scriptA:/opt/app/scriptA/log build: context: . dockerfile: Dockerfile.scriptA scriptB: image: python:3.9 volumes: - ./python_tools/logs/scriptB:/opt/app/scriptB/log build: context: . dockerfile: Dockerfile.scriptB scriptC: image: python:3.9 volumes: - ./python_tools/logs/scriptC:/opt/app/scriptC/log build: context: . dockerfile: Dockerfile.scriptC
每个Dockerfile.scriptX内容:
FROM python:3.9 COPY ./python_tools/scriptX /opt/app/scriptX WORKDIR /opt/app/scriptX RUN pip install -r requirements.txt ENTRYPOINT [ "python", "-u", "main.py" ]
main.py代码:
def log(msg): print(msg) f = open("log/log.txt", "a+") f.write(msg + "\r\n") f.close() if __name__ == "__main__": log("Starting scriptX") while(True): do_something()
遇到的问题:
- 执行
docker logs -f python_scriptB-1时,输出的是scriptA的启动日志,同时报错找不到log文件 - 执行
docker compose build --no-cache时,重复构建scriptA,未按预期构建三个独立服务
问题原因分析
- 镜像名称冲突:三个服务都指定了相同的
image: python:3.9,Docker Compose会将这三个服务关联到同一个镜像。构建时会重复使用第一个服务的构建结果,导致三个服务实际运行的都是scriptA的镜像内容,所以日志串线,且路径不匹配引发文件找不到的错误。 - 日志目录权限/路径问题:若宿主机器上的
python_tools/logs/scriptX目录不存在,Docker会自动创建该目录,但默认是root权限;同时由于镜像串用,scriptB容器实际运行的是scriptA代码,尝试写入的路径与挂载的scriptB日志目录不匹配,双重因素触发找不到文件的错误。
优化后的配置方案
方案1:简化配置,使用唯一镜像名+子目录上下文
修改docker-compose.yml,给每个服务指定唯一镜像名,并将build的context指向对应子目录,减少冗余:
version: "3.8" services: scriptA: image: script-a:latest volumes: - ./python_tools/logs/scriptA:/opt/app/log build: context: ./python_tools/scriptA dockerfile: ../../Dockerfile.script restart: unless-stopped scriptB: image: script-b:latest volumes: - ./python_tools/logs/scriptB:/opt/app/log build: context: ./python_tools/scriptB dockerfile: ../../Dockerfile.script restart: unless-stopped scriptC: image: script-c:latest volumes: - ./python_tools/logs/scriptC:/opt/app/log build: context: ./python_tools/scriptC dockerfile: ../../Dockerfile.script restart: unless-stopped
将三个Dockerfile合并为一个通用的Dockerfile.script:
FROM python:3.9 # 创建工作目录并设置日志目录权限 WORKDIR /opt/app RUN mkdir -p log && chmod 777 log # 复制当前子目录的代码(context已指向scriptX目录) COPY . . # 安装依赖 RUN pip install --no-cache-dir -r requirements.txt # 非root用户运行(可选,提升安全性) RUN useradd -m appuser USER appuser ENTRYPOINT ["python", "-u", "main.py"]
修改main.py中的日志路径(对应挂载的/opt/app/log):
def log(msg): print(msg) with open("log/log.txt", "a+") as f: f.write(msg + "\n") if __name__ == "__main__": log("Starting scriptX") while True: # 替换为实际业务逻辑 do_something()
方案2:使用Docker Compose模板减少重复配置
如果需要保留独立Dockerfile,可使用YAML锚点简化配置:
version: "3.8" x-base-script: &base-script restart: unless-stopped build: context: . services: scriptA: <<: *base-script image: script-a:latest volumes: - ./python_tools/logs/scriptA:/opt/app/scriptA/log build: dockerfile: Dockerfile.scriptA scriptB: <<: *base-script image: script-b:latest volumes: - ./python_tools/logs/scriptB:/opt/app/scriptB/log build: dockerfile: Dockerfile.scriptB scriptC: <<: *base-script image: script-c:latest volumes: - ./python_tools/logs/scriptC:/opt/app/scriptC/log build: dockerfile: Dockerfile.scriptC
关键注意事项
- 每个服务必须指定唯一的镜像名称,避免Docker Compose混淆镜像来源
- 提前创建宿主机器上的日志目录,或在Dockerfile中创建容器内的日志目录并设置合理权限
- 使用
with open替代直接open/close,确保文件句柄正确释放 - 尽量使用非root用户运行容器,提升安全性
内容的提问来源于stack exchange,提问作者Mart
相关产品推荐
相关产品推荐

