Goals
- Learn about how GitLab's CI/CD works
- Learn the different stages
- Understand how jobs are executed
Settings
- Repository specification that you can customise and manage.
- CI/CD section: configure and customise your continuous integration/continuous delivery channel options.
- Variables: Store information, like passwords and secret keys, that you can use in job scripts
- Protected: Only exposed to protected branches or protected tags.
- Masked: Hidden in job logs. Must match masking requirements.
- Expanded: Variables with $ will be treated as the start of a reference to another variable
Stages
- Defines the stages of the project construction and deployment process.
- Each stage represents a specific phase of the workflow, and jobs are grouped into these stages
- Indicate the order in which they should be executed.
- Other stages can be created if necessary
.gitlab-ci.yml
stages: - build - push - deploy
Variables
- used to configure the behaviour of the tools and services used in the CI/CD process.
variables: MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true" MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true"
Build
- Uses a Maven-based Docker image to compile the Maven project.
- The .m2/repository directory is cached to avoid unnecessary downloads of Maven dependencies.
- After compilation, a WAR file is created as an artifact and stored for later use.
.gitlab-ci.yml
# Build the Maven project. build-magnolia: image: maven:3.6-jdk-11-slim stage: build cache: key: "$CI_JOB_NAME" paths: - $CI_PROJECT_DIR/.m2/repository before_script: - mkdir -p $CI_PROJECT_DIR/.m2 script: - mvn $MAVEN_CLI_OPTS package - ls -Fahl paas-training-webapp/target artifacts: expire_in: 30 days paths: - paas-training-webapp/target/*.war
Push
- Creates a Docker image based on the artifacts generated in the build stage.
- Kaniko is used to build and push the image to the GitLab Container Registry.
- Docker credentials are configured to access the registry.
.gitlab-ci.yml
# Build docker images based on artifacts from the build stage. push-docker-image: image: name: gcr.io/kaniko-project/executor:debug entrypoint: [""] stage: push dependencies: - build-magnolia before_script: - export WEBAPP_IMAGE=${CI_REGISTRY_IMAGE}/magnolia-webapp - export GIT_TAG=$CI_COMMIT_SHORT_SHA - mkdir -p /kaniko/.docker - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json script: - cd paas-training-webapp - /kaniko/executor --context . --dockerfile ./Dockerfile --destination "$WEBAPP_IMAGE:$GIT_TAG"
Deploy
- Two jobs, deploy-dev, and deploy-uat, deploy the application to different environments
- The jobs use a values.yml file to generate the necessary configuration before using Helm to deploy the application to a Kubernetes cluster
- Namespace annotation and creation of secrets are performed.
.gitlab-ci.yml
.deploy: image: registry.gitlab.com/mironet/helm-kubectl-gomplate:v0.0.5 stage: deploy before_script: - export GIT_TAG=$CI_COMMIT_SHORT_SHA - helm repo add mironet https://charts.mirohost.ch/ - export HELM_CHART_VERSION=1.7.0 - export KUBECONFIG=$KUBE_CONFIG deploy-dev: extends: .deploy script: - export DEPLOYMENT=dev - export LE_ENVIRONMENT=letsencrypt-prod - cat values.yml | gomplate > ${DEPLOYMENT}.yml - cat ${DEPLOYMENT}.yml - helm upgrade -i ${DEPLOYMENT} mironet/magnolia-helm --version ${HELM_CHART_VERSION} -f ${DEPLOYMENT}.yml --create-namespace -n ${DEPLOYMENT} - kubectl annotate --overwrite namespace ${DEPLOYMENT} field.cattle.io/projectId=`kubectl get namespace default --output="jsonpath={.metadata.annotations.field\.cattle\.io/projectId}"` - kubectl -n default get secret activation-key -o json | jq 'del(.metadata.annotations,.metadata.labels,.metadata.namespace,.metadata.resourceVersion,.metadata.uid,.metadata.namespace,.metadata.creationTimestamp)' | kubectl apply -n ${DEPLOYMENT} -f - - kubectl -n default get secret gitlab -o json | jq 'del(.metadata.annotations,.metadata.labels,.metadata.namespace,.metadata.resourceVersion,.metadata.uid,.metadata.namespace,.metadata.creationTimestamp)' | kubectl apply -n ${DEPLOYMENT} -f - - kubectl -n default get secret s3-backup-key -o json | jq 'del(.metadata.annotations,.metadata.labels,.metadata.namespace,.metadata.resourceVersion,.metadata.uid,.metadata.namespace,.metadata.creationTimestamp)' | kubectl apply -n ${DEPLOYMENT} -f - environment: name: dev when: manual deploy-uat: extends: .deploy script: - export DEPLOYMENT=uat - export LE_ENVIRONMENT=letsencrypt-prod - cat values.yml | gomplate > ${DEPLOYMENT}.yml - cat ${DEPLOYMENT}.yml - helm upgrade -i ${DEPLOYMENT} mironet/magnolia-helm --version ${HELM_CHART_VERSION} -f ${DEPLOYMENT}.yml --create-namespace -n ${DEPLOYMENT} - kubectl annotate --overwrite namespace ${DEPLOYMENT} field.cattle.io/projectId=`kubectl get namespace default --output="jsonpath={.metadata.annotations.field\.cattle\.io/projectId}"` - kubectl -n default get secret activation-key -o json | jq 'del(.metadata.annotations,.metadata.labels,.metadata.namespace,.metadata.resourceVersion,.metadata.uid,.metadata.namespace,.metadata.creationTimestamp)' | kubectl apply -n ${DEPLOYMENT} -f - - kubectl -n default get secret gitlab -o json | jq 'del(.metadata.annotations,.metadata.labels,.metadata.namespace,.metadata.resourceVersion,.metadata.uid,.metadata.namespace,.metadata.creationTimestamp)' | kubectl apply -n ${DEPLOYMENT} -f - - kubectl -n default get secret s3-backup-key -o json | jq 'del(.metadata.annotations,.metadata.labels,.metadata.namespace,.metadata.resourceVersion,.metadata.uid,.metadata.namespace,.metadata.creationTimestamp)' | kubectl apply -n ${DEPLOYMENT} -f - environment: name: dev when: manual
Jobs
- Through the CI/CD option in the pipelines section, we can visualise the different Jobs
- You can run the pipeline manually
- The stages are defined in the gitlab-ci.yml
- Status can be:
- passed
- passed with warnings
- canceled
- running
- failed
- Jobs are executed in the defined order and will wait for a manual action when it reach the deploy stage.
Troubleshoot the jobs
- In case a pipeline has a failure or you want to check the status of what it is doing, it is possible to do troubleshooting on it.
- By clicking on the stage job it is possible to see a log of the actions that have been performed and the reason why it failed.