GitLab Self-Managed Deployment via Docker and Orchestration

The deployment of a GitLab Self-Managed instance utilizing Docker represents a sophisticated intersection of version control, continuous integration, and containerization. By leveraging Docker Engine, Docker Compose, or Docker Swarm, organizations can instantiate a full-featured DevOps platform that maintains the flexibility of the Free, Premium, and Ultimate tiers. This architectural approach allows for the decoupling of the GitLab application from the underlying host operating system, ensuring that dependencies are encapsulated within the container image. However, such a deployment is not a mere act of running a single command; it requires a meticulous orchestration of volume permissions, network configurations, and external service dependencies to ensure stability and security.

Critical Prerequisites for GitLab Containerization

Before initiating the deployment process, several foundational requirements must be satisfied to prevent catastrophic failure during the initialization phase.

  • Docker Installation
    A working Docker installation is mandatory. It is explicitly stated that Docker for Windows is not officially supported. This restriction exists because Docker for Windows introduces known compatibility issues, specifically regarding volume permissions, which can lead to the corruption of GitLab's data directories or the inability of the application to write to the disk. Users attempting to deploy on Windows are directed to community resources, such as IRC or forums, as the official support channel does not guarantee stability on that platform.

  • Mail Transport Agent (MTA)
    GitLab requires an MTA, such as Postfix or Sendmail, to handle the delivery of system notifications, password resets, and alert emails. The official GitLab Docker images do not include a built-in MTA. While it is technically possible to install an MTA within the same container as GitLab, this is strongly discouraged. The primary reason is that any upgrade or restart of the container would necessitate a manual reinstallation of the MTA, creating significant administrative overhead. The professional recommendation is to deploy the MTA in a separate, dedicated container.

  • Hostname Configuration
    A valid, externally accessible hostname is required for the Docker installation. The use of localhost is strictly prohibited for the installation. A proper Fully Qualified Domain Name (FQDN) ensures that Git clones via SSH and HTTP function correctly across different network segments and that SSL/TLS certificates can be properly validated.

  • Kubernetes Constraints
    Deploying the standard GitLab Docker image directly into Kubernetes is discouraged because it creates a single point of failure. For those requiring the scalability and resilience of a Kubernetes cluster, the recommended path is to utilize the GitLab Helm Chart or the GitLab Operator, which are specifically designed for the Kubernetes orchestration layer.

Deployment Methodologies via Docker Engine and Compose

Depending on the scale of the operation and the level of automation required, administrators can choose between a direct Docker run command or a structured Docker Compose orchestration.

Implementation via Docker Compose

Docker Compose provides a declarative way to define the GitLab service, its environment variables, and its persistent storage.

To initiate the deployment, the user should execute the following command:

docker-compose up -d

The deployment process is computationally intensive and network-dependent, typically taking between 10 to 30 minutes. This delay is caused by the initialization of the Omnibus package and the setup of the internal database and Redis instances.

Alternative Manual Volume Deployment

In scenarios where standard Compose files encounter issues, an alternative manual method can be employed. This involves explicitly setting the volume location before deploying the container:

export GITLAB_HOME=/srv/gitlab

This ensures that all configuration, logs, and data are mapped to a consistent path on the host machine, facilitating easier backups and migrations.

SSH Port Configuration and Network Access

GitLab utilizes port 22 by default for interacting with Git over SSH. This is a critical juncture for network administrators.

  • Default Port 22
    If the host server is dedicated to GitLab and port 22 is available, no further configuration is required.

  • Custom SSH Ports
    If port 22 is already occupied by the host OS or another service, the SSH port must be changed. Failing to properly configure the SSH port can prevent Git operations from working with Kerberos, leading to authentication failures during the push or pull process.

Initial Access and Root Credential Retrieval

Once the container is up and running, the system generates a temporary root password. The initialization process can be monitored in real-time to determine when the system is ready for queries:

sudo docker logs -f gitlab

Once the container responds to queries at the configured URL (e.g., gitlab.example.com), the administrator must retrieve the initial root password. There are two primary methods for this depending on the deployment path:

  1. Via Docker Exec:
    sudo docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password

  2. Via Host File Path (for specific Compose setups):
    sudo cat /srv/gitlab/config/initial_root_password

It is imperative to act quickly, as the password file is automatically deleted during the first container restart after 24 hours. Once the password is retrieved, the user logs in via the web interface using the username root.

Advanced Orchestration with Docker Swarm Mode

Docker Swarm mode allows for the deployment of GitLab in a cluster, providing higher availability and a more secure method of handling sensitive data.

Leveraging Secrets and Configurations

Unlike standard Docker Compose, Swarm mode allows the use of Docker secrets and configurations. This removes the need to pass sensitive information, such as the root password, as plain-text environment variables.

  • Docker Secrets: Used to pass the initial root password securely.
  • Docker Configurations: Used to keep the GitLab image generic by injecting configuration files at runtime.

Swarm Stack Implementation

A comprehensive Swarm deployment involves the creation of a docker-compose.yml file that defines the GitLab service and the GitLab Runner service.

