When running a GitLab CI/CD pipeline you can use any public Docker image, but you can also build your own images and use them later on. In this article we'll see how to do that.

Out of the several options we'll see setting up your own Runner and using Docker on it.

A Runner is any real or virtual box. (AFAIK it can be Linux, Windows, and Mac as well.) On this box there is an application provided by GitLab that handles the runner. In a pipeline you can execute code directly on the runner, but in most cases it is better to use a Docker container on top of the Runner for your regular CI system.

However, when building a Docker image you will want to execute the docker commands directly on the Runner.

Create a Virtual Machine

I tried this once with a Digital Ocean Droplet that already had Docker installed and once on Azure where I had to install Docker manually.

Install Docker

Follow the Docker installation on the machine and also the post installation needed on Linux to allow non-root user to run docker. Enable it for the user gitlab-runner.

Install GitLab Runner

First thing is to Install GitLab Runner.

I personally followed the instructions to Setup Docker Runner on Digital Ocean

Also see using docker build.

Register the runner and restart

sudo gitlab-runner register -n --url https://gitlab.com/ --registration-token $TOKEN --executor shell --description "ShellRunner" --tag-list shell-runner
sudo gitlab-runner restart

In order to run the CI jobs in a Docker container we will need another runner:

sudo gitlab-runner register -n --url https://gitlab.com/ --registration-token $TOKEN --executor docker --description "Docker Runner" --tag-list docker-runner --docker-image alpine:3.14.0
sudo gitlab-runner restart

The docker-image parameter sets the default image. I don't think it is very important what you set here as you should always explicitly define it in the .gitlab-ci.yml file anyway.

Edit the following file and comment out everything


Container registry


FROM alpine:latest
RUN date > date.txt


  stage: build
    - hostname
    - uptime
    - uname -a
    - docker info
    - docker build -t $CI_REGISTRY/szabgab/gl-try:latest .
    - docker push $CI_REGISTRY/szabgab/gl-try:latest
    - shell-runner

  stage: test
  image: $CI_REGISTRY/szabgab/gl-try:latest
    - hostname
    - uptime
    - uname -a
    - pwd
    - ls -l
    - ls -l /opt
    - cat /opt/date.txt
    - date