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)