Aller au contenu principal
Please wait...
Image

CI/CD maison : buffet à volonté, food-truck gourmet… ou cuisine 3 étoiles ?

Chez OBI Partner, on adore coder Python et PHP. Mais soyons honnêtes : le moment où tout part en prod, c’est souvent plus proche d’un sketch de Kaamelott que d’une recette de cuisine bien huilée.
Entre les serveurs qui fument, les bases de données qui pleurent et les devs qui jurent “mais chez moi ça marche”… il fallait trouver une meilleure méthode.

C’est là qu’entre en scène le CI/CD auto-hébergé. Pas de SaaS américain indiscret, pas de dépendance à un nuage capricieux : tout tourne chez toi, dans ton infra.

Et bonne nouvelle : j’ai cuisiné pour toi plusieurs recettes 🔥.

🥘 Option A : GitLab CE (le buffet à volonté)

GitLab, c’est le buffet chinois du DevOps : tu y trouves tout. Forge, issues, merge requests, pipelines, registry Docker, monitoring… il ne manque que les rouleaux de printemps.

Pourquoi l’aimer

  • All-in-one : une seule interface, tu n’as pas besoin de courir après 10 outils différents.

  • Pipeline puissant : GitLab Runner sait tout faire (Docker, Kubernetes, SSH).

  • Registry intégré : plus besoin de bricoler pour stocker tes images.

  • Écosystème énorme : si tu demandes de l’aide sur GitLab, tu n’es jamais seul.

Pourquoi souffrir avec

  • Consommation RAM : GitLab est un ogre. Si tu n’as pas 16 Go à lui donner, il te regardera comme si tu essayais de le nourrir avec une salade verte.

  • Monolithique : tu prends tout le package, même si tu n’utilises pas la moitié.

docker-compose GitLab CE

version: '3.7'
services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    restart: always
    hostname: gitlab.local
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.local'
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
    ports:
      - "8080:80"
      - "443:443"
      - "2222:22"
    volumes:
      - ./gitlab/config:/etc/gitlab
      - ./gitlab/logs:/var/log/gitlab
      - ./gitlab/data:/var/opt/gitlab

  runner:
    image: gitlab/gitlab-runner:latest
    restart: always
    volumes:
      - ./runner/config:/etc/gitlab-runner
      - /var/run/docker.sock:/var/run/docker.sock

(Petit conseil : mets-le sur un serveur dédié, sinon il va étrangler tes autres services comme un boa affamé.)

 

🌮 Option B : Gitea + Woodpecker + Harbor (le food-truck gourmet)

Si GitLab est le buffet, Gitea + Woodpecker + Harbor c’est le food-truck gourmet. Chaque outil est léger, rapide, et tu choisis exactement ce que tu mets dans ton assiette.

Pourquoi l’aimer

  • Ultra léger : Gitea démarre plus vite qu’un micro-ondes.

  • Modulaire : tu prends juste ce dont tu as besoin.

  • Woodpecker CI : pipelines lisibles, faciles à maintenir.

  • Harbor : registry avec scanner intégré (ton garde du corps numérique).

Pourquoi souffrir avec

  • Plus de plomberie : il faut relier les briques toi-même.

  • Moins d’outils intégrés : pas de gestion de projets hyper avancée comme GitLab.

docker-compose Gitea + Woodpecker + Harbor

version: '3.8'

services:
  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    volumes:
      - ./gitea:/data
    ports:
      - "3000:3000"
      - "222:22"

  woodpecker-server:
    image: woodpeckerci/woodpecker-server:latest
    container_name: woodpecker-server
    environment:
      - WOODPECKER_OPEN=true
      - WOODPECKER_ADMIN=admin
      - WOODPECKER_GITEA=true
      - WOODPECKER_GITEA_URL=http://gitea:3000
      - WOODPECKER_GITEA_CLIENT=supersecret
      - WOODPECKER_GITEA_SECRET=supersecret
      - WOODPECKER_SECRET=woodpeckersecret
    ports:
      - "8000:8000"
    restart: always
    depends_on:
      - gitea

  woodpecker-agent:
    image: woodpeckerci/woodpecker-agent:latest
    container_name: woodpecker-agent
    environment:
      - WOODPECKER_SERVER=woodpecker-server:9000
      - WOODPECKER_SECRET=woodpeckersecret
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    restart: always
    depends_on:
      - woodpecker-server

  harbor:
    image: goharbor/harbor-core:v2.12.0
    container_name: harbor
    environment:
      - HARBOUR_ADMIN_PASSWORD=Harbor12345
    ports:
      - "8081:8080"
    restart: always
    volumes:
      - ./harbor:/data

 

