Aller au contenu
Conteneurs & Orchestration medium

Buildez des images OCI sans Dockerfile avec Cloud Native Buildpacks

23 min de lecture

Les Cloud Native Buildpacks transforment votre code source en images OCI sans écrire de Dockerfile. Lancés en 2018 par Heroku et Pivotal (CNCF), ils détectent automatiquement votre stack (Python, Node, Java, Go…), installent les dépendances, appliquent les bonnes pratiques de sécurité et génèrent une image prête pour production. Contrairement aux Dockerfiles manuels, les buildpacks garantissent des images optimisées, reproductibles et conformes aux standards OCI.

Ce que vous allez apprendre :

  • Comprendre le lifecycle des buildpacks (detect → build → export)
  • Installer Pack CLI v0.39.1 et builder votre première app Flask
  • Choisir entre Paketo, Google Cloud et Heroku buildpacks selon votre stack
  • Débugger les erreurs courantes (API Docker, détection échouée, cache)

Prérequis : Docker 23.0+ installé, connaissances de base en conteneurs et CI/CD.

Les buildpacks ont été introduits par Heroku en 2011 pour simplifier le déploiement des applications. Leur but : transformer automatiquement du code source en application exécutable sans écrire de Dockerfile.

Rapidement adoptés par d’autres plateformes comme Cloud Foundry et Scalingo (PaaS français souverain), ils ont évolué vers une approche plus modulaire et standardisée avec les Cloud Native Buildpacks (CNB), lancés en 2018 par Heroku et Pivotal sous la CNCF.

Cette évolution marque un tournant : les buildpacks deviennent un outil clé pour la création d’images conteneur automatisée, compatible avec Docker et Kubernetes, idéal pour les pipelines CI/CD.

Un buildpack est un ensemble de scripts et de règles qui analysent un projet pour en déterminer la stack technique, installer les dépendances nécessaires, puis générer une image de conteneur prête à l’exécution.

L’objectif principal d’un buildpack est de supprimer le besoin d’écrire un Dockerfile tout en garantissant une image optimisée, sécurisée et cohérente entre les environnements.

Comment fonctionne un buildpack (détection, build, release)

Section intitulée « Comment fonctionne un buildpack (détection, build, release) »

Un construction d’un buildpack suit un processus en trois étapes clés, orchestré par un composant appelé lifecycle. Chaque étape joue un rôle précis dans la transformation du code source en image exécutable.

Architecture complète des Cloud Native Buildpacks

L’outil commence par analyser le répertoire du projet. Il cherche des fichiers caractéristiques (comme package.json, requirements.txt, etc.) pour déterminer s’il peut s’appliquer.

Fenêtre de terminal
===> DETECTING
[detector] 6 of 9 buildpacks participating
[detector] paketo-buildpacks/ca-certificates 3.11.0
[detector] paketo-buildpacks/cpython 1.18.9
[detector] paketo-buildpacks/pip 0.25.3
[detector] paketo-buildpacks/pip-install 0.7.13
[detector] paketo-buildpacks/python-start 0.15.9
[detector] paketo-buildpacks/procfile 5.12.0

Si aucun buildpack ne correspond, le processus s’arrêtera ici avec une erreur. Si la détection réussit, le buildpack sera utilisé pour la construction de l’image.

Lorsque la détection réussit, le buildpack :

  • Télécharge ou compile les dépendances
  • Prépare l’environnement d’exécution
  • Organise les fichiers pour qu’ils soient prêts à être lancés

Cette phase peut impliquer plusieurs buildpacks, appelés en chaîne (multi-buildpack).

