Aller au contenu
Administration Linux medium

Créer des paquets .deb, .rpm et .apk avec fpm

9 min de lecture

fpm (Effing Package Management) construit des paquets .deb, .rpm et .apk à partir des mêmes fichiers, sans devenir expert du format natif de chaque distribution. Ce guide montre comment installer fpm, empaqueter un binaire ou un script en paquet Debian, RHEL et Alpine, et y ajouter métadonnées, dépendances et scripts d'installation. Pour administrateurs et développeurs débutants à intermédiaires. Toutes les sorties proviennent d'un lab réel (fpm 1.17.0). En fin de guide, le comparatif avec nfpm pour choisir le bon outil.

  • Installer fpm et les outils natifs requis
  • Construire un .deb, un .rpm et un .apk depuis les mêmes sources
  • Ajouter métadonnées, dépendances et scripts d'installation
  • Choisir entre fpm et nfpm
  • Un binaire, un script ou un répertoire à empaqueter
  • Ruby (fpm est écrit en Ruby) et les outils natifs de la cible (dpkg pour le .deb, rpm pour le .rpm)

Chaque distribution a son format de paquet et ses outils : dpkg-deb et les fichiers debian/ côté Debian, rpmbuild et les fichiers .spec côté RHEL. Apprendre chacun est long. fpm part d'une source (-s) et produit une cible (-t), en masquant cette complexité :

  • Sources (-s) : un répertoire (dir), une archive tar, un gem Ruby, un module Python, un paquet npm, ou même un .deb/.rpm existant à reconvertir.
  • Cibles (-t) : deb, rpm, apk (Alpine), pacman, tar, et d'autres.

Le même jeu de fichiers donne donc un paquet pour toutes les distributions visées, en changeant un seul argument.

fpm s'installe en gem Ruby, après les paquets système. Installez aussi l'outil natif de chaque format que vous voulez produire.

Fenêtre de terminal
sudo apt update
sudo apt install -y ruby ruby-dev build-essential
# outils natifs des cibles voulues :
sudo apt install -y dpkg # pour produire des .deb
sudo apt install -y rpm # pour produire des .rpm
sudo gem install fpm

Vérifiez l'installation :

Fenêtre de terminal
fpm --version
1.17.0

Préparez l'arborescence à empaqueter, puis lancez fpm. Ici un script installé dans /usr/local/bin :

Fenêtre de terminal
mkdir -p src/usr/local/bin
printf '#!/bin/sh\necho bonjour\n' > src/usr/local/bin/monoutil
chmod 0755 src/usr/local/bin/monoutil
fpm -s dir -t deb -n monoutil -v 1.0.0 \
--description "Outil de demo" --maintainer "Stephane" \
-C src usr/local/bin/monoutil
{:timestamp=>"...", :message=>"Created package", :path=>"monoutil_1.0.0_amd64.deb"}

L'option -C src (chdir) entre dans src avant de lire les fichiers, pour que l'arborescence du paquet démarre à usr/local/bin. Vérifiez le résultat avec les outils Debian :

Fenêtre de terminal
dpkg -I monoutil_1.0.0_amd64.deb # métadonnées
Package: monoutil
Version: 1.0.0
Architecture: amd64
Maintainer: Stephane
Description: Outil de demo
Fenêtre de terminal
dpkg -c monoutil_1.0.0_amd64.deb # contenu
-rwxr-xr-x 0/0 23 ./usr/local/bin/monoutil
-rw-r--r-- 0/0 125 ./usr/share/doc/monoutil/changelog.gz

Le paquet est installable avec sudo apt install ./monoutil_1.0.0_amd64.deb.

Pour produire les autres formats, seule la cible -t change. Le même mapping de fichiers donne un .rpm :

Fenêtre de terminal
fpm -s dir -t rpm -n monoutil -v 1.2.0 --iteration 1 \
--description "Outil demo" --maintainer "Stephane" --license MIT \
--depends bash \
src/usr/local/bin/monoutil=/usr/local/bin/monoutil

