Search code examples
bashpostgresqldockerdockerhub

How to create User/Database in script for Docker Postgres


I have been trying to set up a container for a development postgres instance by creating a custom user & database. I am using the official postgres docker image. In the documentation it instructs you to insert a bash script inside of the /docker-entrypoint-initdb.d/ folder to set up the database with any custom parameters.

My bash script: make_db.sh

su postgres -c "createuser -w -d -r -s docker"
su postgres -c "createdb -O docker docker"

Dockerfile

FROM library/postgres

RUN ["mkdir", "/docker-entrypoint-initdb.d"]
ADD make_db.sh /docker-entrypoint-initdb.d/

The error I get from the docker logs -f db (db is my container name) is:

createuser: could not connect to database postgres: could not connect to server: No such file or directory

It seems that the commands inside of the /docker-entrypoint-initdb.d/ folder are being executed before postgres is started. My question is, how do I set up a user/database programmatically using the official postgres container? Is there any way to do this with a script?


Solution

  • EDIT - since Jul 23, 2015

    The official postgres docker image will run .sql scripts found in the /docker-entrypoint-initdb.d/ folder.

    So all you need is to create the following sql script:

    init.sql

    CREATE USER docker;
    CREATE DATABASE docker;
    GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
    

    and add it in your Dockerfile:

    Dockerfile

    FROM library/postgres
    COPY init.sql /docker-entrypoint-initdb.d/
    

    But since July 8th, 2015, if all you need is to create a user and database, it is easier to just make use to the POSTGRES_USER, POSTGRES_PASSWORD and POSTGRES_DB environment variables:

    docker run -e POSTGRES_USER=docker -e POSTGRES_PASSWORD=docker -e POSTGRES_DB=docker library/postgres
    

    or with a Dockerfile:

    FROM library/postgres
    ENV POSTGRES_USER docker
    ENV POSTGRES_PASSWORD docker
    ENV POSTGRES_DB docker
    

    for images older than Jul 23, 2015

    From the documentation of the postgres Docker image, it is said that

    [...] it will source any *.sh script found in that directory [/docker-entrypoint-initdb.d] to do further initialization before starting the service

    What's important here is "before starting the service". This means your script make_db.sh will be executed before the postgres service would be started, hence the error message "could not connect to database postgres".

    After that there is another useful piece of information:

    If you need to execute SQL commands as part of your initialization, the use of Postgres single user mode is highly recommended.

    Agreed this can be a bit mysterious at the first look. What it says is that your initialization script should start the postgres service in single mode before doing its actions. So you could change your make_db.ksh script as follows and it should get you closer to what you want:

    NOTE, this has changed recently in the following commit. This will work with the latest change:

    export PGUSER=postgres
    psql <<- EOSQL
        CREATE USER docker;
        CREATE DATABASE docker;
        GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
    EOSQL
    

    Previously, the use of --single mode was required:

    gosu postgres postgres --single <<- EOSQL
        CREATE USER docker;
        CREATE DATABASE docker;
        GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
    EOSQL