Semantic Docker with Semantic Release, Docker, and Travis CI

This tutorial will show you how to combine semantic-release + Docker + CI to automatically version your docker images based on your commit messages!

Why

When you develop software and release it via Docker, it is nice to know which images include breaking changes, minor changes, or bug fixes. And some changes don’t require a new image– for example, if you are just doing developer chores (updating developer dependencies, documentation, or comments, etc). Semantic Versioning (“SemVer”) clearly communicates what kind of changes each new build contains.

But manually keeping track of this information is a slog. Instead, you can follow the Conventional Commits standard and use a tool called semantic-release to do the hard work for you.

I’ll provide instructions for a pipeline which will automatically update your semantic version and rebuild a new docker image with that version.

Prerequisites

  • an app with a Dockerfile which works
  • an account with travis-ci — you could use another CI provider, but you’ll have to alter these steps appropriately for that CI system.

Steps

Step 1: Make sure your Dockerfile works

docker build . -t YOUR_REPO/YOUR_PROJECT:v1.0.0

You must resolve any errors here before proceeding.

If you do not have a Dockerfile yet, you must set one up that works with your app. The contents of your Dockerfile will depend on how your app is set up, which language(s) it uses, etc. Either search for “Dockerfile example” + the name of your application framework, or follow the official getting started guide.

Step 2: Make sure you can log in to the docker registry and push

docker login # follow prompts
docker push YOUR_REPO/YOUR_PROJECT:v1.0.0 YOUR_REPO/YOUR_PROJECT:v1.0.0

Step 3: Initialize a package.json file if you don’t have one

npm init # and follow prompts

Step 4: Install @semantic-release/commit-analyzer, @semantic-release/git, semantic-release, semantic-release-docker as development dependencies:

npm install --save-dev @semantic-release/commit-analyzer
npm install --save-dev @semantic-release/git
npm install --save-dev semantic-release
npm install --save-dev semantic-release-docker

Step 5: Check package.json and configure your semantic-release pipeline

You should have something like:

{
  "name": "YOUR_PROJECT_NAME",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "semantic-release": "semantic-release"
  },
  "devDependencies": {
    "@semantic-release/commit-analyzer": "^6.1.0",
    "@semantic-release/git": "^7.0.8",
    "semantic-release": "^15.13.3",
    "semantic-release-docker": "2.1.0"
  }
}

(package versions may vary)

You want to tell semantic-release which plugins to use and what order to put them in. You do this by adding a release key to your package.json:

{
  "name": "YOUR_PROJECT_NAME",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "semantic-release": "semantic-release"
  },
  "devDependencies": {
    "@semantic-release/commit-analyzer": "^6.1.0",
    "@semantic-release/git": "^7.0.8",
    "semantic-release": "^15.13.3",
    "semantic-release-docker": "2.1.0"
  },
  "release": {
    "plugins": [
      "@semantic-release/commit-analyzer",
      "@semantic-release/git",
      "semantic-release-docker"
    ],
    "publish": [
      {
        "path": "semantic-release-docker",
        "name": "YOUR_REPO_NAME/YOUR_PROJECT_NAME"
      }
    ]
  }
}

Step 6: Dry-run semantic release to make sure that worked

DOCKER_USERNAME=yourusername DOCKER_PASSWORD=yourpassword npx semantic-release --dry-run

NOTE: putting your DOCKER_USERNAME and DOCKER_PASSWORD on the command line like this isn’t great for security, but it is a fast way to test. Our real setup will use encrypt variables in TravisCI. You may want to edit your shell history after running this test or use history -c to clear it.

What you should see is a log of different semantic-release steps, with no errors. semantic-release will report that it is not releasing since this is a dry run.

Step 7: Build your bin/deploy script

bin/deploy is the name we use for all our deploy scripts, but you could use scripts/deploy or any name really. You’ll just need to alter the .travis.yml file below as appropriate.

#!/bin/sh

set -e

# These steps may vary depending on your project-- in my case, this builds all my assets so that they are available to docker
npm install -g npm
(cd assets; npm install; npm run deploy)
npm install

# Docker build and semantic release to docker registry
docker build . -t YOUR_REPO_NAME/YOUR_PROJECT_NAME
npx semantic-release

Every step you need to build the application from scratch goes here and put npx semantic-release at the end. You’ll need this deploy script to be marked executable.

chmod u+x bin/deploy

Step 8: Add your repo to Travis

Use the repositories menu in TravisCI to set up your application for CI, if you have not already.

Step 9: Build your .travis.yml

We don’t want to have to deploy from our laptops every time. Instead, we’d prefer a deploy to happen automatically every time we update our code in GitHub. We use Travis to do that. We need to tell Travis what our build steps are.

language: elixir
elixir:
- 1.8.0
otp_release:
- 21.2.2
env:
  matrix:
  - MIX_ENV=test
  global:
  - secure: # use `travis encrypt DOCKER_USERNAME=yourusername --add` and travis encrypt DOCKER_PASSWORD=yourpassword --add` to set up the username and password for your docker registry account
services:
- docker
before_script:
- nvm install v10.15.0
- mix do ecto.create, ecto.migrate
script:
- mix test
deploy:
  provider: script
  script: bin/deploy
  skip_cleanup: true
  on:
    branch: master

This will look different for different languages. Starting from a working .travis.yml for your language, you’ll make some additions. You’ll add:

services:
- docker

This ensures that Docker is up and running for you before your tests and deployment run.

You’ll add a deploy section:

deploy:
  provider: script
  script: bin/deploy
  skip_cleanup: true
  on:
    branch: master

This runs your deploy script any time a passing build lands in the master branch.

You also need to set environment variables in Travis for semantic-release-docker:

travis encrypt DOCKER_USERNAME=yourusername --add
travis encrypt DOCKER_PASSWORD=yourpassword --add

Step 10: Push all your changes (package.json, bin/deploy, .travis.yml) to GitHub

Commit your changes using a conventional commit message.

Push your changes to GitHub, to the branch that you configured in the deploy section above. At this point, Travis should see your changes and start a build.

Step 11: Watch your build

You should be able to see the build in the TravisCI UI. Watch the build logs. After some time, the build should turn green, meaning your build succeeded.

If the build fails, you’ll need to study the error and do some searching. Double check that all of the above configuration is properly in place.

Step 12: Check the Docker registry

Once you have a green build on the deploy branch, you should have a new docker image in the Docker registry. Visit your Docker registry and check that the build is there. If you don’t see it after a successful build, double check the build log and ensure that the semantic-release actually logged a docker push.

Revel in Victory!

Do you think these kind of tools are exciting? You might just be a great fit for our team.

 Check out our current openings

More Posts by Robert Prehn:

Kubernetes, Delivered

Deploy your first app within 24 hours. Book a demo to get started.