Rapide intro sur Docker, installation, commandes basiques, dockerfile et docker-compose.

Les bases en somme.

Quick start.

Rendez vous sur https://hub.docker.com/ pour télécharger Docker Desktop (850 Mo environ).

Personnellement j’avais Oracle VM sur ma machine et Docker n’a pas aimé. J’ai eu aussi d’autres problèmes par la suite, du coup le plus simple c’est de tout désinstaller et tout réinstaller, à commencer par HyperV sur Windows. Virer aussi les variables d’environnement qui commence par DOCKER.

Une fois installé, ouvrir une fenêtre de commande et taper « docker —version » :

Untitled

Votre installation est correcte.

Les bases

Si comme moi Docker vous l’avez vu de loin, il est peut être bon de revoir les bases, qq tuto sur le net, des petites videos youtubes peuvent vous faire du bien. Par exemple https://www.youtube.com/watch?v=fdlZqRZXWOc&list=PLn6POgpklwWq0iz59-px2z-qjDdZKEvWd

La vidéo nous explique comment créer et executer une image docker basé sur une distrib linux Alpine qui a l’avantage d’être ultra légère (5Mo !)

Commandes utiles

docker --version 

docker ps 
docker ps - a

docker pull alpine

docker run alpine:latest

docker -di --name mycontainername alpine:latest

docker run mycontainername 

docker exec -ti mycontainername sh

docker stop mycontainername 

docker rm mycontainername 


remove all containers forcefully
docker rm -f $(docker ps -a -q)

remove all docker images forcefully
docker rmi -f $(docker images -q)

Monter un serveur web

https://www.youtube.com/watch?v=NJ2berxUmgg&list=PLn6POgpklwWq0iz59-px2z-qjDdZKEvWd&index=2

docker run -tid -p 8080:80 --name web nginx:latest

Cette commande lance un container avec l’image nginx qui est un serveur web, avec une redirection de port 8080 sur la machine host vers le port 80 du container.

Untitled (1)

Si vous avez redémarré votre machine, il faudra relancer le container :

docker start web

Pour avoir des infos sur votre container :

docker inspect web

[
    {
        "Id": "203a6655feec009ab84d8c61bc1135fbd49c9f9da7672cf7efb651594f7ed859",
        "Created": "2020-01-09T15:54:16.1392739Z",
        "Path": "nginx",
        "Args": [
            "-g",
            "daemon off;"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 3045,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-01-09T15:54:17.0341364Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:f7bb5701a33c0e572ed06ca554edca1bee96cbbc1f76f3b01c985de7e19d0657",
        "ResolvConfPath": "/var/lib/docker/containers/203a6655feec009ab84d8c61bc1135fbd49c9f9da7672cf7efb651594f7ed859/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/203a6655feec009ab84d8c61bc1135fbd49c9f9da7672cf7efb651594f7ed859/hostname",
        "HostsPath": "/var/lib/docker/containers/203a6655feec009ab84d8c61bc1135fbd49c9f9da7672cf7efb651594f7ed859/hosts",
        "LogPath": "/var/lib/docker/containers/203a6655feec009ab84d8c61bc1135fbd49c9f9da7672cf7efb651594f7ed859/203a6655feec009ab84d8c61bc1135fbd49c9f9da7672cf7efb651594f7ed859-json.log",
        "Name": "/web",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {
                "80/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "8080"
                    }
                ]
            },
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Capabilities": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                52,
                176
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/6f5597eeb9943113a851aa40f4fa879f9be20b30757ba75495377110a157f0bb-init/diff:/var/lib/docker/overlay2/fb2e13f274925a9b6d047910047d5c41d5cdcd7ce743f13f7343cf862e39ba0c/diff:/var/lib/docker/overlay2/fe36b3a86cae3bbb35c68761d5e56bb8daeba054f7f564dca68d300575078531/diff:/var/lib/docker/overlay2/91166ce1015d94d52e6d00dd3afbbb9c8443be268a9c584cb37296e56bbd5d44/diff",
                "MergedDir": "/var/lib/docker/overlay2/6f5597eeb9943113a851aa40f4fa879f9be20b30757ba75495377110a157f0bb/merged",
                "UpperDir": "/var/lib/docker/overlay2/6f5597eeb9943113a851aa40f4fa879f9be20b30757ba75495377110a157f0bb/diff",
                "WorkDir": "/var/lib/docker/overlay2/6f5597eeb9943113a851aa40f4fa879f9be20b30757ba75495377110a157f0bb/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "203a6655feec",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": true,
            "OpenStdin": true,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.17.6",
                "NJS_VERSION=0.3.7",
                "PKG_RELEASE=1~buster"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "Image": "nginx:latest",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
            },
            "StopSignal": "SIGTERM"
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "c47117b944d6f019ff284a4132f4cf4e528a1c2489fdbcb783523b48e6de1a1a",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "80/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "8080"
                    }
                ]
            },
            "SandboxKey": "/var/run/docker/netns/c47117b944d6",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "5190900bdbb29ebe0ff029f3dd285ed71720a52f4167176902cef5e5b2d7c4d1",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "ed4b431234b99c2152d29f4c589ea7e9c6d2563db1318aaa99dc29288510b8b8",
                    "EndpointID": "5190900bdbb29ebe0ff029f3dd285ed71720a52f4167176902cef5e5b2d7c4d1",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }
        }
    }
]

