Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Postgres with Docker: Postgres fails to load when persisting data

I'm new to Postgres.

I updated the Dockerfile I use and successfully installed Postgresql on it. (My image runs Ubuntu 16.04 and I'm using Postgres 9.6.)

Everything worked fine until I tried to move the database to a Volume with docker-compose (that was after making a copy of the container's folder with cp -R /var/lib/postgresql /somevolume/.)

The issue is that Postgres just keeps crashing, as witnessed by supervisord:

2017-07-26 18:55:38,346 INFO exited: postgresql (exit status 1; not expected)
2017-07-26 18:55:39,355 INFO spawned: 'postgresql' with pid 195
2017-07-26 18:55:40,430 INFO success: postgresql entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2017-07-26 18:55:40,763 INFO exited: postgresql (exit status 1; not expected)
2017-07-26 18:55:41,767 INFO spawned: 'postgresql' with pid 197
2017-07-26 18:55:42,841 INFO success: postgresql entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2017-07-26 18:55:43,179 INFO exited: postgresql (exit status 1; not expected)
(and so on…)

Logs

It's not clear to me what's happening as /var/log/postgresql remains empty.

chown?

I suspect it has to do with the user. If I compare the data folder inside the container and the copy I made of it to the volume, the only difference is that the original is owned by postgres while the copy is owned by root.

I tried running chown -R postgres:postgres on the copy. The operation was performed successfully, however postmaster.pid remains owned by root and I think that would be the issue.

Questions

  • How can I get more information about the cause of the crash?
  • How can I make it so that postmaster.id be owned by postgres ?
  • Should I consider running postgres with root instead?

Any hint welcome.


EDIT: links to the Dockerfile and the docker-compose.xml.

like image 260
Fabien Snauwaert Avatar asked Jul 26 '17 17:07

Fabien Snauwaert


3 Answers

I'll answer my own question:

Logs & errors

What made matters more complicated was that I was not getting any specific error message.

To change that, I disabled the [program:postgresql] section in supervisord and, instead, started postgres manually from the command-line (thanks to Miguel Marques for setting me on the right track with his comment.)

Then I finally got some useful error messages:

2017-08-02 08:27:09.134 UTC [37] LOG:  could not open temporary statistics file "/var/run/postgresql/9.6-main.pg_stat_tmp/global.tmp": No such file or directory

Fixing the configuration

I fixed the error above with this, eventually adding them to my Dockerfile:

mkdir -p /var/run/postgresql/9.6-main.pg_stat_tmp
chown postgres.postgres /var/run/postgresql/9.6-main.pg_stat_tmp -R

(Kudos to this guy for the fix.)

To make the data permanent, I also had to do this, for the volume to be accessible by postgres:

mkdir -p /var/lib/postgresql/9.6/main
chmod 700 /var/lib/postgresql/9.6/main 

I also used initdb to initialize the data directory. BEWARE! This will erase any data found in that folder. Like so:

rm -R /var/lib/postgresql/9.6/main/*
ls /var/lib/postgresql/9.6/main/
/usr/lib/postgresql/9.6/bin/initdb  -D /var/lib/postgresql/9.6/main

Testing

After the above, I could finally run postgres properly. I used this command to run it and test from the command-line:

su postgres
/usr/lib/postgresql/9.6/bin/postgres -D /var/lib/postgresql/9.6/main -c config_file=/etc/postgresql/9.6/main/postgresql.conf # as per the Docker docs

To test, I kept it running and then, from another prompt, checked everything ran fine with this:

su postgres
psql
CREATE TABLE cities ( name varchar(80), location point );
INSERT INTO cities VALUES ('San Francisco', '(-194.0, 53.0)');
select * from cities; # repeat this command after restarting the container to check that the data does persist

…making sure to restart the container and test again to check the data did persist.

And then finally restored the [program:postgresql] section in supervisord, rebuilt the image and restarted the container, making sure everything ran fine (in particular supervisord: tail /var/log/supervisor/supervisord.log), which it did.

(The command I used inside of supervisord.conf is also /usr/lib/postgresql/9.6/bin/postgres -D /var/lib/postgresql/9.6/main -c config_file=/etc/postgresql/9.6/main/postgresql.conf, as per this Docker article and other postgres+supervisord examples. Other options would have been using pg_ctl or an init.d script, but it's not clear to me why/when one would use those.)


I spent a lot of time on this. Hopefully the detailed answer will help someone down the line.

P.S.: I did end up producing a minimal example of my issue. If that can help anyone, here they are: Dockerfile, supervisord.conf and docker-compose.yml.

like image 155
Fabien Snauwaert Avatar answered Nov 11 '22 14:11

Fabien Snauwaert


I do not know if this would be another way to achieve the same result (I'm new on Docker and Postgres too), but have you try the oficial repository image for Postgres (https://hub.docker.com/_/postgres/)?

I'm getting the data out of the container setting the environment variable PGDATA to '/var/lib/postgresql/data/pgdata' and binding this to an external volume on the run command:

docker run --name bd_TEST --network=my_network --restart=always -e POSTGRES_USER="superuser" -e POSTGRES_PASSWORD="myawesomepass" -e PGDATA="/var/lib/postgresql/data/pgdata" -v /var/local/db_data:/var/lib/postgresql/data/pgdata -itd -p 5432:5432 postgres:9.6

When the volume is empty, all the files are created by the image startup script, and if they already exist, the database start to used it.

like image 25
Bruno Eduardo Avatar answered Nov 11 '22 13:11

Bruno Eduardo


From past experience I can see what may be a problem. I can't say if this will help but it is worth a try. I would have added this as a comment, but I can't because my rep isn't hight enough.

I've spied a couple problems with how you have structured your statements in your Dockerfile. You have installed various things multiple times and also updated sporadically through the code. In my own files i've noticed that this can lead to somewhat random behaviour of my services and installation because of the different layers.

This may not seem to solve your problem directly, but cleaning up your file as is outlined in the best practices has solved many Dockerfile problems for me in the past.

One of the first places upon finding such problems is to start here at the best practices for RUN. This has helped me solve tricky problems in the past and I hope it'll solve or at least make it easier.

Pay special attention to this part:

After building the image, all layers are in the Docker cache. Suppose you later modify apt-get install by adding extra package:

 FROM ubuntu:14.04
 RUN apt-get update
 RUN apt-get install -y curl nginx 

Docker sees the initial and modified instructions as identical and reuses the cache from previous steps. As a result the apt-get update is NOT executed because the build uses the cached version. Because the apt-get update is not run, your build can potentially get an outdated version of the curl and nginx packages.

After reading this I would start by consolidating all your dependencies.

like image 1
Archernar Avatar answered Nov 11 '22 15:11

Archernar