问题描述
在使用Docker时,希望设置一个简单的环境,其中包括一个PostgreSQL容器和一个Node.js应用程序。他的主要目标是让PostgreSQL容器的端口不暴露到互联网,但允许Node.js后端通过端口3333接受请求。他已经尝试了一些方法,但遇到了问题。以下是他的当前docker-compose.yml
文件:
version: "3"
services:
redis:
image: redis:latest
ports:
- 6379:6379
command: ["redis-server", "/redis.conf"]
network_mode: host
database:
image: "postgres"
env_file:
- ./database/database.env
volumes:
- database-data:/var/lib/postgresql/data
- ./database/init-db.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- 5432:5432
restart: always
network_mode: host
backend:
depends_on: [database]
build: ./server
volumes:
- ./files:/var/lib/files
ports:
- 3333:3333
restart: always
network_mode: host
volumes:
database-data:
解决方案
在Docker中,你可以使用网络模式(network_mode)来控制容器之间的通信。用户尝试过使用network_mode: host
来达到目的,但这会导致发布的端口被忽略,即使在容器内定义了端口,它们也会与主机上的相同端口一致。
但是,根据Docker Compose文档的默认行为,任何服务都可以通过服务名称与其他服务通信。因此,你不必使用network_mode: host
,而是让Docker创建一个默认的网络。下面是一个示例docker-compose.yml
文件,演示了如何实现这一目标:
version: '3.7'
services:
nginx1:
image: nginx
ports:
- '8080:80'
nginx2:
image: nginx
在上面的示例中,我们定义了两个服务nginx1
和nginx2
。nginx1
通过端口8080
在localhost和网络中对外提供服务。而nginx2
则只是简单地使用了默认端口。
这两个服务仍然可以通过服务名称相互访问,而无需使用特殊的网络模式。例如,可以通过以下方式访问nginx1
:
$ curl -I http://nginx1:80
HTTP/1.1 200 OK
Server: nginx/1.19.10
同时,nginx2
的端口也在主机上有相应的端口:
$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------------
nginx1_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:8080->80/tcp,:::8080->80/tcp
nginx2_1 /docker-entrypoint.sh ngin ... Up 80/tcp
可以看到,nginx1
的端口8080
被映射到了主机的8080
端口上。
总结一下,通过使用Docker默认的网络,你可以轻松地让容器之间相互通信,而无需特殊的网络模式设置。
这里还有一种方法,可以使用links
(新版本中使用networks
),这种方式可以使得两个容器之间能够通信。你可以更新docker-compose.yml
文件并添加links
来将database
服务(数据库容器)连接到backend
服务中,然后在后端数据库配置中,使用database
作为数据库主机。具体示例如下:
version: "3"
services:
redis:
image: redis:latest
ports:
- 6379:6379
command: ["redis-server", "/redis.conf"]
database:
image: "postgres"
env_file:
- ./database/database.env
volumes:
- database-data:/var/lib/postgresql/data
- ./database/init-db.sql:/docker-entrypoint-initdb.d/init.sql
restart: always
backend:
depends_on: [database]
build: ./server
volumes:
- ./files:/var/lib/files
ports:
- 3333:3333
restart: always
links:
- "database"
volumes:
database-data:
在这个示例中,我们将database
服务(数据库容器)通过links
与backend
服务连接起来,然后在后端数据库配置中,使用database
作为数据库主机(这里的database
是在compose.yaml文件中定义的服务名称)。这样就确保了backend
服务可以访问database
服务。
请注意,上述解决方案中的links
在新版本的Docker中已经被networks
取代,你可以根据实际情况使用适合的版本。