我有一些服务与Docker Compose粘在一起。主要服务是自己的容器中的Rails应用程序。它位于Nginx代理后面,也位于自己的容器中。 (其他服务也支持Nginx,但这并不重要。)
在docker-compose.yml
中,我已将名称web
分配给Rails服务。因此,web
是Docker网络中容器的主机名。 Rails容器公开了端口3000.所以我的Nginx反向代理配置如下所示:
location / {
proxy_pass http://web:3000;
}
除了一个问题外,这很有效。从Rails应用程序的角度来看,所有请求都是web:3000
。由于Rails会根据请求的主机名和端口生成内部网址,因此我最终会在回复中找到web:3000
的网址。
例如,如果我把它放在模板中:
<%= link_to 'Admin', admin_url %>
我在渲染的HTML中得到了这个:
<a href="http://web:3000/admin">Admin</a>
我理解为什么会这样,但我不确定修复它的最佳做法。如果我能避免将端口和主机名硬编码到Rails代码中,我宁愿不将其硬编码。
这似乎是Docker和Rails的普遍问题,所以我猜其他人遇到过它。想法?
编辑。我通过让Nginx将原始主机名传递给Rails解决了部分问题,如下所示:
location / {
proxy_set_header Host $host;
proxy_pass http://web:3000;
}
但是,Rails仍然没有看到外部端口或协议(http
vs https
)。
编辑2。根据评论中的要求,此处为docker-compose.yml
。
version: "3.2"
services:
proxy:
image: nginx
ports:
# For flexibility, I'd like to be able to set whatever host-side
# port I want. E.g. 5000:80.
- 80:80
- 443:443
volumes:
- ssl-certs:/ssl-certs
- ssl-webroot:/ssl-webroot
- type: bind
source: ./nginx.conf
target: /etc/nginx/nginx.conf
read_only: true
certbot:
image: certbot/certbot
command: --version
volumes:
- ssl-certs:/etc/letsencrypt
- ssl-webroot:/ssl-webroot
web:
build: ./rails
volumes:
- gems:/gems
environment:
- GEM_HOME=/gems
- MYSQL_DOCKER_HOST
- MYSQL_USER=root
- MYSQL_PASSWORD
- MYSQL_DEVELOPMENT_DB=myapp_dev
- MYSQL_TEST_DB=myapp_test
volumes:
gems:
ssl-certs:
ssl-webroot: