GitLab CI/CD
Vue d'ensemble
GitLab CI/CD est un outil intégré de GitLab pour l'intégration continue et le déploiement continu, permettant d'automatiser les tests, builds et déploiements directement depuis le repository.
Avantages clés
- Intégration native : Directement dans GitLab
- Configuration as Code :
.gitlab-ci.yml
versionné - Runners flexibles : Shared, group, project runners
- Pipeline complexes : Jobs parallèles, conditions, artifacts
Structure de base
# .gitlab-ci.yml
stages:
- test
- build
- deploy
variables:
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
before_script:
- echo "Setting up environment"
after_script:
- echo "Cleaning up"
# Job de test
test:
stage: test
image: php:8.2
script:
- composer install --no-dev --optimize-autoloader
- php artisan test
artifacts:
reports:
junit: tests/results.xml
paths:
- storage/logs/
expire_in: 1 week
only:
- merge_requests
- main
# Job de build
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $DOCKER_IMAGE .
- docker push $DOCKER_IMAGE
only:
- main
Pipeline pour Laravel
# Pipeline complet Laravel
stages:
- prepare
- test
- security
- build
- deploy
variables:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: laravel_test
MYSQL_USER: laravel
MYSQL_PASSWORD: laravel
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- vendor/
- node_modules/
# Installation des dépendances
composer:
stage: prepare
image: composer:latest
script:
- composer install --prefer-dist --no-ansi --no-interaction --no-progress --no-scripts
artifacts:
paths:
- vendor/
expire_in: 1 hour
npm:
stage: prepare
image: node:18
script:
- npm ci
- npm run build
artifacts:
paths:
- node_modules/
- public/build/
expire_in: 1 hour
# Tests unitaires avec Pest
pest_tests:
stage: test
image: php:8.2
services:
- mysql:8.0
dependencies:
- composer
before_script:
- apt-get update -qq && apt-get install -y -qq git unzip
- docker-php-ext-install pdo_mysql
- cp .env.testing .env
- php artisan key:generate
- php artisan migrate:fresh --seed
script:
- php artisan test --parallel --coverage --min=80
artifacts:
reports:
junit: tests/results.xml
coverage_report:
coverage_format: cobertura
path: coverage.xml
# Tests d'intégration avec [React](<../development/react.md>)
react_tests:
stage: test
image: node:18
dependencies:
- npm
script:
- npm run test -- --coverage --watchAll=false
artifacts:
reports:
junit: jest-junit.xml
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
# Analyse de sécurité
security_scan:
stage: security
image: php:8.2
dependencies:
- composer
script:
- composer audit
- php artisan enlightn # Security scanner pour Laravel
allow_failure: true
# Build Docker
build_image:
stage: build
image: docker:latest
services:
- docker:dind
dependencies:
- composer
- npm
script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
only:
- main
# Déploiement staging
deploy_staging:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache curl
script:
- curl -X POST "$STAGING_WEBHOOK_URL" -H "Authorization: Bearer $STAGING_TOKEN"
environment:
name: staging
url: https://staging.example.com
only:
- main
# Déploiement production (manuel)
deploy_production:
stage: deploy
image: alpine:latest
script:
- curl -X POST "$PRODUCTION_WEBHOOK_URL" -H "Authorization: Bearer $PRODUCTION_TOKEN"
environment:
name: production
url: https://example.com
when: manual
only:
- main
Intégration avec Terraform
# Pipeline Infrastructure
terraform_plan:
stage: plan
image: hashicorp/terraform:1.5
before_script:
- cd infrastructure/
- terraform init -backend-config="address=$TF_STATE_ADDRESS" -backend-config="lock_address=$TF_LOCK_ADDRESS" -backend-config="unlock_address=$TF_UNLOCK_ADDRESS"
script:
- terraform plan -out=plan.cache
artifacts:
paths:
- infrastructure/plan.cache
expire_in: 1 week
only:
- merge_requests
terraform_apply:
stage: deploy
image: hashicorp/terraform:1.5
dependencies:
- terraform_plan
before_script:
- cd infrastructure/
- terraform init -backend-config="address=$TF_STATE_ADDRESS" -backend-config="lock_address=$TF_LOCK_ADDRESS" -backend-config="unlock_address=$TF_UNLOCK_ADDRESS"
script:
- terraform apply plan.cache
environment:
name: production
when: manual
only:
- main
Déploiement sur Kubernetes
# Déploiement K8s
deploy_k8s:
stage: deploy
image: bitnami/kubectl:latest
before_script:
- echo $KUBECONFIG_BASE64 | base64 -d > kubeconfig
- export KUBECONFIG=kubeconfig
script:
- kubectl set image deployment/laravel-app laravel-app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- kubectl rollout status deployment/laravel-app
- kubectl get pods -l app=laravel-app
environment:
name: production
url: https://app.example.com
only:
- main
Intégration Ansible
# Déploiement avec Ansible
ansible_deploy:
stage: deploy
image: quay.io/ansible/ansible-runner:latest
before_script:
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
script:
- ansible-playbook -i inventory/production playbooks/deploy.yml -e "app_version=$CI_COMMIT_SHA"
environment:
name: production
only:
- main
Monitoring avec Prometheus
# Push métriques vers Prometheus
push_metrics:
stage: monitor
image: curlimages/curl:latest
script:
- |
cat <<EOF | curl --data-binary @- http://pushgateway:9091/metrics/job/gitlab-deploy/instance/$CI_JOB_ID
deployment_duration_seconds{job="$CI_JOB_NAME",pipeline="$CI_PIPELINE_ID"} $((CI_JOB_FINISHED_AT - CI_JOB_STARTED_AT))
deployment_status{job="$CI_JOB_NAME",pipeline="$CI_PIPELINE_ID",status="success"} 1
EOF
when: on_success
dependencies:
- deploy_production
# Notification échec
notify_failure:
stage: monitor
image: curlimages/curl:latest
script:
- |
curl -X POST http://pushgateway:9091/metrics/job/gitlab-deploy/instance/$CI_JOB_ID \
--data-binary 'deployment_status{job="'$CI_JOB_NAME'",pipeline="'$CI_PIPELINE_ID'",status="failed"} 1'
when: on_failure
Optimisations avancées
# Pipeline optimisé avec cache et parallélisme
variables:
FF_USE_FASTZIP: "true"
CACHE_COMPRESSION_LEVEL: "fastest"
# Cache distribué
cache:
- key: composer-$CI_COMMIT_REF_SLUG
paths:
- vendor/
- key: npm-$CI_COMMIT_REF_SLUG
paths:
- node_modules/
- .npm/
# Tests parallèles
test_unit:
stage: test
parallel: 4
script:
- php artisan test --parallel --processes=4
# Conditional jobs
deploy_staging:
script:
- echo "Deploying to staging"
rules:
- if: $CI_COMMIT_BRANCH == "main"
- if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"
when: manual
# Include external configs
include:
- project: 'devops/ci-templates'
file: '/laravel.yml'
- template: Security/SAST.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
Ressources
- Documentation : docs.gitlab.com/ee/ci
- CI/CD Templates : gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates