Docker over VPN

Containerizing applications makes a lot of sense in a lot of ways, and has really streamlined my local development and my deployment to the cloud. Between build pipelines for Bitbucket, Github, Google Cloud, and AWS – and the need to quickly spin up databases and other dev environments without cluttering my machine, Docker has been a great tool.

Recently, I wanted to clean my machine up further to keep it speedy for remote work, and looked into offloading Docker onto another machine on the network. Instead of making these public to the internet, I wanted to open them up to the subnet over a VPN tunnel.

Install a VPN

I love Algo and use this all the time. It takes a while, and sometimes the settings can be troublesome, but it’s robust and easy to set up a relatively secure server. Make sure to allow client to client communication.

Install Docker and a useful container

brew install docker

or install from source

Create a postgres-multiple-databases container from this repo

# Dockerfile
FROM postgres:latest
COPY create-multiple-postgresql-databases.sh /docker-entrypoint-initdb.d/
# create-multiple-postgresql-databases.sh
#!/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 DATABASE "$database";
      GRANT ALL PRIVILEGES ON DATABASE "$database" TO "$POSTGRES_USER";
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


exec "$@"
docker build db -t db
docker run -id --name rails-db -e POSTGRES_MULTIPLE_DATABASES="db-dev","db-test","db-prod" -e POSTGRES_USER=<user> -e POSTGRES_PASSWORD=<pw> -p 5432:5432 db:latest

Connecting

It’s super easy! Docker’s -p 5432:5432 maps the container’s port to the computer’s, and listens on 0.0.0.0 which covers every interface.

To test, I used a Rails app:

default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5
  timeout: 5000
  username: <user>
  password: <pw>
  host: 10.19.48.3  # IP of computer on VPN; TODO hostname
  port: 5432

development:
  <<: *default
  database: db-dev

test:
  <<: *default
  database: db-test

production:
  <<: *default
  database: db-prod

This works straight away!