👨‍🍳 Recette bonus : Pipelines CI/CD Python + PHP

👉 Ici, le but est simple : vérifier ton code (lint), le tester (unit tests), puis le déployer.

GitLab CI

stages: [lint, test, build, deploy]

lint:python:
  stage: lint
  image: python:3.12
  script:
    - pip install ruff black
    - ruff check .
    - black --check .

lint:php:
  stage: lint
  image: php:8.3-cli
  script:
    - composer install --no-interaction
    - vendor/bin/phpstan analyse
    - vendor/bin/php-cs-fixer fix --dry-run --diff

test:python:
  stage: test
  image: python:3.12
  script:
    - pip install -r requirements.txt
    - pytest -q

test:php:
  stage: test
  image: php:8.3-cli
  script:
    - composer install --no-interaction
    - vendor/bin/phpunit

Woodpecker CI

pipeline:
  lint_python:
    image: python:3.12
    commands:
      - pip install ruff black
      - ruff check .
      - black --check .

  lint_php:
    image: php:8.3-cli
    commands:
      - composer install --no-interaction
      - vendor/bin/phpstan analyse
      - vendor/bin/php-cs-fixer fix --dry-run --diff

  test_python:
    image: python:3.12
    commands:
      - pip install -r requirements.txt
      - pytest -q

  test_php:
    image: php:8.3-cli
    commands:
      - composer install --no-interaction
      - vendor/bin/phpunit

 

🍱 Dockerfiles multi-stage

Laravel (PHP)

FROM composer:2 AS vendor
WORKDIR /app
COPY composer.* ./
RUN composer install --no-dev --prefer-dist --no-progress --no-interaction
COPY . .
RUN php artisan route:cache && php artisan config:cache

FROM php:8.3-fpm-alpine
WORKDIR /var/www/html
COPY --from=vendor /app /var/www/html
RUN docker-php-ext-install pdo pdo_mysql opcache
 

FastAPI (Python)

FROM python:3.12-slim AS builder
WORKDIR /app
COPY pyproject.toml poetry.lock* ./
RUN pip install poetry && poetry export -f requirements.txt -o requirements.txt
RUN pip install -r requirements.txt --target /deps
COPY . .

FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /deps /usr/local/lib/python3.12/site-packages
COPY . .
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
 

 

🚚 Déploiement automatisé avec Ansible (zéro downtime)

Playbook

- hosts: app
  become: true
  tasks:
    - name: Pull nouvelle image
      community.docker.docker_compose:
        project_src: /srv/app/
        pull: yes
        build: no
        state: present
        restarted: yes

    - name: Laravel migrate (si PHP)
      command: docker exec app-php php artisan migrate --force
      when: laravel | default(false)

👉 Et pour éviter tout arrêt : lance deux containers en parallèle (app_v1 et app_v2) et fais tourner le trafic via Traefik en rolling update.

🔒 Air-Gapped Mode (le vase clos)

Certaines boîtes veulent du CI/CD en vase clos : pas de connexion Internet, pas de dépendances qui partent aux USA, tout reste derrière tes murs.
Ça sonne un peu comme la série Dark, mais ça marche.

Les ingrédients secrets

  • Nexus OSS : pour héberger PyPI, Composer, npm, Docker Hub en mode miroir.

  • Harbor : pour stocker tes images Docker en interne.

  • Runner : exécute tout avec des images internes, jamais depuis Docker Hub.

  • Ansible : pour déployer dans ton cluster ou tes VMs sans jamais appeler l’extérieur.

