Aller au contenu

Bonnes pratiques et cas avances

Ce chapitre couvre les sujets avances pour opérer Gitea en production : haute disponibilité, stratégie de sauvegarde, migration depuis d'autres plateformes, hygiène des dépôts et résolution de problèmes courants.


Haute disponibilité

Architecture HA

graph TD
    LB["Load Balancer<br/>(Caddy)"] --> G1["Gitea 1 (RW)"]
    LB --> G2["Gitea 2 (RO)"]
    G1 --> PG["PostgreSQL<br/>Primary + Replica"]
    G2 --> PG
    G1 --> Redis["Redis Sentinel"]
    G2 --> Redis
    PG --- Redis

PostgreSQL réplication

Configurer la réplication en streaming pour PostgreSQL :

; postgresql.conf (primary)
wal_level = replica
max_wal_senders = 5
wal_keep_size = 512MB
synchronous_commit = on
; postgresql.conf (replica)
hot_standby = on
primary_conninfo = 'host=pg-primary port=5432 user=replicator password=xxx'
# Creer l'utilisateur de replication
psql -U postgres -c "CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'xxx';"

# Initialiser la replica
pg_basebackup -h pg-primary -U replicator -D /var/lib/postgresql/data -Fp -Xs -P

Gitea multi-instances

Pour exécuter plusieurs instances Gitea derriere un load balancer :

  1. Stockage partage — les dépôts Git doivent etre accessibles par toutes les instances (NFS, GlusterFS, ou réplication)
  2. Session Redis — les sessions sont stockees dans Redis, pas en local
  3. Cache Redis — même instance Redis pour toutes les instances Gitea
  4. Sticky sessions — pour les uploads et les longues opérations, configurer le LB en sticky session
; app.ini — identique sur toutes les instances
[cache]
ADAPTER = redis
HOST    = redis://:password@redis-sentinel:26379/0?master=mymaster

[session]
PROVIDER        = redis
PROVIDER_CONFIG = redis://:password@redis-sentinel:26379/1?master=mymaster

Écriture concurrente

Git utilise des verrous fichier pour les opérations d'écriture (push). Avec un stockage partage NFS, les verrous doivent etre correctement geres. Privilegiez une architecture avec un nœud d'écriture unique (primary) et des nœuds de lecture (read replicas).


Stratégie de sauvegarde et restauration

Sauvegarde complète

# Methode 1 : gitea dump (tout-en-un)
podman exec gitea gitea dump \
  -c /data/gitea/conf/app.ini \
  -f /tmp/gitea-dump.zip \
  --type zip

# Methode 2 : composant par composant
# PostgreSQL
podman exec gitea-postgres pg_dump -U gitea -Fc gitea > gitea-db.dump

# Depots Git
rsync -avz /var/lib/gitea/repositories/ /backup/repositories/

# LFS (MinIO)
mc mirror local/gitea-lfs /backup/lfs/
mc mirror local/gitea-packages /backup/packages/

# Configuration
cp /etc/gitea/app.ini /backup/app.ini

Restauration

# 1. Restaurer PostgreSQL
podman exec -i gitea-postgres pg_restore -U gitea -d gitea < gitea-db.dump

# 2. Restaurer les depots
rsync -avz /backup/repositories/ /var/lib/gitea/repositories/

# 3. Restaurer LFS
mc mirror /backup/lfs/ local/gitea-lfs

# 4. Restaurer la configuration
cp /backup/app.ini /etc/gitea/app.ini

# 5. Redemarrer Gitea
podman-compose restart gitea

# 6. Regenerer les hooks Git
podman exec gitea gitea admin regenerate hooks

# 7. Regenerer les cles SSH autorisees
podman exec gitea gitea admin regenerate keys

Vérification des sauvegardes

# Script de verification mensuelle
#!/bin/bash
set -euo pipefail

RESTORE_DIR="/tmp/gitea-restore-test"
mkdir -p "${RESTORE_DIR}"

# Restaurer dans un environnement isole
podman run --rm -d --name gitea-test \
  -v "${RESTORE_DIR}:/data" \
  gitea/gitea:latest

# Verifier l'integrite
podman exec gitea-test gitea doctor check --all

# Nettoyer
podman stop gitea-test
rm -rf "${RESTORE_DIR}"

Tester les restaurations

Une sauvegarde non testée est une sauvegarde qui ne fonctionne pas. Planifiez un test de restauration mensuel dans un environnement isole.


Migration depuis d'autres plateformes

API de migration Gitea

Gitea fournit une API de migration qui preserve les dépôts, issues, labels, milestones, releases et pull requests.

Migration depuis GitHub

curl -X POST "https://gitea.example.com/api/v1/repos/migrate" \
  -H "Content-Type: application/json" \
  -H "Authorization: token ${GITEA_ADMIN_TOKEN}" \
  -d '{
    "clone_addr": "https://github.com/org/repo.git",
    "repo_name": "repo",
    "repo_owner": "mon-org",
    "service": "github",
    "auth_token": "ghp_xxx",
    "mirror": false,
    "issues": true,
    "labels": true,
    "milestones": true,
    "releases": true,
    "pull_requests": true,
    "wiki": true
  }'

Migration depuis GitLab

curl -X POST "https://gitea.example.com/api/v1/repos/migrate" \
  -H "Content-Type: application/json" \
  -H "Authorization: token ${GITEA_ADMIN_TOKEN}" \
  -d '{
    "clone_addr": "https://gitlab.com/org/repo.git",
    "repo_name": "repo",
    "repo_owner": "mon-org",
    "service": "gitlab",
    "auth_token": "glpat-xxx",
    "mirror": false,
    "issues": true,
    "labels": true,
    "milestones": true,
    "releases": true,
    "pull_requests": true
  }'

