Useless introduction

Some years ago (two?) I had no idea what Docker was, I’d say that even now I just barely scratched the surface. But now I’ve been using it for a while, I’ve just got back from a couple of workshops about tech talks, tonight I’ve been stood up and was just talking about Docker with a friend, so I thought why not, let’s write a simple tutorial on why and how to use Docker for your little database needs.

Previously on what is Docker

I guess that if you are looking for Docker stuff on the internet you may already have some basic knowledge, but repetita iuvant, they say.

Basically, with Docker you create a kind of virtual machine1 that helps you ship your application and deploy it wherever you want, ensuring that you have the same environment across multiple servers/machines/hosts/whatever. You declare what you want in your container (operating system, dependencies, how to copy your app assets and so on), a bunch of configuration options like ports, and you’re good to go. This is incredibly useful for a variety of reasons, first of all, it helps you avoid the usual pain of things that work just fine in your local environment and then explode as soon as you deploy it someplace else.

It works on my container!

Another good reason is in the development phases: it helps you develop and test things directly on the environment you’re supposed to use, and I can’t stress enough how useful is when it comes to databases: having your schemas and data defined in some files, build everything up with a single command and being able to drop everything and restart with a clean environment from scratch with another single command? Too good to be true!

OK, so how do we do that?

Installing

Well, first, you install it, and the official documentation is better than me at this job.

Then, of course, you pick what database you want to use. I’m very partial to PostgreSQL, but you should be able to follow along with any kind of DBMS you prefer.

Compose to the rescue!

I remember that when I first searched on the internet about how to make Postgres instances with Docker I incurred in a bunch of tutorials making my head spinning with docker run commands and other black satanic magic, so I think the best approach for this job is to use docker-compose. It’s a tool used for creating a multi-container Docker application2.

Let’s say for example that you need to use PostgreSQL with pgAdmin, or maybe add an nginx server: with compose you simply define what images you want in your environment, maybe a couple more things that we’ll see in a moment and call it a day. Example:

services:
  postgres:
    container_name: postgres
    image: postgres:latest
    environment:
      - POSTGRES_USER=valerio
      - POSTGRES_PASSWORD=mylousypassword
      - POSTGRES_DB=dbname
    volumes:
      - ./scripts/a_random_setup_script.sh:/docker-entrypoint-initdb.d/01_random_script.sh
      - ./schemas/users_schema.sql:/docker-entrypoint-initdb.d/02_schema_users.sql
      - ./data/users_dump.sql:/docker-entrypoint-initdb.d/03_users_dump.sql
    ports:
      - "5432:5432"
    restart: always

  pgadmin:
    container_name: pgadmin
    image: dpage/pgadmin4:latest
    environment:
      - PGADMIN_DEFAULT_EMAIL=valerio@mail.zyx
      - PGADMIN_DEFAULT_PASSWORD=mylousypassword
    ports:
      - "5050:80"
    restart: always

As you may have noticed, there is an interesting option in this file, volumes. Docker allows you to mount local folders and files directly into your container, and this is particularly useful when you work with databases, especially in the development phases. You define everything you need for the setup of your DB, you put it into that /docker-entrypoint-initdb.d/ folder (YMMV for other DBMS, but for example it should be the same for MySQL), and you can do all kinds of nasty stuff with it, with the safety net of recreating everything you need with just one command (more on that later).

Tips

A couple of things: never, never, use latest for your containers. You don’t want to be hit, one day, by a breaking change in your containers: latest, like the name suggests, fetches the most recent version from the Docker Hub repository, and it doesn’t care about anything else, especially about you. So, you go there, you pick a version you’re comfortable with, and you pay attention to keep your dependencies updated, like you’re supposed to do already.

And now, how do I run it?

First, you pick a folder, preferably in the root of your project, or the root itself if you prefer. Call it whatever you want, but as usual meaningful names are better3. If you want to call it something like docker or containers, you’d better set an ENV var for your project in a hidden file in the folder, .env: by default, Docker uses the name of the folder as a name for the whole application - so, to distinguish between different applications you have locally, put into the .env file something like this:

COMPOSE_PROJECT_NAME=myawesomedockerproject

Then, in the same folder, you create a file called docker-compose.yaml with something like the file I just gave you a couple of scrolls ago, save it and run to your terminal window and run docker-compose up and behold your application go live with it!

Next steps

I was always not very great at conclusions, so that’s pretty much everything. Additional useful resources on the topic:

Feel free to ping me about whatever issue, tip or random stuff.


  1. Yeah, it’s not the same thing, but let’s keep it simple ↩︎

  2. You can, of course, make a docker-compose file with only one image, nobody will kill you or something. ↩︎

  3. There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors. ↩︎