【问题标题】:Connect to postgresql container from another container (Docker)从另一个容器(Docker)连接到 postgresql 容器
【发布时间】: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 也是)。

标签: postgresql docker localhost docker-compose host


【解决方案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

下面列出了这些文件的内容。

步骤

  1. ./src 目录运行$ npm install(创建package-lock.json)
  2. 使用$ chmod 600 .pgpass 修复 pgpass 权限
  3. 使脚本可执行$ chmod +x wait-for-postgres.sh
  4. 从根目录$ 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"

【讨论】:

    猜你喜欢
    • 2019-02-24
    • 2020-01-30
    • 2017-10-11
    • 2016-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-04
    • 2022-01-04
    相关资源
    最近更新 更多