Fenêtre de terminal
===> BUILDING
[builder]
[builder] Paketo Buildpack for CA Certificates 3.11.0
https://github.com/paketo-buildpacks/ca-certificates
Launch Helper: Contributing to layer
Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper
[builder] Paketo Buildpack for CPython 1.18.9
Resolving CPython version
Candidate version sources (in priority order):
BP_CPYTHON_VERSION -> "3.11"
<unknown> -> ""
Selected CPython version (using BP_CPYTHON_VERSION): 3.11.14
Executing build process
Installing CPython 3.11.14
Completed in 7.548s
[builder]
[builder] Generating SBOM for /layers/paketo-buildpacks_cpython/cpython
[builder] Completed in 0s
[builder]
[builder]
[builder] Configuring build environment
[builder] PYTHONPATH -> "/layers/paketo-buildpacks_cpython/cpython"
[builder] PYTHONPYCACHEPREFIX -> "/tmp"
[builder]
[builder] Configuring launch environment
[builder] PYTHONPATH -> "/layers/paketo-buildpacks_cpython/cpython"
[builder]
[builder] Paketo Buildpack for Python Start 0.14.11
[builder] Assigning launch processes:
[builder] web (default): python
[builder]
[builder]
[builder] Paketo Buildpack for Procfile 5.12.0
https://github.com/paketo-buildpacks/procfile
Process types:
web: gunicorn --bind 0.0.0.0:$PORT --workers 2 app:app

Ici , le buildpack Python détecte la version de CPython à utiliser, installe les dépendances nécessaires, et configure l’environnement d’exécution.

Avec les Cloud Native Buildpacks, cette étape crée une image conteneur OCI-compatible, prête à être poussée sur un registre.

Fenêtre de terminal
===> EXPORTING
[exporter] Adding layer 'paketo-buildpacks/ca-certificates:helper'
[exporter] Adding layer 'paketo-buildpacks/cpython:cpython'
[exporter] Adding layer 'buildpacksio/lifecycle:launch.sbom'
[exporter] Adding 1/1 app layer(s)
[exporter] Adding layer 'buildpacksio/lifecycle:launcher'
[exporter] Adding layer 'buildpacksio/lifecycle:config'
[exporter] Adding layer 'buildpacksio/lifecycle:process-types'
[exporter] Adding label 'io.buildpacks.lifecycle.metadata'
[exporter] Adding label 'io.buildpacks.build.metadata'
[exporter] Adding label 'io.buildpacks.project.metadata'
[exporter] Setting default process type 'web'
[exporter] Saving flask-hello-world...

Normalement après cette étape, l’image est prête à être poussée sur un registre comme Docker Hub ou Google Container Registry, et peut être déployée sur n’importe quel orchestrateur de conteneurs comme Kubernetes ou Docker Swarm.

Fenêtre de terminal
docker images flask-hello-world
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-hello-world latest f3e78a87761b 10 seconds ago 785MB

L’image résultante contient tout le nécessaire pour exécuter l’application, y compris les dépendances, les configurations et les métadonnées nécessaires.

L’image peut ensuite être poussée vers un registre de conteneurs pour être déployée sur n’importe quelle plateforme compatible avec les conteneurs.

Les Cloud Native Buildpacks reposent sur deux composants : le(s) builder(s) et le lifecycle. Ces composants structurent et automatisent tout le processus de création d’images conteneur. Lifecycle buildpacks : détection, build, export

Le lifecycle est un composant central du système CNB. Il se charge de :

  • Analyser le projet (détection)
  • Exécuter chaque buildpack dans le bon ordre
  • Assembler une image finale conforme aux standards OCI
  • Optimiser le résultat via des mécanismes comme le cache ou le rebasage

Il est entièrement stateless, ce qui facilite l’automatisation dans des pipelines CI/CD.

Un builder est une image Docker spéciale qui contient :

  • Un ensemble de buildpacks organisés en ordre d’exécution.
  • Une stack de base (runtime) pour construire et exécuter l’application.
  • Un lifecycle pour orchestrer les étapes.

Les builders peuvent être personnalisés ou utilisés tels quels via des projets comme Paketo, Heroku ou Google Cloud Buildpacks.

Voici une commande typique utilisant un builder avec pack, l’outil CLI CNB :

