从另一个容器(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

现在我尝试将主机设置为databaselocalhost0.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

Dockerfile

我已经从 node js 教程中修改了它,将它固定到 Debian “buster”版本,并安装了该脚本所需的 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" ]

等待-postgres.sh

我稍微修改了脚本,因为我运行了“shellcheck”linter,它抱怨了一些事情。我意识到这个脚本来自 docker 教程页面。
#!/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 容器的主要内容,如果未能解决你的问题,请参考以下文章

无法从另一个容器连接到 mongodb docker 容器

允许 docker 容器连接到本地/主机 postgres 数据库

从 docker-compose 文件连接到 Postgres docker 容器 [重复]

尝试从 Ruby on Rails 连接到 postgres(在 docker 容器中)

无法从 golang 连接到 docker postgres 容器

无法使用 docker 连接到 ipv6 中的 postgres