Docker de Ground Up: Travailler avec des conteneurs, Partie 1

() translation by (you can also view the original English article)
Il s'agit de la première partie d'une série en deux parties concernant le travail avec les conteneurs Docker. Dans cette partie, nous nous concentrerons sur les nombreuses façons et les options pour exécuter une image et comment l'hôte peut interagir avec un conteneur Docker.
Dans la deuxième partie, nous couvrons la liste, le démarrage, l'arrêt et le redémarrage des conteneurs, ainsi que l'exécution des commandes sur les conteneurs en cours d'exécution. Les images Docker sont les unités de déploiement. Lorsque vous exécutez une image, vous instanciez un conteneur Docker qui exécute un processus unique dans son environnement isolé pour l'arborescence des fichiers, des réseaux et des processus.
Les conteneurs Docker sont très flexibles et permettent de nombreux cas d'utilisation trop lourds, complexes et/ou coûteux avec d'autres technologies comme les machines virtuelles et les serveurs en métal nu.
Avant de commencer, assurez-vous que Docker est installé correctement dans votre environnement. Selon la façon dont il est installé et votre utilisateur, vous devrez peut-être l'exécuter en tant que sudo. Je saute le sudo.
Exécuter une image
Vous lancez un conteneur Docker en exécutant une image. Il existe plusieurs façons d'exécuter un conteneur qui affecte la facilité avec laquelle gérer tous les conteneurs. Lorsque le conteneur commence, il exécute généralement la commande définie dans le Dockerfile. Voici le Dockerfile pour le conteneur hello-world:
1 |
FROM scratch |
2 |
COPY hello / |
3 |
CMD ["/hello"] |
La commande exécute simplement le "hello" binaire qui a été copié à la racine du conteneur lors de la construction de l'image.
Premier plan vs. Détaché
Un conteneur peut fonctionner au premier plan où il bloque jusqu'à la fin du processus et le conteneur cesse de fonctionner. En mode au premier plan, le conteneur imprime sa sortie sur la console et peut lire l'entrée standard. En mode détaché (lorsque vous fournissez l'indicateur -d), le contrôle retourne immédiatement et le conteneur
Exécution d'un conteneur sans nom
La manière la plus simple d'exécuter un conteneur est: docker run <image id or name>
.
Lorsque vous exécutez un conteneur à l'aide de cette commande, Docker lui assignera un nom composé de deux mots aléatoires. Par exemple: docker run hello-world
.
Si vous avez déjà l'image du hello world, Docker l'exécutera. Si vous ne le faites pas, il l'extraira du DockerHub officiel du dépôt Docker, puis l'exécutera. La sortie devrait ressembler à:
1 |
Hello from Docker! |
2 |
This message shows that your installation appears to be working correctly. |
3 |
|
4 |
To generate this message, Docker took the following steps: |
5 |
1. The Docker client contacted the Docker daemon. |
6 |
2. The Docker daemon pulled the "hello-world" image from the Docker Hub. |
7 |
3. The Docker daemon created a new container from that image which runs the |
8 |
executable that produces the output you are currently reading. |
9 |
4. The Docker daemon streamed that output to the Docker client, which sent it |
10 |
to your terminal. |
11 |
|
12 |
To try something more ambitious, you can run an Ubuntu container with: |
13 |
$ docker run -it ubuntu bash |
14 |
|
15 |
Share images, automate work-flows, and more with a free Docker ID: |
16 |
https://cloud.docker.com/ |
17 |
|
18 |
For more examples and ideas, visit: |
19 |
https://docs.docker.com/engine/userguide/ |
Le programme hello sort après avoir affiché le message, qui met fin au processus qui se déroule à l'intérieur du conteneur et termine le conteneur. Le conteneur s'arrête toujours au cas où vous souhaitez vous connecter, examiner les registres ou toute autre chose. Pour afficher le conteneur, vous pouvez exécuter la commande suivante:
1 |
docker ps -a --format "table {{.ID}}\t{{.Status}}\t{{.Names}}" |
2 |
|
3 |
CONTAINER ID STATUS NAMES |
4 |
8e2e491accb5 Exited (0) 2 minutes ago clever_liskov |
J'expliquerai plus tard comment faire la liste des conteneurs et toutes les options pertinentes. Pour l'instant, concentrons-nous sur la section Noms. Docker a généré le nom "clever_liskov" automatiquement, et je devrai l'utiliser ou l'ID du conteneur pour faire référence à ce conteneur à des fins telles que le redémarrage, le suppression ou l'exécution d'une commande.
Exécuter un conteneur nommé
L'utilisation d'ID de conteneur ou de noms générés automatiquement est parfois gênant. Si vous interagissez fréquemment avec un conteneur que vous recréez fréquemment, il obtiendra un ID différent et un nom généré automatiquement. En outre, le nom sera aléatoire.
Docker vous permet de nommer vos conteneurs lorsque vous les exécutez en fournissant un argument de ligne de commande "--name <container name>". Dans des cas simples, où vous avez juste un conteneur par image, vous pouvez nommer le conteneur après votre image: docker run --name hello-world hello-world
.
Maintenant, si nous regardons le processus (j'ai supprimé clever_liskov plus tôt), nous verrons que le conteneur s'appelle hello-world:
1 |
docker ps -a --format "table {{.ID}}\t{{.Names}}" |
2 |
CONTAINER ID NAMES |
3 |
f6fe77b3b6e8 hello-world |
Il existe plusieurs avantages pour un conteneur nommé:
- Vous avez un nom stable pour vos conteneurs que vous utilisez de manière interactive et dans les scripts.
- Vous pouvez choisir un nom significatif.
- Vous pouvez choisir un nom abrégé pour plus de commodité lorsque vous travaillez de manière interactive.
- Il vous empêche d'avoir accidentellement plusieurs conteneurs de la même image (aussi longtemps que vous fournissez toujours le même nom).
Regardons la dernière option. Si j'essaie d'exécuter la même commande run avec le même nom "hello-world", j'ai un message d'erreur clair:
1 |
docker run --name hello-world hello-world |
2 |
docker: Error response from daemon: Conflict. The container name |
3 |
"/hello-world" is already in use by container |
4 |
f6fe77b3b6e8e77ccf346c32c599e67b2982893ca39f0415472c2949cacc4a51. |
5 |
You have to remove (or rename) that container to be able to reuse |
6 |
that name. |
7 |
See 'docker run --help'. |
Exécution d'une image de suppression automatique
Les conteneurs mangent par défaut. Parfois, vous n'en avez pas besoin. Au lieu d'enlever manuellement les contenants sortants, vous faites que le conteneur disparaisse seul. L'argument --rm
line de commande fait l'affaire: docker run --rm hello-world
.
Exécuter un autre commandement
Par défaut, Docker exécute la commande spécifiée dans le Dockerfile utilisé pour construire l'image (ou directement le point d'entrée si aucune commande n'est trouvée). Vous pouvez toujours l'annuler en fournissant votre propre commande à la fin de la commande d'exécution. Sortons ls -la
sur l'image busybox (l'image hello-world n'a pas d'exécutable ls
):
1 |
docker run busybox ls -la |
2 |
total 44 |
3 |
drwxr-xr-x 18 root root 4096 Mar 18 17:06 . |
4 |
drwxr-xr-x 18 root root 4096 Mar 18 17:06 .. |
5 |
-rwxr-xr-x 1 root root 0 Mar 18 17:06 .dockerenv |
6 |
drwxr-xr-x 2 root root 12288 Mar 9 00:05 bin |
7 |
drwxr-xr-x 5 root root 340 Mar 18 17:06 dev |
8 |
drwxr-xr-x 2 root root 4096 Mar 18 17:06 etc |
9 |
drwxr-xr-x 2 nobody nogroup 4096 Mar 9 00:05 home |
10 |
dr-xr-xr-x 85 root root 0 Mar 18 17:06 proc |
11 |
drwxr-xr-x 2 root root 4096 Mar 9 00:05 root |
12 |
dr-xr-xr-x 13 root root 0 Mar 18 17:06 sys |
13 |
drwxrwxrwt 2 root root 4096 Mar 9 00:05 tmp |
14 |
drwxr-xr-x 3 root root 4096 Mar 9 00:05 usr |
15 |
drwxr-xr-x 4 root root 4096 Mar 9 00:05 var |
Interagir avec l'hôte
Les conteneurs Docker exécutent des processus isolés dans leur propre petit monde. Mais il est souvent nécessaire et utile de fournir un accès à l'hôte.
Passer des variables d'environnement à un conteneur
Les conteneurs Docker n'héritent pas automatiquement de l'environnement du processus hôte qui les a exécutés. Vous devez fournir explicitement des variables d'environnement au conteneur lorsque vous l'exécutez à l'aide du drapeau de ligne de commande -e
. Vous pouvez passer plusieurs variables d'environnement. Voici un exemple:
1 |
docker run --rm -it -e ENV_FROM_HOST="123" busybox |
2 |
/ # env |
3 |
HOSTNAME=8e7672bce5a7 |
4 |
SHLVL=1 |
5 |
HOME=/root |
6 |
ENV_FROM_HOST=123 |
7 |
TERM=xterm |
8 |
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin |
9 |
PWD=/ |
10 |
/ # |
La première ligne exécute le conteneur busybox, en passant la variable ENV_FROM_HOST, puis dans le conteneur en cours d'exécution env
indique que le ENV_FROM_HOST est correctement configuré.
Vous pouvez également utiliser des variables d'environnement hôte. Cela définit quelques variables d'environnement hôte et les utilise dans la commande Run:
1 |
$ export VAR_1=1 |
2 |
$ export VAR_2=2 |
3 |
$ docker run --rm -it -e VAR_1="$VAR_1" -e VAR_2="$VAR_2" busybox |
À l'intérieur du conteneur, ils sont maintenant visibles:
1 |
/ # env | grep VAR |
2 |
VAR_1=1 |
3 |
VAR_2=2 |
Montage des répertoires d'hôtes
L'une des interactions les plus utiles consiste à installer les répertoires de l'hôte. Cela permet plusieurs cas d'utilisation intéressants:
- Stockage partagé entre conteneurs fonctionnant sur le même hôte.
- Affichage et édition de fichiers à l'aide de votre environnement hôte et de vos outils et utilisation des fichiers dans le conteneur.
- Persistance au niveau de l'hôte au-delà de la durée de vie d'un conteneur.
Ici, je crée un fichier sur l'hôte: $ echo "Yeah, it works!"> ~/data/1.txt
Ensuite, je cours l'image busybox en montant le ~/data directory dans /data dans le conteneur et en affichant le contenu du fichier sur l'écran:
1 |
$ docker run --rm -v ~/data:/data busybox cat /data/1.txt |
2 |
Yeah, it works! |
J'ai utilisé la commande cat /data/1.txt
ici.
Exposer les ports à l'hôte
Si vous exposez un port dans votre Dockerfile en utilisant EXPOSE, il sera accessible uniquement à d'autres conteneurs docker. Pour le rendre accessible sur l'hôte, vous devez utiliser l'argument de ligne de commande -p
. La syntaxe est -p <hostport>:<exposed container port>
.
Voici l'image nginx, qui expose le port 80 et utilise l'argument de ligne de commande -p
pour le rendre visible sur l'hôte sur le port 9000:
1 |
docker run --name nginx --rm -d -p 9000:80 nginx |
Notez que contrairement aux commandes précédentes qui ont effectué certaines tâches et complétées, le conteneur nginx continuera à courir et à écouter les requêtes entrantes. Vérifions que nginx est vraiment opérationnel et répond aux demandes sur le port 9000. Je préfère l'excellent client httpie HTTP sur le curl pour frapper les serveurs Web et les services à partir de la ligne de commande:
1 |
http HEAD localhost:9000 |
2 |
|
3 |
HTTP/1.1 200 OK |
4 |
Accept-Ranges: bytes |
5 |
Connection: keep-alive |
6 |
Content-Length: 612 |
7 |
Content-Type: text/html |
8 |
Date: Sun, 19 Mar 2017 07:35:55 GMT |
9 |
ETag: "58a323e4-264" |
10 |
Last-Modified: Tue, 14 Feb 2017 15:36:04 GMT |
11 |
Server: nginx/1.11.10 |
Conclusion
Il existe plusieurs façons d'exécuter une image Docker pour créer un conteneur, et il existe de nombreuses options. Chaque combinaison prend en charge une utilisation particulière. Il est très utile lorsque vous travaillez avec des conteneurs Docker pour saisir pleinement les détails et utiliser la meilleure méthode pour lancer vos conteneurs.
En outre, l'ajout de volumes d'hôtes et les ports d'exposition et de publication permettent une intégration étroite avec l'hôte et une multitude de scénarios d'utilisation. Dans la deuxième partie, nous nous pencherons sur la gestion d'un tas de contenants et en profitant de la puissance totale fournie par Docker.