Fenêtre de terminal
pack build mon-app --builder paketobuildpacks/builder:base

Cette ligne suffit à transformer un projet en image conteneur, sans Dockerfile.

Pour utiliser les Cloud Native Buildpacks, vous aurez besoin de plusieurs outils. Voici l’écosystème complet des Cloud Native Buildpacks.

Pack est l’interface de ligne de commande officielle pour les Cloud Native Buildpacks. Il permet de :

  • Construire des images à partir du code source
  • Créer des builders personnalisés
  • Inspecter le contenu des images et buildpacks
  • Rebaser les images existantes

Dans un premier temps, installez l’outil Pack :

Fenêtre de terminal
# Linux/macOS via script
(curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.38.2/pack-v0.38.2-linux.tgz" | sudo tar -C /usr/local/bin/ --no-same-owner -xzv pack)
# macOS via Homebrew
brew install buildpacks/tap/pack
# Windows via Chocolatey
choco install pack --version=0.30.0

Docker est requis comme runtime pour exécuter les builders et les images générées.

Fenêtre de terminal
# Vérifier l'installation
docker --version
# Tester avec un exemple simple
docker run hello-world

Si vous n’avez pas Docker installé, suivez les instructions de mon guide dédié à Docker.

L’écosystème des buildpacks s’est considérablement enrichi depuis les Cloud Native Buildpacks. Aujourd’hui, plusieurs acteurs proposent des solutions adaptées à différents besoins et environnements. Voici un panorama des principales options disponibles pour vous aider à choisir la solution la plus adaptée à vos projets.

Paketo Buildpacks - L’écosystème de référence

Section intitulée « Paketo Buildpacks - L’écosystème de référence »

Paketo est devenu le projet le plus mature et complet de l’écosystème CNB. Soutenu par VMware et la communauté Cloud Foundry, il bénéficie d’une gouvernance solide et d’une adoption massive dans l’industrie.

Paketo propose plusieurs builders adaptés à différents cas d’usage, permettant d’optimiser la taille et les fonctionnalités selon vos besoins :

  • paketobuildpacks/builder:base - Builder complet pour applications diverses
  • paketobuildpacks/builder:tiny - Builder minimal (Ubuntu Bionic)
  • paketobuildpacks/builder:full - Builder complet (Ubuntu Jammy)

Le builder base convient à la majorité des cas d’usage, tandis que tiny est idéal pour des déploiements où la taille d’image est critique. Le builder full inclut des outils supplémentaires pour des besoins spécifiques.

Paketo propose des buildpacks spécialisés pour chaque écosystème de développement, avec une détection intelligente des gestionnaires de dépendances :

LangageBuildpack principalGestionnaires supportés
Java/JVMpaketo-buildpacks/javaMaven, Gradle, Spring Boot
Node.jspaketo-buildpacks/nodejsnpm, yarn, pnpm
Pythonpaketo-buildpacks/pythonpip, conda, pipenv
Gopaketo-buildpacks/gogo mod, go dep
.NETpaketo-buildpacks/dotnet-coreNuGet, MSBuild
PHPpaketo-buildpacks/phpComposer
Rubypaketo-buildpacks/rubyBundler, RubyGems

Cette approche modulaire permet une grande flexibilité dans la construction des images, chaque buildpack étant spécialisé dans son domaine tout en s’intégrant parfaitement avec les autres.

Google propose aussi son propre écosystème de buildpacks, optimisé pour Google Cloud Platform.

Builder principal :

  • gcr.io/buildpacks/builder:v1 - Builder Google optimisé pour GCP

Buildpacks spécialisés par langage :

  • gcr.io/buildpacks/java - Buildpack Java optimisé
  • gcr.io/buildpacks/nodejs - Buildpack Node.js optimisé
  • gcr.io/buildpacks/python - Buildpack Python optimisé
  • gcr.io/buildpacks/go - Buildpack Go optimisé

Les buildpacks Google se distinguent par plusieurs caractéristiques techniques importantes :

  • Images distroless : Utilisation d’images de base ultra-légères sans shell ni gestionnaire de paquets
  • Sécurité renforcée : Réduction significative de la surface d’attaque avec moins de CVE
  • Performance : Temps de démarrage optimisés pour les services serverless

Cette approche est particulièrement recommandée pour les applications destinées à fonctionner exclusivement sur l’infrastructure Google Cloud.

Heroku, pionnier des buildpacks, a migré son écosystème vers le standard Cloud Native Buildpacks. Cette migration permet de bénéficier des avantages CNB tout en conservant la simplicité d’utilisation d’Heroku.

Fenêtre de terminal
# Builder Heroku compatible CNB
heroku/buildpacks:20

Cette migration facilite grandement la transition pour les équipes utilisant déjà Heroku qui souhaitent adopter une approche plus portable. Les buildpacks Heroku CNB conservent la philosophie de simplicité tout en gagnant en flexibilité et en portabilité.

Scalingo est une plateforme Platform-as-a-Service française qui intègre nativement les buildpacks pour simplifier le déploiement d’applications. Certifiée ISO 27001 et HDS (Hébergeur de Données de Santé), elle se distingue par son positionnement sur la souveraineté numérique avec des datacenters en France et une conformité RGPD stricte.

Buildpacks officiellement supportés :

Cas d’usage spécifiques Scalingo :

  • Données sensibles : Hébergement conforme HDS pour applications santé
  • Secteur public : Souveraineté numérique pour administrations françaises
  • Multi-buildpacks : Combiner plusieurs buildpacks (ex: Python + APT pour dépendances système)
  • Buildpacks système : APT, GraphicsMagick, Cairo, Wkhtmltopdf, Jemalloc

Scalingo détecte automatiquement le langage via les buildpacks et permet de spécifier un buildpack personnalisé avec la variable d’environnement BUILDPACK_NAME. Contrairement aux Cloud Native Buildpacks qui nécessitent Pack CLI et Docker localement, Scalingo gère l’ensemble du processus côté plateforme via un simple git push.

Plus d’infos sur Scalingo :

Pour illustrer concrètement l’utilisation d’un buildpack Python, créons une application Flask basique et construisons-la avec les Cloud Native Buildpacks.

Créez d’abord la structure de votre projet :

Fenêtre de terminal
mkdir flask-hello-world
cd flask-hello-world
  • Code de l’application (app.py) :

Créez le fichier principal de l’application :

from flask import Flask
import os
app = Flask(__name__)
@app.route('/')
def hello_world():
return '''
<h1>🚀 Bonjour depuis Flask !</h1>
<p>Cette application a été construite avec les Cloud Native Buildpacks.</p>
<p>Version Python : 3.11</p>
<p>Port : {}</p>
'''.format(os.environ.get('PORT', '5000'))
@app.route('/health')
def health_check():
return {'status': 'OK', 'message': 'Application Flask fonctionne parfaitement'}
if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port, debug=True)
  • Fichier des dépendances (requirements.txt) :

