Table des matières
Installation de Docker
Cette page prend en compte la version 1.12 de Docker et supérieure.
Installation sur Ubuntu
→ Documentation officielle:
Installation sur WSL2, sans Docker Desktop:
Installation avec wget
:
# wget -qO- https://get.docker.com | sh
Comme l'installation de Docker le précise, ajouter l'utilisateur au groupe docker
:
$ sudo usermod -aG docker your-user
Permet de ne pas avoir à utiliser sudo
pour les commandes Docker (voir Post-Intallation steps).
Ensuite, se déconnecter de la session et se reconnecter.
Pour essayer voir si l'installation fonctionne :
$ docker run hello-world
Docker Compose
Installation sur Windows
Prérequis:
- Windows 10 64-bit
- Installation propre
- Utilisation pour développement et tests, pas fait pour la production
L'installation de Docker pour Windows est une machine virtuelle Hyper-V qui roule MobyLinuxVM qui exécute Docker.
D'abord il faut activer Hyper-V dans Programs and Features de Windows. Il est possible également que la virtualisation matérielle doive être activée dans le BIOS, soit Intel VT/VT-x ou AMD-V.
Télécharger le paquet sur le site de Docker. Installer ce paquet.
Fonctions de base
$ docker version $ docker info
Images et conteneurs
- Une image est un conteneur qui ne roule pas, un genre de patron, ou modèle, pour créer des conteneurs qui exécuteront une tâche.
- Un conteneur est une image qui exécute une tâche.
Pour la gestion plus simple des images et containers, on peut utiliser LazyDocker.
Images
Récupérer une image
$ docker pull <image-name>
On peut spécifier une version de l'image:
$ docker pull <image-name>:<version>
Exemples:
$ docker pull ubuntu:latest $ docker pull ubuntu:14.04 $ docker pull ubuntu
Quand on ne spécifie pas de version, c'est généralement latest
qui est sélectionné, donc $ docker pull ubuntu
est équivalent à $ docker pull ubuntu:latest
.
Pour obtenir toutes les versions d'une image on utilise -a
:
# docker pull -a fedora
Supprimer une image
Aucun conteneur ne doit utiliser l'image avant de la supprimer.
$ docker rmi <image-name>
Démarrer une image
$ docker run -d --name web -p 80:8080 <image-name>
On utilise la commande run
. Le paramètre -d
est pour le mode detached, le –name
est pour donner un nom au conteneur et -p
est pour faire de la redirection de port: le port 80 sur l'hôte ira au port 8080 sur le conteneur.
Avec variables d'environnement:
$ docker run -d --name containerName --restart=always -e DB_URL='url' -p 44302:3000 registry.example.com/imagedir/imagename:latest
Supprimer les images
$ docker rmi <image-name>
Pour supprimer toutes les images:
$ docker rmi $(docker images -q)
Supprimer les images non utilisées (non tagguées):
$ docker rmi -f $(docker images | grep "<none>" | awk "{print \$3}")
Supprimer tout
Ultimement, on peut supprimer toutes les images, les containers, volumes et réseaux qui ne sont pas utilisés par un conteneur avec:
$ docker system prune
Pour supprimer tout, peu importe si utilisé ou non:
$ docker system prune -a
Transférer une image à un autre machine
Créer l'archive:
$ docker save -o <nom-archive> <nom-image>
Transférer le fichier avec scp.
$ docker load -i <nom-archive>
Travailler avec les conteneurs
Commandes de gestion de containers
Commande | Description |
---|---|
docker start <short guid|container name> | Démarre un container |
docker stop <short guid|container name> | Arrête un container |
docker restart <short guid|container name> | Redémarre un container |
docker kill <short guid|container name> | Arrête un container de façon moins gracieuse |
docker rm <short guid|container name> | Supprime un container arrêté. Utiliser -f pour forcer la suppression d'un container en exécution. |
Liste des conteneurs
$ docker ps --all $ docker ps --filter "status=exited"
Démarrer un conteneur
Tel que mentionné probablement dans une autre page de Docker sur ce wiki, on peut tester l'utilisation d'un conteneur par un hello-world
:
$ docker run hello-world
Arrêter les conteneurs
$ docker stop <container-name|container-guid>
Pour arrêter tous les conteneurs:
$ docker stop $(docker ps -aq)
Le -a
signifie all et le -q
signifie quiet.
Supprimer les conteneurs arrêtés
$ docker container ls --all | grep Exited | cut -d ' ' -f 1 | xargs docker container rm
Supprimer un container sans être certain qu'il existe (utile pour des scripts de CI):
$ docker container rm -f container-name 2>/dev/null || true
Supprimer tous les containers arrêtés:
$ docker rm $(docker ps --filter status=exited -q)
Obtenir un shell d'un container
docker attach
La commande docker attach <shortguid>
permet d'obtenir l'invite de commande du container. Le problème c'est qu'il s'attache au PID 1.
nsenter
Ceci nous permet d'entrer un namespace. Requiert un PID qu'on peut obtenir avec inspect
.
$ docker inspect <shortguid> | grep Pid "Pid": 1923,
Une fois le PID obtenu, on peut faire:
$ nsenter -m -u -n -p -i -t 1923 /bin/bash
Une fois terminé avec le shell, on peut faire exit
et contrairement à un attach
, un exit
n'arrêtera pas le container.
Si nsenter
n'est pas présent sur le système (hôte), on peut l'obtenir avec ce guide.
docker exec
À partir de la version 1.3 de Docker, on peut faire la commande exec
:
$ docker exec -it <shortguid> /bin/bash $ docker exec -it c1 sh $ docker exec -u 0 -it c1 sh # force le root
L'alternative à docker exec
est d'utiliser docker debug.
Docker Logs
Pour avoir la sortie d'un container, il faut utiliser docker logs
.
$ docker logs containerId
Volumes
Exemple d'utilisation de volume:
docker run -d --name postgres \ -p 5432:5432 --restart=always \ -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=database_name \ -e PGDATA=/var/lib/postgresql/data/pgdata \ -v pgdata:/var/lib/postgresql/data \ postgres:14.1
Le pgdata
signifie que ce sera stocké sous le /var/lib/docker/volumes
. On peut spécifier un chemin plus spécifique, ici relatif:
-v ./postgres-data:/var/lib/postgresql/data
Les volumes sont localisés (linux) à : /var/lib/docker/volumes/
.
Réseau
Pour spécifier le réseau d'un conteneur:
docker run -d --name app \ --network <NETWORK_NAME> \ company/app:latest
Networking
Liste des réseaux Docker:
$ docker network ls
Inspecter un réseau:
$ docker network inspect <docker-network-name>
Il y a trois réseaux par défaut:
host
bridge
(synonyme de vitual switch, vswitch, ou nat en Windows)none
Drivers:
- host
- bridge
- overlay
- null
Scopes:
- local
- swarm → multi-host
On peut donc faire:
$ docker network inspect bridge
Utilisation de host.docker.internal
.
--add-host=host.docker.internal:host-gateway
Créer un réseau
On crée un réseau avec le driver bridge
(c'est la valeur par défaut si non spécifié):
$ docker network create -d bridge --subnet 10.0.0.1/24 new-network
Optionnel: $ sudo apt-get install bridge-utils
$ brctl show
$ ip link show
Ajouter un container à un réseau:
$ docker container run -dt --name c1 --network new-network alpine sleep 1d $ docker container run -dt --name c2 --network new-network alpine sleep 1d
Les deux seront dans le réseau new-network
, en faisant:
$ docker network inspect new-network
"Containers": { "872125d8f607269236387b805786a2106b77ecc65147eb3faf030fcc29263b23": { "Name": "c1", "EndpointID": "936949131a5a94bc3b03ae72031ad165084867ab626f68d6402e41181869d7be", "MacAddress": "02:42:0a:00:00:02", "IPv4Address": "10.0.0.2/24", "IPv6Address": "" }, "9ab0378ebcfb60a347ff388b820820796dea510394b98861365d94d1e753438d": { "Name": "c2", "EndpointID": "9c4eb47cd1efb2518f27f14f4653ff9f6b53bda6bc63d7a63decee6f28091639", "MacAddress": "02:42:0a:00:00:03", "IPv4Address": "10.0.0.3/24", "IPv6Address": "" } },
Tester
Une façon de valider, c'est d'aller dans le container:
$ docker exec -it c1 sh
Dans le container:
# ping 10.0.0.3
ou par le nom du container:
# ping c2
Chaque fois qu'on invoque un container avec l'option --name
, une entrée DNS est créée pour résolver le nom.
Publish port
En utilisant l'option -p <hostport>:<containerport>
.
Multi-host networking
Se fait avec le overlay driver. S'applique à plusieurs hosts ou nodes ou machines qui roulent le Docker Engine.
VXLAN tunnel, ports utilisés:
- 2789/udp
- 7946/tcp/udp
- 2377/tcp
user@node1 $ docker swarm init
Ceci donnera une commande pour joindre le swarm qui sera à exécuter sur d'autres machines.
user@node2 $ docker swarm join --token <token> 172.32.45.12:2377
Une fois que le node2 a joint, on peut faire
user@node1 $ docker node ls
Si on regarde les réseaux (docker network ls
), un nouveau est présent: ingress
de type overlay
.
user@node1 $ docker network create -d overlay new-overlay-network
Le réseau new-overlay-network
sera créé sur node1 mais pas sur les autres nodes. Pour qu'il apparaisse, il faut avoir un container qui l'utilise.
user@node1 $ docker service create --name new-svc --network new-overlay-network --replicas 2 alpine sleep 1d user@node1 $ docker service ps new-srv
Un container sera créé sur le node1 et un autre sur le node2. Sur le node2 on verra désormais le réseau new-overlay-network
.
Participer à des réseaux existants
Avec le pilote de Linux MACVLAN
Linux MACVLAN
- Chaque container a son propre IP
- Chaque container a sa propre adresse MAC
Windows l2bridge
- Chaque container a son propre IP
- Tous les containers ont la même adresse MAC
MACVLAN requière le mode promiscuous, ce qui n'est pas disponible sur les services cloud tels que AWS/Azure.
Avec le pilote IPVLAN
- Ne donne pas aux containers des adresses MAC différentes.
- Similaire à Windows l2bridge.
- Considérations spéciales pour le DHCP
- Les containers ne peuvent pas pinger leur host
Prend en considération deux machines physiques ayant Docker Engine sur un réseau 192.168.1.0/24.
$ docker network create -d ipvlan --subnet=192.168.1.0/24 --gateway=192.168.1.254 --ip-range=192.168.1.0/28 -o ipvlan_mode=l2 -o parent=eth0 ps-ip
Le l2
est pour Layer 2.
Ajouter un container participant au réseau:
$ docker run -dt --name c1 --network ps-ip alpine sleep 1d
Services réseau
- Service Discovery
- Port-based routing with the routing mesh
- App-aware routing with the HTTP routing mesh
Service Discovery
Prend en compte quatre nodes, qui participent à un swarm.
user@node1 $ docker network create -d overlay overnet user@node1 $ docker service create --name web -p 5000:8080 --replicas 3 --network overnet image-of/webapp
Le nombre de replicas à 3 est voulu pour démontrer que le 4e node qui n'aura pas de tâche (container du service) pourra quand même résolver le service vers les trois autres nodes.
HTTP Routing Mesh
Application Layer construit sur le L4 routing mesh.
- Permet plusieurs services sur le même port
- Opère sur le layer 7 d'application
Debugging
Pour savoir sur quel réseau se trouve un container:
$ docker inspect container-name -f "{{json .NetworkSettings.Networks }}" | jq
Divers
MySQL
$ docker run --name mysqlserver -v /some/path/to/mysqldata:/var/lib/mysql -e MYSQL_ROOT_HOST=% -p 3306:3306 -d mysql/mysql-server:8.0
Un One-time-password sera créé et affiché dans les logs:
$ docker logs mysqlserver 2>&1 | grep GENERATED
Dockerfile
Application node
FROM node:8.7.0-alpine COPY ["package.json", "./"] RUN npm install --production --silent && mv node_modules ../ COPY . . EXPOSE 3000 CMD npm run start
nsenter
Le programme nsenter
permet de démarrer un programme dans l'espace de nom (namespace) d'un autre processus.
Ubuntu 14.04 n'a pas nsenter
d'installer. Il est possible d'installer les dépendances et de compiler util-linux
pour l'obtenir, mais vu que c'est parfois utilisé dans le cadre d'une gestion Docker, on peut justement utiliser un conteneur pour se faire.
Démarrer le conteneur
$ docker run --name nsenter -it ubuntu:14.04
Avec l'option -it
on tombe dans le conteneur.
Dans le conteneur
$ apt-get update $ apt-get install git build-essential libncurses5-dev libslang2-dev gettext zlib1g-dev libselinux1-dev debhelper lsb-release pkg-config po-debconf autoconf automake autopoint libtool
$ git clone git://git.kernel.org/pub/scm/utils/util-linux/util-linux.git util-linux $ cd util-linux/
$ ./autogen.sh $ ./configure --without-python --disable-all-programs --enable-nsenter
make
Sur l'hôte
Une fois sorti du conteneur, ou bien dans un autre shell sur l'hôte, on fait:
# docker cp nsenter:/util-linux/nsenter /usr/local/bin/ # docker cp nsenter:/util-linux/bash-completion/nsenter /etc/bash_completion.d/nsenter
Ensuite on peut utiliser nsenter
sur l'hôte.