Gitlab CI and Docker

Preetam Keshari Nahak
6 min readFeb 14, 2021

Here, in this article, I will discuss how to use GitLab CI along with Docker to create a seamless flow for building your artifacts such as, a docker image for your application, which you can use to deploy your application easily. In this post, I have discussed how to dockerize a simple react based application. In this post, I will extend this discussion to showcase the benefits of the GitLab CI/CD tool.

As most of you would know, GitLab is a version controlling system just like GitHub. Though GitHub also has the feature for CI/CD, I personally like GitLab for its vast access control options, groups and project management, etc. If you ever came across Jenkins, GitLab CI acts for the same purpose only. As Wikipedia reads:

Jenkins is a free and open source automation server. It helps automate the parts of software development related to building, testing, and deploying, facilitating continuous integration and continuous delivery.

The following figure demonstrates the CI/CD pipeline in a graphical format. To know more about a CI/CD tool, refer to this and this.

Image Source: GitLab

To reiterate, this article will be based mostly on different constructs of the CI pipeline. With that being said, let’s get started!

As mentioned earlier, we will be extending out practical works on this repo. Now let’s get familiar with some important terminologies.

  1. Pipeline: A pipeline is nothing but a set of jobs that needs to be executes
  2. Job: A job is nothing but a series of instructions that perform the desired task. An example of a job can be npm building a react app, creating a docker image for the application, etc.
  3. Runner: A runner is a GitLab specific term and basically an application that helps to execute the pipelines successfully.

There are two types of runners that you can set up for your GitLab repo. One is using dedicated runners and the other is shared runners. All the jobs involved in a pipeline will be run on a machine, which should have GitLab runners installed. As a learner, we will be using the shared runners provided by Gitlab. Generally, your GitLab instance will be supporting a few shared runners already which you can use for this article’s purpose. If no runners are available, please go through the detailed docs here.

Our CI pipeline will perform the following tasks:

  • JOB 1: Generate build artifacts from the react app and share this build artifact to JOB 2
  • JOB 2: Build a docker image out of the build artifacts shared by JOB 1

Now, these 2 jobs should be written in a yml file named .gitlab-ci.yml which should reside in your project root. This is the content of the .gitlab-ci.yml file. We will understand each of them one by one.

stages:
- build
- docker


npm build:
stage: build
image: node
script:
- npm install --save
- npm run build
- mv build npmbuild
artifacts:
paths:
- npmbuild
expire_in: 1 day

docker build:
stage: docker
image: docker:stable
services:
- docker:dind
before_script:
- docker info
- docker login registry.gitlab.com -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD}
script:
- docker build -t ${CI_REGISTRY}/${CI_PROJECT_PATH}:${CI_COMMIT_REF_NAME} .
- docker push ${CI_REGISTRY}/${CI_PROJECT_PATH}:${CI_COMMIT_REF_NAME}
after_script:
- docker logout ${CI_REGISTRY}
only:
- master

The stages section instructs what are the different stages available and their sequence in the pipeline.

Below the stages key, we give descriptions about the jobs. Here, we have mentioned about 2 jobs:

  • npm build
  • docker build

For each job, we have a stage key, which informs what stage this job belongs to. If two jobs belong to the same stage, then those two jobs will run in parallel.

Source: GitLab

Here the jobs test-job1 and test-job2 belong to the stage named as Test. Hence, these two jobs ran in parallel.

The image key depicts which docker image to use in order to execute this job and the script key shows the set of shell instructions to run. The next key artifact is very important. It reserves the files/directories and later jobs can access and use those artifacts stored by the earlier jobs. Here we stored our npm build of the react app in a directory named npmbuild in the npm build job. We can also mention an optional expiration time for those artifacts in the machine.

In the second job, docker build, we mentioned the stage, used docker engine image to build our image, logged in to GitLab's docker registry using our GitLab credentials pre-stored in GitLab's environment, ran the docker build command a tag name for our image, pushed the docker image to the Docker registry of GitLab, logged out of the docker registry, set a rule that these jobs should run only if any commit is pushed to the master branch of the repo. We can specify regex-based rules too.

Now save the file and push your code into the master branch. Go to CI/CD ====> Pipelines menu in your GitLab repo. Here you can all your active running pipelines, failed pipelines as well passed pipelines like this.

Now click on the running pipeline to know more about the jobs in detail. You will see a page similar to this (below). It shows that the job npm build is executed successfully and the job docker build is running.

On clicking on a job, you will the details about the job like this.

If both of your jobs executed successfully, then you will get to know about the image built for your application here (Package and Registries ===> Container Registry).

If your image is listed here, then our goal was partially achieved. Click on this and copy the link of the image with the desired tag using the copy icon provided after the tag name. Now let’s pull this image and run this image in our local to see if we achieved our goal fully. Open up a terminal and run

docker pull registry.gitlab.com/react-flask-docker/react-ui:master

C:\Users\preet>docker pull registry.gitlab.com/react-flask-docker/react-ui:master
master: Pulling from react-flask-docker/react-ui
801bfaa63ef2: Already exists
b1242e25d284: Already exists
7453d3e6b909: Already exists
07ce7418c4f8: Already exists
e295e0624aa3: Already exists
33b006ead708: Pull complete
782766ed6397: Pull complete
Digest: sha256:0de3451e799e5fbc58f22241b9fe8110c96022f42467d147924578611e48dd00
Status: Downloaded newer image for registry.gitlab.com/react-flask-docker/react-ui:master
registry.gitlab.com/react-flask-docker/react-ui:master

Run docker images and you will see that your image is listed there.

C:\Users\preet>docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.gitlab.com/react-flask-docker/react-ui master 86b6daa6d43b 8 minutes ago 22.8MB

Now let’s run a container out of this image. To do this run

docker run -p 5000:80 registry.gitlab.com/react-flask-docker/react-ui:master

Open up a tab in the browser and browse http://localhost:5000. If you were able to see a basic react demo UI page, then YES!! You have successfully set up GitLab CI for your react application!!!

That’s it. I hope you found this article useful and informative. Please find the repo and codes here. CHEERS!!!

--

--

Preetam Keshari Nahak

Technology Enthusiast | Software Engineer | Distributed Systems