|
|
|
|
# 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)
|