Ici on utilise la syntaxe source=destination : le fichier local est placé à /usr/local/bin/monoutil dans le paquet. Vérifiez avec les outils RPM :

Fenêtre de terminal
rpm -qip monoutil-1.2.0-1.x86_64.rpm
Name : monoutil
Version : 1.2.0
Release : 1
License : MIT
Summary : Outil demo

Et le format Alpine se génère de la même façon avec -t apk :

Fenêtre de terminal
fpm -s dir -t apk -n monoutil -v 1.0 \
src/usr/local/bin/monoutil=/usr/local/bin/monoutil
Created package {:path=>"monoutil_1.0_noarch.apk"}

Les métadonnées se passent en options, identiques quelle que soit la cible :

OptionRôle
-n, -vnom et version du paquet
--iterationnuméro de build (la release RPM, la debian_revision)
-aarchitecture (amd64, noarch...)
--dependsune dépendance (répétable)
--description, -m, --url, --licensedescription, mainteneur, URL, licence

fpm sait aussi attacher des scripts de cycle de vie déclenchés à l'installation ou la suppression : --before-install, --after-install, --before-remove, --after-remove.

Fenêtre de terminal
printf '#!/bin/sh\necho post-install lance\n' > after.sh
fpm -s dir -t rpm -n monoutil -v 1.2.0 --after-install after.sh \
src/usr/local/bin/monoutil=/usr/local/bin/monoutil

Le script est bien embarqué, vérifiable côté RPM :

Fenêtre de terminal
rpm -qp --scripts monoutil-1.2.0-1.x86_64.rpm
postinstall scriptlet (using /bin/sh):
#!/bin/sh
echo post-install lance

nfpm (de l'équipe GoReleaser) est l'alternative moderne. Le choix dépend de votre contexte.

Critèrefpmnfpm
Langage / dépendanceRuby (gem)binaire Go autonome, zéro dépendance
Configurationimpérative (CLI)déclarative (nfpm.yaml versionné)
Sources d'entréedir, gem, python, npm, deb, rpm...fichiers uniquement (contents)
Ciblesdeb, rpm, apk, pacman, tar...deb, rpm, apk, ipk, archlinux
Signature des paquetsnon native (outil externe)native (deb, rpm, apk)
Intégration CI/CDà scripterintégrée à GoReleaser

En clair : nfpm brille dans un pipeline CI/CD reproductible (config YAML, binaire unique, signature native), surtout pour distribuer un binaire Go. fpm reste imbattable quand l'entrée n'est pas un simple répertoire : convertir un gem, un module Python ou repackager un .rpm en .deb, ce que nfpm ne fait pas.

  • Dépendance Ruby : fpm impose Ruby et ruby-dev, là où nfpm est un binaire autonome. En CI, prévoyez l'installation du gem.
  • Pas de signature native : fpm ne signe pas les .deb. Signez après coup (dpkg-sig pour deb, rpm --addsign ou --rpm-sign pour rpm).
  • Fichiers de /etc : les outils Debian marquent souvent tout ce qui est sous /etc comme fichier de configuration, ce qui change le comportement aux mises à jour. Vérifiez vos chemins.
  • Pas de résolution de dépendances : --depends pose les métadonnées, mais c'est à vous de déclarer le bon graphe ; fpm ne le calcule pas.
  • fpm construit .deb, .rpm et .apk depuis les mêmes sources : seul -t change.
  • Il s'installe en gem Ruby et exige l'outil natif de chaque cible (dpkg, rpm).
  • -s dir + mapping source=destination est le mode le plus courant ; -C change le répertoire de base.
  • Métadonnées (-n, -v, --depends, --license) et scripts (--after-install...) sont communs à toutes les cibles.
  • fpm ne signe pas les paquets : signez après création pour une distribution publique.
  • Pour un pipeline Go reproductible, regardez nfpm ; pour convertir gem/python/npm, restez sur fpm.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn