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

指定Docker Compose卷后为何无法找到uvicorn?

FastAPI开发环境Docker Compose自动重启问题解决

问题背景

我基于多阶段构建做了一个优化后的FastAPI镜像(最终大小170MB),Dockerfile代码如下:

# The builder image, used to build the virtual environment
FROM python:3.11-bullseye as builder

# Install package manager
RUN pip install poetry==1.7.1

# Define environment
ENV POETRY_NO_INTERACTION=1 \
    POETRY_VIRTUALENVS_IN_PROJECT=1 \
    POETRY_VIRTUALENVS_CREATE=1 \
    POETRY_CACHE_DIR=/tmp/poetry_cache

# Set work directory
WORKDIR /app

# Copy project dependencies
COPY pyproject.toml poetry.lock ./
# Install production dependencies only and remove poetry cache directory
RUN poetry install --without dev --no-root && rm -rf $POETRY_CACHE_DIR

# The runtime image, used to run the service
FROM python:3.11-slim-bullseye as runtime

# Set virtual environment path and add it to the system Path
ENV VIRTUAL_ENV=/app/.venv \
    PATH="/app/.venv/bin:$PATH"

# Copy project dependencies from builder stage
COPY --from=builder ${VIRTUAL_ENV} ${VIRTUAL_ENV}

# Copy project code
COPY app/ /app/

# Run service
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]

未挂载本地代码卷时,docker compose up能正常启动FastAPI服务。但为了实现代码变更自动重启,我给Compose添加了本地代码挂载,修改后的compose.yaml如下:

services:
  api:
    image: pws
    build:
      context: .
      dockerfile: Dockerfile
    restart: on-failure
    ports:
      - "80:80"
    volumes:
      - ./app/:/app/
    command: ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--reload"]

添加挂载后启动报错,错误信息:

Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "uvicorn": executable file not found in $PATH: unknown

错误原因

挂载./app/:/app/时,本地的app目录会完全覆盖容器内的/app目录。而容器里的uvicorn是安装在/app/.venv虚拟环境中的,本地项目的app目录里并没有这个.venv文件夹,导致系统找不到uvicorn可执行文件。

解决方案

方案1:调整挂载路径,保留容器内的虚拟环境

修改Compose的volumes配置,把本地./app挂载到容器内的/app/app,而不是直接覆盖/app:

services:
  api:
    image: pws
    build:
      context: .
      dockerfile: Dockerfile
    restart: on-failure
    ports:
      - "80:80"
    volumes:
      # 挂载本地代码到容器的/app/app,保留/app下的.venv虚拟环境
      - ./app/:/app/app/
    command: ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--reload"]

容器内的项目结构原本就是/app/app/main.py,这样挂载后既可以实时同步本地代码变更,又不会破坏虚拟环境的路径,uvicorn就能正常被找到。

方案2:修改Dockerfile的工作目录(可选)

如果希望挂载路径更直观,可以调整Dockerfile的工作目录,让代码直接放在/app下,同时把虚拟环境移到上级目录:
修改Dockerfile的builder和runtime阶段:

# builder阶段
WORKDIR /src

# runtime阶段
WORKDIR /app
ENV VIRTUAL_ENV=/src/.venv \
    PATH="/src/.venv/bin:$PATH"

COPY --from=builder ${VIRTUAL_ENV} ${VIRTUAL_ENV}
COPY app/ /app/

然后Compose挂载./app/:/app/,这样虚拟环境在/src/.venv,不会被挂载的代码覆盖,同样能解决问题。

方案3:直接安装uvicorn到系统Python(不推荐)

如果只是临时开发用,不想调整路径,可以在runtime阶段把uvicorn直接安装到系统Python环境,这样即使虚拟环境被覆盖,也能找到可执行文件。但这会破坏镜像的大小优化,不建议用于生产环境:
修改Dockerfile的runtime阶段:

FROM python:3.11-slim-bullseye as runtime

# 直接安装uvicorn到系统Python
RUN pip install uvicorn

ENV VIRTUAL_ENV=/app/.venv \
    PATH="/app/.venv/bin:$PATH"

COPY --from=builder ${VIRTUAL_ENV} ${VIRTUAL_ENV}
COPY app/ /app/

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]

内容的提问来源于stack exchange,提问作者Santiago Ortiz Ceballos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 01:35:21