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

Docker Compose Install

Installation sur Windows

Prérequis:

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

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}")

Source

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:

Drivers:

Scopes:

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

Commandes utiles:
  • $ 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:

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

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

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.

Debugging

Pour savoir sur quel réseau se trouve un container:

$ docker inspect container-name -f "{{json .NetworkSettings.Networks }}" | jq 

Divers

MySQL

Docker Hub 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.


Source