【发布时间】:2020-07-28 14:20:47
【问题描述】:
代码优先,这样更容易解释我所追求的。
docker-compose.yml
version: '3.4'
services:
db:
user: '${UID}:${GID}'
image: postgres
container_name: postgres
ports:
- '5432:5432'
restart: always
environment:
POSTGRES_HOST: db
POSTGRES_USER: root
POSTGRES_PASSWORD: secret
POSTGRES_DATABASE: foo
PGDATA: /var/lib/postgresql/data/db
volumes:
- ./db/data:/var/lib/postgresql/data/db
- db-init.sh:/docker-entrypoint-initdb.d/:ro
cache:
image: redis:alpine
container_name: redis
sysctls:
net.core.somaxconn: '511'
ports:
- '6379:6379'
command: ['--requirepass "secret"']
api:
image: node:alpine
container_name: api
working_dir: /var/www/app
command: sh -c "npm start"
ports:
- '5000:5000'
volumes:
- node_modules:/var/www/app/node_modules
- .:/var/www/app
env_file: .env
depends_on:
- db
- cache
volumes:
node_modules:
postgresnode.js 应用的连接设置:
export const {
POSTGRES_USER = 'root',
POSTGRES_PASSWORD = 'secret',
POSTGRES_HOST = 'db',
POSTGRES_PORT = 5432,
POSTGRES_DATABASE = 'foo',
} = process.env
问题:
将服务或容器名称(db 或 postgres)用于 POSTGRES_HOST 设置的 node 应用程序时:
- 我可以成功连接并查询数据库。
-
我无法从主机运行影响容器的命令。例如,播种 db 将不起作用:
npx knex --esm seed:run
这是有道理的,因为db / postgres 的 DNS 解析由 docker 负责,而这些解析仅在连接容器的网络上有意义。从主机运行并针对该容器的命令将失败,因为主机不知道如何在此处解析 DNS。
另一方面,当将localhost 用于node 应用程序的POSTGRES_HOST 设置时:
- 从
api到postgres的查询将失败。 - 从主机运行的命令,例如
npx knex --esm seed:run,将会成功。
同样,这完全有道理。由于docker-compose.yml 中的端口转发,从主机将容器寻址为localhost 将起作用。但在容器的上下文中,它指的是那个容器:因为api localhost 意味着它自己,它试图在localhost:5432 或api:5432 上查找数据库。
我想拥有工作的容器间网络,并从主机运行命令,寻址所述容器。我知道实现这一目标的两种方法:
-
使用容器/服务名称作为
POSTGRES_HOST,并对容器运行命令:docker exec -it <container_name> <command> 将静态
ips 分配给容器并使用它们而不是服务/容器名称。
我还有其他选择吗?
【问题讨论】:
标签: node.js postgresql docker docker-compose