peteris.rocks

Docker GitLab & GitLab CI

How to set up GitLab and GitLab CI in minutes using Docker

Last updated on

GitHub is a popular website for hosting code using the git version control system. It's free for open source projects and plans for hosting 5 private projects start at $7/month. With $5/month you can host hundreds of projects on your DigitalOcean droplet with GitLab. GitLab is an open source alternative to GitHub. It looks like and works very similarly to GitHub. After using it for a while, you may even like it more than GitHub.

GitLab CI (Continuous Integration) is an application for running automated tests. It's similar to Travis CI that's integrated with GitHub, which is also free for public open source projects only.

Here's how to to set up GitLab and GitLab CI on DigitalOcean in minutes. We're going to use Docker for deployment which will let you get up and running quickly and will run GitLab in isolated containers which means you can try this on your existing droplets.

This has been tested with the following software versions:

Docker

Docker is a deployment tool. Applications deployed with Docker are already pre-built (and can be rebuilt from scratch) and are run in isolated containers. It means fast deployment and Dockerized applications won't interfere with other services running on your server. It's also very simple to remove Docker applications without leaving anything behind.

Installation

Ubuntu Server ships an old version of Docker. It is recommended to use the latest stable version.

We'll need to add a custom package repository and install the docker package.

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
sudo sh -c "echo deb https://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
sudo apt-get update
sudo apt-get install -y lxc-docker

You could also install Docker simply by downloading an installation script and executing it. The advantage of this method is that it's a simple one-liner and can also perform other necessary actions for the installation. However, security experts frown upon doing this since the contents of the script may change in the future and execute other unexpected commands.

curl -sSL https://get.docker.com/ubuntu/ | sudo sh

Using Docker requires administrative privileges i.e. you would have to run all commands as the super user (root) with the command sudo docker. Add yourself to the docker group so that you don't have to use sudo all the time.

sudo gpasswd -a ${USER} docker
sudo service docker restart

If you're getting permission denied errors when using the docker command without sudo after this, log out and log in again.

GitLab

GitLab is a ruby application and will run in its own isolated container.

In addition, GitLab requires two databases to run. We're going to run them in separate containers as well.

Redis

Redis is an in-memory database which is used for storing temporary data. Restarting this database will cause all data to be lost but this is expected behavior.

Launch redis:

docker run --name=gitlab-redis -d sameersbn/redis:latest

First, Docker will check if an image (i.e. pre-installed application) called redis, created by user sameersbn with the latest version exists. If it doesn't, it will download it from the Docker cloud which is a collection of freely available Docker images. If you want to download an image but not run it yet, you can do it with docker pull sameersbn/redis:latest.

latest specifies the version to download and is the default version so it can be omitted. So docker pull sameersbn/redis will also download the latest version. This guide was written when the latest version was x.x.x. If there's problems with the latest version, replace latest with x.x.x i.e. docker pull sameersbn/redis:x.x.x.

You can see the downloaded images with docker images.

$ docker images
REPOSITORY         TAG       IMAGE ID         CREATED          VIRTUAL SIZE
sameersbn/redis    latest    a7a9de7127c6     5 days ago       207.4 MB

A Docker image is like a template (a class in programming terms). A Docker container is a running version of this template (a concrete instance in programming terms). You can run several containers from the image. So you would have one redis image and you could run two redis servers created from this image.

You can see the list of running containers with docker ps. You can see all containers (including stopped ones) with docker ps -a.

$ docker ps
CONTAINER ID    IMAGE                    COMMAND    CREATED      STATUS     PORTS      NAMES
bfd4a817b99f    sameersbn/redis:latest   "/start"   2 days ago   Up 2 days  6379/tcp   gitlab-redis

Docker by default will assign random names to containers so it's useful to name them and --name=gitlab-redis does just that.

-d means that the container will be launched in background as a daemon. You can see the output with docker logs gitlab-redis.

PostgreSQL

Launch PostgreSQL

docker run --name=gitlab-postgresql -d \
  -e 'DB_NAME=gitlab' -e 'DB_USER=gitlab' -e 'DB_PASS=gitlab' \
  -v /opt/gitlab/db:/var/lib/postgresql \
  sameersbn/postgresql

GitLab

Launch GitLab

