Skip to main content

GitLab & GitLab Registry - Docker Compose Deployment, GitLab Runner - Bare Metal and Docker Compose version

1629 words·
GitLab GitLab Registry GitLab Runner Docker-Compose
Table of Contents

GitLab Docker Compose deployment with GitLab Registry and GitLab Runner on seperate host.
#

Here is my tutorial for a GitLab deployment with Docker Compose. Initially I had problems getting the GitLab Registry to run, I frist tried to use the same URL as for GitLab but with a different port, which did not work properly.

I settled with two different host names gitlab.jklug.work for GitLab and gitlab-registry.jklug.work for it’s registry. For the TLS encryption I use a Let’s Encrypt wildcard certificate.

Prerequisites
#

SSH Port
#

GitLab Server
#

I have changed the SSH port on the Server that is hosting my GitLab instance, to make it easier to check out projects from GitLab via the default SSH port.

# Open the SSH daemon configuration
sudo vi /etc/ssh/sshd_config

# Define a new SSH port
Port 2280
# Restart the SSH service
sudo systemctl restart sshd

Custom SSH Port
#

If you don’t want to change the SSH port of the GitLab server and instead use a custom SSH port for GitLab, you have to define the GitLab SSH port on your host:

# Open / create SSH config file
sudo vi ~/.ssh/config

# Define a custom SSH port for GitLab
Host gitlab.jklug.work
  Preferredauthentications publickey
  IdentityFile ~/.ssh/id_rsa
  Port 2222

DNS
#

The deployment host and the GitLab Runner need to be able the resolv the DNS for the GitLab Registry, add an entry to your DNS server or define it directly in the hosts file. I also define the DNS entry in the configuration of the Runner itself.

# Edit hosts file
sudo vi /etc/hosts

# Add entry for GitLab and it's Registry
192.168.70.4 gitlab.jklug.work gitlab-registry.jklug.work

GitLab Setup
#

Folder Structure
#

# Create folder structure
sudo mkdir -p /opt/gitlab/{config/ssl,logs,data} && cd /opt/gitlab

# Set permissions
sudo chmod 775 /opt/gitlab/{config/ssl,logs,data}

Environment File
#

# Create environment variable
sudo vi .env

# .env
GITLAB_HOME=/opt/gitlab

Certificates
#

Note: I use a Let’s Encrypt certificate in this tutorial.

# Copy TSL certificate into Gitlab directory
sudo cp fullchain.pem privkey.pem /opt/gitlab/config/ssl/

# Set permissions
sudo chmod 0400 /opt/gitlab/config/ssl/fullchain.pem &&
sudo chmod 0400 /opt/gitlab/config/ssl/privkey.pem
# Generate DHPARAM certificate
sudo openssl dhparam -out /opt/gitlab/config/ssl/dhparams.pem 2048

Docker Compose File
#

# Create Docker Compose file
sudo vi docker-compose.yml
# docker-compose.yml
version: '3.6'
services:
  web:
    image: 'gitlab/gitlab-ce:latest'
    container_name: gitlab-ce
    restart: unless-stopped
    hostname: 'gitlab.jklug.work'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        # Add any other gitlab.rb configuration here, each on its own line
        external_url 'https://gitlab.jklug.work'
        gitlab_rails['gitlab_shell_ssh_port'] = 22
        registry_external_url 'https://gitlab-registry.jklug.work'
        gitlab_rails['registry_enabled'] = true
        registry['enable'] = true
        nginx['redirect_http_to_https'] = true
        nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
        nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"
        nginx['ssl_dhparam'] = "/etc/gitlab/ssl/dhparams.pem"
        registry_nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
        registry_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"        
    ports:
      - '8080:80'
      - '443:443'
      - '22:22'
    volumes:
    - '${GITLAB_HOME}/config:/etc/gitlab'
    - '${GITLAB_HOME}/logs:/var/log/gitlab'
    - '${GITLAB_HOME}/data:/var/opt/gitlab'
    - '${GITLAB_HOME}/config/ssl:/etc/gitlab/ssl'
    shm_size: '256m'

Create & Start Container
#

# Create & start container
sudo docker compose up -d

# Check logs
sudo docker compose logs -f

Docker PS
#

# List container status
sudo docker ps


# Wailt till container status changes from
Up About a minute (health: starting)

# to container status
Up 2 minutes (healthy)

# If the container runs on a minimal setup, wait some more ;)

Initial Login
#

# GitLab webinterface
https://gitlab.jklug.work
# User:
root

# Grep for initial root PW
sudo cat /opt/gitlab/config/initial_root_password | grep Password:

