diff --git a/README.md b/README.md index 3db6ca3..205c511 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,142 @@ # Using multiple databases with the official PostgreSQL Docker image -The [official recommendation](https://hub.docker.com/_/postgres/) for creating -multiple databases is as follows: - -*If you would like to do additional initialization in an image derived from -this one, add one or more `*.sql`, `*.sql.gz`, or `*.sh` scripts under -`/docker-entrypoint-initdb.d` (creating the directory if necessary). After the -entrypoint calls `initdb` to create the default `postgres` user and database, -it will run any `*.sql` files and source any `*.sh` scripts found in that -directory to do further initialization before starting the service.* - This directory contains a script to create multiple databases using that mechanism. +The following script uses the user and password information +in file ./users/users.txt to to create a database per user, +set the password for that database and then initialize the postgis +extensions. + +The user file should contain pairs of lines that are the user and password. +e.g. +``` +user1 +passwd1 +user2 +passwd2 +``` + + ## Usage -### By mounting a volume +* Create a directory 'dbdata' - if you need to re-create it, note that you'll need to use sudo + so `sudo rm -rf ./dbdata ; mkdir dbdata` is useful + +* Run `docker-compose up` + +This should create the default databases (and one called `myapp` with the configuration as is). + +Then, run `users/all-users-add.sh` and it will add databases for individual users. +You can run that multiple times (e.g. if you decide to add a new user). + +The resulting set of databases can be listed by connecting and using `\list`: + + +``` +$ psql postgresql://myapp:changeme@localhost + +myapp=# \list + List of databases + Name | Owner | Encoding | Collate | Ctype | Access privileges +------------------+-------+----------+------------+------------+------------------- + alice | myapp | UTF8 | en_US.utf8 | en_US.utf8 | =Tc/myapp + + | | | | | myapp=CTc/myapp + + | | | | | db1=CTc/myapp + bob | myapp | UTF8 | en_US.utf8 | en_US.utf8 | =Tc/myapp + + | | | | | myapp=CTc/myapp + + | | | | | db2=CTc/myapp + myapp | myapp | UTF8 | en_US.utf8 | en_US.utf8 | + postgres | myapp | UTF8 | en_US.utf8 | en_US.utf8 | + template0 | myapp | UTF8 | en_US.utf8 | en_US.utf8 | =c/myapp + + | | | | | myapp=CTc/myapp + template1 | myapp | UTF8 | en_US.utf8 | en_US.utf8 | =c/myapp + + | | | | | myapp=CTc/myapp + template_postgis | myapp | UTF8 | en_US.utf8 | en_US.utf8 | +(7 rows) + +myapp=# \q +``` -Clone the repository, mount its directory as a volume into -`/docker-entrypoint-initdb.d` and declare database names separated by commas in -`POSTGRES_MULTIPLE_DATABASES` environment variable as follows -(`docker-compose` syntax): +## Test it out - myapp-postgresql: - image: postgres:9.6.2 - volumes: - - ../docker-postgresql-multiple-databases:/docker-entrypoint-initdb.d - environment: - - POSTGRES_MULTIPLE_DATABASES=db1,db2 - - POSTGRES_USER=myapp - - POSTGRES_PASSWORD= +The script `./users/all-users-test.sh` will loop through each user and question run postgres_version() to +insure that the postgis extensions are installed. It will also create a table that uses a `GEOM` +type which would fail if postgis is not setup correctly. -### By building a custom image +``` +beast-61$ ./all-users-test.sh +Databases are... + List of databases + Name | Owner | Encoding | Collate | Ctype | Access privileges +------------------+-------+----------+------------+------------+------------------- + alice | myapp | UTF8 | en_US.utf8 | en_US.utf8 | =Tc/myapp + + | | | | | myapp=CTc/myapp + + | | | | | alice=CTc/myapp + bob | myapp | UTF8 | en_US.utf8 | en_US.utf8 | =Tc/myapp + + | | | | | myapp=CTc/myapp + + | | | | | bob=CTc/myapp + myapp | myapp | UTF8 | en_US.utf8 | en_US.utf8 | + postgres | myapp | UTF8 | en_US.utf8 | en_US.utf8 | + template0 | myapp | UTF8 | en_US.utf8 | en_US.utf8 | =c/myapp + + | | | | | myapp=CTc/myapp + template1 | myapp | UTF8 | en_US.utf8 | en_US.utf8 | =c/myapp + + | | | | | myapp=CTc/myapp + template_postgis | myapp | UTF8 | en_US.utf8 | en_US.utf8 | +(7 rows) -Clone the repository, build and push the image to your Docker repository, -for example for Google Private Repository do the following: +dbuser is alice +dbpasswd is alicePassword +dbuser is alice +dbpasswd is alicePassword + List of schemas + Name | Owner +----------+------- + public | myapp + topology | myapp +(2 rows) - docker build --tag=eu.gcr.io/your-project/postgres-multi-db . - gcloud docker -- push eu.gcr.io/your-project/postgres-multi-db + List of relations + Schema | Name | Type | Owner +----------+-----------------+-------+------- + public | spatial_ref_sys | table | myapp + public | states | table | alice + topology | layer | table | myapp + topology | topology | table | myapp +(4 rows) -You still need to pass the `POSTGRES_MULTIPLE_DATABASES` environment variable -to the container: + postgis_full_version +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + POSTGIS="3.1.1 aaf4c79" [EXTENSION] PGSQL="130" GEOS="3.7.1-CAPI-1.11.1 27a5e771" PROJ="Rel. 5.2.0, September 15th, 2018" LIBXML="2.9.4" LIBJSON="0.12.1" LIBPROTOBUF="1.3.1" WAGYU="0.5.0 (Internal)" TOPOLOGY +(1 row) - myapp-postgresql: - image: eu.gcr.io/your-project/postgres-multi-db - environment: - - POSTGRES_MULTIPLE_DATABASES=db1,db2 - - POSTGRES_USER=myapp - - POSTGRES_PASSWORD= +DROP TABLE +CREATE TABLE +dbuser is bob +dbpasswd is bobPassword +dbuser is bob +dbpasswd is bobPassword + List of schemas + Name | Owner +----------+------- + public | myapp + topology | myapp +(2 rows) -### Non-standard database names + List of relations + Schema | Name | Type | Owner +----------+-----------------+-------+------- + public | spatial_ref_sys | table | myapp + public | states | table | bob + topology | layer | table | myapp + topology | topology | table | myapp +(4 rows) -If you need to use non-standard database names (hyphens, uppercase letters etc), quote them in `POSTGRES_MULTIPLE_DATABASES`: + postgis_full_version +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + POSTGIS="3.1.1 aaf4c79" [EXTENSION] PGSQL="130" GEOS="3.7.1-CAPI-1.11.1 27a5e771" PROJ="Rel. 5.2.0, September 15th, 2018" LIBXML="2.9.4" LIBJSON="0.12.1" LIBPROTOBUF="1.3.1" WAGYU="0.5.0 (Internal)" TOPOLOGY +(1 row) - environment: - - POSTGRES_MULTIPLE_DATABASES="test-db-1","test-db-2" +DROP TABLE +CREATE TABLE +``` diff --git a/create-multiple-postgresql-databases.sh b/create-multiple-postgresql-databases.sh deleted file mode 100755 index aa665fa..0000000 --- a/create-multiple-postgresql-databases.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -set -e -set -u - -function create_user_and_database() { - local database=$1 - echo " Creating user and database '$database'" - psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL - CREATE USER $database; - CREATE DATABASE $database; - GRANT ALL PRIVILEGES ON DATABASE $database TO $database; -EOSQL -} - -if [ -n "$POSTGRES_MULTIPLE_DATABASES" ]; then - echo "Multiple database creation requested: $POSTGRES_MULTIPLE_DATABASES" - for db in $(echo $POSTGRES_MULTIPLE_DATABASES | tr ',' ' '); do - create_user_and_database $db - done - echo "Multiple databases created" -fi diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..94c8a19 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +myapp-postgresql: + image: postgis/postgis:latest + volumes: + - ./users:/opt-users + - ./dbdata:/var/lib/postgresql/data + ports: + - "5432:5432" + environment: + - POSTGRES_USER=myapp + - POSTGRES_PASSWORD=changeme diff --git a/script/create-multiple-postgres-databases.sh b/script/create-multiple-postgres-databases.sh new file mode 100755 index 0000000..aba5fc7 --- /dev/null +++ b/script/create-multiple-postgres-databases.sh @@ -0,0 +1,38 @@ +# +# The following script uses the user and password information +# in file /opt-users/users.txt to to create a database per user, +# set the password for that database and then initialize the postgis +# extensions. +# +# The user file shoudl contain pairs of lines that are the user and password. +# e.g. +# user1 +# passwd1 +# user2 +# passwd2 +# + +set -e +set -u + +while IFS= read -r dbuser; do + echo "dbuser is $dbuser" + read -r dbpasswd + echo "dbpasswd is $dbpasswd" + echo " Creating user and database '$dbuser'" + + psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL1 + CREATE USER $dbuser PASSWORD '$dbpasswd'; + CREATE DATABASE $dbuser; + GRANT ALL PRIVILEGES ON DATABASE $dbuser TO $dbuser; +EOSQL1 + + psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" $dbuser <<-EOSQL2 + CREATE EXTENSION postgis; + CREATE EXTENSION postgis_topology; +\dn. +\dt. + GRANT ALL PRIVILEGES ON SCHEMA topology TO $dbuser; +EOSQL2 + +done < /opt-users/users.txt diff --git a/users/all-users-add.sh b/users/all-users-add.sh new file mode 100755 index 0000000..8dd4147 --- /dev/null +++ b/users/all-users-add.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# +# Test named database for GIS sections +# + +while IFS= read -r dbuser; do + echo "dbuser is $dbuser" + read -r dbpasswd + echo "dbpasswd is $dbpasswd" + ./single-user-add.sh $dbuser $dbpasswd +done < users.txt + +echo "Databases are..." +psql postgresql://myapp:changeme@localhost <