Vous pouvez accéder à votre nouveau seveur web de votre container depuis un browser de votre machine sur localhost:8080

Monter un volume

accéder au container avec un shell

docker exec -ti web sh

On peut modifier la page web d’accueil situé dans /usr/share/nginx/html/index.html et faire un refresh sur le browser, on verra notre modif, ca marche.

Arrêter et relancer ce container n’aura pas d’incidence.

Par contre, si on supprime le container et on le remet en place, il ne va plus rester de trace de notre modification.

Il faut alors utiliser des volumes montés (une sorte de passerelle entre votre disque dur de l’hote du container et celui ci).

on va supprimer notre container pour en refaire un tout propre :

docker rm -f web

docker run -tid -p 8080:80 -v D:\\Docker\\webshare:/usr/share/nginx/html --name web nginx:latest

on a ajouter le paramètre -v pour volume.

Il faut aussi cocher le partage de drives sur la config de Docker Desktop

Untitled (4)

Si on fait un inspect de ce container :

(...)
"Mounts": [
            {
                "Type": "bind",
                "Source": "/host_mnt/d/Docker/webshare",
                "Destination": "/usr/share/nginx/html",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
(...)

On voit notre source qui est « /host_mnt/d/Docker/webshare »

Dans mon dossier D:\Docker\webshare j’ai ajouté un fichier index.html avec un bout de code « <h1>Hello World</h1> ».

Un refresh de ma page localhost:8080 m’affiche mon fichier, magique !

On peut donc monter une image docker avec un serveur web dedans qui execute un site dont le code source se situe ailleurs, qq part sur votre machine. Pratique pour le développement.

Volumes plus proprement

La commande suivante permet de lister les volumes montés :

docker volume ls

Pour une raison que j’ignore, le volume que l’on a monté dans la commande précédente pour le site web n’est pas listée. On appelle ce genre de volume des volumes « Host ». On va créer des volume « Named » :

docker volume create webshare

La précédente commande va créer un volume avec le nom « webshare ». Listons les volumes :

docker volume ls

DRIVER              VOLUME NAME
local               webshare

Inspectons le détail de celui ci :

docker volume inspect webshare

[
    {
        "CreatedAt": "2020-01-10T08:41:00Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/webshare/_data",
        "Name": "webshare",
        "Options": {},
        "Scope": "local"
    }
]

Le mount point est « /var/lib/docker/volumes/webshare/_data », nous on voudrait avoir un path windows « D:\Docker\webshare »

TODO Comment modifier ce mountpoint ???

On va maintenant relancer notre serveur avec ce volume (pensez à faire un stop et un rm de votre précédent container)

docker run -tid --name web -p 8080:80 --mount source=webshare,target=/usr/share/nginx/html nginx:latest

Dockerfile

Le dockerfile est un fichier de configuration permettant d’executer un ensemble de commande pour créer une image docker spécifique à nos besoins.

Par exemple, pour monter un serveur web avec wordpress, on va avoir besoin de wordpress (fichiers code source php), d’un serveur web (nginx par exemple), de php7, d’une base de donnée (mySQL) d’un OS (debian par exemple) et peut être d’un ensemble d’outil (VIM, …)

Tout ces éléments peuvent être « installé » via un dockerfile.

L’avantage c’est que ce fichier une fois en place permet d’être réutilisé facilement et reconstitura un environnement identique. L’image n’étant plus physique et volumineuse mais représentative et très légère. On peut partager un dockerfile par email alors qu’une image disk non.

Voici un example de dockerfile

FROM debian

LABEL Yann <yannvasseur@reactor.Fr>

RUN apt-get update

RUN apt-get install -y nginx

Ce docker file se base sur une image debian.

Label (anciennement MAINTAINER) identifie l’auteur de cette image docker

Run lance une commande. Dans un premier temps on va mettre a jour l’existant, puis installer nginx (le -y permet de répondre yes aux questions demandées).

Pour construire notre image, on va utiliser la commande docker build. Rendez vous dans le dossier où se trouve votre dockerfile (moi D:\Docker\dockerfiles), puis :

docker build -t yann/myctn .

Cette commande construit une image avec un nom yann/myctn (autheur/nom image, une convention). Le point permet de d’indiquer le répertoire courant. Lister les images de votre host :

docker image ls

Vous devriez la voir dans la liste. Maintenant lancer le container et un shell sur votre container :

docker run -tid --name myctn yann/myctn 
docker exec -ti myctn sh

Ca y est, votre container est lancé et vous avez un shell dessus. Rapide !

Docker-Compose

Docker-Compose est une autre façon de créer des conteneurs. L’idée est monter plusieurs containers en une seule fois avec un fichier docker-compose.yml.

Par exemple, essayons de monter un site web wordpress. Dans mon exemple je vais prendre mon site web reactor.fr

Pour que wordpress fonctionne, il faut php + fichier php (wordpress) + mysql (base de donnée) et un serveur web.

version: '2'

services:
  db:
    image: mysql:5.7
    container_name: db_server
    volumes:
      - ./reactorwp.db.sql:/docker-entrypoint-initdb.d/reactorwp.db.sql
    ports:
      - 3306:3306
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: Passw0rd # any random string will do
      MYSQL_DATABASE: wordpress782 # the name of your mysql database
      MYSQL_USER: wordpressuser782 # the name of the database user
      MYSQL_PASSWORD: 123456 # the password of the mysql user

  wordpress:
    depends_on:
      - db
    image: wordpress:php7.1 # we're using the image with php7.1
    container_name: wp_web
    environment:
      WORDPRESS_DB_HOST: db:3306 
      WORDPRESS_DB_USER: wordpressuser782 
      WORDPRESS_DB_PASSWORD: 123456
      WORDPRESS_DB_NAME: wordpress782
    ports:
      - 8000:80
    restart: always
    volumes:
      - ./src:/var/www/html

Le fichier ci dessus est nommé docker-compose.yml

Pour lancer nos containers on va lancer la commande

docker-compose up
ou 
docker-compose up -d

Pour arrêter nos containers:

docker-compose down

Explications :

le fichier docker-compose.yml est composé de deux images

mysql:5.7 https://hub.docker.com/_/mysql (mysql 5.7 debian)

wordpress:php7.1https://hub.docker.com/_/wordpress/ (php7 apache alpine)

On va donc obtenir deux containers différents

Untitled (5)

Notons les deux volumes, le premier concernant la base de donnée :

volumes:
      - ./reactorwp.db.sql:/docker-entrypoint-initdb.d/reactorwp.db.sql

Cette ligne permet de charger un fichier sql pour initialiser la base de données avec des données justement. J’ai au préalable effectué un dump de ma base dans un fichier reactorwp.db.sql que j’ai mis dans le répertoire de travail docker sur mon host local.

Lorsque le container va se lancer, ce script sera appelé et permet donc d’alimenter la base. Ceci peut s’avérer pratique dans le cadre d’un développement pour avoir un jeu de données initiale et commun à tous.

Le second volume concerne le site wordpress :

 volumes:
      - ./src:/var/www/html

J’ai crée un répertoire « src » sur mon host local qui contient le contenu de mon site web en prod que j’ai copié. Ainsi, en montant ce volume, j’indique au container wordpress d’aller me chercher les fichiers du site web non pas habituellement sur /var/www.html mais sur /src, sur mon host.

Tindin ! En tapant l’url localhost:8000 on arrive sur mon site web

Untitled (6)

A noter qu’au clic sur un des liens on est redirigé vers reactor.fr, mais ceci est un autre problème.

 

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée Champs requis marqués avec *

Publier des commentaires