# Shell output:
Password: 5nxwNDs1ll8eVyMv9BXYv5bFP7A7fcKainEZr0+F1ok=
  • Change PW after initial login

GitLab Settings & Maintenance
#

Renew TSL Certificate
#

# Copy the new TSL certificate into the Gitlab directory
sudo cp fullchain.pem privkey.pem /opt/gitlab/config/ssl/
# Exec container terminal
sudo docker exec -it gitlab-ce bash

# Restart Nginx
gitlab-ctl restart nginx

List current GitLab Version
#

# List exact GitLab version: Note this command takes a while to execute
docker exec -it gitlab-ce gitlab-rake gitlab:env:info

# List more details
docker exec -it gitlab-ce cat /opt/gitlab/version-manifest.txt

GitLab Settings
#

GitLab settings like a mail server and LDAP authentication can be defined in the gitlab.rb file.

# GitLab configuration
/opt/gitlab/config/gitlab.rb

# Enable settings
gitlab-ctl reconfigure

GitLab Runner - Bare Metal
#

Install Runner
#

GitLab does not support the older apt version, it’s necessary to update the packet manager with the official repository from GitLab:

# Download & run script
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash

# Update the package manager
sudo apt update 

# Install GitLab Runner
sudo apt install gitlab-runner

Register Runner
#

  • Syntax
# egister one or more runners
gitlab-runner register

# Register one or more runners in system mode
sudo gitlab-runner register
  • Register new Runner
# Register Runer: Start wizard
sudo gitlab-runner register --url https://gitlab.jklug.work --token glrt-FTkHSSxsy53bbdoEeLzc


# Enter a name for the runner. This is stored only in the local config.toml file:
Untagged-Build-Runner-01

# Enter an executor: instance, custom, ssh, parallels, virtualbox, docker-autoscaler, shell, docker, docker-windows, docker+machine, kubernetes:
docker

# Enter the default Docker image (for example, ruby:2.7):
docker:latest

Runner Configuration
#

# Open GitLab Runner config file
sudo vi /etc/gitlab-runner/config.toml
concurrent = 10 # Define number of concurrent jobs
check_interval = 0
shutdown_timeout = 0
log_level = "debug" # Define log options
log_format = "text" # Define log options

[session_server]
  session_timeout = 1800

[[runners]]
  name = "Untagged-Build-Runner-01"
  url = "https://gitlab.jklug.work"
  id = 1
  token = "glrt-FTkHSSxsy53bbdoEeLzc"
  token_obtained_at = 2024-02-03T21:35:10Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  [runners.cache]
    MaxUploadedArchiveSize = 0
  [runners.docker]
    extra_hosts = ["gitlab.jklug.work:192.168.70.4","gitlab-registry.jklug.work:192.168.70.4"] # Define GitLab DNS resolution
    tls_verify = false
    image = "docker:latest"
    privileged = true # Set to true for DockerInDocker
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    network_mtu = 0
# Option: Restart the GitLab Runner (This should not be necessary)
gitlab-runner restart

GitLab Runner Commands
#

# Check version
gitlab-runner -v

# Open manual
gitlab-runner --help
# Restart GitLab Runner
gitlab-runner restart

# Check status
gitlab-runner status
# List all registered GitLab Runners
gitlab-runner list

# Check if runner runs in system oder user mode
sudo gitlab-runner verfiy

Test GitLab Registry Connection
#

# Test the connection to the GitLab Registry
telnet gitlab-registry.jklug.work 443

GitLab Runner - Docker Compose
#

Folder Structure
#

# Create folder structure
sudo mkdir -p /opt/gitlab-runner && cd /opt/gitlab-runner

Docker Compose File
#

# Create Docker Compose file
sudo vi docker-compose.yml

Ubuntu Version
#

version: '3.9'
services:
  gitlab-runner:
    image: gitlab/gitlab-runner:latest
    container_name: gitlab-runner
    restart: unless-stopped
    volumes:
      - ./gitlab-runner/config:/etc/gitlab-runner
      - /var/run/docker.sock:/var/run/docker.sock

Alpine Version
#

# docker-compose.yml
version: '3.9'
services:
  gitlab-runner:
    image: gitlab/gitlab-runner:alpine
    container_name: gitlab-runner
    volumes:
    - ./gitlab-runner/config:/etc/gitlab-runner
    - /var/run/docker.sock:/var/run/docker.sock
    restart: unless-stopped

Create & Start Container
#

# Create & start container
sudo docker compose up -d

# Check logs
sudo docker compose logs -f

