连接到 PostgreSQL 时,位于 PostgreSQL Docker 容器内部。

huangapple go评论56阅读模式
英文:

Connecting to postgres while inside postgres docker container

问题

以下是要翻译的内容:

I am trying to set up a custom Dockerfile for postgres that runs flyway migrations on startup. So far I've managed to get everything built, installed and executable, but I am unable to get flyway to connect to the postgres database inside the docker container on startup due to connection errors.

Before you tell me to set it up in a docker-compose, file I would like to add that I am doing this so that I can use the docker image in gitlab ci/cd as a service container, so using docker-compose is not an option.

Here is my dockerfile

FROM postgres:12 AS db

WORKDIR /home

# Install wget
RUN apt-get update -y \
  && apt-get install wget -y \
  && apt-get install sudo -y \
  && apt-get install lsof

RUN usermod -aG sudo postgres
RUN bash -c 'echo "postgres ALL=(ALL:ALL) NOPASSWD: ALL" | (EDITOR="tee -a" visudo)'

# Install latest version of flyway 7
RUN wget -qO- https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/7.9.2/flyway-commandline-7.9.2-linux-x64.tar.gz | tar xvz && \
  ln -s `pwd`/flyway-7.9.2/flyway /usr/local/bin

# Copy database migrations for flyway
COPY reds/migrations migrations

# Set environment variables for flyway
ENV FLYWAY_LOCATIONS="/home/migrations"
ENV FLYWAY_SCHEMAS="reds"
ENV FLYWAY_CONNECT_RETRIES=5
ENV FLYWAY_BASELINE_ON_MIGRATE=false
ENV FLYWAY_OUT_OF_ORDER=false

# Make postgres startup script run flyway migrations
COPY reds/init.sh /docker-entrypoint-initdb.d/init.sh
RUN chmod +x /docker-entrypoint-initdb.d/init.sh && \
  chown -R postgres /docker-entrypoint-initdb.d

EXPOSE 5432
CMD ["postgres"]

And the following is the script that is executed on container startup

#!/bin/bash
set -eou pipefail

# I've tried localhost, 0.0.0.0 and 127.0.0.1
host="$(hostname -i)"

sudo flyway migrate \
  -url="jdbc:postgresql://$host:5432/$POSTGRES_DB" \
  -schemas="$FLYWAY_SCHEMAS" \
  -locations="$FLYWAY_LOCATIONS" \
  -connectRetries="$FLYWAY_CONNECT_RETRIES" \
  -baselineOnMigrate="$FLYWAY_BASELINE_ON_MIGRATE" \
  -outOfOrder="$FLYWAY_OUT_OF_ORDER" \
  -user="$POSTGRES_USER" \
  -password="$POSTGRES_PASSWORD"

My build command:

$ docker build -t reds-docker:latest -f "Dockerfile.reds" .

My run command:

$ docker run --rm \
  --env POSTGRES_USER="postgres" \
  --env POSTGRES_PASSWORD="postgres" \
  --env POSTGRES_DB="postgres" \
  reds-docker:latest

I get the following error for flyway trying to connect to the database when I run the container:

WARNING: Connection error: Connection to 172.17.0.2:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. (Caused by Connection refused (Connection refused))

Full log from startup:


<details>
<summary>英文:</summary>

I am trying to set up a custom Dockerfile for postgres that runs flyway migrations on startup. So far I&#39;ve managed to get everything built, installed and executable, but **I am unable to get flyway to connect to the postgres database inside the docker container** on startup due to connection errors.

Before you tell me to set it up in a docker-compose, file I would like to add that I am doing this so that I can use the docker image in gitlab ci/cd as a service container, so using docker-compose is not an option.

Here is my dockerfile