Définissez les dépendances Python :

Flask==3.0.0
gunicorn==21.2.0
  • Fichier de processus (Procfile) :

Créez un Procfile pour définir la commande de lancement :

web: gunicorn --bind 0.0.0.0:$PORT --workers 2 app:app

Maintenant, construisons l’image avec le buildpack Python Paketo :

Fenêtre de terminal
pack build flask-hello-world \
--builder paketobuildpacks/builder-jammy-base:latest \
--env BP_CPYTHON_VERSION=3.11 \
--trust-builder

Voici ce que vous devriez voir pendant la construction :

Fenêtre de terminal
===> DETECTING
[detector] 6 of 9 buildpacks participating
[detector] paketo-buildpacks/ca-certificates 3.11.0
[detector] paketo-buildpacks/cpython 1.18.9
[detector] paketo-buildpacks/pip 0.25.3
[detector] paketo-buildpacks/pip-install 0.7.13
[detector] paketo-buildpacks/python-start 0.15.9
[detector] paketo-buildpacks/procfile 5.12.0
===> RESTORING
===> BUILDING
[builder]
[builder] Selected CPython version (using BP_CPYTHON_VERSION): 3.11.4
[builder]
[builder] Executing build process
[builder] Installing CPython 3.11.14
[builder] Completed in 7.548s
[builder]
[builder] Generating SBOM for /layers/paketo-buildpacks_cpython/cpython
[builder] Completed in 0s
[builder]
[builder]
[builder] Configuring build environment
[builder] PYTHONPATH -> "/layers/paketo-buildpacks_cpython/cpython"
[builder] PYTHONPYCACHEPREFIX -> "/tmp"
[builder]
[builder] Configuring launch environment
[builder] PYTHONPATH -> "/layers/paketo-buildpacks_cpython/cpython"
[builder]
[builder] Paketo Buildpack for Pip 0.25.3
Resolving Pip version
[builder] Candidate version sources (in priority order):
[builder] <unknown> -> ""
[builder]
[builder] Selected Pip version (using <unknown>): 25.3.0
[builder]
[builder] Executing build process
[builder] Installing Pip 25.3.0
[builder] Completed in 3.001s
[builder]
[builder] Generating SBOM for /layers/paketo-buildpacks_pip/pip
[builder] Completed in 0s
[builder]
[builder] Configuring build environment
[builder] PYTHONPATH -> "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages:$PYTHONPATH"
[builder]
[builder] Configuring launch environment
[builder] PYTHONPATH -> "/layers/paketo-buildpacks_pip/pip/lib/python3.11/site-packages:$PYTHONPATH"
[builder]
[builder] Paketo Buildpack for Pip Install 0.7.13
Executing build process
Running 'pip install --exists-action=w --cache-dir=/layers/paketo-buildpacks_pip-install/cache --compile --user --disable-pip-version-check --requirement=requirements.txt'
Looking in links: /layers/paketo-buildpacks_pip/pip-source
Collecting Flask==3.0.0 (from -r requirements.txt (line 1))
Downloading flask-3.0.0-py3-none-any.whl.metadata (3.6 kB)
Collecting gunicorn==21.2.0 (from -r requirements.txt (line 2))
Downloading gunicorn-21.2.0-py3-none-any.whl.metadata (4.1 kB)
Collecting Werkzeug>=3.0.0
Downloading werkzeug-3.1.5-py3-none-any.whl.metadata (4.0 kB)
Collecting Jinja2>=3.1.2
Downloading jinja2-3.1.6-py3-none-any.whl.metadata (2.9 kB)
[...dépendances installées]
Completed in 536ms
[builder]
[builder] Paketo Buildpack for Procfile 5.12.0
https://github.com/paketo-buildpacks/procfile
Process types:
web: gunicorn --bind 0.0.0.0:$PORT --workers 2 app:app
===> EXPORTING
[exporter] Adding layer 'paketo-buildpacks/ca-certificates:helper'
[exporter] Adding layer 'paketo-buildpacks/cpython:cpython'
[exporter] Adding layer 'paketo-buildpacks/pip-install:packages'
[exporter] Adding layer 'buildpacksio/lifecycle:launch.sbom'
[exporter] Adding 1/1 app layer(s)
[exporter] Adding layer 'buildpacksio/lifecycle:launcher'
[exporter] Adding layer 'buildpacksio/lifecycle:config'
[exporter] Adding layer 'buildpacksio/lifecycle:process-types'
[exporter] Adding label 'io.buildpacks.lifecycle.metadata'
[exporter] Adding label 'io.buildpacks.build.metadata'
[exporter] Adding label 'io.buildpacks.project.metadata'
[exporter] Setting default process type 'web'
[exporter] Saving flask-hello-world...
[exporter] *** Images (f3e78a87761b):
[exporter] flask-hello-world
[exporter] Adding cache layer 'paketo-buildpacks/cpython:cpython'
[exporter] Adding cache layer 'paketo-buildpacks/pip:pip'
[exporter] Adding cache layer 'paketo-buildpacks/pip-install:cache'
[exporter] Adding cache layer 'paketo-buildpacks/pip-install:packages'
[exporter] Adding cache layer 'buildpacksio/lifecycle:cache.sbom'
Successfully built image flask-hello-world

