184 lines
4.8 KiB
Markdown
184 lines
4.8 KiB
Markdown
\newpage
|
||
|
||
Registres
|
||
=========
|
||
|
||
Nous allons appréhender le fonctionnement d'un registre OCI, en essayant de
|
||
récupérer les couches de quelques images (Debian, Ubuntu, hello, ...) : dans un
|
||
premier temps en nous préoccupant simplement de la couche la plus basse (qui ne
|
||
contient pas de modification ou de suppression : chaque fichier est normal).
|
||
|
||
|
||
## Authentification
|
||
|
||
L'authentification est facultative et est laissée à l'appréciation du
|
||
fournisseur de service. Étant donné que nous allons utiliser le [Docker
|
||
Hub](https://hub.docker.com/), le registre par défaut de `docker`, nous allons
|
||
devoir nous plier à son mécanisme d'authentification : chaque requête au
|
||
registre doit être effectuée avec un jeton, que l'on obtient en s'authentifiant
|
||
auprès d'un service dédié. Ce service peut délivrer un jeton sans authentifier
|
||
l'interlocuteur, en restant anonyme ; dans ce cas, on ne pourra accéder qu'aux
|
||
images publiques. Ça tombe bien, c'est ce qui nous intéresse !
|
||
|
||
Il n'en reste pas moins que le jeton est forgé pour un service donné (ici
|
||
`registry.docker.io`) et avec un objectif bien cerné (pour nous, on souhaite
|
||
récupérer le contenu du dépôt[^quiddepot] `hello-world` : <span
|
||
lang="en-US">`repository:hello-world:pull`</span>). Ce qui nous donne :
|
||
|
||
[^quiddepot]: Dans un registre, les fichiers qui composent l'image forment un
|
||
dépôt (*repository*).
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
42sh$ curl "https://auth.docker.io/token?service=registry.docker.io&" \
|
||
"scope=repository:library/hello-world:pull" | jq .
|
||
```
|
||
```json
|
||
{
|
||
"token": "lUWXBCZzg2TGNUdmMy...daVZxGTj0eh",
|
||
"access_token": "eyJhbGciOiJSUzI1NiIsI...N5q469M3ZkL_HA",
|
||
"expires_in": 300,
|
||
"issued_at": "2012-12-12T12:12:12.123456789Z"
|
||
}
|
||
```
|
||
</div>
|
||
|
||
C'est le `token` qu'il faudra fournir lors de nos prochaines requêtes au
|
||
registre.
|
||
|
||
Avec `jq`, on peut l'extraire grâce à :
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
| jq -r .token
|
||
```
|
||
</div>
|
||
|
||
::::: {.warning}
|
||
|
||
Le token expire ! Pensez à le renouveler régulièrement.
|
||
|
||
:::::
|
||
|
||
En cas d'erreur inexplicable, vous pouvez ajouter un `-v` à la ligne de
|
||
commande `curl`, afin d'afficher les en-têtes. Prêtez une attention toute
|
||
particulière à `Www-Authenticate`.
|
||
|
||
|
||
## Lecture de l'index d'images
|
||
|
||
Une fois en possession de notre jeton, nous pouvons maintenant demander l'index
|
||
d'images à notre registre :
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
curl -s \
|
||
-H "Authorization: Bearer ${TOKEN}" \
|
||
-H "Accept: application/vnd.docker.distribution.manifest.list.v2+json" \
|
||
"https://registry-1.docker.io/v2/library/hello-world/manifests/latest" | jq .
|
||
```
|
||
</div>
|
||
|
||
Dans la liste des *manifests* retournés, nous devons récupérer son `digest`. Dans
|
||
tout l'écosystème OCI, les `digest` servent à la fois de chemin d'accès et de
|
||
somme de contrôle.
|
||
|
||
|
||
## Lecture du *manifest*
|
||
|
||
Demandons maintenant le *manifest* correspondant à notre matériel et à notre
|
||
système d'exploitation :
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
curl -s \
|
||
-H "Authorization: Bearer ${TOKEN}" \
|
||
-H "Accept: ${MEDIATYPE}" \
|
||
"https://registry-1.docker.io/v2/library/hello-world/manifests/
|
||
${MNFST_DGST}"
|
||
```
|
||
</div>
|
||
|
||
Nous voici donc maintenant avec le *manifest* de notre image. Nous pouvons
|
||
constater qu'il n'a bien qu'une seule couche, ouf !
|
||
|
||
|
||
## Récupération de la configuration et de la première couche
|
||
|
||
Les deux éléments que l'on cherche à récupérer vont se trouver dans le
|
||
répertoire `blobs`, il ne s'agit en effet plus de *manifest*. Si les *manifests*
|
||
sont toujours stockés par le registre lui-même, les blobs peuvent être délégués
|
||
à un autre service, par exemple dans le cloud, chez Amazon S3, un CDN, etc.
|
||
|
||
Pour récupérer la configuration de l'image :
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
curl -s --location \
|
||
-H "Authorization: Bearer ${TOKEN}" \
|
||
"https://registry-1.docker.io/v2/library/hello-world/blobs/${CNF_DIGEST}"
|
||
```
|
||
</div>
|
||
|
||
|
||
Enfin, armé du `digest` de notre couche, il ne nous reste plus qu'à la demander gentiment :
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
wget --header "Authorization: Bearer ${TOKEN}" \
|
||
"https://registry-1.docker.io/v2/library/hello-world/blobs/${LAYER_DGST}"
|
||
```
|
||
</div>
|
||
|
||
|
||
## Extraction
|
||
|
||
Le type indiqué par le *manifest* pour cette couche était :
|
||
|
||
application/vnd.docker.image.rootfs.diff.tar.gzip
|
||
|
||
Il s'agit donc d'une tarball compressée au format gzip :
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
mkdir rootfs
|
||
tar xzf ${DL_LAYER} -C rootfs
|
||
```
|
||
</div>
|
||
|
||
Et voilà, nous avons extrait notre première image, nous devrions pouvoir :
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
42sh# chroot rootfs /hello
|
||
Hello from Docker!
|
||
[...]
|
||
```
|
||
</div>
|
||
|
||
|
||
::::: {.exercice}
|
||
|
||
#### Assemblage {-}
|
||
|
||
Réalisez un script pour automatiser l'ensemble de ces étapes :
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
42sh$ cd $(mktemp)
|
||
|
||
42sh$ ./registry_play.sh library/hello-world:latest
|
||
|
||
42sh$ find
|
||
.
|
||
./rootfs
|
||
./rootfs/hello
|
||
|
||
42sh# chroot rootfs /hello
|
||
Hello from Docker!
|
||
[...]
|
||
```
|
||
</div>
|
||
|
||
:::::
|