如何在Heroku单应用中部署并打通Web服务与内部服务?
嘿,我来帮你搞定这个问题!首先得明确一个关键:Heroku里不同进程类型的dyno是独立的容器,它们的端口是动态分配的,而且你没法直接通过端口跨容器访问——这就是你现在访问不了svc2的核心原因。完全不用新建Heroku应用,单应用内就能实现两个服务的通信,给你几个可行的方案:
方案1:把两个服务塞进同一个Docker容器(最省心,免费)
这是最适合大多数场景的方法,操作起来和本地开发差不多:
- 调整你的Dockerfile,把两个Node.js服务的代码都包含进去,分别安装各自的依赖。
- 用一个进程管理器(比如
concurrently、pm2或者supervisord)同时启动两个服务:让svc2监听容器内部的固定端口(比如3001,反正容器内部不会有端口冲突),web服务依然监听Heroku分配的process.env.PORT。 - 把这个合并后的镜像推送到Heroku的
web进程类型,发布后web服务就能像本地一样用http://localhost:3001访问svc2了。
举个简单的Dockerfile例子:
FROM node:18-alpine WORKDIR /app # 复制两个服务的代码到容器里 COPY ./web-service ./web COPY ./svc2-service ./svc2 # 安装web服务依赖 WORKDIR /app/web RUN npm install # 安装svc2服务依赖 WORKDIR /app/svc2 RUN npm install # 装个进程管理器concurrently用来同时启动两个服务 WORKDIR /app RUN npm install -g concurrently # 启动命令 CMD ["concurrently", "npm --prefix ./web start", "npm --prefix ./svc2 start"]
svc2的代码里直接监听固定端口就行:
const port = 3001; app.listen(port, () => { console.log(`svc2 running on port ${port}`); });
方案2:用Heroku私有空间(付费,适合生产级独立缩放)
如果你的两个服务需要独立缩放(比如web服务需要更多资源,svc2只需要少量),可以考虑Heroku的私有空间:
- 把你的应用移入私有空间后,每个进程类型的dyno都可以通过内部域名访问,比如svc2的地址是
http://svc2.foo.internal(foo是你的应用名)。 - 不需要纠结端口的问题,Heroku的内部DNS会自动解析到对应的dyno并处理端口转发。
这个方案需要付费,但能实现服务的隔离和独立缩放,适合生产环境。
方案3:用Redis做服务发现(复杂,不推荐)
如果不想合并容器也不想付费,还可以用Redis来做服务发现,但操作起来比较麻烦:
- 给你的Heroku应用加个Redis插件(比如Heroku Redis)。
- 当svc2启动时,把自己的私有IP和端口注册到Redis里。
- web服务从Redis里读取svc2的地址来访问。
但Heroku的dyno私有IP是动态的,这种方法容易出问题,除非你有特殊需求,否则不推荐。
最后再强调一遍:完全不需要新建Heroku应用,上面的方案都能在单个应用内搞定两个服务的通信,方案1是最省心的选择。
内容的提问来源于stack exchange,提问作者Klaxx
相关产品推荐
相关产品推荐