Une fois l’image construite, testez-la localement :

Fenêtre de terminal
# Lancer l'application
docker run -p 8080:8080 -e PORT=8080 flask-hello-world

Dans un autre terminal, tester les endpoints :

Fenêtre de terminal
curl http://localhost:8080
<h1>🚀 Bonjour depuis Flask !</h1>
<p>Cette application a été construite avec les Cloud Native Buildpacks.</p>
<p>Version Python : 3.11</p>
<p>Port : 8080</p>

Maintenant, testons le endpoint de contrôle de santé :

Fenêtre de terminal
curl http://localhost:8080/health | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 70 100 70 0 0 61457 0 --:--:-- --:--:-- --:--:-- 70000
{
"message": "Application Flask fonctionne parfaitement",
"status": "OK"
}

Voila, notre application Flask est maintenant conteneurisée et prête à être déployée sur n’importe quelle plateforme compatible avec les conteneurs, le tout sans avoir écrit une seule ligne de Dockerfile. Vous pouvez pousser cette image vers un registre comme Docker Hub ou Google Container Registry pour la rendre disponible pour le déploiement.

Les buildpacks sont généralement robustes, mais quelques erreurs courantes peuvent survenir. Voici comment les résoudre rapidement.

SymptômeCause probableSolution
ERROR: failed to initialize analyzer: API version 1.42 too oldDocker API version incompatible avec le builderUtiliser builder-jammy-base compatible API 1.44+ au lieu de builder:base
ERROR: No buildpack groups passed detectionAucun fichier détectable dans le projetVérifier que requirements.txt, package.json, pom.xml, etc. existe à la racine
ERROR: Image build not authorizedBuilder non trustéAjouter --trust-builder à la commande pack build
ERROR: failed to fetch builder imageRegistry inaccessible ou builder inexistantVérifier la connectivité réseau et le nom du builder (pack builder inspect)
Build très lent (> 10 min)Cache désactivé ou non persistéUtiliser --cache-image pour stocker le cache dans une registry

