Principles
Makefile is used as a common descriptor for building, deploying, testing and other operations to be performed.
By looking at the Makefile, the developer should have a quick view of all possible operations that can be performed on that code base, in the form of make targets.
Examples of targets:
- build
- test
- deploy
A developer should be able to clone a repository, set the required variables in the .env
file and successfully run make <target>
without any special setup in their machine other than having make, docker and docker-compose installed.
The main benefit of this pattern is running operations on both developers machine and CI worker the same.
3musketeers
A Makefile and docker-compose.yml file should exist in the repository.
Makefile have targets that call docker-composer run <service>
. The service being a tool or the application itself.
Example:
.env:
cp .env.template .env
assumeRole: .env
docker-compose run --rm aws assume-role.sh >> .env
.PHONY: assumeRole
deploy: assumeRole
docker-compose run --rm deploy ./deploy.sh
.PHONY: deploy
The main target above, deploy
, will first call assumeRole
, which in turn calls .env
.
.env
target creates the file if it doesn’t exist.assumeRole
uses AWS CLI to assume a role and output the credentials to the.env
filedeploy
runs the deploy script using the credentials
The docker-compose.yml file for the example above looks like:
version: '3.2'
services: deploy: image: dnxsolutions/aws:1.4.0 entrypoint: "/bin/bash -c" env_file: - .env volumes: - ./deploy:/work
aws: image: dnxsolutions/aws:1.4.0 entrypoint: "/bin/bash -c" env_file: - .env
In this example, the deploy script uses AWS CLI so we are using the dnxsolutions/aws
image, same as the assumeRole
target, which also uses the AWS CLI.
But in another case where we would deploy to kubernetes, the deploy service would use an image built for that, with kubectl, helm, etc.
Variables
All variables used by make targets should be declared in the .env.compose
file, without values.
Example .env.compose
:
NODE_ENV
When make .env
runs, if the .env
file doesn’t exist, it’s created from .env.compose
.
Now, when running in a CI tool, this value should be set in the pipeline stage and set as an environment variable when the worker is running.
And similarly, when running in a developer’s local machine, the value can be set in as an environment variable, or set directly in the .env
, such as:
NODE_ENV=development
If make .env
is called again, it won’t overwrite the file as it already exists (make has this logic), so the values set there are preserved.
The .env
file should be in the .gitignore
and not pushed to the repository. Examples (like a .env.local
) are ok to push to repository as long as they don’t contain credentials or sensitive information.