能否通过heroku.yml在Heroku上部署含ElasticSearch的容器化MVP应用?
问题描述
我有一个用于测试的MVP应用想要部署在Heroku平台上,该应用依赖的ElasticSearch已在docker-compose文件中定义。Heroku平台上最小规格的ElasticSearch插件每月需67美元,超出了我为这个MVP设定的预算。我正尝试将ElasticSearch与Web应用以容器化方式一同部署,但我查阅到的多进程部署指南均使用Dockerfile而非docker-compose,因此想咨询是否可以通过heroku.yml配置实现该需求?
以下是我的docker-compose.yml文件:
version: '3.6' services: web: image: denoland/deno:latest container_name: my_app build: . ports: - 3001:3001 environment: - DENO_ENV=local - ES_HOST=elasticsearch - DENO_PORT=3001 - ELASTIC_URL=http://elasticsearch:9200 volumes: - .:/usr/src/app command: deno run --allow-net --allow-read --allow-env src/main.ts links: - elasticsearch depends_on: - elasticsearch networks: - es-net elasticsearch: container_name: es-container image: docker.elastic.co/elasticsearch/elasticsearch:8.5.2 volumes: - esdata:/usr/share/elasticsearch/data environment: - xpack.security.enabled=false - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - discovery.type=single-node logging: driver: none ports: - 9300:9300 - 9200:9200 networks: - es-net volumes: esdata: networks: es-net: driver: bridge
解决方案
可以通过heroku.yml配置实现将Web应用和ElasticSearch一同部署到Heroku,以下是具体步骤和注意事项:
1. 创建并配置heroku.yml
Heroku支持通过heroku.yml定义多进程部署,替代docker-compose的功能。创建heroku.yml文件,内容如下:
build: docker: web: Dockerfile elasticsearch: Dockerfile.es run: web: deno run --allow-net --allow-read --allow-env src/main.ts elasticsearch: /usr/share/elasticsearch/bin/elasticsearch release: image: web command: - echo "Release command (if needed)"
2. 为ElasticSearch创建单独的Dockerfile
由于Heroku需要为每个进程指定Dockerfile,你需要创建Dockerfile.es来构建ElasticSearch镜像:
FROM docker.elastic.co/elasticsearch/elasticsearch:8.5.2 # 设置环境变量 ENV xpack.security.enabled=false ENV bootstrap.memory_lock=true ENV ES_JAVA_OPTS=-Xms512m -Xmx512m ENV discovery.type=single-node # 暴露端口(Heroku内部网络会自动处理端口映射) EXPOSE 9200 9300 # 启动命令 CMD ["/usr/share/elasticsearch/bin/elasticsearch"]
3. 调整Web应用的Dockerfile
确保你的Web应用根目录有Dockerfile,并调整环境变量适配Heroku的内部网络:
FROM denoland/deno:latest WORKDIR /usr/src/app # 复制应用代码 COPY . . # 设置环境变量,ES_HOST在Heroku内部可直接用进程名elasticsearch ENV DENO_ENV=production ENV ES_HOST=elasticsearch ENV DENO_PORT=${PORT} # Heroku会自动分配端口,必须使用${PORT}变量 ENV ELASTIC_URL=http://elasticsearch:9200 # 启动命令 CMD ["deno", "run", "--allow-net", "--allow-read", "--allow-env", "src/main.ts"]
4. 启用Heroku容器栈
在终端执行以下命令,告诉Heroku使用容器部署:
heroku stack:set container
5. 部署应用
提交所有配置文件到Git,然后部署:
git add heroku.yml Dockerfile Dockerfile.es git commit -m "Add multi-container deployment config" git push heroku main
关键注意事项
- 资源限制:Heroku免费/基础dyno资源有限,ElasticSearch需要一定内存,基础dyno(512MB)可能不足以稳定运行,建议至少使用标准dyno(1GB内存),同时需监控内存占用情况。
- 数据持久化:Heroku的dyno是临时的,重启后本地存储会完全丢失。若需保留ES数据,需搭配外部存储服务(如AWS S3快照、Heroku附加存储),否则每次重启ES都会清空数据。
- 端口配置:Web应用必须监听Heroku分配的
${PORT}环境变量指定的端口,不能硬编码3001;ElasticSearch的端口在Heroku内部网络可直接使用9200/9300,无需映射到外部。 - 网络连通性:Heroku内部dyno进程可直接通过进程名(如
elasticsearch)互相访问,因此Web应用的ES_HOST设置为elasticsearch即可正常连接。
内容的提问来源于stack exchange,提问作者Nimrod Sadeh
相关产品推荐
相关产品推荐

