GitLab - extends keyword

In the previous post I had written about the include keyword. Now, let's dive in the extends keyword.

What can you do with this? Here is the definition from GitLab documentation:

extends defines entry names that a job that uses extends inherits from.
It’s an alternative to using YAML anchors and is a little more flexible and readable.

So, when is it useful? It is useful when you want to be DRY and keep your setup cleanly. Let's assume that you want to build a docker image and give developers possibility to deploy the image on dev, staging and prod environments. We are going to do that without the extends keyword, and after that we will think how we can do it better.

Example without the extends keyword:

stages:
- build
- deploy
variables:
REPOSITORY_URL: <link-to-repository>/$CI_PROJECT_NAME
build:
stage: build
script:
- docker build -t $REPOSITORY_URL:$CI_COMMIT_SHORT_SHA .
- docker push $REPOSITORY_URL:$CI_COMMIT_SHORT_SHA
deploy dev:
stage: deploy
image: alpine/k8s:1.17.5
when: manual
environment:
name: dev
script:
- helm upgrade
--create-namespace --install --wait --namespace <namespace> <release_name>
--set image.tag=$CI_COMMIT_SHORT_SHA
--set image.repository=$REPOSITORY_URL
deploy staging:
stage: deploy
image: alpine/k8s:1.17.5
when: manual
environment:
name: staging
script:
- helm upgrade
--create-namespace --install --wait --namespace <namespace> <release_name>
--set image.tag=$CI_COMMIT_SHORT_SHA
--set image.repository=$REPOSITORY_URL
deploy prod:
stage: deploy
image: alpine/k8s:1.17.5
when: manual
environment:
name: prod
script:
- helm upgrade
--create-namespace --install --wait --namespace <namespace> <release_name>
--set image.tag=$CI_COMMIT_SHORT_SHA
--set image.repository=$REPOSITORY_URL

As you can see, there is a lot of code which repeats itself: stage, image, when and script. We can remove a lot of code! So, let's do that. We are going to create a hidden job .deploy (you will not see this job in a pipeline) and the rest of the jobs will inherit from it:

stages:
- build
- deploy
variables:
REPOSITORY_URL: <link-to-repository>/$CI_PROJECT_NAME
build:
stage: build
script:
- docker build -t $REPOSITORY_URL:$CI_COMMIT_SHORT_SHA .
- docker push $REPOSITORY_URL:$CI_COMMIT_SHORT_SHA
.deploy:
stage: deploy
image: alpine/k8s:1.17.5
when: manual
script:
- helm upgrade
--create-namespace --install --wait --namespace <namespace> <release_name>
--set image.tag=$CI_COMMIT_SHORT_SHA
--set image.repository=$REPOSITORY_URL
deploy dev:
extends: .deploy
environment:
name: dev
deploy staging:
extends: .deploy
environment:
name: staging
deploy prod:
extends: .deploy
environment:
name: prod

Looks much better. This way, when you want to change the logic of the deployment you just need to edit one job. Every other job which uses the extends keyword and use the .deploy job will inherit the rest.

One more thing.

What if you want to send info about deployments to Slack for example? But you only care about staging and prod? You can use the after_script section. We are going to add the logic for this to the .deploy job, but we also want to do that only for staging and prod. We can use one of predefined environment variable: $CI_ENVIRONMENT_NAME and check it.

stages:
- build
- deploy
variables:
REPOSITORY_URL: <link-to-repository>/$CI_PROJECT_NAME
build:
stage: build
script:
- docker build -t $REPOSITORY_URL:$CI_COMMIT_SHORT_SHA .
- docker push $REPOSITORY_URL:$CI_COMMIT_SHORT_SHA
.deploy:
stage: deploy
image: alpine/k8s:1.17.5
when: manual
script:
- helm upgrade
--create-namespace --install --wait --namespace <namespace> <release_name>
--set image.tag=$CI_COMMIT_SHORT_SHA
--set image.repository=$REPOSITORY_URL
after_script:
- if [[ $CI_ENVIRONMENT_NAME != "dev" ]] ; then ./send-to-slack.sh $CI_ENVIRONMENT_NAME ; fi
deploy dev:
extends: .deploy
environment:
name: dev
deploy staging:
extends: .deploy
environment:
name: staging
deploy prod:
extends: .deploy
environment:
name: prod

Instead of this, we could have also added the after_script section to deploy staging and deploy prod jobs with removing IF which checks the environment.

I have also added a video:



Comments

Popular posts from this blog

Managing Secrets in GitLab / Git

GitLab - trigger keyword