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 :
- Stockage partage — les dépôts Git doivent etre accessibles par toutes les instances (NFS, GlusterFS, ou réplication)
- Session Redis — les sessions sont stockees dans Redis, pas en local
- Cache Redis — même instance Redis pour toutes les instances Gitea
- 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 :
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)