← Blog

1 min de lecture

docker push échoue, crane push passe

Pousser une image vers le registre de Forgejo échouait systématiquement à la toute fin. Explication et contournement fiable dans une CI Forgejo Actions.

#ci#forgejo#docker

Le symptôme

Dans mes pipelines Forgejo Actions, docker push vers le registre intégré de Forgejo échouait presque toujours, et de la pire des façons : toutes les couches affichent Pushed, puis :

received unexpected HTTP status: 499 Client Closed Request

Ce qui se passe

C’est un bug connu de Forgejo. Pendant un push, le client Docker envoie des requêtes en parallèle (notamment des vérifications d’existence de blobs) et en annule certaines en cours de route. Forgejo gère mal cette annulation et la transforme en erreur 499/500, ce qui fait échouer le push entier.

Ce que j’ai essayé sans succès :

  • limiter la concurrence (--max-concurrent-uploads=1) : plus lent, toujours en échec ;
  • chercher un réglage côté reverse proxy : l’équivalent nginx (proxy_ignore_client_abort) n’existe pas dans Traefik.

Le contournement : crane

crane (Google) est un binaire statique qui parle directement au registre, sans le comportement concurrent du client Docker. On construit l’image avec Docker comme d’habitude, on l’exporte en archive, et c’est crane qui pousse :

- name: Setup crane
  run: |
    curl -fsSL https://github.com/google/go-containerregistry/releases/latest/download/go-containerregistry_Linux_x86_64.tar.gz \
      | tar -xz -C /usr/local/bin crane

- name: Build
  run: |
    docker build -t mon-image:build .
    docker save mon-image:build -o /tmp/image.tar

- name: Push
  run: |
    crane auth login forgejo.example.org -u "$USER" -p "${{ secrets.REGISTRY_TOKEN }}"
    crane push /tmp/image.tar forgejo.example.org/moi/mon-image:${{ github.sha }}

Depuis, aucun échec.

Bonus : la dernière ligne qui disparaît

Dans le même dépôt, une boucle lisait la liste des images à copier :

while read line; do ...; done < images.txt

Si le fichier ne se termine pas par un retour à la ligne, la dernière ligne est ignorée en silence. Une image n’a jamais été copiée pendant des jours. Correction :

while read line || [ -n "$line" ]; do ...; done < images.txt