Async Drink

Getting started with Gitlab CI

Sep 10, 2019

Gitlab originally started out as a place to store your Git repositories. Over the past few years it has grown to be much more though. Just like competitor Github it offers project management tooling. However, unlike Github Gitlab also offers Continuous Integration (or CI for short).

With CI you can start automating your build and deploy system. No longer do you need to manually build each version of your project and then manually update running deployments.

Why use CI?

There are many reasons why adding CI to your project is a good idea. I've listed several convincing reasons below.

Save time

This one is obvious: once you automate something you won't have to spend time on it anymore. Automating your build and deploy process means you can spend more time doing actual programming. You know, the job you are actually paid for...

Minimize human mistakes

Humans make mistakes. Even the most focused individual will every now and then slip up. This means if you do a thousand deployments manually you are bound to mess up some of them. These mistakes could be innocent or they could really hurt you or the company you work for.

By automating even simple steps which are performed many times you cut out the human factor. Thereby you reduce the risk of messing up.

Free documentation!

Every CI system uses some kind of scripting language, configuration file or interface to configure the build and deployment steps. Effectively this is a form of documentation! New programmers will be able to take a look at these tools and understand how a build is made or a deployment is done. This can help decrease the bus factor.

Basics

I'll quickly discuss the basics before using a real world example.

This may be obvious but you can only use Gitlab CI if you have your Git repository hosted on Gitlab (or self-hosted Gitlab).

Gitlab CI configuration file

Every CI system has to be configured. Gitlab CI makes use of a single configuration file part of your repository. This file is called .gitlab-ci.yml.

A simple Gitlab CI configuration file looks like this:

stages:
  - build

build:
  stage: build
  script:
    - npm install
    - npm run build

We define a basic CI street with only one stage: a build stage. Next we define the build stage as the combination of two commands. First we install any NPM packages. Next we run a build command. The exact build command isn't relevant now. This will of course depend on the programming language and framework used.

Note how the build steps are just plain Shell commands. This is what makes Gitlab CI so easy to configure. If you are already comfortable building from a terminal you'll have an easy time porting the steps you currently do manually to Gitlab CI!

Gitlab CI runners

In order to automate your builds and deployments Gitlab CI needs something called a Gitlab Runner. A Gitlab Runner is nothing more than a computer which is accessible to Gitlab. This could be a hosted server on a service like Digital Ocean or AWS. It can also be a computer you've got running at home or at your company. As long as Gitlab can access it you are good to go.

Even better though: Gitlab offers a collection of shared runners free of charge! So if you do not want to set up your own Gitlab Runner at this point you don't even need to.

Because the Gitlab Shared Runners are shared with many other people your builds and deployment will most likely be slower. Also keep in mind if your builds and deployment contain sensitive data running them on a shared runner might not be smart.

A basic example

Gitlab CI doesn't care about which language or framework you use. To help us get started I have therefore chosen a very simple and basic example.

I have created a simple NodeJS application written in Typescript. As part of the build process the Typescript code will have to be transpiled to Javascript. Once the build succeeds we want to run a few simple unit tests to make sure nothing is broken.

You can find the final code here. I suggest you fork this repository so you can experiment with it.

The configuration file

Let's first take a look at the Gitlab CI configuration file:

image: "node"

stages:
  - build
  - test

build:
  stage: build
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - dist
    expire_in: 1 day

test:
  stage: test
  dependencies:
    - build
  script:
    - npm install
    - npm run test

You'll find we have defined two stages at this point: a build and test stage. We have also defined an image to use when building (image: "node"). This refers to the Docker NodeJS image we will use to run our build and test in.

The build stage will simply install any NPM packages. Next it will run the build command we have defined in our package.json. Lastly it will upload the build files to Gitlab. All our build files are outputted to the dist folder so we can simply upload the entire folder. We specify we want these files to expire in 1 day because we don't need them any longer.

The test stage will again install any NPM packages (these are lost between stages). Next it will run the test command we defined in our package.json. Gitlab CI will automatically download any previous build artifacts. In our case this means the dist folder we previously uploaded will be downloaded again. Because of this we do not need to run the build step again.

Triggering a build

To trigger a build all you need to do is push the repository to Gitlab. Once pushed you can go to the pipelines page to view the current (and previous) builds.

This web page shows you the current running build (and at which stage it is). It allows you to download any available build artifacts. Lastly it shows you previous builds (and if they succeeded or failed).

By selecting a current or previous pipeline you can also view the terminal output. This is useful if a build failed to determine the cause.

Deploying your changes

Actually deploying this application is a bit out of scope. In my opinion Gitlab CI shines when it comes to building and testing your project. As a deployment tool though it can feel a bit clunky at times.

It is certainly possible to handle your deployment with Gitlab CI as well. However Gitlab CI does not currently have any features which you might expect from a deployment tool (think scheduled deployment or automatic rollbacks).

If you are really committed to doing your deployments with Gitlab CI you could consider using a combination of SFTP and SSH to copy your files to your server and trigger a restart.

Looking at the configuration file we use now you would need to add a third stage called deploy. This stage would run after the build and test stage so only successfully built and tested commits are deployed.

Conclusion

I have shown you the basics on how to get started with Gitlab CI using a simple NodeJS application. The Gitlab CI configuration file used could easily be tweaked so it targets other languages or frameworks. The basics remain the same.

Want to learn more about Gitlab CI? Check out my other articles about this subject!

Got any feedback or questions? Or just want to send me a message? You can contact me at info@asyncdrink.com
© Copyright 2019 by Mathyn