Introduction

En tant qu’“ingénieur” DevOps, j’ai déjà été amené à intervenir dans une équipe utilisant Gitlab.

C’est une plateforme complète. Surtout connue pour l’hébergement du code et l’intégration continue (Gitlab CI), Gitlab est également utilisable pour la gestion de produit au sens général. Au fil des années l’offre s’est étoffée en proposant la gestion des tickets, des epics, tableau de suivi et d’autres features. Ainsi Gitlab peut être utilisé aujourd’hui comme outil principal pour une équipe voir une entreprise gérant du code. Tout le cycle de vie d’une application peut être gérable depuis Gitlab.

Gitlab a un atout important également, c’est le fait qu’il propose une offre auto-hébergée gratuite. Cela a un intérêt par exemple pour la résidence des données et/ou la cybersécurité (maîtrise de bout en bout en interne), voir pour une optimisation de coûts.

Dans le cadre de mes travaux sur Gitlab, j’ai souvent voulu réaliser différents tests qui ne sont pas forcément possible sur les plateformes hébergées par les clients. Par ailleurs, il est intéressant d’étudier comment fonctionne la plateforme que l’on utilise, certains modules ou évènements devenant ainsi plus compréhensibles.

C’est pour ces raisons que j’ai réalisé l’installation d’une instance GitLab auto-hébergée.

Afin de pousser le mode démo, je vais créer des groupes, des projets et des utilisateurs. Je vais également insérer des éléments supplémentaires afin de voir le comportement lors de sauvegarde/restauration et/ou de migration de machine. Pour cela je vais configurer un runner GitLab, ajouter des secrets et faire tourner quelques pipelines.

Les éléments présentés ne se veulent pas exhaustifs mais assez représentatifs d’un travail d’administration de la plateforme Gitlab.

Dans cette première partie, nous allons donc réaliser l’installation et l’initialisation. Le code de cette première partie est disponible dans Gitlab.

Dans un second article, je parlerais de sauvegarde, de migration et de mise à jour.

Prérequis et préparation du serveur

Dans les grandes lignes, je suis la documentation de l’architecture de référence.

Environnement technique

Système d’exploitation : Debian 13.

Matériel : Un serveur avec au moins 4 cœurs CPU, 8 Go de RAM, et 50 Go d’espace disque. On est en dessous des précos Gitlab mais pour cette démo il aura au plus 3 utilisateurs connectés simultanément.

Outils nécessaires :

  • Docker et Docker Compose installés.
  • Accès root ou sudo sur le serveur.
  • Un nom de domaine ou une adresse IP publique pour accéder à GitLab.

La partie Hardening de debian est détaillée dans un autre article

Une note rapide sur SSH :

Les appels types git pull et git push sont souvent paramétrés pour passer par SSH. Dans ce cas, la connection SSH pour ‘Gitlab’ doit aller dans le container et non pas dans la VM host. Pour cela il faut donc 1) garder le mapping de port 22 dans le docker-compose.yml (cf plus bas) mais surtout 2) changer le port de connexion SSH pour le host.

Pour cela, c’est relativement simple, il suffit de modifier la configuration /etc/ssh/sshd_config. Il suffit de décommenter la ligne #Port 22 pour y mettre Port 2222 par exemple.

Puis recharger le service SSH via sudo systemctl restart sshd

Par sécurité il est possible de valider la config via sudo sshd -t avant de redémarrer !

La raison pour laquelle la session n’est pas déconnectée lors du redémarrage du service, c’est que la session n’est pas “attachée” à ce processus. Lors d’une connexion entrante, sshd créé un nouveau processus de connexion (spawn) Ce nouveau processus reste vivant même en cas de redémarrage de service.

Ne pas oublier la règle de rate limit sur le nouveau port !

Installation de Docker et Docker Compose

Une fois la partie sécurisation du serveur réalisée, on passe à la dernière étape de préparation.

L’installation Docker est des plus classique. Voici les étapes clés (disponibles sur le site officiel de Docker) :

echo "[INFO] Removing old packages ..."
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done

# Add Docker's official GPG key:
echo "[INFO] Installing GPG key ..."
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo "[INFO] Adding repo ..."
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

echo "[INFO] Updating to new repo ..."
sudo apt-get update

echo "[INFO] Installing packages ..."
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

echo "[INFO] Running verifications ..."
sudo docker run hello-world

echo "[INFO] All done !"

L’installation est donc réussie, docker récupère l’image sur son hub et la fait tourner. Passons aux choses sérieuses.

Installation de GitLab avec Docker Compose

Configuration du fichier docker-compose.yml

Je choisis des binds mounts pour l’instant. Dans une orientation prod on choisira plutôt des volumes Docker.

Pour le bind mount tous les éléments seront sous /srv/gitlab, je force donc la variable GITLAB_HOME à ce chemin ainsi :

echo 'export GITLAB_HOME=/srv/gitlab' >> ~/.bashrc
. ~/.bashrc

