Liens de conteneurs hérités
WarningLe drapeau
--link
est une fonctionnalité héritée de Docker. Il pourrait éventuellement être supprimé. Sauf si vous avez absolument besoin de continuer à l'utiliser, nous recommandons d'utiliser des réseaux définis par l'utilisateur pour faciliter la communication entre deux conteneurs au lieu d'utiliser--link
. Une fonctionnalité que les réseaux définis par l'utilisateur ne prennent pas en charge que vous pouvez faire avec--link
est le partage de variables d'environnement entre conteneurs. Cependant, vous pouvez utiliser d'autres mécanismes tels que les volumes pour partager des variables d'environnement entre conteneurs de manière plus contrôlée.Voir Différences entre les bridges définis par l'utilisateur et le bridge par défaut pour quelques alternatives à l'utilisation de
--link
.
Les informations de cette section expliquent les liens de conteneurs hérités dans le
réseau bridge
par défaut de Docker qui est créé automatiquement lorsque vous installez
Docker.
Avant la fonctionnalité réseaux Docker, vous pouviez utiliser la
fonctionnalité de lien Docker pour permettre aux conteneurs de se découvrir et transférer de manière sécurisée
des informations d'un conteneur à un autre conteneur. Avec l'
introduction de la fonctionnalité réseaux Docker, vous pouvez toujours créer des liens mais ils
se comportent différemment entre le réseau bridge
par défaut et
les réseaux définis par l'utilisateur.
Cette section discute brièvement de la connexion via un port réseau puis entre dans
le détail sur la liaison de conteneurs dans le réseau bridge
par défaut.
Se connecter en utilisant le mappage de port réseau
Disons que vous avez utilisé cette commande pour exécuter une simple application Python Flask :
$ docker run -d -P training/webapp python app.py
NoteLes conteneurs ont un réseau interne et une adresse IP. Docker peut avoir une variété de configurations réseau. Vous pouvez voir plus d'informations sur les réseaux Docker ici.
Quand ce conteneur a été créé, le drapeau -P
a été utilisé pour mapper automatiquement
tout port réseau à l'intérieur vers un port élevé aléatoire dans une plage de ports
éphémères sur votre hôte Docker. Ensuite, quand docker ps
a été exécuté, vous avez vu que le port
5000 dans le conteneur était lié au port 49155 sur l'hôte.
$ docker ps nostalgic_morse
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse
Vous avez aussi vu comment vous pouvez lier les ports d'un conteneur à un port spécifique en utilisant
le drapeau -p
. Ici le port 80 de l'hôte est mappé au port 5000 du
conteneur :
$ docker run -d -p 80:5000 training/webapp python app.py
Et vous avez vu pourquoi ce n'est pas une si bonne idée car cela vous contraint à un seul conteneur sur ce port spécifique.
Au lieu de cela, vous pouvez spécifier une plage de ports d'hôte pour lier un port de conteneur à qui est différente de la plage de ports éphémères par défaut :
$ docker run -d -p 8000-9000:5000 training/webapp python app.py
Cela lierait le port 5000 dans le conteneur à un port disponible aléatoirement entre 8000 et 9000 sur l'hôte.
Il y a aussi quelques autres façons de configurer le drapeau -p
. Par
défaut le drapeau -p
lie le port spécifié à toutes les interfaces sur
la machine hôte. Mais vous pouvez aussi spécifier une liaison à une interface
spécifique, par exemple seulement au localhost
.
$ docker run -d -p 127.0.0.1:80:5000 training/webapp python app.py
Cela lierait le port 5000 à l'intérieur du conteneur au port 80 sur l'
interface localhost
ou 127.0.0.1
sur la machine hôte.
Ou, pour lier le port 5000 du conteneur à un port dynamique mais seulement sur le
localhost
, vous pourriez utiliser :
$ docker run -d -p 127.0.0.1::5000 training/webapp python app.py
Vous pouvez aussi lier les ports UDP et SCTP (typiquement utilisés par des protocoles télécom tels que SIGTRAN, Diameter, et S1AP/X2AP) en ajoutant un /udp
ou /sctp
final. Par exemple :
$ docker run -d -p 127.0.0.1:80:5000/udp training/webapp python app.py
Vous avez aussi appris le raccourci utile docker port
qui nous a montré les
liaisons de port actuelles. C'est aussi utile pour montrer des configurations de port
spécifiques. Par exemple, si vous avez lié le port du conteneur au
localhost
sur la machine hôte, alors la sortie docker port
reflète cela.
$ docker port nostalgic_morse 5000
127.0.0.1:49155
NoteLe drapeau
-p
peut être utilisé plusieurs fois pour configurer plusieurs ports.
Se connecter avec le système de liaison
NoteCette section couvre la fonctionnalité de lien héritée dans le réseau
bridge
par défaut. Référez-vous aux différences entre les bridges définis par l'utilisateur et le bridge par défaut pour plus d'informations sur les liens dans les réseaux définis par l'utilisateur.
Les mappages de port réseau ne sont pas la seule façon dont les conteneurs Docker peuvent se connecter les uns aux autres. Docker a aussi un système de liaison qui permet de lier plusieurs conteneurs ensemble et d'envoyer des informations de connexion de l'un à l'autre. Quand les conteneurs sont liés, des informations sur un conteneur source peuvent être envoyées à un conteneur destinataire. Cela permet au destinataire de voir des données sélectionnées décrivant les aspects du conteneur source.
L'importance du nommage
Pour établir des liens, Docker s'appuie sur les noms de vos conteneurs.
Vous avez déjà vu que chaque conteneur que vous créez a un nom automatiquement
créé ; en effet vous êtes devenu familier avec notre vieil ami
nostalgic_morse
pendant ce guide. Vous pouvez aussi nommer les conteneurs
vous-même. Ce nommage fournit deux fonctions utiles :
-
Il peut être utile de nommer les conteneurs qui font des fonctions spécifiques d'une manière qui facilite leur mémorisation, par exemple nommer un conteneur contenant une application web
web
. -
Il fournit à Docker un point de référence qui lui permet de se référer à d'autres conteneurs, par exemple, vous pouvez spécifier de lier le conteneur
web
au conteneurdb
.
Vous pouvez nommer votre conteneur en utilisant le drapeau --name
, par exemple :
$ docker run -d -P --name web training/webapp python app.py
Cela lance un nouveau conteneur et utilise le drapeau --name
pour
nommer le conteneur web
. Vous pouvez voir le nom du conteneur en utilisant la
commande docker ps
.
$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aed84ee21bde training/webapp:latest python app.py 12 hours ago Up 2 seconds 0.0.0.0:49154->5000/tcp web
Vous pouvez aussi utiliser docker inspect
pour retourner le nom du conteneur.
NoteLes noms de conteneurs doivent être uniques. Cela signifie que vous ne pouvez appeler qu'un seul conteneur
web
. Si vous voulez réutiliser un nom de conteneur vous devez supprimer l'ancien conteneur (avecdocker container rm
) avant de pouvoir créer un nouveau conteneur avec le même nom. Comme alternative vous pouvez utiliser le drapeau--rm
avec la commandedocker run
. Cela supprime le conteneur immédiatement après qu'il soit arrêté.
Communication à travers les liens
Les liens permettent aux conteneurs de se découvrir et de transférer de manière sécurisée des
informations d'un conteneur à un autre conteneur. Quand vous établissez un lien, vous créez un
conduit entre un conteneur source et un conteneur destinataire. Le destinataire peut
alors accéder à des données sélectionnées sur la source. Pour créer un lien, vous utilisez le drapeau --link
.
D'abord, créez un nouveau conteneur, cette fois un contenant une base de données.
$ docker run -d --name db training/postgres
Cela crée un nouveau conteneur appelé db
à partir de l'image training/postgres
,
qui contient une base de données PostgreSQL.
Maintenant, vous devez supprimer le conteneur web
que vous avez créé précédemment pour pouvoir le remplacer
par un lié :
$ docker container rm -f web
Maintenant, créez un nouveau conteneur web
et liez-le avec votre conteneur db
.
$ docker run -d -P --name web --link db:db training/webapp python app.py
Cela lie le nouveau conteneur web
avec le conteneur db
que vous avez créé
plus tôt. Le drapeau --link
prend la forme :
--link <name or id>:alias
Où name
est le nom du conteneur que nous lions et alias
est un
alias pour le nom du lien. Cet alias est utilisé bientôt.
Le drapeau --link
prend aussi la forme :
--link <name or id>
Dans ce cas l'alias correspond au nom. Vous pourriez écrire l'exemple précédent comme :
$ docker run -d -P --name web --link db training/webapp python app.py
Ensuite, inspectez vos conteneurs liés avec docker inspect
:
$ docker inspect -f "{{ .HostConfig.Links }}" web
[/db:/web/db]
Vous pouvez voir que le conteneur web
est maintenant lié au conteneur db
web/db
. Ce qui lui permet d'accéder aux informations sur le conteneur db
.
Alors que fait réellement la liaison des conteneurs ? Vous avez appris qu'un lien permet à un
conteneur source de fournir des informations sur lui-même à un conteneur destinataire. Dans
notre exemple, le destinataire, web
, peut accéder aux informations sur la source db
. Pour faire
cela, Docker crée un tunnel sécurisé entre les conteneurs qui n'a pas besoin d'exposer
de ports en externe sur le conteneur ; quand nous avons démarré le
conteneur db
nous n'avons utilisé ni le drapeau -P
ni -p
. C'est un gros avantage de
la liaison : nous n'avons pas besoin d'exposer le conteneur source, ici la base de données PostgreSQL, au
réseau.
Docker expose les informations de connectivité pour le conteneur source au conteneur destinataire de deux façons :
- Variables d'environnement,
- Mise à jour du fichier
/etc/hosts
.
Variables d'environnement
Docker crée plusieurs variables d'environnement quand vous liez des conteneurs. Docker
crée automatiquement des variables d'environnement dans le conteneur cible basées sur
les paramètres --link
. Il expose aussi toutes les variables d'environnement
provenant de Docker du conteneur source. Celles-ci incluent les variables de :
- les commandes
ENV
dans le Dockerfile du conteneur source - les options
-e
,--env
, et--env-file
sur la commandedocker run
quand le conteneur source est démarré
Ces variables d'environnement permettent la découverte programmatique depuis le conteneur cible d'informations liées au conteneur source.
WarningIl est important de comprendre que toutes les variables d'environnement provenant de Docker dans un conteneur sont rendues disponibles à tout conteneur qui lui est lié. Cela pourrait avoir de sérieuses implications de sécurité si des données sensibles sont stockées dedans.
Docker définit une variable d'environnement <alias>_NAME
pour chaque conteneur cible
listé dans le paramètre --link
. Par exemple, si un nouveau conteneur appelé
web
est lié à un conteneur de base de données appelé db
via --link db:webdb
,
alors Docker crée une variable WEBDB_NAME=/web/webdb
dans le conteneur web
.
Docker définit aussi un ensemble de variables d'environnement pour chaque port exposé par le
conteneur source. Chaque variable a un préfixe unique de la forme <n>_PORT_<port>_<protocol>
Les composants dans ce préfixe sont :
- l'alias
<n>
spécifié dans le paramètre--link
(par exemple,webdb
) - le numéro de
<port>
exposé - un
<protocol>
qui est soit TCP soit UDP
Docker utilise ce format de préfixe pour définir trois variables d'environnement distinctes :
- La variable
prefix_ADDR
contient l'adresse IP de l'URL, par exempleWEBDB_PORT_5432_TCP_ADDR=172.17.0.82
. - La variable
prefix_PORT
contient juste le numéro de port de l'URL par exempleWEBDB_PORT_5432_TCP_PORT=5432
. - La variable
prefix_PROTO
contient juste le protocole de l'URL par exempleWEBDB_PORT_5432_TCP_PROTO=tcp
.
Si le conteneur expose plusieurs ports, un ensemble de variables d'environnement est défini pour chacun. Cela signifie, par exemple, si un conteneur expose 4 ports que Docker crée 12 variables d'environnement, 3 pour chaque port.
De plus, Docker crée une variable d'environnement appelée <alias>_PORT
.
Cette variable contient l'URL du premier port exposé du conteneur source.
Le 'premier' port est défini comme le port exposé avec le numéro le plus bas.
Par exemple, considérez la variable WEBDB_PORT=tcp://172.17.0.82:5432
. Si
ce port est utilisé pour tcp et udp, alors celui tcp est spécifié.
Finalement, Docker expose aussi chaque variable d'environnement provenant de Docker
du conteneur source comme une variable d'environnement dans la cible. Pour chaque
variable Docker crée une variable <alias>_ENV_<n>
dans le conteneur
cible. La valeur de la variable est définie à la valeur que Docker a utilisée quand il
a démarré le conteneur source.
Revenant à notre exemple de base de données, vous pouvez exécuter la commande env
pour lister les variables d'environnement du conteneur spécifié.
$ docker run --rm --name web2 --link db:db training/webapp env
<...>
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5432_TCP=tcp://172.17.0.5:5432
DB_PORT_5432_TCP_PROTO=tcp
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_ADDR=172.17.0.5
<...>
Vous pouvez voir que Docker a créé une série de variables d'environnement avec
des informations utiles sur le conteneur source db
. Chaque variable est préfixée
avec
DB_
, qui est rempli à partir de l'alias
que vous avez spécifié ci-dessus. Si l'alias
était db1
, les variables seraient préfixées avec DB1_
. Vous pouvez utiliser ces
variables d'environnement pour configurer vos applications pour se connecter à la base de données
sur le conteneur db
. La connexion est sécurisée et privée ; seul le
conteneur web
lié peut communiquer avec le conteneur db
.
Notes importantes sur les variables d'environnement Docker
Contrairement aux entrées d'hôte dans le fichier /etc/hosts
,
les adresses IP stockées dans les variables d'environnement ne sont pas automatiquement mises à jour
si le conteneur source est redémarré. Nous recommandons d'utiliser les entrées d'hôte dans
/etc/hosts
pour résoudre l'adresse IP des conteneurs liés.
Ces variables d'environnement ne sont définies que pour le premier processus dans le
conteneur. Certains démons, comme sshd
, les nettoient quand ils génèrent des shells
pour la connexion.
Mise à jour du fichier /etc/hosts
En plus des variables d'environnement, Docker ajoute une entrée d'hôte pour le
conteneur source au fichier /etc/hosts
. Voici une entrée pour le conteneur web
:
$ docker run -t -i --rm --link db:webdb training/webapp /bin/bash
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7 aed84ee21bde
<...>
172.17.0.5 webdb 6e5cdeb2d300 db
Vous pouvez voir deux entrées d'hôte pertinentes. La première est une entrée pour le conteneur web
qui utilise l'ID du conteneur comme nom d'hôte. La deuxième entrée utilise l'
alias du lien pour référencer l'adresse IP du conteneur db
. En plus de
l'alias que vous fournissez, le nom du conteneur lié, s'il est unique de l'alias
fourni au paramètre --link
, et le nom d'hôte du conteneur lié sont
aussi ajoutés à /etc/hosts
pour l'adresse IP du conteneur lié. Vous pouvez ping
cet hôte via n'importe laquelle de ces entrées :
root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping
root@aed84ee21bde:/opt/webapp# ping webdb
PING webdb (172.17.0.5): 48 data bytes
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms
56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms
NoteDans l'exemple, vous avez dû installer
ping
car il n'était pas inclus dans le conteneur initialement.
Ici, vous avez utilisé la commande ping
pour ping le conteneur db
en utilisant son entrée d'hôte,
qui se résout à 172.17.0.5
. Vous pouvez utiliser cette entrée d'hôte pour configurer une application
pour faire usage de votre conteneur db
.
NoteVous pouvez lier plusieurs conteneurs destinataires à une seule source. Par exemple, vous pourriez avoir plusieurs conteneurs web (nommés différemment) attachés à votre conteneur
db
.
Si vous redémarrez le conteneur source, les fichiers /etc/hosts
sur les conteneurs liés
sont automatiquement mis à jour avec la nouvelle adresse IP du conteneur source,
permettant à la communication liée de continuer.
$ docker restart db
db
$ docker run -t -i --rm --link db:db training/webapp /bin/bash
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7 aed84ee21bde
<...>
172.17.0.9 db