This post describes how you may achieve a postgres container initialization using a bash script using
docker secrets (you could use
configs as well) without having to
modify official image for postgres
This post requires docker swarm to be active, though you don’t need a cluster
First of all initialize docker swarm if you haven’t done so
docker swarm init
Before we start, let’s see why we may use docker secrets to achieve it, since we will be using docker-compose (service based) to allow us to do it, from the docs we get :
You can use secrets to manage any sensitive data which a container needs at runtime but you don’t want to store in the image or in source control…
So this allows us to have files managed by docker under containers at runtime.
Without getting into the security specifications for docker secrets, we may jump to how we may use it.
docker secret create path/to/file/in/host name_of_secret[.optional extension]
Ok so now we have a way to create a docker managed secret from a file.
We also have that there are a few flags we may use when setting the container access to the secret.
The default simple usage is just to pass the secret name to the container with:
docker run --secret name_of_secret.ext some_image
This will mount the secret under
/run/secrets/name_of_secret.ext by the default
But there are other flags via csv
Being the explicitly documented:
source target #Example: --secret source=name_of_secret,target=/path/to/secret/inside/the/container
This will mount the secret under
/path/to/secret/inside/the/container and the path doesn’t have to exist prior to mounting.
We also have others modifiers when setting the secret inside the container
UID GID Mode --secret source=name_of_secret,target=/path/to/secret/inside,uid:1000,gid:1000,mode:400 th container
There are no examples in the referred link for documentation of docker secrets
So this allows us to set a secret inside a container, that may belong to a specific user and group, an most important for our use case, the
mode that allows us to set the permission bit for execution we will require for our bash script.
Please not the mode must be an octal for permissions, will not get into details on permission octals.
So what this has to do with postgresql official docker image you may ask?
Well, from the documentation for image usage we get that it is possible to extend the image by setting scripts inside the
/docker-entrypoint-initdb.d/ folder, and an example would be:
#!/bin/bash set -e echo "Creating DB" psql <<- EOSQL CREATE USER docker_secret; CREATE DATABASE docker_secrets; GRANT ALL PRIVILEGES ON DATABASE docker_secrets TO docker_secret; EOSQL echo "Done Creating DB"
Of course you may set an extremely complex bash, or multiple bash scripts inside this folder in order to fully set your postgres container on initialization.
So now let’s check an example of this merge.
For simplicity, we will use a docker-compose.yml example.
Let’s create the following
version: '3.6' services: postgres: image: postgres:11.1 secrets: - source: database_initialization target: "/docker-entrypoint-initdb.d/create-db.sh" #Grant read and execute permission to owner, execute and read to group and others mode: 0755 #The uid for root is due to the permissions for the init.db folder for image uid: "0" secrets: database_initialization: file: create-db.sh
With the contents from the example above for database creation under a file a named:
create-db.sh in our root folder for this example.
As you see we are not modifying the official image, and not referencing a single dockerfile to be built etc..
If you are in windows watch out for CRLF line endings, and change them to LF.
So secrets using UID GID an Mode are only support with swarm mode active.
So let’s start our postgres service with
$docker stack deploy --compose-file=docker-compose.yml Creating network postgres_default Creating secret postgres_database_initialization Creating service postgres_echo_secret
Lets check our service logs to see what is going on.
postgres_postgres.1.mqms6d4f2224@linuxkit-00155d51a607 | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/create-db.sh postgres_postgres.1.mqms6d4f2224@linuxkit-00155d51a607 | Creating DB postgres_postgres.1.mqms6d4f2224@linuxkit-00155d51a607 | CREATE ROLE postgres_postgres.1.mqms6d4f2224@linuxkit-00155d51a607 | CREATE DATABASE postgres_postgres.1.mqms6d4f2224@linuxkit-00155d51a607 | GRANT postgres_postgres.1.mqms6d4f2224@linuxkit-00155d51a607 | Done Creating DB
And there we have it, the script has been ran an our database has been created.
This example was for postgresql , but may be used with many other images.
This could also have used
docker configs as usage is extremely smilar,here is the compose file to achieve it below:
version: '3.6' services: postgres: image: postgres:11.1 configs: - source: database_initialization target: "/docker-entrypoint-initdb.d/create-db.sh" #Grant read and execute permission mode: 0755 uid: "0" configs: database_initialization: file: create-db.sh
Hope you enjoyed reading, and that somehow it helped you somehow.