Voici le fichier docker-compose.yml :

version: 3.6
services:
  gitlab:
    image: gitlab/gitlab-ee:16.10.10-ee.0
    container_name: gitlab
    restart: unless-stopped
    hostname: 'gitlab.watylocal'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        # Add any other gitlab.rb configuration here, each on its own line
        external_url 'http://gitlab.watylocal'        
    ports:
      - '80:80'
      - '443:443'
      - '22:22'
    volumes:
      - '$GITLAB_HOME/config:/etc/gitlab'
      - '$GITLAB_HOME/logs:/var/log/gitlab'
      - '$GITLAB_HOME/data:/var/opt/gitlab'
    shm_size: '256m'

Le choix d’une vieille image dans le premier compose est voulue. Ainsi dans le partie suivante (upgrade) on pourra voir les différentes étapes.

Lancement de GitLab

Exécutez la commande suivante pour démarrer GitLab : docker-compose up -d

Récupération du mot de passe root

Une fois GitLab démarré, récupérez le mot de passe root initial :

docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password.

Vous obtiendrez un mot de passe de la forme Password: xyz. Notez-le précieusement.

Le container se lance rapidement mais pas Gitlab, il faut attendre quelques minutes.

Connexion à l’interface d’administration

Connectez-vous à l’interface web de GitLab via http://gitlab.watylocal (ou l’URL que vous avez configurée) avec :

Nom d’utilisateur : root.

Mot de passe : celui que l’on vient de récupérer.

Configuration initiale de GitLab

Une fois l’accès admin établi, nous allons pouvoir réaliser quelques actions préparatoires pour la suite:

  • préparer la création des groupes et projets
  • créer un token pour utiliser l’API
  • créer un runner Gitlab

Autorisation des imports de projets

Pour permettre la création de projets par import depuis d’autres plateformes (GitHub notamment):

Allez dans Admin Area > Settings > General > Import export settings. Cochez Repository by URL et sauvegardez.

Création d’un Personal Access Token (PAT)

Pour automatiser les interactions avec l’API GitLab, créez un Personal Access Token (PAT) :

Allez dans Administrator > Préférences > Access Token. Générez un nouveau token avec les droits nécessaires (API et admin). Copiez ce token dans un fichier .env pour votre projet d’appels API.

Création d’un runner Gitlab

Pour ajouter un runner Gitlab, il faut aller dans l’espace Admin Area > Settings > CI/CD > Runners. Ici on créer un nouveau runner, on prépare sa configuration (par exemple untagged jobs). En validant, Gitlab nous donne la ligne de commande à passer pour enregistrer le runner. Le token a un format glrt-XYZ. Ce token sera passé à l’étape suivante.

Configuration d’un runner GitLab

Les runners Gitlab sont des systèmes permettant de faire tourner les pipelines d’intégration continue de Gitlab. Il existe plusieurs façon d’installer et paramétrer ces runners. Le choix ici est d’utiliser une image docker afin de ‘coupler’ le runner et l’instance Gitlab. L’exécuteur est ici docker.

Cela signifie que sur la VM host, un container tournera pour Gitlab et un autre tournera pour le runner. Ces deux containers tourneront en permanence. Lorsqu’un pipeline sera démarré, le container du runner ira chercher les jobs et lancera donc (via docker) un nouveau container pour chaque job.

Dans le cas d’une démo, ou avec une machine puissante, ou avec (très) peu de pipelines, cela peut ne pas poser de problème.

Attention cependant, cumuler des containers sur une même machine peut mener à une surcharge et donc à une chute de l’instance !

Pour une installation plus robuste, il faudra donc privilégier une seconde machine, dédiée aux runners. Ainsi si celle-ci tombe, seuls les pipelines seront impactés.

Ajout du runner dans le fichier docker-compose.yml

Ajoutez un service pour le runner GitLab dans votre fichier docker-compose.yml :

  gitlab-runner:
    image: gitlab/gitlab-runner:alpine3.19-v16.11.4
    container_name: gitlab-runner-main
    restart: unless-stopped
    ports:
      - '8093:8093'
    volumes:
      - '/srv/gitlab-runner/config:/etc/gitlab-runner'
      - '/var/run/docker.sock:/var/run/docker.sock'

Les éléments importants ici sont :

  • la version de l’image, qui doit être proche de celle de Gitlab
  • le port ouvert pour la communication
  • le mapping de la socket docker, pour lancer de nouveaux containers.

Enregistrement du runner

Connectez-vous au conteneur du runner et enregistrez-le :

sudo docker exec -ti gitlab-runner-main bash
gitlab-runner register \
  --non-interactive \
  --url "http://gitlab.watylocal" \
  --token "glrt-XYZ" \
  --executor "docker" \
  --docker-image alpine:latest \
  --description "docker-runner"

Remplacez glrt-XYZ par votre token de votre runner.

