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:
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.
The database cluster will be initialized with locale "en_US.utf8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".
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 "trust" 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 "/var/run/postgresql/.s.PGSQL.5432"
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...
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 behaviour without creating your own image with a modified startup script.
Related
I've installed posgresql:
nix-env -iA nixos.postgresql
Now I wanto use it.
psql
psql: error: connection to server on socket "/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
Is the server running locally and accepting connections on that socket?
Must I add something in /etc/nixos/configuration.nix ?
update
I've tried to do like this link. i.e. install in nix-shell and not in nix-env.
I've the same shell.nix
nix-shell --pure shell.nix
done
server started
psql
psql: error: could not connect to server: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/mnt/c/Users/Pierre-Olivier/nix/psql/.pg/.s.PGSQL.5432"?
psql is the PostgreSQL interactive terminal.
What you are trying to do is connect to database without PostgreSQL running in first place.
Follow these steps:
Initialize the database with initdb -D .data
Start a PostgreSQL server with pg_ctl -D .data -l logfile start
Make sure it's running pg_ctl -D .data status
Connect to database with psql -d postgres (by default, postgres database is created)
At the end, make sure to stop database with pg_ctl -D .data stop when leaving the nix shell.
I am running postgres 12 and it won't start after server reboot (run manually by reboot). The attached EBS volume has not changed and I don't see any evidence of a data loss.
When I run psql, I get (this used to work before restart)
psql -h localhost -U postgres
psql: error: could not connect to server: Connection refused
Is the server running on host "localhost" (127.0.0.1) and accepting
TCP/IP connections on port 5432?
pg_lsclusters does not help -
pg_lsclusters 12 main start
Ver Cluster Port Status Owner Data directory Log file
12 main 5432 down postgres /var/lib/postgresql/12/main /var/log/postgresql/postgresql-12-main.log
The error in /var/log/postgresql/postgresql-12-main.log is
pg_ctl: could not start server
Examine the log output.
2021-03-01 00:33:24.976 UTC [1866] FATAL: could not access file "anon": No such file or directory
2021-03-01 00:33:24.976 UTC [1866] LOG: database system is shut down
When I start postgres, I don't get any error -
sudo service postgresql start
If you don’t want to start PostgreSQL manually every time your Linux restarts, run the following command :
sudo update-rc.d postgresql enable
If it can not find LSB script then do this :
sudo systemctl enable postgresql
I'm trying to extend the postgres Docker image to potentially (via an environment variable flag) execute flyway DB migrations on DB init. My Dockerfile is here:
FROM postgres:9.6
# Install curl and java (for Flyway)
RUN set -x \
&& apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl openjdk-8-jre
# Install Flyway
ENV FLYWAY_VERSION 4.2.0
ENV FLYWAY_INSTALL_DIR /usr/src/flyway
ENV FLYWAY_CONF ${FLYWAY_INSTALL_DIR}/flyway-${FLYWAY_VERSION}/conf/flyway.conf
ENV FLYWAY_EXE ${FLYWAY_INSTALL_DIR}/flyway-${FLYWAY_VERSION}/flyway
RUN mkdir -p ${FLYWAY_INSTALL_DIR} && \
curl -L https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/${FLYWAY_VERSION}/flyway-commandline-${FLYWAY_VERSION}.tar.gz | \
tar -xzC ${FLYWAY_INSTALL_DIR} && \
chmod +x ${FLYWAY_EXE}
# Copy migration scripts
ENV MIGRATIONS_LOCATION /flyway/migrations
COPY migrations $MIGRATIONS_LOCATION
COPY init_db.sh /docker-entrypoint-initdb.d/init_db.sh
With my init_db.sh startup script:
#!/bin/bash
set -e
RUN_MIGRATIONS="${RUN_MIGRATIONS:-false}"
DB_URL="jdbc:postgresql://localhost:5432/$DB_NAME"
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
CREATE DATABASE $DB_NAME;
EOSQL
if [ "$RUN_MIGRATIONS" == "true" ]; then
echo "running migrations ..."
${FLYWAY_EXE} -user=$POSTGRES_USER -password=$POSTGRES_PASSWORD -url=$DB_URL -locations="filesystem:$MIGRATIONS_LOCATION" migrate
fi
However, when running the container with RUN_MIGRATIONS=true, flyway fails to connect to postgres:
docker build . -t postgres-flyway && docker run -e DB_NAME=db -e RUN_MIGRATIONS=true -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres postgres-flyway
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.
The database cluster will be initialized with locale "en_US.utf8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".
Data page checksums are disabled.
fixing permissions on existing directory /var/lib/postgresql/data ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok
WARNING: enabling "trust" 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.
Success. You can now start the database server using:
pg_ctl -D /var/lib/postgresql/data -l logfile start
waiting for server to start....LOG: database system was shut down at 2018-08-06 02:19:32 UTC
LOG: MultiXact member wraparound protections are now enabled
LOG: autovacuum launcher started
LOG: database system is ready to accept connections
done
server started
ALTER ROLE
/usr/local/bin/docker-entrypoint.sh: sourcing /docker-entrypoint-initdb.d/init_db.sh
CREATE DATABASE
running migrations ...
Flyway 4.2.0 by Boxfuse
ERROR:
Unable to obtain Jdbc connection from DataSource (jdbc:postgresql://localhost:5432/db) for user 'postgres': Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL State : 08001
Error Code : 0
Message : Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
The postgres image runs postgres on port 5432 (as usual) so I'm at a loss on why flyway is unable to connect to postgres over localhost:5432.
I also noticed that within this context, pg_isready states that postgres is accepting connections but when specifying the hostname as localhost or 127.0.0.1 it is unable to reach postgres either. That is, by inserting a few pg_isready commands in my init_db.sh script:
...
pg_isready
pg_isready -p 5432
pg_isready -h localhost -p 5432
...
I see the following log output on postgres init:
...
/var/run/postgresql:5432 - accepting connections
/var/run/postgresql:5432 - accepting connections
localhost:5432 - no response
...
I'm suspicious that I've reached a limitation of postgres' initialize context, but I would like to understand why postgres is unreachable over localhost/127.0.0.1:5432 at this point of initialization.
I had the same problem running flyway when creating a docker image for my database based on the postgres:10.5 image. I added the following to my entrypoint.sh before running flyway, to confirm that the problem I was seeing was caused by the docker-entrypoint.sh change #Nick Maraston posted in his answer:
echo "$(date) - waiting for database to start"
while ! pg_isready -h localhost -p 5432 -d $POSTGRES_DB
do
echo "$(date) - waiting for database to start"
sleep 10
done
The result was that the above code looped for ever. I then replaced it with the following code to restart the database listening for TCP/IP connections on localhost:
pg_ctl -D "$PGDATA" -m fast -w stop
pg_ctl -D "$PGDATA" \
-o "-c listen_addresses='localhost'" \
-w start
Rather than restarting the database like this, a cleaner solution would be to use the JDBC -socketFactory option explained here.
I discovered the problem while digging through the images entry point script. A recent change to the image restricts postgres to only listen for connections over a unix domain socket during internal initialization: https://github.com/docker-library/postgres/pull/440
It is true that postgres docker is listening to a unix socket, eg. /var/run/postgresql/.s.PGSQL.5432. But it is not necessary to force the server to switch its listening address. Postgres database URI allows a connection string to point to a unix socket.
Reference: Connect to a database over a unix socket using SQLAlchemy
The example provided:
export DATABASE_URL=postgres://user:password#/dbname?host=/path/to/unix/socket
I was able to omit the host, and decided to use this environment variable in my /docker-entrypoint-initdb.d/*.sh script instead. Note that no string follows the # symbol, nor is there a host query string here. You may need to explicitly define the host depending on your application.
Solution:
export DATABASE_URL="postgres://$POSTGRES_USER:$POSTGRES_PASSWORD#/$POSTGRES_DB"
There seems to be lots of questions likes this on stackoverflow, but none of them seemed to help me. I am runing Ubuntu on my windows linux subsystem and trying to install and use postgresql.
I installed in like this:
sudo apt-get install postgresql postgresql-contrib postgresql-client
pgadmin3
which worked fine:
near the bottom the install log says:
Creating new cluster 9.5/main ...
config /etc/postgresql/9.5/main
data /var/lib/postgresql/9.5/main
locale C
socket /var/run/postgresql
port 5433
update-alternatives: using /usr/share/postgresql/9.5/man/man1/postmaster.1.gz to provide /usr/share/man/man1/postmaster.1.gz (postmaster.1.gz) in auto mode
invoke-rc.d: could not determine current runlevel
Setting up postgresql (9.5+173) ...
Setting up postgresql-client (9.5+173) ...
Setting up postgresql-contrib-9.5 (9.5.8-0ubuntu0.16.04.1) ...
Setting up postgresql-contrib (9.5+173) ...
Processing triggers for systemd (229-4ubuntu16) ...
Processing triggers for ureadahead (0.100.0-19) ...
So the port is 5433. This is also the port listed in the postgresql.conf file.
When I type psql I get:
psql: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5433"?
When I do:
ps -df | grep postgres
I get a different port though (5432) and this is returned:
spotter 12 2 0 18:55 tty1 00:00:00 /usr/lib/postgresql/9.5/bin/psql -h 199.92.170.64 -d rtu_prod -Usv-read -p 5432
spotter 1835 2 0 20:21 tty1 00:00:00 grep --color=auto -a postgres
spotter 6134 2 0 20:51 tty1 00:00:00 grep --color=auto -a postgres
spotter 9348 2 0 22:06 tty1 00:00:00 grep --color=auto postgres
I think this might mean I have two versions of postgresql installed but I'm not sure.
Based on other posts I should enter /usr/lib/postgresql/9.5/bin/psql -h 199.92.170.64 -d rtu_prod -Usv-read -p 5432 to start it, but this asks for a password I have never heard of Password for user sv-read:
PostgreSQL works just fine with WSL. To fully run it, follow these steps:
Installation Steps:
sudo apt update
sudo apt install postgresql postgresql-contrib
sudo service postgresql start
sudo -i -u postgres
psql
User setup from psql:
CREATE USER <Your User name> WITH PASSWORD '<Your Password>';
CREATE DATABASE <Your database> WITH OWNER <Your User name>;
\password postgres
I was connected with remote postgres-9.3 by pgAdmin III. After close pgAdmin i try to connect on another day with the same db.
/etc/init.d/postgresql-9.3 status
dead but pid file exists
service postgresql-9.3 start FAIL
In pgstartup.log file i have:
This account is currently not available
pg_hba.conf:
# "local" is for Unix domain socket connections only
local all all peer
host all all 127.0.0.1/32 trust
host all all 89.70.224.82/32 md5
Operating system on server is CentOS. I don't know unfortunately how postgres was installed on the server because someone else done that.
What i can do with this?
The solution is reset your PostgreSQL logs
[root#user /]#/usr/pgsql-9.3/bin/pg_resetxlog -f /usr/pgsql-9.3/data/
after executing above command display "Transaction log reset"
and then restart PostgreSQL server
[root#user /]# /etc/init.d/postgresql-9.3 restart
Stopping postgresql-9.3 service: [FAILED]
Starting postgresql-9.3 service: [ OK ]
[root#qa /]# /etc/init.d/postgresql-9.3 status
(pid 3003) is running...
after checking your pgadmin
Try to start cluster using native postgres utility.
Assuming you have CentOS 6.6 and postgresql 9.4
sudo -u postgres /usr/pgsql-9.4/bin/pg_ctl -D <YOUR_DATA_DIR> start
You will get some reasonable output.
Then try to start postgres in single user mode
sudo -u postgres /usr/pgsql-9.4/bin/postgres --single -D <YOUR_DATA_DIR> -P -d 1
Beware that resetting xlogs will cause some data lost.
I also recommend to read this article http://blog.endpoint.com/2014/11/when-postgres-will-not-start.html