Resources attached to the Road To DevOps tutorial https://blog.noobtoroot.xyz/road-to-devops/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

794 lines
25 KiB

# Docker
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Schema Docker Swarm](images/docker-wave-whale.svg "Schema Docker Swarm")
__Images de conteneurs__
Maxime Poullain • Christian Tritten
### Qu'est-ce qu'une image de conteneur ?
Une image :
- Est un template de conteneur en lecture seule.
- Est composée de fichiers et de métadonnées.
- Peut par exemple contenir un système d'exploitation Debian avec Apache et une application web pré-installés.
- Est "instanciée" pour créer un ou plusieurs conteneurs.
![Les images Docker les plus populaires en 2020](images/most-popular-docker-official-images-in-2020.png)
<small>Source : https://www.docker.com/blog/docker-index-shows-continued-massive-developer-adoption-and-activity-to-build-and-share-apps-with-docker/</small>
### Images incrémentales et réutilisables
![Images réutilisables](images/docker-image-reusability.png)
**Remarque importante**
Si l'image de base est modifiée (par exemple dans le cadre de l'application d'une mise à jour de sécurité), et que l'on souhaite propager cette mise à jour sur les images dérivées, il faudra reconstruire ces dernières.
### Système de fichiers multi-couches
- Les images sont composées d'une ou plusieurs couches superposées.
- Chaque couche représente un différentiel des changements apportés par rapport à la couche inférieure.
- Lorsque plusieurs images partagent des couches, cela permet d'optimiser l'espace disque, et les temps de transfert.
<!-- .slide: style="text-align: center" -->
![Système de fichiers multi-couches](images/docker-image-layers.jpg)
- La principale différence entre un conteneur et une image réside dans la _couche en r/w_ du sommet.
- Toutes les écritures qui ajoutent ou modifient des données dans un conteneur sont stockées sur cette couche.
- Quand le conteneur est supprimé la couche en r/w est aussi supprimée, les couches inférieures de l'image de base restent inchangées.
- On peut sauvegarder les modifications effectuée au sein d'un conteneur en utilisant la commande : `docker commit`
- Ceci va ajouter une _nouvelle couche_ en lecture seule au dessus de la pile composant l'image.
Lorsqu'une image est modifiée, une nouvelle couche est ajoutée au sommet de la pile :
![Ajout d'une nouvelle couche](images/docker-image-new-layer.jpg)
### Partage d'image entre plusieurs conteneurs
<!-- .slide: style="text-align: center" -->
![Partage d'image entre plusieurs conteneurs](images/docker-container-sharing-layers.jpg)
## Gestion des images
Outils et commandes pour la gestion des images
### Images locales
`docker image ls`
<!-- .slide: data-state="small-code" -->
```none
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
composeformation_web latest 0d2d42971538 20 hours ago 237MB
debian-formation latest 257c415ffcc7 20 hours ago 237MB
mariadb 10.1.24 98f78d96be9c 2 weeks ago 395MB
debian jessie 3e83c23dba6a 3 weeks ago 124MB
hello-world latest 48b5124b2768 4 months ago 1.84kB
```
### Le Docker Hub
Le [Docker Hub](https://hub.docker.com/) est un entrepôt d'images de conteneurs sur lequel on peut télécharger :
* des images _officielles_ certifiées par Docker
* des images _publiques_ maintenues par la communauté
![Recherche mariadb sur le Docker Hub](images/docker-hub.png)
__Attention !__
Docker ne garantie pas le bon fonctionnement
ni même l'absence de faille de sécurité
sur les images non officielles.
### Chercher une image sur le Docker Hub
`docker search IMAGE`
<!-- .slide: data-state="small-code" -->
```none
$ docker search mariadb
NAME DESCRIPTION STARS OFFICIAL
mariadb MariaDB is a community-developed for... 1354 [OK]
bitnami/mariadb Bitnami MariaDB Docker Image 37
paintedfox/mariadb A docker image for running MariaDB 5... 29
million12/mariadb MariaDB 10 on CentOS-7 with UTF8 default 14
toughiq/mariadb-cluster Dockerized Automated MariaDB Galera ... 11
webhippie/mariadb Docker images for mariadb 9
gists/mariadb MariaDB on Alpine 7
panubo/mariadb-galera MariaDB Galera Cluster 7
kakilangit/mariadb Docker for MariaDB with OQGraph & To... 6
maxexcloo/mariadb Service container with MariaDB insta... 4
tianon/mariadb DEPRECATED; use mariadb:* -- ♪ "I ju... 4
takaomag/mariadb docker image of archlinux (mariadb) 2
drupaldocker/mariadb MariaDB for Drupal 1
...
```
### Récupérer une image sur le Docker Hub
`docker pull IMAGE[:TAG]`
<!-- .slide: data-state="small-code" -->
```none
$ docker pull mariadb:10.7.1
Using default tag: latest
latest: Pulling from library/mariadb
10a267c67f42: Pull complete
c2dcc7bb2a88: Pull complete
17e7a0445698: Pull complete
9a61839a176f: Pull complete
64675690edb1: Pull complete
3de17e251488: Pull complete
f814b22b783e: Pull complete
733ce1f03439: Pull complete
fb7b719835fd: Pull complete
8d3f82357729: Pull complete
a4f4cbdfcf7c: Pull complete
Digest: sha256:4b54358541679032f6c3a9d9fc944ad96d77ae72fecd6cb44bf18cf97743da24
Status: Downloaded newer image for mariadb:10.7.1
```
### Visualiser l'historique d'une image
`docker history IMAGE`
<!-- .slide: data-state="small-code" -->
```none
$ docker history mariadb:10.7.1
IMAGE CREATED CREATED BY SIZE
98f78d96be9c 2 weeks ago /bin/sh -c #(nop) CMD ["mysqld"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) EXPOSE 3306/tcp 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ENTRYPOINT ["docker-ent... 0B
<missing> 2 weeks ago /bin/sh -c ln -s usr/local/bin/docker-entr... 34B
<missing> 2 weeks ago /bin/sh -c #(nop) COPY file:d559178e6a2929... 5.6kB
<missing> 2 weeks ago /bin/sh -c #(nop) VOLUME [/var/lib/mysql] 0B
<missing> 2 weeks ago /bin/sh -c sed -Ei 's/^(bind-address|log)/... 5.27kB
<missing> 2 weeks ago /bin/sh -c { echo mariadb-server-$MARIAD... 252MB
<missing> 2 weeks ago /bin/sh -c echo "deb https://repo.percona.... 114B
<missing> 2 weeks ago /bin/sh -c set -ex; export GNUPGHOME="$(m... 21.1kB
<missing> 2 weeks ago /bin/sh -c apt-get update && apt-get insta... 14.3MB
<missing> 2 weeks ago /bin/sh -c set -x && apt-get update && ap... 4.58MB
<missing> 2 weeks ago /bin/sh -c groupadd -r mysql && useradd -r... 330kB
<missing> 3 weeks ago /bin/sh -c #(nop) ADD file:f4e6551ac34ab44... 124MB
```
### "Inspecter" une image
`docker inspect IMAGE`
<!-- .slide: data-state="small-code" -->
```none
$ docker inspect mariadb
[
{
"Id": "sha256:98f78d96be9c7f513f21de040d083ee7ba23d74c8f3bc499373e56e93c...",
"RepoTags": [
"mariadb:10.7.1"
],
"RepoDigests": [
"mariadb@sha256:4b54358541679032f6c3a9d9fc944ad96d77ae72fecd6cb44bf1..."
],
"Parent": "",
"Comment": "",
"Created": "2017-05-09T17:28:06.071608373Z",
"Container": "83ce76bba170200d3783bde70b7c1d06a61ed2b91bec7351a5c5a664f5...",
"ContainerConfig": {
"Hostname": "200591939db7",
"Domainname": "",
"User": "",
"ExposedPorts": {
"3306/tcp": {}
```
### Supprimer une image
`docker image rm IMAGE [IMAGE...]`
<!-- .slide: data-state="small-code" -->
```none
$ docker image rm mariadb:10.7.1
Untagged: mariadb:10.7.1
Untagged: mariadb@sha256:4b54358541679032f6c3a9d9fc944ad96d77ae72fecd6cb44bf18cf...
Deleted: sha256:98f78d96be9c7f513f21de040d083ee7ba23d74c8f3bc499373e56e93c8e9ec9
Deleted: sha256:bea03b338eb87d64861847305aa63f6104212c60719168f25b54ca713db4b870
Deleted: sha256:519db73d66bef13a78573160ddf2059f9dc382e03fd2e85f354c3172ded67b90
Deleted: sha256:7f728a3fd818a51a5425306ef40f398c7698f4252ade70cb83b3d26b825bb613
Deleted: sha256:48159803f1446a31e60af329025fc5c3ae8ef07f950d8750a7e14d46d1d1191c
Deleted: sha256:ff5b1cc6d50c6f7ab9e6ee77ff89b0b037a6840f7b1f44cbe234499362221c15
Deleted: sha256:d147674f5cce42f85942e815f154c6a7ecb86359689d823a9840b28126a12f4e
Deleted: sha256:571be45150dde0fb8f6c3862abbcfa06fbad0e6a128d459a6b8ad0660f9f0660
Deleted: sha256:458271f19a2c854fc6fd3338f9151662173b96a14cfe1a2e46eca95d27e4102c
Deleted: sha256:ba779192baede4aadd009c269406b5e8fd885c653ce19719316bf40cc66a6cf3
Deleted: sha256:2302bd8bbdd530199aa432c357a4da9eab2621c3ba4c4dacb4ea0f4afecbcae7
Deleted: sha256:00771f8e1e12bdfc9d47bc52a78e3f5ce5306a1caa5dd6237731cff9ca106040
Deleted: sha256:8d4d1ab5ff74fc361fb74212fff3b6dc1e6c16d1e1f0e8b44f9a9112b00b564f
```
### Importer / Exporter une image
<!-- .slide: data-state="cheat-sheet" -->
1. Export
`$ docker save -o mon-image.tar IMAGE`
2. Import
`$ docker load -i mon-image.tar`
### Travaux pratiques
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Travaux pratiques](images/tp.gif)
<small>[TP Docker Images](../travaux-pratiques/slides/docker/tp-images.html)</small>
## Dockerfile
Automatiser la construction d'une image
- Il est possible de construire une image à la main puis de la sauvegarder avec un `docker commit`.
- Toutefois ceci est fastidieux, non parfaitement reproductible et donc potentiellement source d'erreur.
- D'autre part, comment gérer les mises à jours d'une telle image ?
- Docker est capable de construire des images automatiquement à partir des instructions d'un _Dockerfile_.
- Le Dockerfile est un fichier texte qui contient toutes les instructions permettant de construire une image Docker pour une application donnée.
<small>[https://docs.docker.com/engine/reference/builder/](https://docs.docker.com/engine/reference/builder/)</small>
![Dockerfile](images/dockerfile-image-container.jpg)
- Le Dockerfile est versionnable et permet de produire une image à tout moment.
- Ceci s'inscrit dans la philosophie _Infrastructure as Code_ qui prône la définition d'une architecture dans des fichiers textes déclaratifs.
- Grâce au Dockerfile on peut reconstruire périodiquement une image afin quelle intègre les dernières mises à jour applicatives et les derniers patches de sécurité.
### Exemple de Dockerfile
<!-- .slide: data-state="small-code" -->
```docker
FROM debian:bullseye
LABEL maintainer "robert@produpot.com"
# On installe Apache httpd
ENV DEBIAN_FRONTEND noninteractive
RUN apt update \
&& apt install -y apache2 \
&& rm -rf /var/lib/apt/lists/*
# Ajout d'un script d'init
ADD run.sh /run.sh
RUN chmod 755 /run.sh
# Importe l'application
RUN mkdir -p /app && rm -fr /var/www/html && ln -s /app /var/www/html
ADD homepage/ /app
# On expose le port 80
EXPOSE 80
# On indique le script qui doit être lancé au démarrage du conteneur
ENTRYPOINT ["/run.sh"]
```
### Principales directives
<!-- .slide: data-state="medium-table" -->
Directive | Description
- | -
`FROM` | Spécifie l'image de départ pour la construction de la nouvelle image.
`LABEL` | Ajoute des métadonnées à la nouvelle image.
`ENV` / `ARG` | Ajoute des variables d'environnement.
`ADD` / `COPY` | Copie des fichiers ou des dossiers sur le système de fichiers de l'image.
`VOLUME` | Créé un point de montage à l'instanciation du conteneur.
### Principales directives (suite)
<!-- .slide: data-state="medium-table" -->
Directive | Description
- | -
`RUN` | Exécute une commande et "commite" le résultat dans une nouvelle couche de l'image.
`USER` | Spécifie l'utilisateur à utiliser pour jouer les instructions `RUN` et `ENTRYPOINT`.
`HEALTHCHECK` | Indique une commande qui sera lancée à l'intérieur du conteneur pour vérifier que celui-ci tourne correctement.
`ENTRYPOINT` | Définie une commande de base à exécuter dans le conteneur.
`CMD` | Définie les paramètres par défaut de la commande de base.
### LABEL
```docker
LABEL maintainer="user@example.com" \
vendor=ACME\ Incorporated \
com.example.version="0.0.1-beta" \
com.example.release-date="2015-02-12"
```
### Choisir entre `ARG` et `ENV`
* `ARG` et `ENV` permettent de déclarer des variables qui sont utilisables à partir du moment où elles sont déclarées dans le Dockerfile.
* Les `ARG` peuvent être surchargées au moment du build via l'option `--build-arg`.
* Les `ENV` peuvent être surchargées à l'exécution via l'option `-e`.
* Si une variable `ARG` est utilisée sans valeur par défaut et qu'aucune valeur n'est fournie via `--build-arg`, cela déclenche une erreur lors du build.
![ARG vs ENV](images/docker-environment-args-env.png)
<small>https://vsupalov.com/docker-arg-env-variable-guide/</small>
<!-- .slide: data-state="small-code" -->
`Dockerfile`
```docker
ARG MY_VAR_1 <---- expect a build-time variable
ARG MY_VAR_2=pouet <---- set a build-time variable
RUN touch "$MY_VAR_2"
ARG A_VARIABLE <---- expect a build-time variable
ENV another_var=$A_VARIABLE <---- use the value to set the ENV var default
if not overridden, that value of another_var
will be available to your containers!
```
### Choisir entre `ADD` et `COPY`
Les deux directives ont la même syntaxe :
```docker
COPY <src>... <dest>
ADD <src>... <dest>
```
Selon le guide des bonnes pratiques Docker :
* Utilisez `COPY` dans tous les cas, sauf si vous avez besoin d'extraire automatiquement le contenu d'une archive, dans ce cas précis utilisez `ADD`.
* Pour récupérer des fichiers distants, préférez plutôt l'instruction `RUN wget ...`.
### CMD et ENTRYPOINT
Les commandes `CMD` et `ENTRYPOINT` permettent
de définir la commande par défaut à exécuter
à l'intérieur du conteneur.
- `ENTRYPOINT` définie la commande de base pour le conteneur,
- `CMD` définie les paramètres par défaut pour cette commande.
```docker
FROM debian:bullseye
RUN apt update && apt install -y cowsay
ENTRYPOINT ["/usr/games/cowsay"]
CMD ["hello"]
```
```none
$ docker build -t cowsay .
...
Successfully built a27691083512
Successfully tagged cowsay:latest
```
```none
$ docker run cowsay
-------
< hello >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
```
```none
$ docker run cowsay 2,21 Gigowatts ?!
-------------------
< 2,21 Gigowatts ?! >
-------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
```
### HEALTHCHECK
L'exemple suivant teste toutes les 5 minutes que le conteneur est capable de servir une ressource HTTP en moins de 3 secondes :
```docker
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
```
Le test de santé étant lancé depuis l'intérieur du conteneur, _la commande `curl` utilisée dans l'exemple ci-dessus doit être présente dans le conteneur_.
<!-- .slide: data-state="small-code" -->
Le status _healthy_ / _unhealthy_ est consultable
via `docker ps` ou `docker inspect`
```none
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
9e2ea5f59f8b xian/web "/start.sh" 28 minutes ago Up 28 minutes (healthy)
20851619e1af xian/web "/start.sh" 23 minutes ago Up 23 minutes (unhealthy)
```
```none
$ docker inspect -f '{{json .State.Health.Status}}' conteneur
"healthy"
```
Il s'agit d'un simple message informatif, en effet Docker ne relance pas de lui-même un conteneur détecté comme _unhealthy_.
* Toutefois, Le changement de santé d’un conteneur génère un évenement Docker que les outils de monitoring et d’orchestration peuvent intercepter.
* Par exemple l'orchestrateur Swarm utilise cette information pour remplacer automatiquement le conteneur défectueux par une nouvelle instance.
### Construire l'image à partir du Dockerfile
`docker build -t IMAGE[:TAG] .`
Les tags permettent de proposer
plusieurs versions d'une image.
`docker build -t mon-image:v1 .`
Une même image peut
être tagguée plusieurs fois :
ex : `debian:10` et `debian:buster`
### Derrière un proxy
<!-- .slide: data-state="medium-code" -->
`--build-arg http_proxy=PROXY`
```none
$ docker build --build-arg http_proxy=http://my.proxy.url:3128 \
--tag debian-formation .
```
## Travaux pratiques
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Travaux pratiques](images/tp.gif)
<small>[TP Dockerfile](../travaux-pratiques/slides/docker/tp-dockerfile.html)</small>
### Rendre une image publique
* On peut rendre une image publique en la poussant sur le Docker Hub.
* La création d'un Docker ID est nécessaire.
* Le Docker ID sera le nom d'utilisateur pour le Docker Hub.
* La commande `docker login` permet de se connecter au Hub.
Pour pouvoir pousser une image sur le Hub, il faut la nommer avec un nom de la forme `docker-id/image:tag`
Ceci se fait avec la commande `docker tag` :
```none
$ docker tag mon-image mon-docker-id/mon-image:1.0.0
```
Il est ensuite possible de pousser l'image avec la commande `docker push` :
```none
$ docker push mon-docker-id/mon-image:1.0.0
```
A partir de là, l'image devient accessible publiquement par n'importe qui.
### Dockerfile
#### les bonnes pratiques
Réutiliser au maximum la même image de base afin de mutualiser les couches entre vos différentes images applicatives.
Eviter d'installer tout ce qui n'est pas strictement nécessaire.
<small>Paquets de la distribution, paquets applicatifs, ...</small>
Alléger les images en supprimant les données inutiles, mais pas n'importe comment !
```docker
RUN apt-get update && apt-get install -y package
RUN rm -rf /var/lib/apt/lists/*
```
Chaque couche est commitée en readonly avant de passer à l'instruction suivante !
Il faut nettoyer dans la même couche !
```docker
RUN apt update \
&& apt install -y package \
&& rm -rf /var/lib/apt/lists/*
```
```docker
RUN wget archive.tar.gz \
&& tar xzvf archive.tar.gz \
&& rm archive.tar.gz
```
(Combiner plusieurs instructions `RUN` permet également de diminuer le nombre de couches constituant l'image.)
Ne pas utiliser `apt-get upgrade` ou `apt-get dist-upgrade` dans vos images spécialisées.
Ceci doit être fait dans l'image OS de base.
Chaque conteneur devrait se focaliser sur une seule tâche.
![Un processus par conteneur](images/docker-one-process.png) <!-- .element: width="80%" -->
Utiliser une image de base légère.
Par exemple, [debian:bullseye-slim](https://hub.docker.com/_/debian/) pèse ~30MB tout en restant une distribution complète.
Proscrire l'utilisation du tag `latest` en production.
__Attention !__
<small>`docker pull myimage` == `docker pull myimage:latest`</small>
Le tag `latest` est utilisé par défaut si vous n'en fournissez pas un dans vos commandes Docker !
3 bonnes raisons de ne pas utiliser le tag `latest`
* Votre outil de déploiement ne déploiera pas une nouvelle version de votre application taggué latest, tout simplement parce qu'il ne détectera pas la différence avec l'ancienne version elle aussi tagguée avec latest.
* Tagguer une image avec un numéro de version unique permet d'effectuer de la tracabilité. On sait exactement quelle version est déployée.
* En réutilisant systématiquement le tag latest, tout retour arrière à une ancienne version de l'image est impossible, car vous écrasez systématiquement la précédente version de l'image docker.
Déterminer une stratégie pour les tags
* Lorsque on crée une image, il nous appartient de lui ajouter des tags appropriés.
* Utiliser une stratégie pour les tags qui soit cohérente et consistante sur toutes les images produites.
* La stratégie doit être facilement compréhensible par les utilisateurs de ces images.
<!-- .slide: data-state="medium-code" -->
__L'exécution de processus avec l'utilisateur `root` à l'intérieur d'un conteneur est un préliminaire à de nombreux types d'attaques.__
Déclarer un utilisateur dédié permet d'éviter un grand nombre d'attaques :
```docker
RUN useradd -d /home/my-app-user -m -s /bin/bash my-app-user
USER my-app-user
```
On peut forcer l'utilisateur à l'exécution :
```none
$ docker run --user my-app-user -d -t my-application
```
L'utilisateur doit exister dans `/etc/passwd` à l'intérieur du conteneur.
Ne pas écrire de secrets dans le Dockerfile.
<small>(secret == mot de passe, clé de chiffrement, clé d'API)</small>
Injecter la configuration à l'exécution du conteneur.
Utiliser la fonctionnalité de _multi-stage build_ (Docker > v17.05) pour produire des images plus petites.
Un cas d'usage est celui où l'on doit compiler une binaire afin de produire l'image applicative finale.
En découpant le processus de build, on va tout d'abord construire une image dédié à la compilation du binaire et injecter le résultat de cette compilation dans l'image finale qui sera ainsi d'une beaucoup plus réduite.
<!-- .slide: data-state="medium-code" -->
`Dockerfile`
```docker
FROM golang:1.10 as builder
WORKDIR /tmp/go
COPY hello.go ./
RUN CGO_ENABLED=0 go build -a -ldflags '-s' -o hello
FROM scratch
CMD [ "/hello" ]
COPY --from=builder /tmp/go/hello /hello
```
`$ docker build -t hello:1 .`
<!-- .slide: data-state="small-code" -->
`$ docker image ls`
```none
REPOSITORY TAG IMAGE ID CREATED SIZE
hello latest 212f44bc4048 4 seconds ago 3.2MB
<none> <none> 08370cf772b1 5 seconds ago 693MB
```
Le résultat final est une image d'environ 3Mb au lieu de 700Mb sans le multi-stage build.
Pour le reste des bonnes pratiques :
* https://sysdig.com/blog/dockerfile-best-practices/
* https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/
* https://cloud.google.com/solutions/best-practices-for-building-containers
#### Haskell Dockerfile Linter
Un outil pour vérifier les bonnes pratiques
sur les fichiers Dockerfile
<!-- .slide: data-state="small-code" -->
```none
$ docker run --rm -i hadolint/hadolint < Dockerfile
/dev/stdin:2 DL3020 Use COPY instead of ADD for files and folders
/dev/stdin:4 DL3025 Use arguments JSON notation for CMD and ENTRYPOINT arguments
```
https://github.com/hadolint/hadolint
Alternatives : [Dockle](https://github.com/goodwithtech/dockle) | [Trivy](https://aquasecurity.github.io/trivy/)
## Nettoyer les images
Les images ont tendance à s'accumuler et à remplir progressivement l'espace de stockage sur les hôtes.
* `$ docker image prune`
Supprime toutes les images qui ne sont ni taguées ni référencées par au moins un conteneur.
* `$ docker image prune -a`
Supprime toutes les images qui ne sont pas référencées par au moins un conteneur.
## Registry
* Le composant Docker Registry permet le stockage et la distribution d'images Docker.
* Docker Inc. fourni une image officielle prête à l'emploi pour déployer facilement un Registry.
### Fonctionnalités
* Authentification des utilisateurs
* Push/Pull d'images
* Stockage des images sur une grande variété de backends (S3, Posix Filesystems, Ceph, Swift...)
### Utilisation du Docker Registry
<!-- .slide: data-state="medium-code" -->
```none
$ docker pull hello-world
$ docker tag hello-world mon_nom_de_domaine:5000/hello-world
$ docker push mon_nom_de_domaine:5000/hello-world
...
$ docker pull mon_nom_de_domaine:5000/hello-world
```
## Sécurité - rapports
* __NCC Group__
Understanding and Hardening Linux Containers
Juin 2016
[www.nccgroup.trust/](https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/2016/april/ncc_group_understanding_hardening_linux_containers-1-1.pdf)
* __NIST__
Application Container Security Guide
Sept. 2017
[http://nvlpubs.nist.gov/](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf)
### Sécurité - outils
* Docker Bench for Security
[github.com/docker/docker-bench-security](https://github.com/docker/docker-bench-security)
* Trivy - Analyse de vulnérabilités sur les images
[https://aquasecurity.github.io/trivy/](https://aquasecurity.github.io/trivy/)
### Outils alternatifs pour construire des Images compatibles OCI
* Kaniko
<small>[https://github.com/GoogleContainerTools/kaniko](https://github.com/GoogleContainerTools/kaniko)</small>
* makisu
<small>[https://github.com/uber/makisu](https://github.com/uber/makisu)</small>
* Buildah
<small>[https://github.com/containers/buildah](https://github.com/containers/buildah)</small>
* Pas besoin d'élévation de privilèges (Docker build nécessite d'être root).
* Utilisation d'un cache distribué pour optimiser les performances sur un cluster de build.
* Permet de contrôler les couches générées dans l'image.
### Inspecter les couches d'une image
* Dive
https://github.com/wagoodman/dive
![dive](images/dive.gif)