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:/dataRecette 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/phpunitWoodpecker 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/phpunitDockerfiles 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 opcacheFastAPI (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 --devExemple 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
Clone ton code depuis Git (Gitea, GitLab, ou autre).
Installe tes dépendances Composer.
Lance les optimisations Laravel (
config:cache,route:cache).Déploie ton app dans un dossier versionné (
releases/20250926xxxx).Met à jour le symlink
current→ déploiement instantané sans downtime.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
deploy:production:
stage: deploy
image: php:8.3-cli
script:
- composer install --no-dev
- php vendor/bin/dep deploy production -vvv
only:
- mainEt voilà : tes devs commitent → pipeline → Deployer → serveur à jour.
Pas de sueur froide, pas de git pullfoireux 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 ?
Related posts
- Streaming comme dans un blockbuster : Laravel-HLS entre en scène
Chez OBI Partner, on a l’habitude de sauver des projets comme Tom Cruise sauve le monde dans Mission...
19 novembre 20250Like - Métallurgie, sidérurgie : comment gagner en efficacité face aux tâches chronophages ?
Dans l'industrie, les tâches administratives répétitives freinent la performance. Surcharges, erreurs et lenteurs sont fréquentes, impactant qualité et...
3 juillet 20250Like - Mission 3ème : Inès au cœur de l’IA chez OBI Partner
Qui a dit qu’un stage de troisième consistait uniquement à observer en silence et à prendre des notes...
20 février 20260Like