How to create User/Database in script for Docker Postgres
With docker compose there's a simple alternative (no need to create a Dockerfile). Just create a init-database.sh:
#!/bin/bash
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE USER docker;
CREATE DATABASE my_project_development;
GRANT ALL PRIVILEGES ON DATABASE my_project_development TO docker;
CREATE DATABASE my_project_test;
GRANT ALL PRIVILEGES ON DATABASE my_project_test TO docker;
EOSQL
And reference it in the volumes section:
version: '3.4'
services:
postgres:
image: postgres
restart: unless-stopped
volumes:
- postgres:/var/lib/postgresql/data
- ./init-database.sh:/docker-entrypoint-initdb.d/init-database.sh
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
ports:
- 5432:5432
volumes:
postgres:
By using docker-compose
:
Assuming that you have following directory layout:
$MYAPP_ROOT/docker-compose.yml
/Docker/init.sql
/Docker/db.Dockerfile
File: docker-compose.yml
version: "3.3"
services:
db:
build:
context: ./Docker
dockerfile: db.Dockerfile
volumes:
- ./var/pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
File: Docker/init.sql
CREATE USER myUser;
CREATE DATABASE myApp_dev;
GRANT ALL PRIVILEGES ON DATABASE myApp_dev TO myUser;
CREATE DATABASE myApp_test;
GRANT ALL PRIVILEGES ON DATABASE myApp_test TO myUser;
File: Docker/db.Dockerfile
FROM postgres:11.5-alpine
COPY init.sql /docker-entrypoint-initdb.d/
Composing and starting services:
docker-compose -f docker-compose.yml up --no-start
docker-compose -f docker-compose.yml start
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