DockerPostgres

Docker Postgres for Development

Posted on by

In a previous post (Creating a simple Postgres VM for development) we already covered how to set up a local Postgres environment for development with vagrant. In this post we will use Docker to achieve the same. I assume you already know what Docker is and how to install it on your local machine.

Side note: If you don't care about your already existing docker containers and want to remove them, you can have a look at our post on how to easily remove docker containers and images in one line (Remove all Docker containers/images ).

Let's start with some requirements. We would like to have a Postgres database for development. Ideally we need two, one for local development and one which we can run automated tests. Furthermore we would like to keep the data so we don't need to start from scratch each time. And, of course, we want a simple and convenient handling.

To cover the last point we just decide to create a bash script which we can easily call to set up our environment. So we create a new folder in our project (choose any name you like). In this tutorial I will use docker as subfolder. In this folder we will create the initial file platform:

#!/bin/bash
cd $(dirname $0)/..

It does not much so far, it just jumps out of our docker folder to the root of our project. From now we can start fulfilling our requirements. Since we want to keep our data, lets ensure our database data is persisted in a special folder data like this:

#!/bin/bash
cd $(dirname $0)/..

function setup {
    # Create test data folder for development and test
    [ -d data/pgdata ] || mkdir data/pgdata
    [ -d data/pgdata_test ] || mkdir data/pgdata_test
}

Now that we have everything ready to start, lets pull a very basic Docker image postgres:9-alpine for Postgres:

#!/bin/bash
cd $(dirname $0)/..

function setup {
    # Create test data folder for development and test
    [ -d data/pgdata ] || mkdir data/pgdata
    [ -d data/pgdata_test ] || mkdir data/pgdata_test
}

function pull {
    docker pull postgres:9-alpine
}

Great! Now we can create our containers with the required environment variables:

#!/bin/bash
cd $(dirname $0)/..

function setup {
    # Create test data folder for development and test
    [ -d data/pgdata ] || mkdir data/pgdata
    [ -d data/pgdata_test ] || mkdir data/pgdata_test
}

function pull {
    docker pull postgres:9-alpine
}

function runDev {
    docker run -d \
        -p 5432:5432 \
        -e "POSTGRES_USER=myprojectdev" \
        -e "POSTGRES_PASSWORD=dev" \
        -e "POSTGRES_DB=myprojectdev" \
        -e "PGDATA=/var/lib/postgresql/data/pgdata" \
        -v $(pwd)/data/pgdata:/var/lib/postgresql/data/pgdata \
        --name=myprojectdev-postgres postgres:9-alpine
}

function runTest {
    docker run -d \
        -p 5433:5432 \
        -e "POSTGRES_USER=myprojecttest" \
        -e "POSTGRES_PASSWORD=test" \
        -e "POSTGRES_DB=myprojecttest" \
        -e "PGDATA=/var/lib/postgresql/data/pgdata" \
        -v $(pwd)/data/pgdata:/var/lib/postgresql/data/pgdata \
        --name=myprojecttest-postgres postgres:9-alpine
}

A short explanation. We created two new functions in our bash script startDev and startTest. Both are running new containers but with different parameters. The important part is the binding of a volume (-v) to our data folder we created earlier. This way we can simply destroy and recreate our containers and keep the data.

Now we can setup and run our containers. But what about stopping them? Let's create a new function in the same file:

#!/bin/bash
cd $(dirname $0)/..

...

function stopAll {
    # destroy postgres container
    docker rm -f myprojectdev-postgres

    # destroy postgres test container
    docker rm -f myprojecttest-postgres
}

Ok, cool, we can just throw away our containers (recreation is fast because we keep the base image). As the last step, let's make this whole thing usable by adding a switch case on the first parameter:

case "$1" in
  start)
    setup
    stopAll
    startDev
    startTest
    ;;
  stop)
    stopAll
    ;;
  restart)
    stopAll
    startDev
    startTest
    ;;
  pull)
    # pull postgres container
    docker pull postgres:9-alpine
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|pull}" >&2
    exit 1
    ;;
esac

With all things in place, we can try our script like this:

./docker/platform pull
./docker/platform start

Now our script will pull the image and start our containers for development. We can use docker ps to check if our containers are present. To stop containers, we can use:

./docker/platform stop

I hope this tutorial helps you in your daily development. If you have any questions or comments please feel free to use the area below.