从另一个容器(Docker)连接到 postgresql 容器
Posted
技术标签:
【中文标题】从另一个容器(Docker)连接到 postgresql 容器【英文标题】:Connect to postgresql container from another container (Docker) 【发布时间】:2017-10-15 12:30:55 【问题描述】:我正在尝试关注tutorial 并设置一个 postgresql 容器。
我有以下脚本:
#!/bin/bash
# wait-for-postgres.sh
set -e
host="$1"
shift
cmd="$@"
until psql -h "$host" -U "postgres" -c '\l'; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - executing command"
exec $cmd
还有以下docker-compose.yml
:
version: '2'
services:
server:
build: .
ports:
- 3030:3030
depends_on:
- database
command: ["./setup/wait-for-postgres.sh", "localhost:5432", "--", "node", "src"]
database:
image: postgres
environment:
- "POSTGRES_USER=postgres"
- "POSTGRES_PASSWORD=postgres"
- "POSTGRES_DB=tide_server"
ports:
- 5432:5432
问题是当我运行docker-compose up
时出现以下错误:
server_1 | Postgres is unavailable - sleeping
server_1 | psql: could not translate host name "192.168.64.2:5432" to address: Name or servi
ce not known
server_1 | Postgres is unavailable - sleeping
server_1 | psql: could not translate host name "192.168.64.2:5432" to address: Name or servi
ce not known
server_1 | Postgres is unavailable - sleeping
server_1 | psql: could not translate host name "192.168.64.2:5432" to address: Name or servi
ce not known
现在我尝试将主机设置为database
、localhost
、0.0.0.0
,甚至是容器 IP 但没有任何效果,我不知道它应该是什么或如何调试它,我不是 100 % 确定 docker-compose
如何链接容器。
【问题讨论】:
像host:port
这样的命令参数传递是wait-for-it.sh 脚本的一个特性:github.com/vishnubob/wait-for-it/blob/master/wait-for-it.sh#L74 这不是 psql 为你拆分出来的,psql 希望你通过-p
选项的端口。也就是说,5432 是默认值,因此不是强制性的。在您的示例中,您使用 database
作为主机,因此在 docker compose 网络中,该名称应该解析。上面发布的错误都显示了“192.168.64.2:5432”的用法,如果您使用“数据库”会发生什么?我怀疑 psql 在等待密码时会失败。
是的,psql: fe_sendauth: no password supplied
会失败,我在答案中提供了完整的解决方案。
如果你使用 5433:5432 它不会暴露 5433 端口,你会得到连接被拒绝。只要将其更改为“5433:5432”,它就会起作用。用官方 postgres:13.2 镜像测试(13 也是)。
【参考方案1】:
不要使用depends_on。用“链接”试试
version: '2'
services:
server:
build: .
ports:
- 3030:3030
links:
- database
#environment could be usefull too
environment:
DATABASE_HOST: database
command: ["./setup/wait-for-postgres.sh", "localhost:5432", "--", "node", "src"]
database:
image: postgres
environment:
- "POSTGRES_USER=postgres"
- "POSTGRES_PASSWORD=postgres"
- "POSTGRES_DB=tide_server"
ports:
- 5432:5432
更多信息https://docs.docker.com/compose/compose-file/#links
【讨论】:
谢谢你,我已经尝试了链接和depends_on,但仍然没有运气,干杯。links
已弃用 docs.docker.com/compose/compose-file/#links ,建议改用用户定义的网络。 depends_on
很好,但它不等待数据库准备好,只等待容器启动 docs.docker.com/compose/compose-file/#depends_on。根据 OP 在此问题中提供的文档“教程”链接,这是故意的,这就是为什么他们建议使用 wait-for-it
和其他方法来明确处理来自您的应用程序(而不是容器基础架构)的健壮连接和重新连接。【参考方案2】:
这里的问题是主机本身。
psql -h "$host" -U "" -c '\l'
您传递了错误的主机名“localhost:5432”/“192.168.64.2:5432”
我所做的是设置一个 ~/.pgpass 有 本地主机:5432:数据库:用户:密码
而不是传递“localhost:5432”,省略端口。只需使用“本地主机”
这对我有用......
【讨论】:
使用 -d 选项指定数据库会有所帮助 不知道为什么这被否决了,如果有点简短的话,它是非常正确的。【参考方案3】:可能是一个旧线程来回答,但我一直在使用 depends_on 和以下 docker-compose 文件
version: '3.4'
volumes:
postgres_data:
driver: local
services:
postgres:
image: postgres
volumes:
- ./postgres_data:/var/lib/postgresql:rw
- ./deployments:/opt/jboss/wildfly/standalone/deployments:rw
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
ports:
- 5432:5432
keycloak:
image: jboss/keycloak
environment:
POSTGRES_ADDR: postgres
POSTGRES_DATABASE: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: Pa55w0rd
ports:
- 8080:8080
- 9990:9990
depends_on:
- postgres
【讨论】:
这似乎是对其他人答案的回复/评论,而不是对 OP 问题本身的回答。可能值得将此(有用的)点与您的其他答案结合起来。【参考方案4】:本教程跳过了一些内容,令人困惑的是它提到了 wait-for-it.sh
脚本,但随后显示了一个非常简化的版本,如果您将 hostname:port
作为一个参数传递给它,则该版本将不起作用。
我很擅长让它发挥作用,对于未来的我和其他人,我将添加以下步骤。我在 MacOS 上做了这个,并且安装了 docker 和 docker-compose 以及 nodejs。
我手边没有你的节点应用程序,所以我使用了这里描述的那个https://nodejs.org/de/docs/guides/nodejs-docker-webapp/
我的目录结构如下:
/src/package.json
/src/server.js
/.pgpass
/docker-compose.yml
/Dockerfile
/wait-for-postgres.sh
下面列出了这些文件的内容。
步骤
-
从
./src
目录运行$ npm install
(创建package-lock.json)
使用$ chmod 600 .pgpass
修复 pgpass 权限
使脚本可执行$ chmod +x wait-for-postgres.sh
从根目录$ docker-compose up
它将拉取 postgres 映像并构建节点应用程序容器。 完成后,它将等待 postgres,当 postgres 启动时,您会看到它已准备就绪。
文件
src 文件完全按照上面的节点 js dockerize 链接
/src/package.json
"name": "docker_web_app",
"version": "1.0.0",
"description": "Node.js on Docker",
"author": "First Last <first.last@example.com>",
"main": "server.js",
"scripts":
"start": "node server.js"
,
"dependencies":
"express": "^4.16.1"
/src/server.js
'use strict';
const express = require('express');
// Constants
const PORT = 8080;
const HOST = '0.0.0.0';
// App
const app = express();
app.get('/', (req, res) =>
res.send('Hello world\n');
);
app.listen(PORT, HOST);
console.log(`Running on http://$HOST:$PORT`);
.pgpass
这使用用户名:密码postgres:postgres
,纯粹用于开发演示目的。在野外,您将使用其他一些秘密管理方法,并且永远不会将 pgpass 文件提交给版本控制
#host:port:db:user:pass
db:5432:*:postgres:postgres
我已将docker-compose.yml
wait-for-postgres.sh
脚本添加为托管卷,在最初的问题中,它将它与 app src 捆绑在一起,这很奇怪。
我还在根用户的主目录中安装了.pgpass
文件,psql 将在该目录中查找自动密码补全。如果你没有某种方法来提供这个,那么你会得到一个错误:
psql: fe_sendauth: 未提供密码
请注意,server
容器的命令是指 database
,这是 postgres 容器的有效 docker-compose 内部 dns 名称。
version: '2'
services:
server:
build: .
ports:
- 3030:3030
depends_on:
- database
volumes:
- ./wait-for-postgres.sh:/usr/app/setup/wait-for-postgres.sh
- ./.pgpass:/Users/root/.pgpass
command: ["/usr/app/setup/wait-for-postgres.sh", "database", "--", "node", "src"]
database:
image: postgres
environment:
- "POSTGRES_USER=postgres"
- "POSTGRES_PASSWORD=postgres"
- "POSTGRES_DB=tide_server"
ports:
- 5432:5432
我已经从 node js 教程中修改了它,将它固定到 Debian “buster”版本,并安装了该脚本所需的Dockerfile
psql
。
FROM node:10-buster
RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
RUN apt-get -y update - && \
apt-get -y install libpq-dev && \
apt-get -y install postgresql-client-11
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN npm install
# If you are building your code for production
# RUN npm ci --only=production
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "node", "server.js" ]
我稍微修改了脚本,因为我运行了“shellcheck”linter,它抱怨了一些事情。我意识到这个脚本来自 docker 教程页面。等待-postgres.sh
#!/bin/bash
# wait-for-postgres.sh
set -e
host="$1"
shift
cmd="$*"
export PGPASSFILE=./pgpass
until psql -h "$host" -U "postgres" -c '\l'; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - executing command"
exec "$cmd"
【讨论】:
以上是关于从另一个容器(Docker)连接到 postgresql 容器的主要内容,如果未能解决你的问题,请参考以下文章
允许 docker 容器连接到本地/主机 postgres 数据库
从 docker-compose 文件连接到 Postgres docker 容器 [重复]
尝试从 Ruby on Rails 连接到 postgres(在 docker 容器中)