如何在Heroku上部署含API、客户端、MySQL的多容器Docker应用
Heroku 多容器Docker应用部署步骤
Heroku的容器运行逻辑和本地docker-compose有不少差异,你需要先调整配置适配平台限制,再按步骤部署即可:
一、前置架构调整(必须修改,否则无法正常运行)
- 放弃自行部署MySQL容器:Heroku的dyno文件系统是临时存储,不管你怎么挂载volume,只要dyno重启、休眠、扩容,所有存在本地的文件都会被清空,完全无法持久保存数据库数据。直接使用Heroku官方提供的MySQL附加组件即可,比如ClearDB MySQL、JawsDB MySQL,附加组件会自动处理数据持久化、备份、主从这些问题。
- 移除自定义网络配置:Heroku同一应用下的容器默认可以通过内部网络通信,不需要你自行定义backend、frontend这类自定义网络,直接删除原docker-compose里的networks相关配置即可。
- 端口适配规则:Heroku会给每个对外提供服务的web进程自动分配动态端口,存在
$PORT环境变量中,不支持硬写80、3306这类固定端口,也不支持自定义端口映射,你的API、前端服务都要监听运行时的$PORT变量,而不是本地配置的固定端口。 - 单应用仅支持一个web入口:Heroku规定每个应用只能有一个web类型的进程可以接收外部HTTP请求,如果你需要前端和API都对外暴露,两种方案可选:1、把前端和API打包到同一个镜像,用Nginx做路由,/api前缀的请求转发给API服务,其他请求返回前端静态资源;2、把API和前端拆成两个独立的Heroku应用分别部署。
二、替换docker-compose为Heroku专用配置
你本地的docker-compose.yml无法直接在Heroku上使用,需要在项目根目录新建heroku.yml文件,内容参考如下(以拆成两个应用部署为例,这里是前端应用的配置,API应用单独写对应配置即可):
build: docker: web: ./client/Dockerfile # 前端Dockerfile路径 args: - VITE_API_URL=${VITE_API_URL} - VITE_API_KEY=${BPFMGR_API_KEY} run: web: /bin/sh -c "envsubst '\$PORT' < /etc/nginx/conf.d/default.conf > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
如果是API应用的heroku.yml参考:
build: docker: web: ./api/Dockerfile run: web: # 这里写你的API启动命令,比如 node main.js 或者 java -jar xxx.jar
提示:如果前端用Nginx托管静态资源,要提前修改Nginx配置文件,把
listen 80;改成listen ${PORT};,启动的时候用envsubst替换环境变量即可。
三、部署操作步骤
- 先安装Heroku CLI,完成后执行
heroku login登录你的Heroku账号,再执行heroku container:login登录容器镜像仓库。 - 分别创建前端和API两个Heroku应用:
heroku create 你的API应用名、heroku create 你的前端应用名。 - 给API应用安装MySQL附加组件:切换到API项目目录,执行
heroku addons:create cleardb:ignite,安装完成后Heroku会自动把数据库连接信息注入到环境变量CLEARDB_DATABASE_URL中,你只需要在API代码里读取这个变量拆分出数据库地址、用户名、密码、库名即可,不需要自己配置数据库相关环境变量。 - 配置所有自定义环境变量:比如前端需要的VITE_API_URL(就是你API应用的访问地址)、BPFMGR_API_KEY,API需要的其他自定义变量,都通过
heroku config:set 变量名=变量值命令设置。 - 给每个应用设置运行栈为容器模式:
heroku stack:set container -a 你的应用名。 - 分别推送两个应用的代码部署:切换到对应项目目录,执行
git push heroku main,Heroku会自动按照heroku.yml的配置构建镜像、启动容器。 - 部署完成后执行
heroku open -a 你的应用名即可打开对应服务验证运行状态。
四、常见问题排查
- API连不上数据库:确认你的API代码读取的是
CLEARDB_DATABASE_URL环境变量,而不是本地用的DB_HOST、DB_PASSWORD这类自定义变量,连接字符串格式为mysql://用户名:密码@主机地址:端口/数据库名,拆分对应字段使用即可。 - 前端打开报错404/502:检查Nginx配置是不是正确监听了
$PORT,有没有硬写固定端口,VITE_API_URL的配置是不是和你部署后的API应用地址完全一致。 - 服务运行一段时间后数据丢失:确认没有自行部署MySQL容器,所有数据都存在Heroku官方的MySQL附加组件中。
内容的提问来源于stack exchange,提问作者Damien STEPHAN
相关产品推荐
相关产品推荐

