Ce document décrit les condensés d'images, ce qu'ils sont, comment les trouver et comment les utiliser dans des clusters Kubernetes. Ce document est destiné aux développeurs et aux opérateurs qui créent et déploient des images de conteneurs.
Un condensé d'image de conteneur permet d'identifier de manière unique et immuable une image de conteneur. Lorsque vous déployez des images par condensé, vous évitez les inconvénients des déploiements par tags d'image.
Les commandes de ce document supposent que vous avez accès à un environnement shell
Linux ou macOS avec des outils déjà installés
tels que
Google Cloud CLI,
Docker, cURL,
jq
,
et
pack
. Vous pouvez également utiliser
Cloud Shell,
sur lequel ces outils sont
préinstallés.
Images de conteneur et tags d'image
Lorsque vous travaillez avec des images de conteneur, vous avez besoin d'un moyen de faire référence aux images que
vous utilisez.
Les tags d'image constituent un moyen courant de faire référence à différentes révisions d'une image. Une approche courante consiste à ajouter des tags aux images avec un identifiant de version pendant la durée de la compilation. Par exemple, v1.0.1
peut faire référence à une version que vous appelez 1.0.1
.
Les tags facilitent la recherche de révisions d'images par des chaînes lisibles. Cependant, les tags sont des références modifiables, ce qui signifie que l'image référencée par un tag peut changer, comme illustré dans le schéma suivant :
Comme le montre le schéma précédent, si vous publiez une nouvelle image en utilisant le même tag que celui d'une image existante, la balise cesse de pointer vers l'image existante et commence à pointer vers la nouvelle image.
Inconvénients des tags d'image
Étant donné que les tags sont modifiables, ils présentent les inconvénients suivants lorsque vous les utilisez pour déployer une image :
Dans Kubernetes, le déploiement par tag peut générer des résultats inattendus. Par exemple, supposons que vous disposiez d'une ressource de déploiement existante qui fait référence à une image de conteneur avec le tag
v1.0.1
. Pour corriger un bug ou apporter une légère modification, votre processus de compilation crée une image avec le même tagv1.0.1
. Les nouveaux pods créés à partir de votre ressource de déploiement peuvent aboutir à l'aide de l'ancienne ou de la nouvelle image, même si vous ne modifiez pas votre spécification de ressource de déploiement. Ce problème s'applique également à d'autres ressources Kubernetes telles que les StatefulSets, les objets DaemonSets, les ReplicaSets et les tâches.Si vous utilisez des outils pour scanner ou analyser des images, les résultats de ces outils ne sont valides que pour l'image scannée. Pour garantir que vous déployez l'image scannée, vous ne pouvez pas compter sur le tag, car l'image référencée par le tag peut avoir changé.
Si vous utilisez l'autorisation binaire avec Google Kubernetes Engine (GKE), le déploiement basé sur des tags n'est pas autorisé, car il est impossible de déterminer l'image exacte utilisée lors de la création d'un pod.
Lorsque vous déployez vos images, vous pouvez utiliser un condensé d'image pour éviter les inconvénients liés à l'utilisation de tags. Vous pouvez ajouter des tags à vos images si vous le souhaitez, mais ce n'est pas obligatoire.
Structure d'une image
Une image comprend les composants suivants :
- Un fichier manifeste d'image
- Un objet de configuration
- Un tableau d'une ou de plusieurs couches de système de fichiers
- Un index d'images facultatif
Ces composants sont illustrés dans le schéma suivant :
L'image précédente montre des détails supplémentaires sur les composants de l'image :
- Le fichier manifeste d'image est un document JSON qui contient une référence à l'objet de configuration, les couches de système de fichiers et des métadonnées facultatives.
- Le fichier manifeste de l'image fait référence à l'objet de configuration et à chacune des
couches de système de fichiers à l'aide de leurs attributs
digest
. La valeur d'un attributdigest
est un hachage cryptographique du contenu auquel le condensé fait référence, généralement calculé à l'aide de l'algorithme SHA-256. - Les valeurs du condensé permettent de construire des adresses immuables pour les objets. Ce processus est appelé stockage adressable par le contenu et permet de récupérer des fichiers manifestes d'images, des index d'images, des objets de configuration et des calques en fonction de leurs condensés.
- Le condensé d'image est le hachage de l'index d'image ou du document JSON dd fichier manifeste de l'image.
- L'objet de configuration est un document JSON qui définit les propriétés de l'image, telles que l'architecture du processeur, le point d'entrée, les ports exposés et les variables d'environnement.
- Le tableau de couches de système de fichiers définit l'ordre dans lequel l'environnement d'exécution
des conteneurs utilise les couches. Les couches sont distribuées sous forme de fichiers tar, généralement compressés à l'aide de l'utilitaire
gzip
. - L'index d'images facultatif, parfois appelé
liste de fichiers manifestes,
fait référence à un ou plusieurs fichiers manifestes d'images. La référence est le condensé du
fichier manifeste de l'image. Un index d'images est utile lorsque vous produisez plusieurs images associées
pour différentes
plates-formes,
telles que les architectures
amd64
etarm64
.
Pour en savoir plus, consultez la section Explorer les fichiers manifestes, les condensés et les tags d'images.
Rechercher des condensés d'images
Pour utiliser des condensés d'images en vue du déploiement, vous devez d'abord trouver le condensé. Vous pouvez ensuite utiliser le condensé avec votre commande de déploiement ou l'inclure dans vos fichiers manifestes Kubernetes.
Vous pouvez obtenir le condensé d'une image de différentes manières, en fonction de votre situation actuelle. Les sections suivantes contiennent des exemples pour différents produits et outils.
Dans les sections suivantes, exécutez les commandes dans Cloud Shell ou dans un environnement shell à l'aide d'outils déjà installés tels que gcloud CLI, Docker, cURL et jq
.
Artifact Registry
Pour les images stockées dans Artifact Registry, vous pouvez exécuter la commande
gcloud artifacts docker images describe
.gcloud artifacts docker images describe \ LOCATION-docker.pkg.dev/PROJECT/REPOSITORY/IMAGE:TAG \ --format 'value(image_summary.digest)'
Remplacez les éléments suivants :
LOCATION
: l'emplacement régional ou multirégional de votre dépôtPROJECT
: ID de votre projet Google CloudREPOSITORY
: nom de votre dépôtIMAGE
: nom de votre imageTAG
: tag de votre image
Container Registry
Pour les images stockées dans Container Registry, vous pouvez utiliser la commande
gcloud container images describe
pour obtenir le condensé d'une image en indiquant le nom et un tag. Utilisez l'option--format
pour n'afficher que le condensé :gcloud container images describe \ gcr.io/google-containers/pause-amd64:3.2 \ --format 'value(image_summary.digest)'
Le résultat ressemble à ce qui suit, bien que la valeur de votre condensé puisse être différente :
sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
Cloud Build
Pour les images compilées à l'aide de Cloud Build, vous pouvez obtenir le condensé de l'image à l'aide de la commande gcloud builds describe
avec l'option --format
. Cette approche fonctionne quel que soit le registre
que vous avez utilisé pour publier votre image.
Pour une compilation terminée, procédez comme suit :
Obtenez une liste des builds de votre projet :
gcloud builds list
Notez le
BUILD_ID
.Obtenez le condensé de l'image :
gcloud builds describe BUILD_ID \ --format 'value(results.images[0].digest)'
Remplacez
BUILD_ID
par l'ID unique que Cloud Build a attribué à votre compilation.
Obtenez le nom et le condensé de l'image pour la dernière compilation de Cloud Build pour votre projet actuel :
gcloud builds describe \ $(gcloud builds list --limit 1 --format 'value(id)') \ --format 'value[separator="@"](results.images[0].name,results.images[0].digest)'
Si votre compilation a produit plusieurs images, filtrez le résultat et obtenez le condensé de l'une des images :
gcloud builds describe BUILD_ID --format json \ | jq -r '.results.images[] | select(.name=="YOUR_IMAGE_NAME") | .digest'
Remplacez
YOUR_IMAGE_NAME
par le nom de l'une des images de votre fichiercloudbuild.yaml
.Si vous envoyez une compilation à Cloud Build à l'aide de la commande
gcloud builds submit
, vous pouvez capturer le condensé de l'image à partir du résultat dans une variable d'environnement :IMAGE_DIGEST=$(gcloud builds submit \ --format 'value(results.images[0].digest)' | tail -n1)
Packs de création cloud natifs
Si vous utilisez des packs de création cloud natifs et le compilateur Google Cloud pour créer et publier des images, vous pouvez capturer le nom et le condensé de l'image à l'aide de l'option
--quiet
avec la commandepack
:pack build --builder gcr.io/buildpacks/builder:v1 --publish --quiet \ LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE \ > image-with-digest.txt
Remplacez les éléments suivants :
LOCATION
: l'emplacement régional ou multirégional de votre dépôtPROJECT_ID
: ID de votre projet Google CloudREPOSITORY
: nom de votre dépôtIMAGE
: nom de votre image
Le fichier
image-with-digest.txt
contient le nom et le condensé de l'image.Utilisez l'option
--tag
si vous souhaitez ajouter des tags à l'image.
Client Docker
La sous-commande
manifest
du client de ligne de commandedocker
peut récupérer les fichiers manifestes d'images et les listes de manifestes à partir de registres d'images de conteneurs.Obtenez le condensé à partir de la liste de manifestes de l'image
registry.k8s.io/pause:3.9
, pour l'architecture de processeuramd64
et pour le système d'exploitationlinux
:docker manifest inspect --verbose registry.k8s.io/pause:3.9 | \ jq -r 'if type=="object" then .Descriptor.digest else .[] | select(.Descriptor.platform.architecture=="amd64" and .Descriptor.platform.os=="linux") | .Descriptor.digest end'
La sortie ressemble à ceci :
sha256:8d4106c88ec0bd28001e34c975d65175d994072d65341f62a8ab0754b0fafe10
Pour les images qui sont stockées dans votre daemon Docker local et qui ont été extraites ou transférées vers un registre d'images, vous pouvez utiliser l'outil de ligne de commande Docker pour obtenir le condensé de l'image :
Extrayez l'image sur votre daemon Docker local :
docker pull docker.io/library/debian:bookworm
Obtenez le condensé de l'image :
docker inspect docker.io/library/debian:bookworm \ | jq -r '.[0].RepoDigests[0]' \ | cut -d'@' -f2
Le résultat ressemble à ce qui suit, bien que la valeur de votre condensé puisse être différente :
sha256:3d868b5eb908155f3784317b3dda2941df87bbbbaa4608f84881de66d9bb297b
Répertoriez toutes les images et tous les condensés dans votre daemon Docker local :
docker images --digests
Le résultat affiche des condensés des images ayant une valeur de condensé. Les images n'ont une valeur de condensé que si elles ont été extraites d'un registre d'images ou transférées dans ce dernier.
crane
et gcrane
Vous pouvez utiliser les outils de ligne de commande crane
et gcrane
en Open Source pour obtenir le condensé d'une image sans l'extraire d'un daemon Docker local.
Téléchargez
crane
etgcrane
dans votre répertoire actuel :VERSION=$(curl -sL https://api.github.com/repos/google/go-containerregistry/releases/latest | jq -r .tag_name) curl -L "https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_$(uname -s)_$(uname -m).tar.gz" | tar -zxf - crane gcrane
Obtenez des condensés d'images :
./gcrane digest gcr.io/distroless/static-debian11:nonroot
crane
etgcrane
disposent d'autres fonctionnalités qui sortent du cadre de ce document. Pour en savoir plus, consultez la documentation concernantcrane
etgcrane
.
Imposer l'utilisation des condensés d'images dans les déploiements Kubernetes
Si vous souhaitez imposer l'utilisation de condensés pour les images que vous déployez sur vos clusters Kubernetes, vous pouvez utiliser Policy Controller ou Open Policy Agent (OPA) Gatekeeper. Policy Controller est conçu à partir du projet Open Source OPA Gatekeeper.
Policy Controller et OPA Gatekeeper s'appuient tous deux sur le moteur de règles OPA. Policy Controller et OPA Gatekeeper fournissent un webhook d'admission de validation Kubernetes pour appliquer les règles, ainsi que des définitions de ressources personnalisées (CRD) pour les modèles de contraintes et les contraintes.
Les modèles de contrainte contiennent une logique de règles exprimée à l'aide d'un langage déclaratif de haut niveau appelé Rego. Vous trouverez ci-dessous un modèle de contrainte qui valide le fait que les conteneurs, les conteneurs d'initialisation et les conteneurs éphémères dans une spécification de ressource Kubernetes utilisent des images avec des condensés :
La stratégie précédente contient une expression régulière en tant qu'entrée de la
fonction re_match
.
Cette expression régulière correspond au condensé d'image du conteneur. Elle est basée sur
le
format récapitulatif de la spécification d'image Open Container Initiative.
Les contraintes appliquent la stratégie aux ressources Kubernetes en fonction des
attributs tels que kind
et namespace
. L'exemple de contrainte suivant
applique la stratégie du modèle de contrainte à toutes les ressources Pod
de
l'espace de noms default
.
Après avoir créé le modèle de contrainte et la contrainte, tous les nouveaux pods dans l'espace de noms default
doivent utiliser des condensés d'images pour référencer les images de conteneurs.
Pour obtenir l'exemple complet, reportez-vous à la règle imagedigests
de la bibliothèque de règles Gatekeeper.
À propos des fichiers manifestes, des condensés et des tags d'images
Dans cette section, vous allez apprendre à explorer les images existantes dans les registres à l'aide d'outils de ligne de commande tels que curl
et docker
. Exécutez les commandes dans Cloud Shell ou dans un environnement shell à l'aide d'outils déjà installés, tels que gcloud CLI, Docker, cURL et jq
. Les commandes suivantes utilisent des images publiques dans
Artifact Registry.
Obtenez le fichier manifeste de l'image
gcr.io/google-containers/pause-amd64:3.2
à l'aide de cURL et de l'URL du fichier manifeste :curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2
Le résultat ressemble à ce qui suit :
{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 759, "digest": "sha256:80d28bedfe5dec59da9ebf8e6260224ac9008ab5c11dbbe16ee3ba3e4439ac2c" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 296534, "digest": "sha256:c74f8866df097496217c9f15efe8f8d3db05d19d678a02d01cc7eaed520bb136" } ] }
La section
config
comporte un attribut de condensé, qui vous permet de récupérer l'objet de configuration. De même, chaque couche possède un attributdigest
que vous pouvez utiliser pour récupérer le fichier tar de cette couche.Si l'image inclut l'index facultatif, une requête HTTP
GET
adressée à l'URL du fichier manifeste à l'aide d'un tag renvoie l'index d'image à la place du fichier manifeste de l'image.Obtenez l'index de l'image
gcr.io/google-containers/pause:3.2
:curl -s https://gcr.io/v2/google-containers/pause/manifests/3.2
Le résultat ressemble à ce qui suit :
{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:bbb7780ca6592cfc98e601f2a5e94bbf748a232f9116518643905aa30fc01642", "platform": { "architecture": "arm", "os": "linux", "variant": "v7" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:31d3efd12022ffeffb3146bc10ae8beb890c80ed2f07363515580add7ed47636", "platform": { "architecture": "arm64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:7f82fecd72730a6aeb70713476fb6f7545ed1bbf32cadd7414a77d25e235aaca", "platform": { "architecture": "ppc64le", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:1175fd4d728641115e2802be80abab108b8d9306442ce35425a4e8707ca60521", "platform": { "architecture": "s390x", "os": "linux" } } ] }
Filtrez le résultat pour extraire le condensé d'image de la plate-forme de votre choix. Obtenez le condensé du fichier manifeste de l'image pour l'architecture du processeur
amd64
et pour le système d'exploitationlinux
:curl -s https://gcr.io/v2/google-containers/pause/manifests/3.2 | \ jq -r '.manifests[] | select(.platform.architecture=="amd64" and .platform.os=="linux") | .digest'
Le filtrage de cette commande imite la manière dont les environnements d'exécution de conteneur, tels que containerd, sélectionnent l'image correspondant à la plate-forme cible de l'index d'image.
Le résultat ressemble à ce qui suit :
sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
Le condensé de l'image est le résultat de l'application d'un hachage anticollision à l'index de l'image ou au fichier manifeste de l'image, généralement l'algorithme SHA-256.
Obtenez le condensé de l'image
gcr.io/google-containers/pause-amd64:3.2
:curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | shasum -a 256 \ | cut -d' ' -f1
Le résultat ressemble à ce qui suit :
4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
Pour référencer cette image, utilisez la valeur du condensé de l'image comme suit :
gcr.io/google-containers/pause-amd64@sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
À l'aide du concept de stockage adressable par le contenu, obtenez le fichier manifeste de l'image en utilisant le condensé comme référence :
curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
De nombreux registres d'images de conteneurs renvoient le condensé des fichiers manifestes, des index d'images, des objets de configuration et des couches de système de fichiers dans l'en-tête
Docker-Content-Digest
en réponse aux requêtes HTTPHEAD
. Obtenez le condensé de l'index de l'imagegcr.io/google-containers/pause-amd64:3.2
:curl -s --head https://gcr.io/v2/google-containers/pause/manifests/3.2 \ | grep -i Docker-Content-Digest \ | cut -d' ' -f2
Le résultat ressemble à ce qui suit :
sha256:927d98197ec1141a368550822d18fa1c60bdae27b78b0c004f705f548c07814f
L'en-tête
Docker-Content-Digest
n'est pas imposé par les spécifications d'Open Container Initiative Distribution. Il est donc possible que cette approche ne fonctionne pas avec tous les registres d'images de conteneurs. Vous pouvez l'utiliser avec Artifact Registry et Container Registry.Pour récupérer un objet de configuration d'image à l'aide de la valeur de condensé depuis le fichier manifeste de l'image, procédez comme suit :
Obtenez le condensé de la configuration :
CONFIG_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | jq -r '.config.digest')
Utilisez le condensé de configuration pour récupérer l'objet de configuration et utilisez
jq
pour formater le résultat pour faciliter la lecture :curl -sL https://gcr.io/v2/google-containers/pause-amd64/blobs/$CONFIG_DIGEST \ | jq
Le résultat ressemble à ce qui suit :
{ "architecture": "amd64", "config": { "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Entrypoint": [ "/pause" ], "WorkingDir": "/", "OnBuild": null }, "created": "2020-02-14T10:51:50.60182885-08:00", "history": [ { "created": "2020-02-14T10:51:50.60182885-08:00", "created_by": "ARG ARCH", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2020-02-14T10:51:50.60182885-08:00", "created_by": "ADD bin/pause-amd64 /pause # buildkit", "comment": "buildkit.dockerfile.v0" }, { "created": "2020-02-14T10:51:50.60182885-08:00", "created_by": "ENTRYPOINT [\"/pause\"]", "comment": "buildkit.dockerfile.v0", "empty_layer": true } ], "os": "linux", "rootfs": { "type": "layers", "diff_ids": [ "sha256:ba0dae6243cc9fa2890df40a625721fdbea5c94ca6da897acdd814d710149770" ] } }
Pour récupérer les couches du système de fichiers à l'aide de valeurs de condensé du fichier manifeste d'image, procédez comme suit :
Obtenez le condensé de la couche que vous souhaitez récupérer :
LAYER_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | jq -r '.layers[0].digest')
Utilisez le condensé de la couche pour récupérer le fichier tar de la couche et répertorier son contenu :
curl -sL https://gcr.io/v2/google-containers/pause-amd64/blobs/$LAYER_DIGEST \ | tar --list
Cette couche contient un seul fichier, appelé
pause
.
Pour rechercher les tags associés à un condensé d'image, procédez comme suit :
Définissez le condensé que vous souhaitez rechercher :
IMAGE_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | shasum -a 256 \ | cut -d' ' -f1)
La variable d'environnement
IMAGE_DIGEST
contient le condensé de l'image référencée par le tag3.2
.Utilisez le point de terminaison de la liste des tags d'image,
/tags/list
, pour répertorier les informations sur les tags, puis extrayez les tags pour la valeur de condensé :curl -s "https://gcr.io/v2/google-containers/pause-amd64/tags/list?n=1" \ | jq ".manifest.\"sha256:$IMAGE_DIGEST\".tag"
Le résultat ressemble à ce qui suit :
[ "3.2" ]
Pour obtenir le fichier manifeste d'une image à partir d'un dépôt d'images de conteneurs Artifact Registry à l'aide de cURL, incluez un jeton d'accès dans l'en-tête de requête
Authorization
:curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \ https://LOCATION-docker.pkg.dev/v2/PROJECT_ID/REPOSITORY/IMAGE/manifests/DIGEST
Remplacez les éléments suivants :
LOCATION
: l'emplacement régional ou multirégional de votre dépôtPROJECT_ID
: ID de votre projet Google CloudREPOSITORY
: nom de votre dépôtIMAGE
: nom de votre imageDIGEST
: le condensé de votre image au formatsha256:DIGEST_VALUE
Étapes suivantes
- Découvrez les bonnes pratiques à suivre pour créer des conteneurs.
- Découvrez les bonnes pratiques pour l'exploitation de conteneurs.
- Pour en savoir plus sur les images, consultez les spécifications Open Container Initiative relatives au format d'image et à la distribution.