Container Structure Test valide automatiquement la structure de vos images Docker : présence des fichiers, permissions, variables d’environnement et commandes. Développé par GoogleContainerTools, cet outil s’intègre dans vos pipelines CI/CD pour détecter les erreurs de configuration avant le déploiement. Contrairement à Hadolint qui analyse le Dockerfile, Container Structure Test teste l’image après sa construction pour vérifier son contenu réel.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Installer Container Structure Test (v1.22.1) sur Linux ou macOS
- Écrire des tests YAML pour valider métadonnées, fichiers et commandes
- Exécuter les tests et interpréter les résultats
- Intégrer dans CI/CD (GitHub Actions, GitLab CI)
- Générer des rapports JUnit pour vos pipelines
Pourquoi tester une image de conteneur ?
Section intitulée « Pourquoi tester une image de conteneur ? »Une image de conteneur peut sembler correcte après son build, mais contient-elle les bons fichiers ? Les bonnes permissions ? Les bonnes configurations ?
Vérifier la conformité aux bonnes pratiques
Section intitulée « Vérifier la conformité aux bonnes pratiques »Une image doit respecter certaines bonnes pratiques pour garantir sa maintenabilité et sa performance :
- Éviter les images trop volumineuses : une image légère réduit les temps de build et de déploiement.
- Utiliser un utilisateur non-root : exécuter des conteneurs avec un utilisateur privilégié est une faille de sécurité.
- Limiter les permissions sur les fichiers sensibles : éviter qu’un fichier critique ne soit modifiable par accident.
- S’assurer de la présence des fichiers requis : un conteneur doit contenir les fichiers et dépendances nécessaires à son bon fonctionnement.
Avec Container Structure Test, je peux écrire des tests automatisés pour vérifier que mon image respecte certaines de ces règles.
Détecter les erreurs avant le déploiement
Section intitulée « Détecter les erreurs avant le déploiement »Un conteneur mal conçu peut causer des erreurs imprévues en production :
- Une dépendance manquante empêche l’application de démarrer.
- Une variable d’environnement critique est absente.
- Une configuration par défaut est mal définie.
- Une mise à jour d’un package introduit une régression.
Avec des tests de structure, je peux détecter ces problèmes avant même de lancer un conteneur, évitant ainsi des déploiements défectueux.
Renforcer la sécurité des images Docker
Section intitulée « Renforcer la sécurité des images Docker »Un conteneur peut contenir des fichiers sensibles (clés API, certificats, variables d’environnement) qui ne devraient jamais être accessibles publiquement. De plus, certaines configurations non sécurisées peuvent exposer mon application à des attaques :
- Ports inutiles ouverts
- Permissions trop larges sur les fichiers
- Exécution en tant que root
En testant mon image avec Container Structure Test, je peux vérifier automatiquement ces points et éviter les mauvaises surprises en production.
Assurer la reproductibilité des builds
Section intitulée « Assurer la reproductibilité des builds »Dans un pipeline CI/CD, les builds doivent être reproductibles. Si une modification dans le Dockerfile ou un package cassé change le comportement de mon image, je veux le détecter immédiatement. Un test de structure permet de s’assurer que :
- L’image contient toujours les bonnes dépendances.
- Les commandes essentielles fonctionnent correctement.
- Les variables d’environnement attendues sont présentes.
Ainsi, en intégrant Container Structure Test dans mon workflow, je m’assure que mon image fonctionne de manière identique d’un environnement à l’autre.
Présentation de Container Structure Test
Section intitulée « Présentation de Container Structure Test »Container Structure Test est un outil développé par GoogleContainerTools permettant de tester la structure des images Docker. Il me permet de m’assurer que mes images sont correctes, sécurisées et conformes aux bonnes pratiques, en validant plusieurs aspects comme :
- Les métadonnées de l’image (labels, user, entrypoint…)
- Les fichiers présents dans l’image (permissions, existence, contenu…)
- Les variables d’environnement
- L’exécution de commandes à l’intérieur du conteneur
Contrairement à un simple linting de Dockerfile comme Hadolint, Container Structure Test teste l’image une fois qu’elle est construite, ce qui me permet de vérifier réellement son contenu et son comportement.
Fonctionnement
Section intitulée « Fonctionnement »L’outil fonctionne à partir d’un fichier de test écrit en YAML. Ce fichier contient des règles définissant les tests que je veux exécuter. Ensuite, j’utilise Container Structure Test pour :
- Charger mon image Docker (locale ou depuis un registre)
- Exécuter les tests définis
- Fournir un rapport détaillé des résultats
Installation et configuration de Container Structure Test
Section intitulée « Installation et configuration de Container Structure Test »Avant de pouvoir tester mes images Docker, je dois d’abord installer Container Structure Test sur mon système. Cet outil est disponible sous forme de binaire précompilé, ce qui simplifie son installation.
Prérequis :
Avant d’installer Container Structure Test, je dois m’assurer que :
- Un runtime de container est installé et fonctionne sur ma machine
- J’ai un accès à un terminal (Linux/macOS) ou PowerShell (Windows)
Installation de container-structure-test
Section intitulée « Installation de container-structure-test »Téléchargez le binaire v1.22.1 :
curl -sLO https://github.com/GoogleContainerTools/container-structure-test/releases/download/v1.22.1/container-structure-test-linux-amd64chmod +x container-structure-test-linux-amd64sudo mv container-structure-test-linux-amd64 /usr/local/bin/container-structure-testcurl -sLO https://github.com/GoogleContainerTools/container-structure-test/releases/download/v1.22.1/container-structure-test-darwin-amd64chmod +x container-structure-test-darwin-amd64sudo mv container-structure-test-darwin-amd64 /usr/local/bin/container-structure-testcurl -sLO https://github.com/GoogleContainerTools/container-structure-test/releases/download/v1.22.1/container-structure-test-darwin-arm64chmod +x container-structure-test-darwin-arm64sudo mv container-structure-test-darwin-arm64 /usr/local/bin/container-structure-testOu via Homebrew :
brew install container-structure-testVous pouvez aussi utiliser l’image officielle :
docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v $(pwd):/workspace \ gcr.io/gcp-runtimes/container-structure-test:v1.22.1 \ test --image alpine:3.21 --config /workspace/test.yamlVérification de l’installation
Section intitulée « Vérification de l’installation »container-structure-test versionv1.22.1Rédiger un test pour une image
Section intitulée « Rédiger un test pour une image »Maintenant que Container Structure Test est installé, je vais apprendre à écrire un fichier de test pour analyser la structure de mon image Docker. L’outil utilise un fichier YAML dans lequel je peux définir différents types de tests.
Structure d’un fichier de test
Section intitulée « Structure d’un fichier de test »Un fichier Container Structure Test suit une structure simple en YAML. Il est structuré en plusieurs sections, chacune définissant un type de test spécifique. Voici un exemple de fichier de test complet :
schemaVersion: '2.0.0'
metadataTest: env: - key: "NODE_ENV" value: "production" labels: - key: "maintainer" value: "devops@example.com" exposedPorts: ["8080", "2345"] volumes: ["/test"] entrypoint: [] cmd: ["/bin/bash"] workdir: "/app" user: "bob"
fileExistenceTests: - name: "Vérifier la présence du fichier entrypoint" path: "/app/entrypoint.sh" shouldExist: true permissions: "-rwxr-xr-x"
fileContentTests: - name: "Vérifier la configuration du serveur" path: "/etc/nginx/nginx.conf" expectedContents: - "worker_processes auto;" - "include /etc/nginx/sites-enabled/*;"
commandTests: - name: "Vérifier la version de Node.js" command: "node" args: ["--version"] expectedOutput: ["v16.13.0"] exitCode: 0 setup: [["apt-get", "update"], ["apt-get", "install", "-y", "nodejs"]] teardown: [["apt-get", "remove", "-y", "nodejs"]]Je vais maintenant détailler les types de tests disponibles.
Tests de métadonnées
Section intitulée « Tests de métadonnées »metadataTest: env: - key: "NODE_ENV" value: "production" labels: - key: "maintainer" value: "devops@example.com" exposedPorts: ["8080", "2345"] volumes: ["/test"] entrypoint: [] cmd: ["/bin/bash"] workdir: "/app" user: "bob"Cet exemple définit un test de métadonnées pour une image Docker à l’aide de Container Structure Test. Il vérifie plusieurs aspects clés du conteneur, notamment les variables d’environnement, les labels, les ports exposés, les volumes, le point d’entrée, la commande par défaut, le répertoire de travail et l’utilisateur.
Variables d’environnement
Section intitulée « Variables d’environnement »envVars: - key: foo value: bazCe test vérifie que la variable d’environnement foo est bien définie à baz dans l’image Docker.
Labels de l’image
Section intitulée « Labels de l’image »labels: - key: 'com.example.vendor' value: 'ACME Incorporated' - key: 'build-date' value: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}$' isRegex: true- Le label com.example.vendor doit être défini avec la valeur ACME Incorporated.
- Le label build-date doit correspondre à un format de date ISO 8601
précis (AAAA-MM-JJTHH:MM:SS.ssssss). L’option
isRegex: trueindique que la valeur est une expression régulière, permettant de vérifier un format plutôt qu’une valeur exacte.
Ports exposés
Section intitulée « Ports exposés »exposedPorts: ["8080", "2345"]Ce test vérifie que l’image expose bien les ports 8080 et 2345.
Volumes déclarés
Section intitulée « Volumes déclarés »volumes: ["/test"]L’image doit déclarer un volume montable à l’emplacement /test.
Point d’entrée (ENTRYPOINT)
Section intitulée « Point d’entrée (ENTRYPOINT) »entrypoint: []Ce test s’assure que l’image n’a pas de point d’entrée défini (ENTRYPOINT
est vide dans le Dockerfile).
Commande par défaut (CMD)
Section intitulée « Commande par défaut (CMD) »cmd: ["/bin/bash"]L’image doit exécuter /bin/bash par défaut si aucune autre commande n’est
spécifiée lors du lancement du conteneur.
Répertoire de travail (WORKDIR)
Section intitulée « Répertoire de travail (WORKDIR) »workdir: "/app"Ce test vérifie que le répertoire de travail par défaut de l’image est bien /app.
Utilisateur par défaut
Section intitulée « Utilisateur par défaut »user: "bob"L’image doit être exécutée sous l’utilisateur bob et non sous root.
Tests de présence de fichiers (fileExistenceTests)
Section intitulée « Tests de présence de fichiers (fileExistenceTests) »Exemple :
fileExistenceTests: - name: "Vérifier la présence du fichier entrypoint" path: "/app/entrypoint.sh" shouldExist: true permissions: "-rwxr-xr-x"Explication :
- name : Nom du test (facultatif, mais recommandé pour identifier facilement les tests).
- path : Chemin absolu du fichier ou répertoire à tester dans l’image.
- shouldExist : Si
true, le fichier doit être présent. Sifalse, il ne doit pas exister. - permissions : Vérifie les permissions du fichier sous format Unix
(
rwxpour lecture/écriture/exécution).
Pourquoi c’est utile ?
Ce type de test garantit que les fichiers critiques sont bien présents dans l’image (comme un script d’entrée ou un fichier de configuration). Il permet aussi de s’assurer que des fichiers sensibles ne sont pas accidentellement inclus.
Tests de contenu de fichiers (fileContentTests)**
Section intitulée « Tests de contenu de fichiers (fileContentTests)** »Exemple :
fileContentTests: - name: "Vérifier la configuration du serveur" path: "/etc/nginx/nginx.conf" expectedContents: - "worker_processes auto;" - "include /etc/nginx/sites-enabled/*;" excludedContents: - "server_tokens on;"Explication :
- path : Chemin du fichier à analyser.
- expectedContents : Liste des chaînes de texte qui doivent être présentes dans le fichier.
- excludedContents : Liste des chaînes qui ne doivent pas apparaître dans le fichier.
Pourquoi c’est utile ?
Je peux vérifier que les bons paramètres sont bien configurés dans mes
fichiers de configuration et qu’aucune directive dangereuse (comme
server_tokens on; en Nginx) n’est présente.
Tests d’exécution de commandes (commandTests)
Section intitulée « Tests d’exécution de commandes (commandTests) »Exemple :
commandTests: - name: "Vérifier la version de Node.js" setup: [["apt-get", "update"], ["apt-get", "install", "-y", "nodejs"]] command: "node" args: ["--version"] expectedOutput: ["v16.13.0"] excludedOutput: ["v14.*"] exitCode: 0 teardown: [["apt-get", "remove", "-y", "nodejs"]]Explication :
- setup : Commandes à exécuter avant le test (exemple : installation de Node.js).
- command : Commande principale à exécuter.
- args : Arguments à passer à la commande.
- expectedOutput : Liste des sorties attendues.
- excludedOutput : Liste des sorties interdites.
- exitCode : Code de sortie attendu (
0pour succès, autre valeur pour une erreur). - teardown : Commandes exécutées après le test (exemple : suppression de Node.js).
Pourquoi c’est utile ?
Je peux m’assurer que les logiciels installés dans l’image fonctionnent correctement et retournent la bonne version. Ce test est aussi utile pour vérifier qu’une commande critique ne produit pas d’erreurs.
Tests de licences (licenseTests)
Section intitulée « Tests de licences (licenseTests) »Exemple :
licenseTests: - debian: true files: ["/foo/bar", "/baz/bat"]Explication :
- debian : Si
true, vérifie la liste des licences fournies par Debian. - files : Liste de fichiers contenant des informations de licence à vérifier.
Pourquoi c’est utile ? Ce test garantit que toutes les licences présentes dans l’image sont autorisées et conformes aux exigences de l’organisation. Il est particulièrement utile pour s’assurer qu’aucune licence non conforme n’est introduite par des paquets tiers.
Variables d’environnement globales (globalEnvVars)
Section intitulée « Variables d’environnement globales (globalEnvVars) »Exemple :
globalEnvVars: - key: "VIRTUAL_ENV" value: "/env" - key: "PATH" value: "/env/bin:$PATH"Explication :
- Définit des variables d’environnement qui seront accessibles à tous les tests.
- Substitution Unix (
$PATH) est supportée, ce qui permet d’étendre les valeurs dynamiquement.
Pourquoi c’est utile ? Ce test est particulièrement utile lorsque certaines commandes ou scripts nécessitent des variables d’environnement spécifiques pour fonctionner correctement.
Options supplémentaires pour l’exécution des tests (containerRunOptions)
Section intitulée « Options supplémentaires pour l’exécution des tests (containerRunOptions) »Ces options permettent d’ajouter des paramètres spécifiques au conteneur de test, comme le choix de l’utilisateur, le montage de volumes, ou l’ajout de capacités Linux.
Exemple :
containerRunOptions: user: "root" # Exécuter le conteneur en tant que root privileged: true # Activer le mode privilégié (désactivé par défaut) allocateTty: true # Allouer un pseudo-TTY (équivalent à -t) envFile: path/to/.env # Charger des variables d’environnement depuis un fichier envVars: # Passer des variables d’environnement spécifiques - SECRET_KEY_FOO - OTHER_SECRET_BAR capabilities: # Ajouter des capacités Linux - NET_BIND_SERVICE bindMounts: # Monter des volumes (équivalent à --volume/-v) - /etc/example/dir:/etc/dirExplication des options :
- user : Définit l’utilisateur sous lequel le test sera exécuté (
root,nobody, etc.). - privileged : Active le mode privilégié (
--privileged), ce qui donne plus de permissions au conteneur. - allocateTty : Permet d’allouer un pseudo-terminal (
-tdans Docker). - envFile : Charge des variables d’environnement à partir d’un fichier
(
--env-file). - envVars : Liste de variables d’environnement à transmettre directement.
- capabilities : Ajoute des capabilités Linux (
--cap-adddans Docker). - bindMounts : Monte des volumes sur des emplacements spécifiques (
-vdans Docker).
Pourquoi c’est utile ?
Ces options sont essentielles lorsque l’image nécessite un environnement spécifique pour être testée correctement. Par exemple, un conteneur qui manipule des fichiers système peut exiger des permissions élevées ou des volumes montés.
Mise en pratique avec une image Docker contenant Bandit
Section intitulée « Mise en pratique avec une image Docker contenant Bandit »Je vais maintenant illustrer Container Structure Test avec un cas concret : tester une image Docker contenant Bandit, un outil permettant d’analyser du code Python à la recherche de failles de sécurité.
J’utilise cette image dans GitLab CI, ce qui signifie qu’elle doit être optimisée, sécurisée et conforme aux bonnes pratiques. Pour cela, j’ai mis en place un Dockerfile multi-stage, qui permet de limiter la taille de l’image finale en copiant uniquement l’environnement virtuel nécessaire.
Dockerfile utilisé :
FROM alpine:3.14.2 as builderENV PYROOT=/venvENV PYTHONUSERBASE=$PYROOTWORKDIR /COPY Pipfile* ./RUN apk update && \ apk add --no-cache bc gcc libffi-dev musl-dev openssl-dev python3-dev py3-pip && \ pip3 install --no-cache-dir --no-compile pipenv && \ pipenv lock && \ PIP_USER=1 pipenv sync --system
FROM alpine:3.14.2 as default
RUN adduser -D user && \ apk add --no-cache py3-pipCOPY --from=builder /venv /venv
# Définition de l’environnementENV PATH="/venv/bin:$PATH"ENV PYTHONPATH="/venv/lib/python3.9/site-packages/"
USER userWORKDIR /srcENTRYPOINT ["bandit", "-r"]CMD ["--version"]Ce Dockerfile :
- Construit l’environnement virtuel dans un premier conteneur (
builder) - Copie uniquement le strict nécessaire dans l’image finale (
default) - Définit les variables d’environnement (
PATH,PYTHONPATH) - Configure l’utilisateur non-root (
user) - Spécifie l’ENTRYPOINT et la CMD
Tests à réaliser :
Avec Container Structure Test, je vais vérifier que mon image est conforme aux attentes :
-
Métadonnées :
PATHdoit contenir /venv/binPYTHONPATHdoit être défini correctement- L’utilisateur doit être
user WORKDIRdoit être/srcENTRYPOINTdoit être["bandit", "-r"]CMDdoit être["--version"]
-
Commandes :
- La commande
bandit --versiondoit retourner la bonne version - La commande
which banditdoit pointer vers /venv/bin/bandit
- La commande
-
Fichiers :
/etc/os-releasedoit contenir la version correcte d’Alpine Linux- Un certificat spécifique ne doit pas être présent dans
/etc/ssl/certs/my-cert.crt
Fichier de test Container Structure Test :
schemaVersion: '2.0.0'
metadataTest: envVars: - key: PATH value: "/venv/bin.*" isRegex: true - key: PYTHONPATH value: "/venv/lib/python3.9/site-packages/" entrypoint: ["bandit", "-r"] cmd: ["--version"] workdir: "/src" user: "user"
commandTests: - name: "bandit version" command: "bandit" args: ["--version"] expectedOutput: ["bandit 1.7.0"] - name: "bandit path" command: "which" args: ["bandit"] expectedOutput: ["/venv/bin/bandit"]
fileExistenceTests: - name: "Certificat" path: "/etc/ssl/certs/my-cert.crt" shouldExist: false
fileContentTests: - name: "Linux Version" path: "/etc/os-release" expectedContents: - "VERSION_ID=3.14.2" - "NAME=\"Alpine Linux\""Explication des tests :
-
Tests de métadonnées
- Vérifie que les variables d’environnement sont bien définies.
- Vérifie le répertoire de travail, l’utilisateur, l’entrée de commande et la commande par défaut.
-
Tests de commandes
bandit --versiondoit afficher bandit 1.7.0.which banditdoit retourner /venv/bin/bandit, garantissant que l’outil est bien installé dans le bon chemin.
-
Tests de fichiers
- Le certificat
/etc/ssl/certs/my-cert.crtne doit pas exister, assurant qu’aucun certificat sensible n’a été embarqué par erreur. - La version du système Alpine Linux doit être correcte, en validant le
contenu de
/etc/os-release.
- Le certificat
Exécution des tests :
Je peux exécuter mes tests avec la commande suivante :
container-structure-test test --image artefacts.robert.local/bandit:1.7.0 --config unit-test.yamlRésultat des tests :
============================================= Test file: unit-test.yaml =============================================
=== RUN: Command Test: bandit version--- PASSduration: 463.749977msstdout: bandit 1.7.0 python version = 3.9.5 (default, May 12 2021, 20:44:22) [GCC 10.3.1 20210424]
=== RUN: Command Test: bandit path--- PASSduration: 325.957628msstdout: /venv/bin/bandit
=== RUN: File Content Test: Linux Version--- PASSduration: 0s
=== RUN: File Existence Test: Certificat--- PASSduration: 0s
=== RUN: Metadata Test--- PASSduration: 0s
====================================================== RESULTS ======================================================Passes: 5Failures: 0Duration: 789.707605msTotal tests: 5
PASSConclusion :
Les tests sont tous passés avec succès, ce qui signifie que l’image Docker est conforme aux attentes.
En intégrant Container Structure Test dans un pipeline CI/CD, je peux valider automatiquement mes images avant leur déploiement. Associé à Trivy (pour l’analyse des vulnérabilités), cet outil permet de garantir que l’image est sécurisée, fiable et optimisée avant d’être utilisée en production.
Intégration dans les pipelines CI/CD
Section intitulée « Intégration dans les pipelines CI/CD »Container Structure Test s’intègre facilement dans vos pipelines CI/CD. Depuis
la version 1.22.0, l’option --output junit génère des rapports au format JUnit
XML, compatibles avec la plupart des plateformes CI.
name: Test Container Image
on: push: branches: [main] pull_request: branches: [main]
jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Build image run: docker build -t my-app:test .
- name: Install container-structure-test run: | curl -sLO https://github.com/GoogleContainerTools/container-structure-test/releases/download/v1.22.1/container-structure-test-linux-amd64 chmod +x container-structure-test-linux-amd64 sudo mv container-structure-test-linux-amd64 /usr/local/bin/container-structure-test
- name: Run structure tests run: | container-structure-test test \ --image my-app:test \ --config tests/structure-test.yaml \ --output junit > test-results.xml
- name: Upload test results uses: actions/upload-artifact@v4 if: always() with: name: test-results path: test-results.xmlstages: - build - test
variables: CST_VERSION: "1.22.1"
build: stage: build image: docker:24-dind services: - docker:24-dind script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
test-structure: stage: test image: docker:24-dind services: - docker:24-dind before_script: - apk add --no-cache curl - curl -sLO https://github.com/GoogleContainerTools/container-structure-test/releases/download/v$\{CST_VERSION\}/container-structure-test-linux-amd64 - chmod +x container-structure-test-linux-amd64 - mv container-structure-test-linux-amd64 /usr/local/bin/container-structure-test script: - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA - container-structure-test test --image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --config tests/structure-test.yaml --output junit > junit-report.xml artifacts: when: always reports: junit: junit-report.xmlOptions de ligne de commande utiles
Section intitulée « Options de ligne de commande utiles »| Option | Description |
|---|---|
--output json | Sortie JSON (machine-readable) |
--output junit | Sortie JUnit XML pour CI/CD |
--test-report FILE | Écrit les résultats dans un fichier |
--save | Sauvegarde le tar de l’image localement |
--pull | Force le pull de l’image depuis le registre |
À retenir
Section intitulée « À retenir »- Container Structure Test valide la structure des images Docker après leur construction, contrairement à Hadolint qui analyse le Dockerfile
- Quatre types de tests : métadonnées, fichiers, contenu de fichiers et commandes
- Le format de sortie JUnit XML (
--output junit) facilite l’intégration CI/CD - Combinez avec Trivy pour une validation complète (structure + vulnérabilités)
- Utilisez un fichier YAML par image ou par famille d’images pour une maintenance facile
Prochaines étapes
Section intitulée « Prochaines étapes »Questions fréquentes
Section intitulée « Questions fréquentes »Hadolint vs Container Structure Test
| Aspect | Hadolint | Container Structure Test |
|---|---|---|
| Phase | Avant build | Après build |
| Analyse | Dockerfile (statique) | Image construite (dynamique) |
| Vérifie | Syntaxe, bonnes pratiques | Fichiers, métadonnées, commandes |
| Trouve | Erreurs de syntaxe | Erreurs de configuration |
Les deux outils sont complémentaires : Hadolint vérifie le "comment" (Dockerfile), Container Structure Test vérifie le "quoi" (image résultante).
Installation Linux
curl -sLO https://github.com/GoogleContainerTools/container-structure-test/releases/download/v1.22.1/container-structure-test-linux-amd64
chmod +x container-structure-test-linux-amd64
sudo mv container-structure-test-linux-amd64 /usr/local/bin/container-structure-test
Vérification :
container-structure-test version
# v1.22.1
Architectures disponibles : linux-amd64, darwin-amd64, darwin-arm64.
Types de tests disponibles
| Type | Vérifie |
|---|---|
metadataTest |
Labels, env, entrypoint, cmd, user, workdir |
fileExistenceTests |
Présence/absence de fichiers, permissions |
fileContentTests |
Contenu des fichiers (patterns attendus/exclus) |
commandTests |
Sortie des commandes, code retour |
Exemple minimal :
schemaVersion: '2.0.0'
fileExistenceTests:
- name: "Config présente"
path: "/app/config.yaml"
shouldExist: true
Test de présence de fichier
schemaVersion: '2.0.0'
fileExistenceTests:
- name: "Entrypoint présent"
path: "/app/entrypoint.sh"
shouldExist: true
permissions: "-rwxr-xr-x"
- name: "Secret absent"
path: "/app/.env.local"
shouldExist: false
Options :
shouldExist: true: le fichier doit existershouldExist: false: le fichier ne doit pas existerpermissions: droits Unix attendus
Test des variables d'environnement
schemaVersion: '2.0.0'
metadataTest:
env:
- key: "NODE_ENV"
value: "production"
- key: "PATH"
value: "/usr/local/bin.*"
isRegex: true
Options :
key: nom de la variablevalue: valeur attendue (exacte ou regex)isRegex: true: interpréter value comme regex
Test de commande
schemaVersion: '2.0.0'
commandTests:
- name: "Version Node.js"
command: "node"
args: ["--version"]
expectedOutput: ["v20."]
exitCode: 0
Options avancées :
commandTests:
- name: "Test complet"
setup: [["apt-get", "update"]]
command: "my-app"
args: ["--check"]
expectedOutput: ["OK"]
excludedOutput: ["ERROR"]
exitCode: 0
teardown: [["rm", "-f", "/tmp/test"]]
GitHub Actions
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t my-app:test .
- name: Install CST
run: |
curl -sLO https://github.com/GoogleContainerTools/container-structure-test/releases/download/v1.22.1/container-structure-test-linux-amd64
chmod +x container-structure-test-linux-amd64
sudo mv container-structure-test-linux-amd64 /usr/local/bin/container-structure-test
- name: Run tests
run: container-structure-test test --image my-app:test --config test.yaml --output junit > results.xml
Rapport JUnit XML
container-structure-test test \
--image my-app:latest \
--config test.yaml \
--output junit > junit-report.xml
Formats disponibles :
| Option | Format |
|---|---|
| (défaut) | Texte lisible |
--output json |
JSON machine-readable |
--output junit |
JUnit XML (v1.22.0+) |
Le format JUnit est reconnu nativement par GitHub, GitLab, Jenkins et Azure DevOps.
Runtime requis
Container Structure Test nécessite un runtime de conteneur pour :
- Charger les images locales ou depuis un registre
- Exécuter les tests de commandes
Options :
- Docker (recommandé)
- Podman
- containerd
Alternative sans runtime :
# Tester une archive tar
container-structure-test test \
--image /path/to/image.tar \
--config test.yaml
Vérification utilisateur non-root
schemaVersion: '2.0.0'
metadataTest:
user: "app"
Bonnes pratiques sécurité :
metadataTest:
user: "app" # Pas root
workdir: "/app" # Répertoire dédié
fileExistenceTests:
- name: "Pas de secrets"
path: "/root/.ssh"
shouldExist: false
Cette vérification est essentielle pour la sécurité des conteneurs en production.