Docker makes for Easy Databases


As our various JSON API implementations expect to be able to save and retrieve data beyond the lifetime of a single request, it makes sense that sooner or later, we're going to need a database.

Depending on your preference, you may wish to use MySQL, or Postgres for your database. Sometimes one is easier than the other, sometimes it makes no difference.

We're going to use Docker for our database. You do not need to. It just makes life easier, in my opinion.

Whichever database you want to use, a docker-compose.yml file is going to make working with Docker the easiest it can be.

Whether using MySQL or Postgres, create a docker-compose.yml in the root of your project's directory.

MySQL

Here's what we'll use for MySQL:

version: '3'

services:

    db_dev:
        image: mysql:5.7.21
#        volumes:
#          - "./volumes/mysql_dev:/var/lib/mysql"
        ports:
          - "3306:3306"
        environment:
          - MYSQL_ROOT_PASSWORD=password
          - MYSQL_DATABASE=your_db_name_here
          - MYSQL_USER=dbuser
          - MYSQL_PASSWORD=dbpassword

I have a Beginner friendly Docker tutorial right here on the site. There's nothing we are going to do here that requires anything but the most commonly used Docker commands.

Simply put this configuration will bring up a MySQL instance, running version 5.7.21 (the latest in the 5.x branch at the time of recording).

This MySQL database will be available on port 3306.

You won't need to create a database in this container. Instead the container comes up with an already available database - called in this case: your_db_name_here.

We have defined a user and password of dbuser / dbpassword.

The root password needs to be set. These are all mandatory environment variables for bringing a MySQL docker container online. Change any of the values as you see fit.

Postgres

Here's what we'll use for Postgres:

version: '3'

services:

  postgres:
    image: postgres:10.2
#    volumes:
#      - "./volumes/postgres:/var/lib/postgresql/data"
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=dbuser
      - POSTGRES_PASSWORD=dbpass
      - POSTGRES_DB=your_db_name_here

Again, very similar to MySQL. A Postgres container will come online with a preset database - your_db_name_here, with the user and password of dbuser / dbpass. Change as needed.

This container will be available on port 5432.

Volumes

Docker volumes are an interesting subject. I strongly recommend you watch the relevant videos in the Beginner friendly Docker tutorial if at all curious.

I have left both volumes commented out in the respective docker-compose.yml file definitions.

You do not need volumes to complete this series. However, if you'd like the data to stick around then be aware these are configured as bind mounts.

Ports

In both MySQL and Postgres definitions we have exposed the default ports.

For MySQL this is port 3306. And for Postgres, this is 5432.

There is a potential gotcha here.

If you are running multiple instances of the MySQL or Postgres container concurrently, or you have an existing MySQL / Postgres server running locally, only one of these may take the port.

This means you may need to change the definition slightly, to use a different port:

version: '3'

services:

  postgres:
    image: postgres:10.2
    ports:
      - "5433:5432"
    environment:
      - #etc

Here we've remapped the Postgres port to 5433. This still maps internally on the container to 5432. This means we can now have multiple Postgres containers up and running without risk of port conflict.

I typically just increment the number by one on a new project.

Of course, be sure to update your project to use the alternate port as appropriate.

Going Online and Offline

In order to bring this database up and online, we need to run a command:

docker-compose down && \
    docker-compose build --pull --no-cache && \
    docker-compose \
        -f docker-compose.yml \
    up -d --remove-orphans

Again, you don't need to know much about this command in order to use it. Please watch this course if you would like to understand it further.

To save from having to remember all that, I would advise creating a Makefile:

touch Makefile

And add the following contents:

dev:
    @docker-compose down && \
        docker-compose build --pull --no-cache && \
        docker-compose \
            -f docker-compose.yml \
        up -d --remove-orphans

Now you can simply run make dev to bring up your MySQL server.

To shut it down, docker-compose down.

Don't want to remember, or type all that? Add it to your Makefile:

dev:
    @docker-compose down && \
        docker-compose build --pull --no-cache && \
        docker-compose \
            -f docker-compose.yml \
        up -d --remove-orphans

down:
    @docker-compose down

Now you can run make dev to go up, and make down when you're done. Change the names of these commands to whatever you like.

Boom, crash course in Docker: done.

Episodes

# Title Duration
1 What will our JSON API actually do? 08:46
2 What needs to be in our Database for our Tests to work? 12:32
3 Cleaning up after each Test Run 02:40
4 Docker makes for Easy Databases 09:01
5 Healthcheck [Raw Symfony 4] 07:53
6 Send in JSON data using POST [Raw Symfony 4] 05:33
7 Keep your data nice and tidy using Symfony's Form [Raw Symfony 4] 10:48
8 Validating incoming JSON [Raw Symfony 4] 08:26
9 Nicer error messages [Raw Symfony 4] 06:23
10 GET'ting data from our Symfony 4 API [Raw Symfony 4] 08:11
11 GET'ting a collection of Albums [Raw Symfony 4] 01:50
12 Update existing Albums with PUT [Raw Symfony 4] 05:00
13 Upsetting Purists with PATCH [Raw Symfony 4] 02:39
14 Hitting DELETE [Raw Symfony 4] 02:11
15 How to open your API to the outside world with CORS [Raw Symfony 4] 07:48
16 Getting Setup with Symfony 4 and FOSRESTBundle [FOSRESTBundle] 09:11
17 Healthcheck [FOSRESTBundle] 06:14
18 Handling POST requests [FOSRESTBundle] 08:31
19 Saving POST data to the database [FOSRESTBundle] 09:44
20 Work with XML, or JSON, or Both [FOSRESTBundle] 04:31
21 Going far, then Too Far with the ViewResponseListener [FOSRESTBundle] 03:19
22 GET'ting data from your Symfony 4 API [FOSRESTBundle] 05:58
23 GET'ting a Collection of data from your Symfony 4 API [FOSRESTBundle] 01:27
24 Updating with PUT [FOSRESTBundle] 02:58
25 Partially Updating with PATCH [FOSRESTBundle] 02:15
26 DELETE'ing Albums [FOSRESTBundle] 01:27
27 Handling Errors [FOSRESTBundle] 08:58
28 Introducing the API Platform [API Platform] 08:19
29 The Entry Point [API Platform] 04:30
30 The Context [API Platform] 05:52
31 Healthcheck - Custom Endpoint [API Platform] 05:17
32 Starting with POST [API Platform] 07:08
33 Creating Entities with the Schema Generator [API Platform] 07:38
34 Defining A Custom POST Route [API Platform] 07:31
35 Finishing POST [API Platform] 06:29
36 GET'ting One Resource [API Platform] 02:50
37 GET'ting Multiple Resources [API Platform] 02:59
38 PUT to Update Existing Data [API Platform] 02:19
39 DELETE to Remove Data [API Platform] 01:15
40 No One Likes Errors [API Platform] 03:28