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 Pages #
Docker Compose YAML Manifest #
Add the following section to the Docker Compose manifest:
# GitLab Pages
pages_external_url 'https://gitlab-pages.jklug.work'
gitlab_pages['enable'] = true
pages_nginx['redirect_http_to_https'] = true
pages_nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
pages_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"
## GitLab Pages: Storage Configuration
gitlab_rails['pages_local_store_enabled'] = true
gitlab_rails['pages_local_store_path'] = "/var/opt/gitlab/gitlab-rails/shared/pages"
Notes:
-
A wildcard TLS certificate like this
*.gitlab-pages.jklug.work
is necessary for the define GitLab Pages URL to work:pages.gitlab.jklug.work
-
Fore more storage options, open the
config/gitlab.rb
configuration file.
The Docker Compose manifest should now look like this:
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
#registry['registry_http_addr'] = "0.0.0.0:5050"
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"
# GitLab Pages
pages_external_url 'https://gitlab-pages.jklug.work'
gitlab_pages['enable'] = true
pages_nginx['redirect_http_to_https'] = true
pages_nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
pages_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"
## GitLab Pages: Storage Configuration
gitlab_rails['pages_local_store_enabled'] = true
gitlab_rails['pages_local_store_path'] = "/var/opt/gitlab/gitlab-rails/shared/pages"
ports:
- '8080:80'
- '443:443'
- '22:22'
#- '5050:5050'
extra_hosts:
- "sonarqube.jklug.work:192.168.70.11"
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'
Verify GitLab Pages #
The “Pages” section should now be available in GitLab projects:
-
Open a GitLab project
-
Go to: (Project) “Deploy” > “Pages”
GitLab Pages GUI Settings #
-
Use administrator credentials to log in to the GitLab instance
-
On the left sidebar, at the bottom, select “Admin”
-
Go to: “Settings” / “Preferences”
-
Open the “Pages” selection
Mattermost Integration #
Create Mattermost Directory #
And create a mattermost
directory on the host:
# Create "mattermost" directory:
sudo mkdir /opt/gitlab/mattermost
Docker Compose YAML Manifest #
Add the following section to the Omnibus configuration of the Docker Compose manifest:
## Mattermost
mattermost_external_url 'https://mattermost.jklug.work'
mattermost_nginx['redirect_http_to_https'] = true
mattermost_nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
mattermost_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"
Open the default Mattermost port in the ports section:
ports:
- '8065:8065' # Mattermost port
Map the mattermost configuration to the host in the volumes section:
volumes:
- '${GITLAB_HOME}/mattermost:/var/opt/gitlab/mattermost' # Mattermost configuration
The Docker Compose manifest should now look like this:
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
#registry['registry_http_addr'] = "0.0.0.0:5050"
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"
# GitLab Pages
pages_external_url 'https://gitlab-pages.jklug.work'
gitlab_pages['enable'] = true
pages_nginx['redirect_http_to_https'] = true
pages_nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
pages_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"
## GitLab Pages: Storage Configuration
gitlab_rails['pages_local_store_enabled'] = true
gitlab_rails['pages_local_store_path'] = "/var/opt/gitlab/gitlab-rails/shared/pages"
## Mattermost
mattermost_external_url 'https://mattermost.jklug.work'
mattermost_nginx['redirect_http_to_https'] = true
mattermost_nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
mattermost_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"
ports:
- '8080:80'
- '443:443'
- '22:22'
- '8065:8065' # Mattermost port
#- '5050:5050'
extra_hosts:
- "sonarqube.jklug.work:192.168.70.11"
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'
- '${GITLAB_HOME}/mattermost:/var/opt/gitlab/mattermost' # Mattermost configuration
shm_size: '256m'
Start the Container #
# Start the GitLab Compose stack
sudo docker compose up -d
Adapt Mattermost Configuration #
Adapt the Mattermost configuration to allow the upload of plugins:
# Adapt the Mattermost configuration
sudo vi /opt/gitlab/mattermost/config.json
Set the “PluginSettings” > “EnableUploads” to “true”:
"PluginSettings": {
"Enable": true,
"EnableUploads": true, # Set to true
Apply Changes #
Restart the Docker Compose stack to apply the changes.
The upload plugins option should now be available:
-
Go to: “System Console” > (PLUGINS) “Plugin Management”
-
Click Upload Plugin: “Choose File”
Install Mattermost Focalboard #
Find latest Focalboard release:
https://github.com/mattermost-community/focalboard/releases
-
Go to: “System Console” > (PLUGINS) “Plugin Management”
-
Click: “Choose File” and select the
mattermost-plugin-focalboard-v8.0.0-linux-amd64.tar.gz
file -
Click “Upload”
-
Scroll down to “Installed Plugins:”
Mattermost Boards (focalboard - 8.0.0)
The Mattermost Boards plugin
Enable - Remove - Settings
This plugin is not enabled.
-
Click “Enable”
-
The status should change as follows:
Mattermost Boards (focalboard - 8.0.0)
The Mattermost Boards plugin
Disable - Remove - Settings
This plugin is running.
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