Dans la page Runners de Gitlab le nouveau runner doit être visible (et activé).

Création de groupes, projets, utilisateurs

Cette création est réalisé par appel d’API. Le code en Python est disponible à :

Le fichier .env contient donc notre instance et notre token d’admin:

export GL_TOKEN="glpat-ezretrtyutgrfdsqdfdgh"
export GL_SERVER="http://gitlab.watylocal"

Notre fichier bootstrap_gitlab.py récupère ces informations ainsi:

GITLAB_URL = os.environ.get('GL_SERVER', 'https://gitlab.com')
GITLAB_TOKEN = os.environ.get('GL_TOKEN')

if not GITLAB_TOKEN:
    print("Please set the GL_TOKEN env variable.")
    sys.exit(1)

Il faut créer également un venv pour installer le module gitlab:

python3 -m venv venv
. venv/bin/activate
pip install python-gitlab
# pour executer
python bootstrap_gitlab.py

Extrait :

$ python bootstrap_gitlab.py
[+] User créé : jsnow
[+] User créé : dtargaryen
[+] User créé : tlanister
[+] User créé : clannister
[+] User créé : nstark
[+] User créé : astark
.....
[+] Groupe créé : Product (product)
[+] Groupe créé : Platform (platform)
[+] Groupe créé : Customer (customer)
.....
[+] Ajouté jsnow au groupe product (owner)
[+] Ajouté dtargaryen au groupe product (owner)
[+] Ajouté tlanister au groupe product (developer)
[+] Ajouté clannister au groupe product (developer)
[+] Ajouté nstark au groupe product (developer)
.....
[+] Ajouté projet MobileApp au groupe product/frontend
[+] Ajouté projet API Service au groupe product/backend
[+] Ajouté projet Data Pipeline au groupe product/data
[+] Ajouté projet Terraform GKE au groupe platform/infra
[+] Ajouté projet Ansible Playbooks au groupe platform/infra
.....

Suite à cela, on se retrouve avec 14 groupes, 13 projets et 58 utilisateurs.

Un élément clé pour les utilisateurs est de forcer à ne pas confirmer son email. Pour cela l’appel à users.create() devra avoir 'skip_confirmation': True.

J’ai passé un bon moment à retravailler mon runner et l’administration gitlab car aucun utilisateur ne pouvait lancer de pipeline, ni manuellement ni par le code.

Quand je me suis rendu compte que l’administrateur n’avait pas de soucis à lancer un pipeline, j’ai compris qu’il s’agissait de la configuration des utilisateurs.

Derniers éléments

On ajoute les derniers éléments afin d’avoir une couverture des features assez complète.

Ajout d’une clé SSH pour un utilisateur

Allez dans Settings > SSH Keys. Ajoutez votre clé publique SSH. Ici je crée un couple de clé exprès depuis ma machine, afin de distinguer la connexion Host (clé SSH existante) et la connexion Gitlab (nouvelle clé).

Configuration des secrets

Pour les projets ou groupes, vous pouvez ajouter des variables CI/CD :

Allez dans Settings > CI/CD > Variables. J’ajoute comme secret des variables pour l’instant bidon. La valeur importe peu mais il est important qu’elle soit conservée lors d’un backup/restore ou d’une migration. En effet il est possible (mais non recommandé !) que ce soit là le seul endroit où l’on retrouve cette information.

Test de validation

Pour valider le fonctionnement, on va récupérer un dépôt de code existant, ajouter un fichier .gitlab-ci.yml puis pousser le code pour déclencher un pipeline.

Le contenu du fichier pouvant simplement être :

test-lancement:
  stage: test
  script:
    - echo "Lancement ..."

Bilan et validation

Vérification des éléments configurés

L’installation est assez rapide, une fois connue et/ou scriptée :

  • la sécurisation et la préparation prend 15 minutes max
  • le démarrage de Gitlab prend entre 5 et 10 minutes (voir 15 selon le réseau)
  • la préparation admin et runner prend 10 minutes
  • l’ajout des groupes/projets/utilisateurs prend 5 minutes
  • les derniers éléments prennent aussi 5 minutes

On est sur un total de 45 minutes environ, maxi 1 heure si le réseau est capricieux.

Suite à cette installation, on a donc :

  • 14 groupes (et sous-groupes) : format startup / petite structure.
  • 13 projets : avec ou sans code existant.
  • 58 utilisateurs : divers privilèges.
  • 1 runner : Opérationnel et enregistré.
  • Pipeline et code : Fonctionnels pour le site web.
  • Gestion des clés SSH : Validée (pull et push).
  • 2 secrets : Configurés pour le projet frontend.

Conclusion

Voilà pour l’installation d’une instance GitLab fonctionnelle et prête à être utilisée pour les projets. Ce guide couvre les étapes essentielles d’installation et de configuration.

Nous verrons dans la seconde partie :

Comment backuper son instance. Comment restaurer/migrer son instance. Comment mettre à jour son instance.