Published on

Using Docker-Compose and a Makefile to Setup Local Test Infrastructure

Authors

Docker-compose is awesome when you want to quickly spin up some infrastructure to test something. I often reach for it when testing an app that has multiple different pieces that need to run together for example there is a DB, queue and the app itself which needs all this.

Even in a Kubernetes environment, I find it can still be faster and easier to dev locally using compose.

One issue I ran into today was trying to have a common config you use and version control so that it can be used by others for their local infrastructure. My project structure looks as follows:

.env
.gitignore
makefile
-> app/
     -> ...
     -> Dockerfile
-> infrastructure/
    -> ...
    -> testing/
        -> docker-compose.yaml
-> deployement/
    -> local/
        -> data/
        -> common/
            -> someFile.properties
           -> application-1.properties

The .env file is used by docker-compose where it substitutes ${SOME_VAR} in your compose file with the value of that var or command line environment variable as described here.

I use my .gitignore to ignore any testing infrastructure folders and files that are stored in volumes that are mounted against the local environment's data directory.

In my compose file I define a section that mounts deployment/local/data and deployment/local/common so that my app can write its runtime data to data and read its config from common. My compose file looks similar to the below:

version: '3.7'

services:
  spring-app-1:
    image: someorg/app1
    volumes:
      - '${DATA_VOLUME_1:?NO_DATA_VOLUME_PROVIDED}:/data/'
      - '${COMMON_VOLUME:?NO_COMMON_VOLUME}:/config/'
    environment:
      - spring.config.location=/config/application-1.properties

  queue-1:
    image: ibmcom/mq
    restart: unless-stopped
    ports:
      - '1414:1414'
      - '9443:9443'
    volumes:
      - 'qm1data:/mnt/mqm'
    environment:
      - LICENSE=accept
      - MQ_QMGR_NAME=QM1

volumes:
  qm1data:

In the above, app-1 uses /data for any storage-related tasks.

The last issue to sort out with the above setup was how the docker-compose file could be easily run from any dev's machine without having to change anything. I ended up with a makefile that defines a variable pointing to deployment/local relative to the code root using pwd. The file with a target to run and stop the test infrastructure is below:

APP_DIRS_ROOT=$(shell pwd)/deployement/local

help:
    @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

docker-build-app-container: ## Builds the app container
    docker build -t someorg/app1:0.1 ./app/ -f ./app/Dockerfile

docker-build-all-containers:  docker-build-app-container ## Builds all containers

start-test-infrastructure: docker-build-all-containers ## Runs the docker-compose test infrastructure
    docker-compose -f ./infrastructure/testing/docker-compose.yaml up -d

stop-test-infrastructure: local-app-wipe ## Stops the docker-compose test infrastructure
    docker-compose -f ./infrastructure/testing/docker-compose.yaml down || true
    docker volume prune -f || true
    docker network prune -f || true