yaml services: gitlab: image: gitlab/gitlab-ee:<version>-ee.0 container_name: gitlab restart: always hostname: 'gitlab.example.com' ports: - "22:22" - "80:80" - "443:443" volumes: - $GITLAB_HOME/data:/var/opt/gitlab - $GITLAB_HOME/logs:/var/log/gitlab - $GITLAB_HOME/config:/etc/gitlab shm_size: '256m' environment: GITLAB_OMNIBUS_CONFIG: "from_file('/omnibus_config.rb')" configs: - source: gitlab target: /omnibus_config.rb secrets: - gitlab_root_password gitlab-runner: image: gitlab/gitlab-runner:alpine deploy: mode: replicated replicas: 4 configs: - gitlab secrets: - gitlab_root_password

To support this stack, a gitlab.rb file must be created to handle the external URL and the reading of the root password secret:

ruby external_url 'https://my.domain.com/' gitlab_rails['initial_root_password'] = File.read('/run/secrets/gitlab_root_password').gsub("\n", "")

Additionally, a root_password.txt file is created containing the desired password (e.g., MySuperSecretAndSecurePassw0rd!). The final deployment is executed via:

docker stack deploy --compose-file docker-compose.yml mystack

Continuous Deployment with GitLab and Docker Compose

Implementing a Continuous Deployment (CD) pipeline requires a tight integration between the GitLab CI/CD engine and the deployment server.

Deployment Server Preparation

A dedicated user must be created on the server to handle the deployment tasks without requiring root privileges for every action.

  • User Creation:
    sudo adduser <project>

  • Docker Group Assignment:
    sudo adduser <project> docker

  • SSH Key Generation:
    The user must generate a 4096-bit RSA key pair to allow secure, passwordless authentication:

sudo su <project>
cd ~
ssh-keygen -t rsa -b 4096

  • Authorization:
    The public key must be added to the authorized keys list:

cat .ssh/id_rsa.pub > .ssh/authorized_keys

CI/CD Variable Configuration

To allow the GitLab runner to communicate with the deployment server, specific variables must be configured in the GitLab web interface under Settings > CI/CD > Variables.

  • SSH_PRIVATE_KEY: The content of the private key, retrieved via cat .ssh/id_rsa.
  • SSH_HOST_KEY: The fingerprint of the server, retrieved using ssh-keyscan -t rsa -H <deploy.server>.

Pipeline Architecture

The deployment process is governed by a .gitlab-ci.yaml file, which defines the build and deploy stages.

The build stage utilizes a Docker-in-Docker (DinD) configuration to build and push images to the registry:

```yaml
stages:
- build
- deploy

build:
stage: build
tags:
- dind
image: docker:20.10.16
services:
- docker:20.10.16-dind
variables:
DOCKERTLSCERTDIR: "/certs"
beforescript:
- docker login -u $CI
REGISTRYUSER -p $CIREGISTRYPASSWORD $CIREGISTRY
script:
- docker pull $CIREGISTRYIMAGE:latest || true
- docker build --cache-from $CIREGISTRYIMAGE:latest --tag $CIREGISTRYIMAGE:$CICOMMITSHA --tag $CIREGISTRYIMAGE:latest .
- docker push $CIREGISTRYIMAGE:$CICOMMITSHA
- docker push $CIREGISTRYIMAGE:latest
```

The subsequent deploy stage involves the use of a docker-compose.tmpl file, which is processed into a final docker-compose.yaml on the deployment server, followed by an SSH command to restart the containers.

Technical Specification Summary

The following table outlines the technical requirements and configurations for a standard GitLab Docker deployment.

Requirement Specification/Value Impact of Non-Compliance
Docker Version Non-Windows Docker Engine Volume permission failures
MTA Postfix or Sendmail (External) Failure of system notifications
Hostname Valid FQDN (Not localhost) SSH/HTTP clone failures
Port (SSH) 22 (Default) or Custom Kerberos operation failures
Root Password /etc/gitlab/initialrootpassword Loss of administrative access after 24h
RAM/SHM Size 256m (shm_size) Performance degradation/Crashes
CI/CD Image docker:20.10.16 Build stage incompatibility

Final Analysis and Deployment Synthesis

The deployment of GitLab via Docker is a strategic decision that trades the simplicity of a cloud-hosted offering for total control over data and configuration. The use of Docker Compose is ideal for standalone instances, providing a clear mapping of persistent volumes to the host. However, for production environments requiring high availability, the transition to Docker Swarm is necessary. Swarm mode not only provides orchestration but solves the security vulnerability of plain-text environment variables through the implementation of Docker Secrets.

The integration of a CI/CD pipeline via .gitlab-ci.yaml completes the loop, allowing the GitLab instance to manage its own deployment. By utilizing a dedicated deployment user with restricted Docker access and SSH key-based authentication, the attack surface of the server is minimized. The most critical failure point in this architecture remains the initialization phase; the reliance on the initial_root_password and the necessity of a separate MTA highlight that GitLab is not a "plug-and-play" container but a complex suite of services requiring a coordinated environment. Failure to adhere to the hostname and volume requirements will invariably lead to a state where the container is running, but the application is unreachable or unable to persist data.

Sources

  1. GitLab Documentation
  2. The New Stack
  3. CyLab Blog

Related Posts