```dockerfile
FROM postgres:12 AS db

WORKDIR /home

# Install wget
RUN apt-get update -y \
  &amp;&amp; apt-get install wget -y \
  &amp;&amp; apt-get install sudo -y \
  &amp;&amp; apt-get install lsof

RUN usermod -aG sudo postgres
RUN bash -c &#39;echo &quot;postgres ALL=(ALL:ALL) NOPASSWD: ALL&quot; | (EDITOR=&quot;tee -a&quot; visudo)&#39;

# Install latest version of flyway 7
RUN wget -qO- https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/7.9.2/flyway-commandline-7.9.2-linux-x64.tar.gz | tar xvz &amp;&amp; \
  ln -s `pwd`/flyway-7.9.2/flyway /usr/local/bin

# Copy database migrations for flyway
COPY reds/migrations migrations

# Set environment variables for flyway
ENV FLYWAY_LOCATIONS=&quot;/home/migrations&quot;
ENV FLYWAY_SCHEMAS=&quot;reds&quot;
ENV FLYWAY_CONNECT_RETRIES=5
ENV FLYWAY_BASELINE_ON_MIGRATE=false
ENV FLYWAY_OUT_OF_ORDER=false

# Make postgres startup script run flyway migrations
COPY reds/init.sh /docker-entrypoint-initdb.d/init.sh
RUN chmod +x /docker-entrypoint-initdb.d/init.sh &amp;&amp; \
  chown -R postgres /docker-entrypoint-initdb.d

EXPOSE 5432
CMD [&quot;postgres&quot;]

And the following is the script that is executed on container startup

#!/bin/bash
set -eou pipefail

# I&#39;ve tried localhost, 0.0.0.0 and 127.0.0.1
host=&quot;$(hostname -i)&quot;

sudo flyway migrate \
  -url=&quot;jdbc:postgresql://$host:5432/$POSTGRES_DB&quot; \
  -schemas=&quot;$FLYWAY_SCHEMAS&quot; \
  -locations=&quot;$FLYWAY_LOCATIONS&quot; \
  -connectRetries=&quot;$FLYWAY_CONNECT_RETRIES&quot; \
  -baselineOnMigrate=&quot;$FLYWAY_BASELINE_ON_MIGRATE&quot; \
  -outOfOrder=&quot;$FLYWAY_OUT_OF_ORDER&quot; \
  -user=&quot;$POSTGRES_USER&quot; \
  -password=&quot;$POSTGRES_PASSWORD&quot;

My build command:

$ docker build -t reds-docker:latest -f &quot;Dockerfile.reds&quot; .

My run command:

$ docker run --rm \
  --env POSTGRES_USER=&quot;postgres&quot; \
  --env POSTGRES_PASSWORD=&quot;postgres&quot; \
  --env POSTGRES_DB=&quot;postgres&quot; \
  reds-docker:latest

I get the following error for flyway trying to connect to the database when I run the container:

> WARNING: Connection error: Connection to 172.17.0.2:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. (Caused by Connection refused (Connection refused))

Full log from startup:

The files belonging to this database system will be owned by user &quot;postgres&quot;.
This user must also own the server process.

The database cluster will be initialized with locale &quot;en_US.utf8&quot;.
The default database encoding has accordingly been set to &quot;UTF8&quot;.
The default text search configuration will be set to &quot;english&quot;.

Data page checksums are disabled.

fixing permissions on existing directory /var/lib/postgresql/data ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default time zone ... Etc/UTC
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok


Success. You can now start the database server using:

    pg_ctl -D /var/lib/postgresql/data -l logfile start

initdb: warning: enabling &quot;trust&quot; authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.
waiting for server to start....2023-02-06 13:36:59.228 UTC [48] LOG:  starting PostgreSQL 12.13 (Debian 12.13-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
2023-02-06 13:36:59.229 UTC [48] LOG:  listening on Unix socket &quot;/var/run/postgresql/.s.PGSQL.5432&quot;
2023-02-06 13:36:59.237 UTC [49] LOG:  database system was shut down at 2023-02-06 13:36:59 UTC
2023-02-06 13:36:59.239 UTC [48] LOG:  database system is ready to accept connections
 done
server started

/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/init.sh
WARNING: This version of Flyway is out of date. Upgrade to Flyway 9.14.1:https://flywaydb.org/documentation/learnmore/staying-up-to-date/?ref=v7.9.2_cmd-line
Flyway Community Edition 7.9.2 by Redgate
WARNING: Connection error: Connection to 172.17.0.2:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. (Caused by Connection refused (Connection refused)) Retrying in 1 sec...
WARNING: Connection error: Connection to 172.17.0.2:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. (Caused by Connection refused (Connection refused)) Retrying in 2 sec...

答案1

得分: 1

以下是您要翻译的内容:

"Just to be clear, the scripts in docker-entrypoint-initdb.d aren't run on container start as you say. They're run on database initialization. So they're only run when a fresh database is initialized and as such don't work well for migrations that usually change an existing database.

That being said, the reason your script isn't working is that while the database is being initialized, Postgres is running in a state where it isn't accepting TCP/IP connections. You can only talk to it using a Unix socket. You can see that in the log in the message listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432".

I don't know if Flyway supports connecting over a Unix socket. But you can't connect over TCP/IP in a database initialization script.

The code that starts the database is this part of the container startup script:

start socket-only postgresql server for setting up or running scripts

all arguments will be passed along as arguments to postgres (via pg_ctl)

docker_temp_server_start() {
if [ "$1" = 'postgres' ]; then
shift
fi

internal start of server in order to allow setup using psql client

does not listen on external TCP/IP and waits until start finishes

set -- "$@" -c listen_addresses='' -p "${PGPORT:-5432}"

PGUSER="${PGUSER:-$POSTGRES_USER}"
pg_ctl -D "$PGDATA"
-o "$(printf '%q ' "$@")"
-w start
}

As you can see, it sets listen_addresses to a blank string and that causes Postgres to not listen on any TCP/IP ports. There doesn't seem to be a way to modify this behavior without creating your own image with a modified startup script.

英文:

Just to be clear, the scripts in docker-entrypoint-initdb.d aren't run on container start as you say. They're run on database initialization. So they're only run when a fresh database is initialized and as such don't work well for migrations that usually change an existing database.

That being said, the reason your script isn't working is that while the database is being initialized, Postgres is running in a state where it isn't accepting TCP/IP connections. You can only talk to it using a Unix socket. You can see that in the log in the message listening on Unix socket &quot;/var/run/postgresql/.s.PGSQL.5432&quot;.

I don't know if Flyway supports connecting over a Unix socket. But you can't connect over TCP/IP in a database initialization script.

The code that starts the database is this part of the container startup script:

# start socket-only postgresql server for setting up or running scripts
# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
docker_temp_server_start() {
	if [ &quot;$1&quot; = &#39;postgres&#39; ]; then
		shift
	fi

	# internal start of server in order to allow setup using psql client
	# does not listen on external TCP/IP and waits until start finishes
	set -- &quot;$@&quot; -c listen_addresses=&#39;&#39; -p &quot;${PGPORT:-5432}&quot;

	PGUSER=&quot;${PGUSER:-$POSTGRES_USER}&quot; \
	pg_ctl -D &quot;$PGDATA&quot; \
		-o &quot;$(printf &#39;%q &#39; &quot;$@&quot;)&quot; \
		-w start
}

As you can see, it sets listen_addresses to a blank string and that causes Postgres to not listen on any TCP/IP ports. There doesn't seem to be a way to modify this behaviour without creating your own image with a modified startup script.

huangapple
  • 本文由 发表于 2023年2月6日 22:13:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/75362449-2.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定