We all know that Gitlab CI build uses docker image to do the job, But have you ever tried to build a docker image inside gitlab CI build ?
As we know gitlab CI start on docker container. So when we want to build a docker image inside gitlab CI build, it's docker in docker (DinD)
Without transition lets take a look at the .gitla-ci.yml
file :
image: docker:latest
variables:
DOCKER_DRIVER: overlay2
stages:
- build
- push
services:
- docker:dind
before_script:
# docker login needs the password to be passed through stdin for security
# we use $CI_JOB_TOKEN here which is a special token provided by GitLab
- echo -n $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY
- docker version
- docker info
after_script:
- docker logout registry.gitlab.com
Build:
stage: build
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- >
docker build
--pull
--cache-from $CI_REGISTRY_IMAGE:latest
--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
.
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
Push_When_tag:
stage: push
only:
# We want this job to be ran on tags only.
- tags
script:
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
Step 1 - Images & services
image: docker:latest
variables:
DOCKER_DRIVER: overlay2
stages:
- build
- push
services:
- docker:dind
yaml
We start by defining the docker image that will be used by GitlabCI build. In our case and as example we used the latest docker image .
image: docker:latest
⚠️ In production for example , I don't recommend using
latest
orstable
versions. For many reasons ...
One of them is reproducibility, Another reason is we want our pipeline to work in 10 month or 10 years. If a new feature is needed , then an upgrade is planned .
variables:
DOCKER_DRIVER: overlay2
yaml
When using docker:dind
, Docker uses the vfs
storage driver which copies the filesystem on every run. This is a very disk-intensive operation which can be avoided if a different driver is used, for example overlay2
Step 2 - before and after Script
before_script:
# docker login needs the password to be passed through stdin for security
# we use $CI_JOB_TOKEN here which is a special token provided by GitLab
- echo -n $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY
- docker version
- docker info
after_script:
- docker logout registry.gitlab.com
yaml
Nothing special on this step :
- Connection to Gitlab Registry
- Check docker daemon and config
- Logout from docker registry
Step 3 - Build and Push
Build:
stage: build
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
# notice the cache-from, which is going to use the image we just pulled locally
# the built image is tagged locally with the commit SHA, and then pushed to
# the GitLab registry
- >
docker build
--pull
--cache-from $CI_REGISTRY_IMAGE:latest
--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
.
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
We pull the last pushed image on the registry ; the `|| true` assure that the pipeline will not fail if no image was found .
After pulling the last image , this one will be used for the cache when building a new image using the `--cache-from` .
Then we push to registry with the image flagged with `$CI_COMMIT_SHA` that contains the commit SHA .
yaml
Step 4 - Tag management
Push_When_tag:
stage: push
only:
- tags
script:
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
yaml
We want to keep our Git tags in sync with our Docker tags. That helps a lot when debugging and trying to reproduce specific version bugs .
If you have not automated this, you probably have found yourself in the situation of wondering “which git tag is this image again?”.
⚠️ This stage is triggered only when a tag is created .
Top comments (0)