Register Runner
#

# Execute container terminal
sudo docker exec -it gitlabrunner_name bash

# Register Gitlab-Runner
gitlab-runner register

# Exit container terminal
exit

Enter the GitLab instance URL (for example, https://gitlab.com/):
https://gitlab.jklug.work
Enter the registration token:
token_copied_from_website
Enter a description for the runner:
Name of your GitLab Runner
Enter tags for the runner (comma-separated):
gitlab-runner,docker-runner
Enter optional maintenance note for the runner:
<Enter>
Enter an executor: parallels, ssh, docker-ssh+machine, instance, custom, docker-ssh, shell, virtualbox, docker+machine, kubernetes, docker:
docker
Enter the default Docker image (for example, ruby:2.7):
docker:20.10.21

It is possible to create several runners with the same container, just run gitlab runner register again. To remove a runner remove the [[runners]] part from the config.toml file and restart the container.


config.toml
#

# Open GitLab Runner configuration
sudo vi /opt/gitlab-runner/gitlab-runner/config/config.toml

Add docker.sock to the config.toml file: volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache", "/builds:/builds:rw"] The whole config file should look like this:

concurrent = 10 # Define number of concurrent jobs
check_interval = 0
shutdown_timeout = 0
log_level = "debug" # Define log options
log_format = "text" # Define log options

[session_server]
  session_timeout = 1800

[[runners]]
  name = "Untagged-Build-Runner-02"
  url = "https://gitlab.jklug.work"
  id = 2
  token = "mks47Uej6sFcyNEBa9Yz"
  token_obtained_at = 2024-02-03T21:35:10Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  limit = 5
  [runners.custom_build_dir]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    extra_hosts = ["gitlab.jklug.work:192.168.70.4","gitlab-registry.jklug.work:192.168.70.4"] # Define GitLab DNS resolution
    tls_verify = false
    image = "docker:latest"
    privileged = false # Define root permissions
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache", "/builds:/builds:rw"]
    shm_size = 0

GitLab Runner Troubleshooting
#

DNS Troubleshooting
#

When the GitLab runner picks up the wrong DNS resolution an error like this appears in the GitLab Job logs abd the Jobs fails:

# GitLab Job log error:
fatal: unable to access 'https://gitlab.jklug.work/root/project-1.git/': Could not resolve host: gitlab.jklug.work

Use the following ways to define the correct DNS server.

Netpaln
#

  • Make sure to define the DNS server in the network configuration
# /etc/netplan/00-installer-config.yaml
network:
  ethernets:
    ens33:
      addresses:
      - 192.168.30.90/24
      nameservers:
        addresses:
        - 192.168.30.1 # Define DNS server
        search: []
      routes:
      - to: default
        via: 192.168.30.1
  version: 2
  • Reboot the server after the network configuration changes
# Reboot server
sudo reboot
  • Test the DNS resolution
# Test DNS resolution: Define DNS server
dig @192.168.70.1 gitlab.jklug.work

config.toml
#

  • Define the DNS server in the GitLab Runner configuration
# Define DNS server
dns = ["192.168.70.1"]
  • Enable extended logging in the GitLab Runner configuration
# Enable extended logging in GitLab Jobs console
environment = ["GIT_CURL_VERBOSE=1"] 
  • The whole configuration looks like this:
# Open GitÖab-Runner configuration
sudo vi /opt/gitlab-runner/gitlab-runner/config/config.toml
# /opt/gitlab-runner/gitlab-runner/config/config.toml
concurrent = 1
check_interval = 0
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  dns = ["192.168.70.1"] # Define DNS server
  environment = ["GIT_CURL_VERBOSE=1"] # Verbose logging
  name = "dr1"
  url = "https://gitlab.jklug.work"
  id = 1
  token = "QZVLzy4BSzeW7VMXi55x"
  token_obtained_at = 2024-01-07T17:56:55Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  [runners.cache]
    MaxUploadedArchiveSize = 0
  [runners.docker]
    tls_verify = false
    image = "docker:latest"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache", "/builds:/builds:rw"]
    shm_size = 0
    network_mtu = 0

GitLab CI Tags
#

  • To run a job on a specific runner, add the specific tag from the GitLab Runner to the pipeline stage
stages:
  - publish

publish:
  image: docker:latest
  stage: publish
  tags:
    - deploy-runner-01 # Define GitLab Runner tag

Links #

# GitLab Official Documentation
https://docs.gitlab.com/ee/install/docker.html

# DockerHub GitLab Tags
https://hub.docker.com/r/gitlab/gitlab-ce/tags