## Exercise 6: Change the order of the pipeline steps ## ### Objective ### Learn how to change the order of pipeline stages, and how to build a parallel pipeline ### Change the order of stages ### Build stages have dependencies, which give them access to the artifacts from other stages, but the order is determined by the **stages:** declaration in the **.gitlab-ci.yml** file. After the last exercise, your **stages:** section will look something like this: ``` > cat .gitlab-ci.yml | grep --after-context=5 --before-context=1 stages stages: - build - test - deploy - test-docker ``` If you simply swap the order of the **test** and **deploy** stages, commit, tag and push your code, you should see that the build pipeline runs in a different order, with the **deploy** (create and push the docker image) happening before the **test** (running the executable). It's up to you to decide if it makes sense to 'deploy' before testing, or after, this simply illustrates how to do it. ### Sequential and parallel builds ### In our example, testing the executable and testing the docker image could, in principle, happen in parallel. If the tests were long-running, and we have enough resources in our gitlab runners, this can save time. We can do this very simply by removing the **test-docker** stage from the **stages:** piece and changing the **run-docker** step to execute the **test** stage, instead of having it execute the **test-docker** stage. In other words, there will be two steps, **run** and **run-docker**, both of which run the **test** stage. They will happen in the correct order, after the **deploy** stage, but they are eligible to run in parallel if there are sufficient resources. If there are not sufficient resources for the steps to run in parallel, they will simply happen sequentially, in a random order. Make this change to your YAML file, commit it, tag it, and push it to the server. Take a look at the pipeline page and see how it shows the parallel steps. It should look like this: ![](/static/images/resops2019/gitlab-04-parallel-steps.png) ### Conclusion ### - You now know how to write pipelines which can run stages sequentially, or in parallel. - Each **stage** of a pipeline can have many **steps** that run that stage. - Each **step** in a stage must succeed, or the whole pipeline fails - Each **step** in a stage must complete before the next stage is free to start - Parallel stages can speed up testing, e.g. by running tests in many environments at the same time ### Best Practices ### - Think carefully about what you are trying to achieve in your pipeline. Keep the steps small, and parallelise where it makes sense. ### Cheat-sheet ### In case you get stuck, this is what your **.gitlab-ci.yml** file should now look like. Don't peek until you've had a go yourself though! ``` > cat .gitlab-i.yml variables: DOCKER_TLS_CERTDIR: "" GIT_STRATEGY: clone REGISTRY_USER: tonywildish APPLICATION: tiny-test LATEST_IMAGE: $CI_REGISTRY/$REGISTRY_USER/$APPLICATION:latest RELEASE_IMAGE: $CI_REGISTRY/$REGISTRY_USER/$APPLICATION:$CI_BUILD_REF_NAME DOCKER_DRIVER: overlay before_script: - echo "Starting..." - export DOCKER_IMAGE=$RELEASE_IMAGE - if [ "$CI_BUILD_REF_NAME" == "master" ]; then export DOCKER_IMAGE=$LATEST_IMAGE; fi - echo "Build docker image $DOCKER_IMAGE" stages: - build - deploy - test compile: stage: build image: gcc:6 services: - docker:dind artifacts: name: "${CI_BUILD_NAME}_${CI_BUILD_REF_NAME}" untracked: true expire_in: 1 week script: - make run: stage: test dependencies: - compile only: - tags script: - echo "Testing application. First, list the files here, to show we have the git repo + the artifacts from the build step" - ls -l - echo 'Now try running it' - ./hello - echo "If that failed you won't see this because you'll have died already" install: stage: deploy image: docker:latest services: - docker:dind dependencies: - compile script: - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY - echo Building $DOCKER_IMAGE - docker build -t $DOCKER_IMAGE . - echo Deploying $DOCKER_IMAGE - docker push $DOCKER_IMAGE run-docker: stage: test image: docker:latest services: - docker:dind script: - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY - docker run $DOCKER_IMAGE after_script: - echo "Congratulations, this step succeeded" ```