docker-compose Nexus

version: '3.7'
services:
  nexus:
    image: sonatype/nexus3:latest
    container_name: nexus
    restart: always
    ports:
      - "8082:8081"
    volumes:
      - ./nexus-data:/nexus-data

(Pro-tip : configure Nexus en mode proxy → il va télécharger les libs une fois, puis les servir en interne comme un bon fromager affineur 🧀).

🎩 Déploiement façon chef étoilé : Deployer PHP pour Laravel

Parce que parfois, tu n’as pas envie de t’embêter avec Docker Compose, Ansible ou Kubernetes.
Tu veux juste que ton code Laravel parte sur ton serveur vite, bien, et avec des migrations DB exécutées sans trembler.
C’est là que Deployer PHP entre en scène.

Imagine : un seul fichier deploy.php, un petit dep deploy production, et ton app Laravel est servie sur ton serveur comme une assiette bien dressée par Bocuse 🍽️.

Installation

Ajoute simplement Deployer en dépendance :

composer require deployer/deployer --dev

Exemple de deploy.php

<?php
namespace Deployer;

require 'recipe/laravel.php';

// Nom du projet
set('application', 'MonSuperLaravel');

// Repo Git
set('repository', 'git@gitea:moncompte/monrepo.git');

// Branch par défaut
set('branch', 'main');

// Hosts (serveurs cibles)
host('production')
    ->setHostname('monserveur.example.com')
    ->setRemoteUser('deploy')
    ->setPort(22)
    ->set('deploy_path', '/var/www/{{application}}');

// Options Laravel
set('keep_releases', 5);
set('php_fpm_service', 'php8.3-fpm');

// Hooks personnalisés
after('deploy:failed', 'deploy:unlock');

// Tâche de migration auto
after('deploy:symlink', 'artisan:migrate');
 

Ce que ça fait

  1. Clone ton code depuis Git (Gitea, GitLab, ou autre).

  2. Installe tes dépendances Composer.

  3. Lance les optimisations Laravel (config:cache, route:cache).

  4. Déploie ton app dans un dossier versionné (releases/20250926xxxx).

  5. Met à jour le symlink currentdéploiement instantané sans downtime.

  6. Exécute tes migrations DB (php artisan migrate --force).

Résultat : tu passes d’un serveur où tu fais git pull à la mano (et où tu pries pour que rien ne casse 🙏), à un déploiement carré, traçable et rollbackable.

Intégration CI/CD

Dans ton .gitlab-ci.yml ou .woodpecker.yml, ajoute simplement :

deploy:production:
  stage: deploy
  image: php:8.3-cli
  script:
    - composer install --no-dev
    - php vendor/bin/dep deploy production -vvv
  only:
    - main

Et voilà : tes devs commitent → pipeline → Deployer → serveur à jour.
Pas de sueur froide, pas de git pull foireux en SSH à 2h du matin.

Conclusion

➡️ GitLab CE = buffet à volonté : tout est inclus, mais prépare-toi à déployer sur un serveur obèse en RAM.
➡️ Gitea + Woodpecker = food-truck gourmet : léger, rapide, savoureux, mais demande un peu plus de cuisine maison.
➡️ Air-Gapped Mode = bunker high-tech : parfait pour les environnements sensibles (industrie, défense, médical).
➡️ Deployer PHP = chef étoilé : déploiement Laravel aussi raffiné qu’un service en gants blancs.

Chez OBI Partner, on dit souvent :
“Peu importe la forge, tant que la prod sort chaude, sans fumée et sans pizza froide.” 🔥

👉 Alors, tu es plutôt buffet géant, food-truck artisanal, cuisine en bunker, ou service à la française avec Deployer PHP ?

Ajouter un commentaire

HTML restreint

  • Vous pouvez aligner les images (data-align="center"), mais également les vidéos, citations, etc.
  • Vous pouvez légender les images (data-align="center"), mais également les vidéos, citations, etc.