\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">
```
| 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 entrer
dedans :

<div lang="en-US">
```
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">
```
42sh$ cd $(mktemp -d)

42sh$ ./registry_play library/hello-world:latest

42sh$ find
.
./rootfs
./rootfs/hello

42sh# chroot rootfs /hello
Hello from Docker!
[...]
```
</div>

:::::