Migration en masse (script batch)

#!/bin/bash
# migrate-repos.sh — migrer tous les depots d'une organisation GitHub

ORG="mon-org-github"
GITEA_ORG="mon-org"
GITHUB_TOKEN="ghp_xxx"
GITEA_TOKEN="xxx"
GITEA_URL="https://gitea.example.com"

# Lister les depots GitHub
repos=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \
  "https://api.github.com/orgs/${ORG}/repos?per_page=100" | \
  jq -r '.[].clone_url')

for repo_url in ${repos}; do
  repo_name=$(basename "${repo_url}" .git)
  echo "Migration de ${repo_name}..."

  curl -s -X POST "${GITEA_URL}/api/v1/repos/migrate" \
    -H "Content-Type: application/json" \
    -H "Authorization: token ${GITEA_TOKEN}" \
    -d "{
      \"clone_addr\": \"${repo_url}\",
      \"repo_name\": \"${repo_name}\",
      \"repo_owner\": \"${GITEA_ORG}\",
      \"service\": \"github\",
      \"auth_token\": \"${GITHUB_TOKEN}\",
      \"mirror\": false,
      \"issues\": true,
      \"labels\": true,
      \"pull_requests\": true
    }"

  echo "  OK"
  sleep 2  # Rate limiting
done

Hygiène des dépôts

Git LFS pour les fichiers volumineux

# .gitattributes — a la racine du depot
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.tar.gz filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text

Templates .gitignore

Configurer des templates .gitignore globaux dans Gitea :

; app.ini
[repository]
PREFERRED_LICENSES = MIT License,Apache License 2.0

Les templates .gitignore sont disponibles par defaut dans Gitea (Go, Python, Java, Node, etc.).

Politique de nommage

Élément Convention Exemple
Organisation kebab-case mon-equipe
Dépôt kebab-case api-gateway
Branche type/description feat/add-login
Tag Semantic Versioning v1.2.3
Commit Conventional Commits feat: add OAuth2 login

Protection des branches par defaut

Automatiser la protection de main sur chaque nouveau dépôt :

# Hook post-repo-create (webhook)
# Appliquer automatiquement la protection de branche
curl -X POST "${GITEA_URL}/api/v1/repos/${OWNER}/${REPO}/branch_protections" \
  -H "Authorization: token ${TOKEN}" \
  -d '{
    "branch_name": "main",
    "enable_push": false,
    "required_approvals": 1,
    "enable_status_check": true,
    "dismiss_stale_approvals": true
  }'

Troubleshooting

Problèmes SSH

Symptome Cause probable Solution
Permission denied (publickey) Cle SSH non enregistree Ajouter la cle dans le profil Gitea
Connection refused Port SSH non expose Vérifier le mapping de port (2222:22)
Host key verification failed Cle host changee Supprimer l'ancienne cle dans known_hosts
Timeout SSH Firewall bloque le port Vérifier les regles de pare-feu
# Debug SSH
ssh -vvv git@gitea.example.com -p 22

# Verifier les cles autorisees dans le conteneur
podman exec gitea cat /data/gitea/.ssh/authorized_keys

Problèmes de webhooks

Symptome Cause probable Solution
Webhook timeout Endpoint CI trop lent Augmenter DELIVER_TIMEOUT dans app.ini
Webhook 403 Secret incorrect Vérifier le secret dans la config webhook
Webhook non declenche Événement non selectionne Vérifier les événements actives
Webhook ALLOWED_HOST_LIST Host non autorise Ajouter l'host dans ALLOWED_HOST_LIST
# Voir les deliveries de webhook (via API)
curl -s "https://gitea.example.com/api/v1/repos/org/repo/hooks/1/deliveries" \
  -H "Authorization: token ${TOKEN}" | jq '.[].status'

Problèmes de base de données

Symptome Cause probable Solution
database is locked SQLite en prod (ne pas) Migrer vers PostgreSQL
Connexion refusee PostgreSQL arrete podman-compose up -d postgres
too many connections Pool epuise Augmenter max_connections
Requêtes lentes Index manquants gitea doctor check --run
# Diagnostic Gitea
podman exec gitea gitea doctor check --all

# Verifier les connexions PostgreSQL
podman exec gitea-postgres psql -U gitea -c "SELECT count(*) FROM pg_stat_activity;"

Clones lents

Symptome Cause probable Solution
Clone initial tres lent Dépôt trop volumineux Activer LFS, nettoyer l'historique
Fetch lent Pack files non optimises git gc --aggressive sur le serveur
Clone via HTTP lent Pas de smart HTTP Vérifier la config reverse proxy
# Recompresser les depots sur le serveur
podman exec gitea gitea admin repo-sync-releases

# Git garbage collection sur un depot
podman exec gitea su -c "cd /data/gitea/repositories/org/repo.git && git gc --aggressive" git

Checklist operationnelle

Quotidien (automatise)

  • Sauvegarde PostgreSQL + vérification d'intégrité
  • Sauvegarde des dépôts Git
  • Vérification des metriques (CPU, RAM, disque)
  • Vérification des logs d'erreur

Hebdomadaire

  • Revue des webhooks en echec
  • Vérification de l'espace disque LFS
  • Revue des nouveaux dépôts crees

Mensuel

  • Test de restauration de sauvegarde
  • Mise à jour Gitea (si nouvelle version stable)
  • Revue des permissions et accès
  • Nettoyage des dépôts archives

Trimestriel

  • Audit de sécurité (permissions, tokens, cles SSH)
  • Revue de la politique de branches
  • Capacity planning (stockage, compute)
  • Test du plan de reprise d'activité (PRA)