Commandes de diagnostic :

Fenêtre de terminal
# Vérifier version Pack CLI
pack version
# Attendu : 0.39.1+git-dc9220d.build-6702
# Vérifier version Docker
docker version --format '{{.Server.APIVersion}}'
# Attendu : 1.42 ou supérieur
# Inspecter un builder
pack builder inspect paketobuildpacks/builder:base
# Logs verbeux
pack build myapp --verbose --builder paketobuildpacks/builder:base
  1. Buildpacks = Dockerfile automatique : Analysent votre code source, détectent le langage, installent les dépendances et génèrent une image OCI prête pour production
  2. Lifecycle : Orchestrateur en 3 étapes (detect → build → export) qui garantit la reproductibilité
  3. Pack CLI : Outil principal pour builder localement avec pack build
  4. Builders recommandés : Paketo (usage général), Google Cloud (GCP), Heroku (migration legacy)
  5. SBOM automatique : Généré pour chaque image, garantit la traçabilité des dépendances
  6. Cas d’usage idéaux : Prototypage rapide, CI/CD multi-langage, standardisation des builds
  7. Limitations : Moins de contrôle qu’un Dockerfile custom, nécessite Docker, courbe d’apprentissage initiale
  8. Bonnes pratiques : Pin builder digest, utiliser cache-image en CI/CD, scanner l’image finale avec Trivy

buildpacks.

La révolution buildpack a commencé. Êtes-vous prêt à l’adopter ?

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.