ansible-lint on gitlab-ciFebruary 24, 2021
As ansible-lint checks playbooks and roles for common problems and possible improvements we will explore how to run the linter on top of Gitlab CI.
I prefer containers as CI tasks should produce idempotent results. This way one can use different linting runtimes on many projects while offering great flexibility without modifying the base OS. As ansible-lint is written in Python we need a python-runtime. The resulting linter image can be reused and therefore the build time decreases drastically. The gitlab docs describe the runner installation and registration process in depth.
A first approach
By using the python3 slim base image one can define a basic gitlab CI-configuration like this:
.gitlab-ci.yml – draft, do not use
image: python:3-slim before_script: - pip install ansible-lint - ansible-lint --version stages: - ansible-lint ansible-lint: stage: ansible-lint script: - ansible-lint site.yml
Not bad, but this approach has two problems:
As the version of ansible-lint is still unconfigured package updates could cause issues you do not want to deal with regularly. The base image is updated very frequently. So by not configuring any base image version this would create a lot of different images wasting precious disk space.
Creating a custom docker image
I’ve based my docker image on the popular python3 slim image available on docker hub (running debian buster under the hood). So let’s create a docker image.
FROM python:3-slim ENV ANSIBLE_VERSION="2.10.6." ENV ANSIBLE_LINT_VERSION="4.3.7." RUN pip install ansible-lint==$ANSIBLE_LINT_VERSION ansible==$ANSIBLE_VERSION
As you can see both versions are configured by environment variables while I keep the ansible version always in sync with my locally used version. I’m using a private docker registry so whenever this Dockerfile changes it’s rebuilt by the CI and pushed again.
docker image .gitlab-ci.yml
build: stage: deploy tags: - shell script: - export BUILD_VERSION=$(date +%s) - docker build -t your.registry.example.org/dynpages/ansible-lint:$BUILD_VERSION . - docker tag your.registry.example.org/dynpages/ansible-lint:$BUILD_VERSION your.registry.example.org/dynpages/ansible-lint:latest - docker push your.registry.example.org/dynpages/ansible-lint:$BUILD_VERSION - docker push your.registry.example.org/dynpages/ansible-lint:latest
The image is always tagged twice, by a timestamp and as latest version. The final gitlab-CI configuration I ended up looks like this:
image: your.registry.example.org/dynpages/ansible-lint:latest stages: - ansible-lint ansible-lint: stage: ansible-lint script: - ansible-lint -L - ansible-lint -r ./ site.yml
ansible-lint -L is executed first to list all available rules.