Scripts de démarrage
os.startup_scripts crée un travail systemd one-shot borné pour l’image résultante. Chaque entrée déclare une commande shell, les paquets requis, l’utilisateur d’exécution et l’unité d’ordonnancement.
Les scripts de démarrage sont du code capable root sauf si run_as indique le contraire. Ils doivent recevoir la même relecture que tout script d’installation.
Forme canonique
{
"os": {
"startup_scripts": [
{
"name": "write-build-marker",
"description": "Create a local readiness marker after networking is available.",
"command": "set -Eeuo pipefail\ninstall -d -m 0755 /var/lib/example\nprintf '%s\\n' ready > /var/lib/example/build-ready",
"packages": [],
"run_as": "root",
"after": "network-online.target"
}
]
}
}Les champs sont description et command, pas l’ancien champ script. run_as et after utilisent aussi snake_case. after est une chaîne d’unité systemd, pas un tableau.
Le schéma accepte au plus 32 entrées et une taille de commande bornée. La validation rejette les commandes vides et les octets NUL, mais ne rend pas le contenu shell sûr ni idempotent.
Concevoir pour les nouvelles tentatives et l’échec partiel
Un boot peut être interrompu après que certains effets se sont produits. Écrivez les scripts pour qu’une autre invocation termine en sécurité ou sorte avec un état clair et inspectable.
Les bons motifs incluent :
- écrire dans un fichier temporaire, le vérifier, puis renommer atomiquement ;
- vérifier si utilisateurs, répertoires ou entrées de configuration existent déjà ;
- utiliser
installpour propriétaire et mode explicites ; - appliquer
set -Eeuo pipefailet gérer délibérément les résultats non nuls attendus ; - utiliser des délais réseau bornés et un nombre fini de tentatives ; et
- écrire un marqueur de disponibilité seulement après succès de toutes les étapes requises.
Ne comptez pas sur sleep comme vérification de disponibilité. Sondez la dépendance réelle.
Téléchargements externes
Évitez curl ... | sh. Si le first boot doit récupérer un artefact :
- utilisez HTTPS avec vérification de certificat ;
- épinglez la version d’artefact ou de source attendue ;
- vérifiez un digest cryptographique ou une signature approuvée avant exécution ;
- définissez des délais de connexion et totaux ;
- échouez fermé si la vérification échoue ; et
- évitez de journaliser identifiants ou URL signées.
Pour un comportement vraiment hors ligne ou reproductible, incluez du contenu revu dans l’image ou un dépôt de paquets approuvé plutôt que de télécharger au first boot.
Secrets
N’intégrez jamais d’identifiants en clair dans la recette, la commande, l’URL ou le marqueur généré. Le JSON de recette et les journaux de build sont des preuves conservées et peuvent être visibles aux opérateurs. Utilisez un mécanisme d’enrollment ou de livraison de secret approuvé au moment du déploiement et limitez l’identifiant résultant à la cible.
Identité d’exécution
Préférez un compte de service non privilégié. Si root est requis, réduisez la commande à la plus petite étape privilégiée et définissez la propriété explicite des fichiers. Confirmez que run_as nomme un compte créé avant le démarrage de l’unité.
Vérification
Testez les résultats plutôt que seulement le code de sortie de l’unité :
{
"type": "file_contains",
"description": "The startup unit wrote its readiness marker.",
"params": {
"path": "/var/lib/example/build-ready",
"content": "ready"
}
}Testez aussi un second boot, une dépendance indisponible et la reprise après un premier run interrompu. Inspectez systemctl status et le journal de l’unité en cas d’échec.