90% des organisations utilisent au moins un Internal Developer Platform en 2026. Le Platform Engineering réduit le cognitive load des développeurs tout en standardisant infrastructure et sécurité. Guide complet avec Backstage.
Plan
- Qu'est-ce que le Platform Engineering ?
- Architecture d'un Internal Developer Platform
- Backstage : le framework IDP de référence
- Implémenter golden paths et templates
- Self-service infrastructure avec Terraform
- Portal catalog et documentation
- Intégration CI/CD et observabilité
- Mesurer le succès d'un IDP
- Conclusion
Qu'est-ce que le Platform Engineering ?
Définition et contexte 2026
Platform Engineering = discipline qui construit et maintient des Internal Developer Platforms (IDP) pour améliorer la developer experience et standardiser les pratiques.
Problème résolu :
- Équipes DevOps submergées de tickets (provision infra, debug)
- Développeurs bloqués par complexité Kubernetes/cloud
- Outils fragmentés (10-30 outils différents)
- Knowledge silos et duplication d'efforts
- Onboarding nouveaux développeurs : 2-4 semaines
Solution IDP :
- Self-service portal (provision en 5 minutes)
- Golden paths (templates pré-configurés)
- Abstraction complexité infrastructure
- Documentation centralisée
- Standardisation sécurité/observabilité
Statistiques 2026
- 90% des organisations utilisent ≥1 IDP
- 40% réduction tickets DevOps après IDP
- 70% réduction temps onboarding (2 semaines → 2 jours)
- 35% amélioration déploiement frequency
- Platform Engineer = 5ème poste tech le plus demandé
Platform Engineering vs DevOps
| Aspect | DevOps traditionnel | Platform Engineering |
| Focus | CI/CD, automation | Developer experience |
| Approche | Outils éparpillés | Plateforme unifiée |
| Self-service | Limité | Central |
| Abstraction | Faible | Haute (golden paths) |
| Cognitive load | Élevé | Réduit |
| Tickets | Nombreux | -40% |
Architecture d'un Internal Developer Platform
Composants essentiels
┌─────────────────────────────────────────────────┐
│ Developer Portal (Backstage) │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Catalog │ │Templates │ │ Documentation│ │
│ └──────────┘ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ Control Plane │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │GitOps │ │ Policy │ │ Secrets │ │
│ │(ArgoCD) │ │(OPA) │ │ (Vault) │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ Infrastructure Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │Kubernetes│ │Terraform │ │ Cloud APIs │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ Observability & Security │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │Prometheus│ │ Logs │ │ Security │ │
│ │Grafana │ │(Loki) │ │ Scanning │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────┘
Principe : Platform as a Product
Traiter l'IDP comme un produit :
- Product manager dédié
- Roadmap features
- User feedback loops
- SLA/SLO pour la plateforme
- Internal NPS (Net Promoter Score)
Équipe Platform typique :
- 1 Product Manager
- 3-5 Platform Engineers
- 1 Technical Writer
- Ratio : 1 platform engineer pour 30-50 developers
Backstage : le framework IDP de référence
Pourquoi Backstage ?
Backstage = open-source IDP framework créé par Spotify, adopté par Netflix, American Airlines, Zalando, DAZN.
Avantages :
- Open source (Apache 2.0)
- Extensible (plugins)
- Communauté active (200+ plugins)
- Intégrations natives (GitHub, GitLab, Kubernetes, AWS, etc.)
- Templates Scaffolder puissants
Installation Backstage
# Prérequis
node --version # v18+
yarn --version
# Créer app Backstage
npx @backstage/create-app@latest
# Nom : my-platform
cd my-platform
# Structure générée :
# packages/
# app/ # Frontend React
# backend/ # Backend Node.js
# plugins/ # Plugins custom
# app-config.yaml
# Démarrer dev
yarn dev
# Frontend: http://localhost:3000
# Backend: http://localhost:7007
Configuration initiale
# app-config.yaml
app:
title: Engineering Platform
baseUrl: https://platform.company.com
organization:
name: MyCompany
backend:
baseUrl: https://platform.company.com
listen:
port: 7007
database:
client: pg
connection:
host: ${POSTGRES_HOST}
port: ${POSTGRES_PORT}
user: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
cors:
origin: https://platform.company.com
# Intégrations
integrations:
github:
- host: github.com
token: ${GITHUB_TOKEN}
gitlab:
- host: gitlab.company.com
token: ${GITLAB_TOKEN}
# Catalog (source des entities)
catalog:
rules:
- allow: [Component, System, API, Resource, Location]
locations:
# Fichier local
- type: file
target: ../../catalog-info.yaml
# Org GitHub
- type: url
target: https://github.com/myorg/backstage-catalog/blob/main/all.yaml
rules:
- allow: [User, Group]
# Auth (GitHub OAuth)
auth:
environment: production
providers:
github:
production:
clientId: ${GITHUB_CLIENT_ID}
clientSecret: ${GITHUB_CLIENT_SECRET}
Déploiement production
Option 1 : Kubernetes (recommandé)
# kubernetes/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: backstage
namespace: platform
spec:
replicas: 2
selector:
matchLabels:
app: backstage
template:
metadata:
labels:
app: backstage
spec:
containers:
- name: backstage
image: backstage:v1.0.0
ports:
- containerPort: 7007
env:
- name: POSTGRES_HOST
value: postgresql.platform.svc.cluster.local
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: backstage-secrets
key: postgres-password
- name: GITHUB_TOKEN
valueFrom:
secretKeyRef:
name: backstage-secrets
key: github-token
livenessProbe:
httpGet:
path: /healthcheck
port: 7007
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
---
apiVersion: v1
kind: Service
metadata:
name: backstage
namespace: platform
spec:
selector:
app: backstage
ports:
- port: 80
targetPort: 7007
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: backstage
namespace: platform
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- platform.company.com
secretName: backstage-tls
rules:
- host: platform.company.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backstage
port:
number: 80
# Build image
yarn tsc
yarn build:backend
docker build -t backstage:v1.0.0 .
# Deploy
kubectl apply -f kubernetes/
Implémenter golden paths et templates
Qu'est-ce qu'un Golden Path ?
Golden Path = chemin pré-configuré et opinionné pour créer un nouveau service/application respectant les best practices.
Exemple : "Créer une API Node.js"
- Repository GitHub créé
- CI/CD configuré (GitHub Actions)
- Kubernetes manifests générés
- Observabilité intégrée (Prometheus, logs)
- Security scanning activé
- Documentation générée
Créer un template Backstage
# templates/nodejs-api/template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: nodejs-api
title: Node.js API Service
description: Create a new Node.js REST API with best practices
tags:
- nodejs
- api
- recommended
spec:
owner: platform-team
type: service
parameters:
- title: Service Info
required:
- name
- description
- owner
properties:
name:
title: Name
type: string
description: Unique service name
pattern: '^[a-z0-9-]+$'
description:
title: Description
type: string
description: What does this service do?
owner:
title: Owner
type: string
description: Team owning this service
ui:field: OwnerPicker
ui:options:
allowedKinds:
- Group
- title: Infrastructure
properties:
cpu:
title: CPU Limit
type: string
enum:
- "500m"
- "1000m"
- "2000m"
default: "1000m"
memory:
title: Memory Limit
type: string
enum:
- "512Mi"
- "1Gi"
- "2Gi"
default: "1Gi"
replicas:
title: Replicas
type: integer
default: 2
minimum: 1
maximum: 10
steps:
# 1. Fetch template base
- id: fetch-base
name: Fetch Base
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
description: ${{ parameters.description }}
owner: ${{ parameters.owner }}
# 2. Create GitHub repo
- id: publish
name: Publish to GitHub
action: publish:github
input:
allowedHosts: ['github.com']
description: ${{ parameters.description }}
repoUrl: github.com?owner=myorg&repo=${{ parameters.name }}
repoVisibility: internal
defaultBranch: main
# 3. Create Kubernetes manifests
- id: create-k8s-manifests
name: Create K8s Manifests
action: fetch:template
input:
url: ./k8s-skeleton
targetPath: ./k8s
values:
name: ${{ parameters.name }}
cpu: ${{ parameters.cpu }}
memory: ${{ parameters.memory }}
replicas: ${{ parameters.replicas }}
# 4. Register in catalog
- id: register
name: Register Component
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: '/catalog-info.yaml'
output:
links:
- title: Repository
url: ${{ steps.publish.output.remoteUrl }}
- title: Open in catalog
icon: catalog
entityRef: ${{ steps.register.output.entityRef }}
Skeleton template
templates/nodejs-api/skeleton/
├── .github/
│ └── workflows/
│ └── ci.yaml
├── src/
│ ├── index.js
│ ├── routes/
│ └── middleware/
├── tests/
│ └── api.test.js
├── Dockerfile
├── package.json
├── README.md
└── catalog-info.yaml
# templates/nodejs-api/skeleton/catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: ${{values.name}}
description: ${{values.description}}
annotations:
github.com/project-slug: myorg/${{values.name}}
backstage.io/kubernetes-id: ${{values.name}}
prometheus.io/rule: ${{values.name}}
tags:
- nodejs
- api
links:
- url: https://${{values.name}}.company.com
title: Production
icon: web
spec:
type: service
lifecycle: production
owner: ${{values.owner}}
system: platform
providesApis:
- ${{values.name}}-api
Self-service infrastructure avec Terraform
Intégrer Terraform dans IDP
Objectif : Permettre aux développeurs de provisionner infra via UI sans connaître Terraform.
Architecture :
Backstage Template
↓
GitOps Repo (PR auto)
↓
Atlantis / Terraform Cloud
↓
Infrastructure provisioned
↓
Catalog updated
Plugin Terraform pour Backstage
// packages/app/src/components/catalog/EntityPage.tsx
import { EntityTerraformContent } from '@roadiehq/backstage-plugin-terraform';
const serviceEntityPage = (
<EntityLayout>
<EntityLayout.Route path="/" title="Overview">
<Grid container spacing={3}>
<Grid item md={6}>
<EntityAboutCard />
</Grid>
</Grid>
</EntityLayout.Route>
<EntityLayout.Route path="/terraform" title="Infrastructure">
<EntityTerraformContent />
</EntityLayout.Route>
</EntityLayout>
);
Template avec Terraform
# templates/aws-rds-postgres/template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: aws-rds-postgres
title: AWS RDS PostgreSQL Database
description: Provision managed PostgreSQL database
spec:
owner: platform-team
type: resource
parameters:
- title: Database Configuration
properties:
dbName:
title: Database Name
type: string
instanceClass:
title: Instance Class
type: string
enum:
- db.t3.micro
- db.t3.small
- db.t3.medium
- db.r5.large
default: db.t3.small
storageSize:
title: Storage (GB)
type: integer
default: 20
steps:
- id: fetch-terraform
name: Fetch Terraform Module
action: fetch:template
input:
url: ./terraform
values:
dbName: ${{ parameters.dbName }}
instanceClass: ${{ parameters.instanceClass }}
storageSize: ${{ parameters.storageSize }}
- id: publish-terraform
name: Create Terraform PR
action: publish:github:pull-request
input:
repoUrl: github.com?owner=myorg&repo=terraform-infra
branchName: add-db-${{ parameters.dbName }}
title: Add RDS PostgreSQL ${{ parameters.dbName }}
description: |
Automated PR from Backstage IDP
Database: ${{ parameters.dbName }}
Instance: ${{ parameters.instanceClass }}
Storage: ${{ parameters.storageSize }}GB
# templates/aws-rds-postgres/terraform/main.tf
resource "aws_db_instance" "${{values.dbName}}" {
identifier = "${{values.dbName}}"
engine = "postgres"
engine_version = "14.7"
instance_class = "${{values.instanceClass}}"
allocated_storage = ${{values.storageSize}}
db_name = "${{values.dbName}}"
username = "admin"
password = random_password.db_password.result
vpc_security_group_ids = [aws_security_group.db.id]
db_subnet_group_name = aws_db_subnet_group.db.name
backup_retention_period = 7
backup_window = "03:00-04:00"
maintenance_window = "Mon:04:00-Mon:05:00"
enabled_cloudwatch_logs_exports = ["postgresql"]
tags = {
Name = "${{values.dbName}}"
ManagedBy = "Backstage"
Environment = "production"
}
}
resource "random_password" "db_password" {
length = 32
special = true
}
resource "aws_secretsmanager_secret" "db_password" {
name = "rds/${{values.dbName}}/password"
}
resource "aws_secretsmanager_secret_version" "db_password" {
secret_id = aws_secretsmanager_secret.db_password.id
secret_string = random_password.db_password.result
}
output "endpoint" {
value = aws_db_instance.${{values.dbName}}.endpoint
}
output "secret_arn" {
value = aws_secretsmanager_secret.db_password.arn
}
Portal catalog et documentation
Software Catalog
Catalog = inventaire centralisé de tous les composants (services, APIs, resources, teams).
Entities types :
- Component : service, library, website
- API : interface REST, GraphQL, gRPC
- Resource : database, S3 bucket, queue
- System : collection de components
- Domain : collection de systems
- User : personne
- Group : équipe
Exemple catalog-info.yaml complet
# catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payment-service
description: Handles payment processing
annotations:
# GitHub
github.com/project-slug: myorg/payment-service
# Kubernetes
backstage.io/kubernetes-id: payment-service
backstage.io/kubernetes-namespace: production
# CI/CD
github.com/workflows: ci.yaml,release.yaml
# Observability
prometheus.io/rule: payment-service-alerts
grafana/dashboard-selector: payment-service
# Security
snyk.io/org-id: org-abc123
sonarqube.org/project-key: payment-service
# Documentation
backstage.io/techdocs-ref: dir:.
tags:
- nodejs
- payment
- pci-dss
links:
- url: https://payment.company.com
title: Production
icon: web
- url: https://wiki.company.com/payment-service
title: Wiki
icon: docs
- url: https://pagerduty.com/services/payment-service
title: PagerDuty
icon: alert
spec:
type: service
lifecycle: production
owner: payments-team
system: checkout
dependsOn:
- resource:default/postgres-payments
- resource:default/redis-cache
- component:default/fraud-detection
providesApis:
- payment-api
consumesApis:
- stripe-api
- paypal-api
---
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
name: payment-api
description: Payment processing API
spec:
type: openapi
lifecycle: production
owner: payments-team
system: checkout
definition: |
openapi: 3.0.0
info:
title: Payment API
version: 1.0.0
paths:
/payments:
post:
summary: Create payment
requestBody:
content:
application/json:
schema:
type: object
properties:
amount:
type: number
currency:
type: string
TechDocs (documentation)
TechDocs = docs-as-code avec MkDocs, intégrées dans Backstage.
# mkdocs.yml
site_name: Payment Service
site_description: Documentation for payment processing service
nav:
- Home: index.md
- Architecture: architecture.md
- API Reference: api.md
- Runbooks: runbooks.md
- Security: security.md
theme:
name: material
plugins:
- techdocs-core
# docs/index.md
# Payment Service
## Overview
The payment service handles all payment transactions...
## Quick Start
```bash
npm install
npm run dev
Architecture

API Documentation
See API Reference
**Génération docs :**
```bash
# Local
npx @techdocs/cli generate
# CI/CD (GitHub Actions)
- name: Generate TechDocs
uses: backstage/techdocs-container-action@v1
Intégration CI/CD et observabilité
Plugin GitHub Actions
# app-config.yaml
integrations:
github:
- host: github.com
token: ${GITHUB_TOKEN}
// packages/app/src/components/catalog/EntityPage.tsx
import { EntityGithubActionsContent } from '@backstage/plugin-github-actions';
<EntityLayout.Route path="/ci-cd" title="CI/CD">
<EntityGithubActionsContent />
</EntityLayout.Route>
Plugin Kubernetes
# app-config.yaml
kubernetes:
serviceLocatorMethod:
type: 'multiTenant'
clusterLocatorMethods:
- type: 'config'
clusters:
- url: https://k8s-prod.company.com
name: production
authProvider: 'serviceAccount'
serviceAccountToken: ${K8S_TOKEN}
skipTLSVerify: false
caData: ${K8S_CA_DATA}
// Entity page
import { EntityKubernetesContent } from '@backstage/plugin-kubernetes';
<EntityLayout.Route path="/kubernetes" title="Kubernetes">
<EntityKubernetesContent />
</EntityLayout.Route>
Plugin Prometheus / Grafana
// packages/app/src/components/catalog/EntityPage.tsx
import { EntityPrometheusContent } from '@roadiehq/backstage-plugin-prometheus';
import { EntityGrafanaDashboardsCard } from '@k-phoen/backstage-plugin-grafana';
<EntityLayout.Route path="/monitoring" title="Monitoring">
<Grid container spacing={3}>
<Grid item md={12}>
<EntityPrometheusContent />
</Grid>
<Grid item md={12}>
<EntityGrafanaDashboardsCard />
</Grid>
</Grid>
</EntityLayout.Route>
Mesurer le succès d'un IDP
Métriques Platform Engineering
Developer Experience (DevEx) :
- Time to first deployment (nouveau dev)
- Self-service adoption rate
- Ticket reduction (DevOps team)
- Developer satisfaction (NPS)
Efficiency :
- Deployment frequency
- Lead time for changes
- MTTR (Mean Time To Recovery)
- Environment provisioning time
Quality :
- Security scan coverage
- Policy compliance rate
- Documentation coverage
- Golden path adoption
Tableau de bord IDP
# Métriques Prometheus
platform_template_usage{template="nodejs-api"} 45
platform_catalog_entities{type="component"} 234
platform_self_service_requests_total 1234
platform_ticket_reduction_percent 42
platform_onboarding_time_days 2
Grafana dashboard :
- Services créés / semaine
- Time to first deploy (tendance)
- Top templates utilisés
- Tickets DevOps évités
- Coverage sécurité/docs
Survey Developer Experience
# Quarterly survey
Questions:
- "How satisfied are you with the platform? (1-10)"
- "How easy is it to create a new service? (1-10)"
- "How often do you need to contact DevOps? (daily/weekly/monthly/rarely)"
- "What feature would you like to see next?"
Target NPS: ≥ 50
Checklist implémentation IDP
✅ Phase 1 : Foundation (Semaine 1-4)
- Backstage installé et déployé
- Auth configuré (GitHub OAuth)
- Catalog initial (teams, existing services)
- 1er golden path (service simple)
- Documentation portal actif
✅ Phase 2 : Adoption (Semaine 5-12)
- 3-5 golden paths disponibles
- Self-service infra (Terraform)
- CI/CD intégration
- Kubernetes plugin actif
- 20%+ services dans catalog
✅ Phase 3 : Scale (Mois 3-6)
- Observabilité intégrée
- Security scanning automatique
- TechDocs généralisé
- 60%+ services dans catalog
- Metrics IDP collectées
✅ Phase 4 : Optimize (Mois 6+)
- NPS Developer ≥50
- 80%+ adoption golden paths
- <40% réduction tickets DevOps
- <2 jours onboarding
- Custom plugins développés
Conclusion
Le Platform Engineering avec un IDP comme Backstage réduit drastiquement le cognitive load des développeurs tout en standardisant infrastructure, sécurité et observabilité. L'adoption massive en 2026 (90%) confirme que c'est devenu un standard.
Points clés :
- IDP = plateforme self-service pour developers
- Backstage = framework open source mature
- Golden paths = best practices automatisées
- Platform as a Product = mentalité requise
- Mesurer DevEx et adoption essentiels
Gains typiques :
- Onboarding : -70% (2 semaines → 2 jours)
- Tickets DevOps : -40%
- Time to production : -60%
- Security compliance : +80%
- Developer satisfaction : +50 NPS
Actions prioritaires :
- Installer Backstage (POC en 1 semaine)
- Créer 1er golden path (Node.js ou Python API)
- Importer services existants dans catalog
- Mesurer baseline (onboarding time, tickets)
- Itérer avec feedback developers