docker run --name=gitlab -d \
  -e 'GITLAB_PORT=10080' -e 'GITLAB_SSH_PORT=10022' \
  -e 'GITLAB_BACKUPS=daily' \
  -p 10022:22 -p 10080:80 \
  -v /opt/gitlab/repos:/home/git/data \
  -v /var/run/docker.sock:/run/docker.sock \
  -v $(which docker):/bin/docker \
  --link gitlab-postgresql:postgresql \
  --link gitlab-redis:redisio \
  sameersbn/gitlab

This may take a while. You can see what's going on with docker logs gitlab.

Go to http://localhost:10080 and log in with

GitLab CI

Launch redis

docker run --name=gitlab-ci-redis -d sameersbn/redis

Launch PostgreSQL

docker run --name=gitlab-ci-postgresql -d \
  -e 'DB_NAME=gitlab_ci_production' -e 'DB_USER=gitlab_ci' -e 'DB_PASS=gitlab_ci' \
  -v /opt/gitlab-ci/db:/var/lib/postgresql \
  sameersbn/postgresql

Launch GitLab CI

docker run --name=gitlab-ci -d \
  -p 11080:80 \
  -v /opt/gitlab-ci/data:/home/gitlab_ci/data \
  -v /var/run/docker.sock:/run/docker.sock \
  -v $(which docker):/bin/docker \
  --link gitlab:gitlab \
  --link gitlab-ci-postgresql:postgresql \
  --link gitlab-ci-redis:redisio \
  sameersbn/gitlab-ci

Go to http://localhost:11080 and log in with your GitLab credentials.

GitLab CI Runners

Note down the registration token at http://localhost:11080/admin/runners.

export CI_TOKEN=xxx
export CI_HOST=`hostname -I | cut -d' ' -f1`

Mono C#/.NET

Let's create a runner for testing C#/.NET applications with mono.

You're probably going to modify it several times to get it right, so we're going also going to create a Dockerfile and Makefile instead of using a one-liner.

mkdir -p ~/gitlab-ci-runners/mono
cd ~/gitlab-ci-runners/mono

Dockerfile

cat > Dockerfile <<END
FROM sameersbn/gitlab-ci-runner:latest
MAINTAINER me@localhost

RUN apt-get update && apt-get install -y curl && \
    curl -s http://download.mono-project.com/repo/xamarin.gpg | apt-key add - && \
    echo "deb http://download.mono-project.com/repo/debian wheezy main" > /etc/apt/sources.list.d/xamarin.list && \
    apt-get update && \
    apt-get -y install mono-complete && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

RUN mozroots --import --sync --machine && echo "y\n\y\n" | certmgr -ssl -m https://nuget.org
END

Makefile

cat > Makefile <<END
all: build

build:
        @docker build --tag=$USER/gitlab-ci-runner-mono .
END

Build it

make

Launch the runner

docker run --name gitlab-ci-runner-mono -d \
  -e "CI_SERVER_URL=http://$CI_HOST:11080" -e "REGISTRATION_TOKEN=$CI_TOKEN" \
  -v /opt/gitlab-ci/runners/mono:/home/gitlab_ci_runner/data \
  $USER/gitlab-ci-runner-mono

C++

Let's create another one for C++ development.

docker build -t $USER/gitlab-ci-runner-cpp - <<END
FROM sameersbn/gitlab-ci-runner:latest
MAINTAINER me@localhost

RUN apt-get update && \
    apt-get install -y build-essential libboost-all-dev && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
END

docker run --name gitlab-ci-runner-cpp -d \
  -e "CI_SERVER_URL=http://$CI_HOST:11080" -e "REGISTRATION_TOKEN=$CI_TOKEN" \
  -v /opt/gitlab-ci/runners/cpp:/home/gitlab_ci_runner/data \
  $USER/gitlab-ci-runner-cpp

TODO

Summary

You now have a working GitLab instance and also a GitLab CI instance. You can remove GitLab CI at any time or add new runners. Everything is persisted in /opt/gitlab and /opt/gitlab-ci.

Troubleshooting

You can see the list of running docker processes with docker ps. If it's not there, it's not running. Use docker ps -a to see recently exited processes.

You can see the logs with docker logs gitlab.

Testing before committing

Instead of -d which daemonizes the process, use -it --rm which will remove the container after exit or Ctrl+C. Since you're persisting data locally, you can safely delete the container and launch it again.

Based on the following guides:

They are extensive and explain all options and use cases. These here are my public notes. You can set up a running GitLab and GitLab CI installation by copy and pasting the commands below.