Docker容器部署FastAPI到Heroku启动失败求助
问题解决:Heroku部署Docker镜像启动失败(start.sh not found)
问题根源分析
从日志/bin/sh: 1: ./start.sh 53182: not found可以看出,shell将./start.sh 53182当成了单个命令名,而非./start.sh加参数53182;同时大概率存在脚本无执行权限、shebang缺失的问题。
解决方案步骤
1. 给start.sh添加可执行权限
Docker复制文件时会保留主机权限,若主机上脚本无执行权限,容器内也会继承该状态。在Dockerfile中添加权限设置:
WORKDIR /opt/app/server COPY ./start.sh . # 新增:赋予脚本执行权限 RUN chmod +x start.sh
2. 修正Dockerfile的CMD写法
当前CMD "./start.sh ${PORT}"的shell格式,在Heroku解析时容易出现参数合并问题,推荐两种更可靠的写法:
写法一:用exec格式CMD(通过shell解析环境变量)
exec格式不会自动替换环境变量,因此用shell包裹执行:
CMD ["/bin/sh", "-c", "./start.sh $PORT"]
写法二:让start.sh直接读取PORT环境变量(更简洁)
修改start.sh,不再传递端口参数,直接读取Heroku提供的环境变量:
#!/bin/sh uvicorn api.app:app --host 0.0.0.0 --port $PORT
随后Dockerfile的CMD简化为:
CMD ["./start.sh"]
这种方式完全贴合Heroku的环境变量使用逻辑,避免参数传递问题。
3. 确保start.sh有正确的shebang
在start.sh的第一行必须添加shebang,指定执行脚本的shell:
#!/bin/sh # 或#!/bin/bash,根据容器内预装的shell选择
缺失shebang会导致系统无法识别脚本的执行环境,进而触发"not found"错误。
4. 本地验证容器运行
修改完成后,本地重新构建镜像并运行,确认启动逻辑正常:
docker build -t my-fastapi-app . docker run -p 8000:8000 -e PORT=8000 my-fastapi-app
可选:用Heroku.yml指定启动命令(若仍有问题)
如果以上调整后仍存在异常,可在项目根目录创建Heroku.yml,明确指定web进程的启动命令:
build: docker: web: Dockerfile run: web: /bin/sh -c "./start.sh $PORT"
gonuit/heroku-docker-deploy会自动识别该文件并应用配置。
最终修改后的Dockerfile示例
FROM node:21 as ui-build WORKDIR /opt/ui COPY ui . RUN npm ci && npm run build FROM python:3.11 as final-build WORKDIR /opt/app COPY --from=ui-build /opt/ui/build ./ui/build COPY server server RUN cd server && pip install -r requirements.txt EXPOSE $PORT WORKDIR /opt/app/server COPY ./start.sh . RUN chmod +x start.sh # 使用exec格式CMD,通过shell解析环境变量 CMD ["/bin/sh", "-c", "./start.sh $PORT"]
内容的提问来源于stack exchange,提问作者HopAlongPolly
相关产品推荐
相关产品推荐

