Include Git Commit Id In Docker Container Build
The Problem
When working on containerizing an API service with Docker for the CI/CD pipeline, I needed to include into container current Git commit ID and branch - so I could know what code is running in production by just asking the API to return these values.
Essentially there are two simple ways to do it:
- store anv variables in a .env file, which would be easily recognisable by modules like dotenv for Node.js architecture or python-dotenv in Python.
- set them into regular environment variables with Dockerfile ENV instruction
The first is kinda simpler to implement and looks contained to Dockerfile (becasue I can bake Git commands and file creation inside Dockerfile), but has several downsides:
- it requires loading .git inside Docker image, even if only for build stage - it takes time. And it's easy to let the whole repo to slip through into container image.
- .git might be restricted in .dockerignore, and removing it from there might have undesirable consequences later.
- storing things in .env promotes storing env in file, which is not too bad for a git commit ID, but a larger potential security issue for credentials.
The Solution
So I chose to store in env variables, which required following:
- Specifying input parameters via ARG instruction, like so:
ARG GIT_COMMIT_BRANCH ARG GIT_COMMIT_ID
- Setting them into environment variables inside the container image:
Note: if you have several stages in Dockerfile, ARG and ENV should be at the same stage as final CMD instruction.ENV GIT_COMMIT_BRANCH=$GIT_COMMIT_BRANCH ENV GIT_COMMIT_ID=$GIT_COMMIT_ID
- Identifying Git commands to get branch name and commit ID:
git branch --show-current git rev-parse --short HEAD
- provide arg values as input parameters for
docker build
, like so:docker build --build-arg GIT_COMMIT_BRANCH=`git branch --show-current` --build-arg GIT_COMMIT_ID=`git rev-parse --short HEAD` -t containername
And that did it - I get the required information when launching docker build inside Git repository, where I invariably have repository information, and pass it to the build process that bakes it into the container image so it stays the same for each instance and is available for the application code inside container to use however it pleases.