| Work | Research and Development (R&D) | Engineering | Infrastructure | How to setup GitLab Runner using Digital Ocean
How to setup GitLab Runner using Digital Ocean

Overview

GitLab Runner allows you to run CI jobs.

Can you run Runner on the same server as your GitLab instance?
- It's possible however I wouldn't recommend it. It's better to keep your DevOps tooling (source code management, etc.) separate from code execution due to security and performance concerns.
- The security concern is due to malicious code execution in your jobs, for example, it may be possible for someone to write a unit test that traverses your server's file system providing them with access to other data on that server.
- The performance concern is simply that your jobs will be competing for the same resources (CPU, memory, storage) as the rest of your GitLab instance and you may notice a slow down in the responsiveness of your GitLab instance whenever there's a job running.

Deploy a Digital Ocean Instance and Setup Docker

See https://jeromezng.com/how-to-install-docker-on-digital-ocean

Setup VPC
It might make sense to setup a VPC with my GitLab Instance on Digital Ocean to limit network access into thet runner, however, I need to think this through a bit more.

Create Docker Volume

Docker volumes allow you to persist state data across containers. We'll be creating a volume to allow us to persist gitlab-runner configuration data across our containers.

docker volume create gitlab-runner-config

Inspect the full details of your volume by running:

docker volume inspect gitlab-runner-config

This will specifically show you the mountpoint:

[
    {
        "CreatedAt": "2021-12-19T09:30:54Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/gitlab-runner-config/_data",
        "Name": "gitlab-runner-config",
        "Options": {},
        "Scope": "local"
    }

Change directory to the mountpoint to see what data is persisted across containers.

cd /var/lib/docker/volumes/gitlab-runner-config/_data

Start the GitLab runner container

Start the GitLab Runner container and expose port -p 8093:8093

docker run -d --name gitlab-runner --restart always \
    -p 8093:8093 \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v gitlab-runner-config:/etc/gitlab-runner \
    gitlab/gitlab-runner:latest

List all your docker containers

docker ps

Ensure that the gitlab-runner container is running and exposing port 8093.

CONTAINER ID   IMAGE                         COMMAND                  CREATED       STATUS          PORTS                                       NAMES
1234567890   gitlab/gitlab-runner:latest   "/usr/bin/dumb-init …"   3 hours ago   Up 46 minutes   0.0.0.0:8093->8093/tcp, :::8093->8093/tcp   gitlab-runner

Once you've confirmed the gitlab-runner container is running, you will also need to confirm that gitlab-runner's session_server is listening and advertising on port 8093.

Open your config file

cd /var/lib/docker/volumes/gitlab-runner-config/_data
nano config.toml

Add the following session_server configuration and save

[session_server]
  listen_address = "[::]:8093"
  advertise_address = "code.example.com:8093"
  session_timeout = 1800

Restart gitlab-runner

docker restart gitlab-runner

Register your Docker container

Now that the gitlab-runner container is started, you will now need to register the runner with your GitLab instance.

You can choose to register your runner as a (1) shared runner for your entire instance (2) a group-specific runner (3) a project-specific runner. Since my GitLab instance is for personal use, I decided to use shared runner which can be used by all my groups and projects.

You can register your gitlab-runner using

docker run --rm -it -v gitlab-runner-config:/etc/gitlab-runner gitlab/gitlab-runner:latest register

You will be prompted for a few details. Your registration token for a shared runner can be found in GitLab by navigating to Admin > Overview > Runners (https://code.example.com/admin/runners). These details will be saved into config.toml.

Enter the GitLab instance URL (for example, https://gitlab.com/): https://code.example.com
Enter the registration token: 1234567890
Enter a description for the runner: `code-example-com-shared-runner`
Enter tags for the runner (comma-separated): 
Enter an executor: virtualbox, docker+machine, docker-ssh+machine, kubernetes, docker-ssh, parallels, ssh, custom, docker, shell:
docker
Enter the default Docker image (for example, ruby:2.6):
ruby:latest

Open your config file

cd /var/lib/docker/volumes/gitlab-runner-config/_data
nano config.toml

Ensure that your config file now contains the registration details you previously entered

concurrent = 1
check_interval = 0

[session_server]
  listen_address = "[::]:8093"
  advertise_address = "code.example.com:8093"
  session_timeout = 1800

[[runners]]
  name = "code-example-com-shared-runner"
  url = "https://code.example.com"
  token = "1234567890"
  executor = "docker"
  [runners.custom_build_dir]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = "ruby:latest"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0

Restart gitlab-runner

docker restart gitlab-runner

Check the logs of gitlab-runner

docker logs gitlab-runner

Your logs should look something like this. I'm not sure why the logs say listen_address not defined, metrics & debug endpoints disabled builds=0 but it seems to be working and I'll look into that another time.

Configuration loaded                                builds=0
listen_address not defined, metrics & debug endpoints disabled  builds=0
Session server listening                            address=[::]:8093 builds=0

Verify your runner was successfully registered by navigating back into your GitLab instance. For shared runners, navigate to Admin > Overview > Runners (https://code.example.com/admin/runners). Your runner should now be listed on this page. Ensure that the Last contact is showing a recent time, otherwise it means your GitLab instance hasn't been able to make contact with your runner which could be for a number of reasons including having the incorrect config.toml or not exposing the right ports in your docker container.

Type/State: Shared
Runner: code-example-com-shared-runner
Version: 14.6.0
IP Address: 0.0.0.0
Projects: n/a
Jobs: 1
Tags: 
Last contact: 1 min ago

Run a test job

In order to verify your runners were successfully setup, you will need to run a test job on an existing project to see if a pipeline is successfully created. The easiest way I found to do this is to clone an existing project which already has /.gitlab-ci.yml defined.

I chose to clone the GitLab Pages Jekyll project https://gitlab.com/pages/jekyll into my GitLab instance. After cloning the project, I navigated to the Project Name > CI/CD > Jobs (https://code.jeromezng.com/my-projects/jekyll/-/jobs) and pressed the "retry" icon on an existing job. If there are no existing jobs, you may need to make a commit to trigger the pipeline.

When the job is running, click into the job and view the logs. You should see the job being run on the runner you provisioned code-example-com-shared-runner

Running with gitlab-runner 14.6.0 (1234567890)
  on code-example-com-shared-runner 1234567890
Preparing the "docker" executor 00:05
Using Docker executor with image ruby:latest ...
Pulling docker image ruby:latest ...
...

Conclusion

That's it! You now have GitLab's runner setup. You can now modify your .gitlab-ci.yml to according to your integration or deployment needs.