Ce tutoriel a pour but de découvrir la solution de conteneur Docker et son écosystème.
| Les fichiers utilisés dans ce tutoriel sont disponibles dans le dépot git suivant : https://gitlab.in2p3.fr/cavet/tp-docker-obs |
Pour récupérer les fichiers vous pouvez cloner le dépot git :
$ git clone https://gitlab.in2p3.fr/cavet/tp-docker-obs.git
Dans ce tutoriel, nous allons utiliser différents OS pour les exécuter les conteneurs : CentOS 7, Ubuntu, Alpine…
Installation de Docker
Utilisation de Docker version 19.03.5-ce, disponible ici : Docker Website.
-
Linux CentOs : Docker Website
-
Docker client/démon :
-
$ yum install -y yum-utils device-mapper-persistent-data lvm2 $ yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo $ yum install -y docker-ce docker-ce-cli containerd.io $ systemctl start docker
-
Linux Ubuntu : Docker Website
-
Docker client/démon :
-
$ apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - $ add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" $ apt-get install docker-ce docker-ce-cli containerd.io
-
Docker Compose (v1.24.1) :
$ curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose $ chmod +x /usr/local/bin/docker-compose $ ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
-
Docker Machine (v0.16.2) :
$ curl -L https://github.com/docker/machine/releases/download/v0.16.2/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine &&
chmod +x /tmp/docker-machine &&
sudo cp /tmp/docker-machine /usr/local/bin/docker-machine
$ ln -s /usr/local/bin/docker-machine /usr/bin/docker-machine
-
Mac OS : Docker Website pour Docker Desktop.
-
Windows : Docker Website pour Docker Desktop.
Pour tester :
$ docker version $ docker-compose version $ docker-machine version
L’aide de Docker est accessible via la commande suivante :
$ docker help
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/root/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env
var and default context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
builder Manage builds
config Manage Docker configs
container Manage containers
context Manage contexts
engine Manage the docker engine
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes
Commands:
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
Run 'docker COMMAND --help' for more information on a command.
Instructions globales pour le tutoriel
-
root@id : super utilisateur dans le conteneur avec l’identifiant
id = CONTAINER ID = bb9720… -
Toutes les instructions (noms, commandes) sont en minuscule sauf le
Dockerfile. -
Commande : précédé d’un
$. -
Output d’une commande : sans
$. -
Instruction sur la ligne suivante :
\. -
Attention au chemin local :
$ pwd.
Mes premiers conteneurs
Exécution du premier conteneur
Lancer un conteneur basique avec le client Docker :
-
Récupérer la dernière version de l’image CentOS depuis le Docker Hub (Docker Store) et l’éxécuter en ouvrant un shell bash.
-
Options : i - STDIN open, t - pseudo-tty terminal, rm - remove container after use.
$ docker pull centos:latest $ docker run -it --name mycontainer --rm centos [root@id /]$ cat /etc/redhat-release CentOS Linux release 8.0.1905 (Core) [root@id /]$ yum install -y nano [root@id /]$ exit
$ docker ps $ docker images $ docker logs mycontainer $ docker inspect mycontainer $ docker ps -a
| Le client Docker permet de lancer des conteneurs de deux manières : |
$ docker run ... $ docker container run ...
Quelques commandes pour gérer le système, nettoyer les conteneurs et les images
Ne pas supprimer l’image Jupyter avec : $ docker rmi $(docker images -q)
|
$ docker system df $ docker system prune $ docker rm -f id $ docker rm -f $(docker ps -a -q) $ docker rmi id $ docker rmi $(docker images -q)
Exécution du second conteneur
Lancer un conteneur avec Python :
-
Récupérer et lancer un conteneur utilisant une image avec le shell Python pré-installé puis le même conteneur en ouvrant le shell bash.
-
Choisir le tag de l’image : 2.7 ou 3.7.
$ export tag=3.7
$ docker run -it --name mycontainer --rm python:$tag
Python XXX
>>> print('Hello Python')
Hello Python
>>> exit()
$ docker run -it --name mycontainer --rm python:$tag /bin/bash
[root@id /]$ python
Python XXX
$ docker ps -a
Mes premières applications
| On distingue deux types d’applications : micro-service ou application scientifique. |
Exécution de la première application
Lancer une application micro-service permettant d’exécuter des Notebooks Python :
-
Récupérer l’image Jupyter Scipy Notebook qui est basée sur Ubuntu et qui contient le Jupyter Notebook serveur, Scipy et JupyterLab (vous pouvez aussi utiliser une image de taille plus petite, la Jupyter Base Notebook :
base-notebook). Attention : la taille compressée de Jupyter Scipy Notebook est de 2 GB (4,39 GB décompréssée), le temps de téléchargement avoisine ∼10min. -
Lancer l’image en mode détaché et avec la publication des ports réseaux (association des ports conteneur/hote).
-
Options : d - detach processus, p - network port.
$ docker pull jupyter/scipy-notebook Already exists Download complete Extracting Pull complete $ docker run -d --name myjupyter -p 8888:8888 jupyter/scipy-notebook $ docker ps
Se connecter à l’interface Jupyter :
-
Vérifier que l’utilisateur est
jovyanet récupérer son jeton de connexion.
$ docker logs myjupyter http://127.0.0.1:8888/?token=... $ docker exec myjupyter jupyter notebook list $ docker exec myjupyter pwd /home/jovyan
http://127.0.0.1:8888/?token=...
Copier un fichier stocké localement dans le conteneur pour l’exécuter :
-
Utiliser un Notebook Python ou récupérer celui du détecteur d’ondes gravitationnelles LIGO, mettre le Notebook dans un répertoire local et le copier dans le conteneur :
$ mkdir local_work && cd local_work $ wget https://losc.ligo.org/s/events/LOSC_Event_tutorial.ipynb $ docker cp LOSC_Event_tutorial.ipynb myjupyter:/home/jovyan/work
> Run LOSC_Event_tutorial.ipynb ModuleNotFoundError: No module named 'readligo'
Exécution de la deuxième application
Lancer une deuxième instance du serveur Jupyter afin d’exécuter le Notebook permettant d’analyser les données d’un évènement de LIGO :
-
Récupérer l’ensembles des données de LIGO.
-
Exporter le chemin local dans une variable d’environnement.
-
Changer le port du conteneur redirigé localement.
-
Monter le répertoire local
local_workdans le conteneur. -
Options : v - mount volume.
$ wget https://losc.ligo.org/s/events/LOSC_Event_tutorial.zip && unzip LOSC_Event_tutorial.zip $ export user_path=`pwd` $ docker run -d --name myjupyter2 -p 8889:8888 -v $user_path/LOSC_Event_tutorial:/home/jovyan/work jupyter/scipy-notebook
> Run LOSC_Event_tutorial.ipynb
Tuer les deux instances Jupyter.
Création d’images
Création de la première image
Construire l’image d’une application echo et la lancer dans un conteneur :
-
Copier le
Dockerfile(recette de construction d’image) et le fichier.dockerignore(sélectionne les fichiers copiés dans le conteneur lors dubuild) dans un répertoirelocal_build. -
Construire une image de l’application et la lancer.
-
Options : t - tag name
FROM centos:7.7.1908 MAINTAINER Cecile Cavet "ccavet@apc.in2p3.fr" RUN yum install -y nano ENTRYPOINT ["echo"] CMD ["Le runscript est la commande par défaut du conteneur !"]
#.dockerignore .DS_Store .git Dockerfile*
$ mkdir local_build && cd local_build $ ls -a .dockerignore Dockerfile $ docker build -t myapp . $ docker images myapp latest 208c47af0787 3 days ago 918MB $ docker run myapp Le runscript est ... $ docker run myapp hello world hello world
Création de la deuxième image
Construire une image d’une application scientifique en installant des paquets spécifiques et la lancer dans un conteneur :
-
Copier le
Dockerfiledans un fichierDockerfile.appdans le répertoirelocal_build. -
Copier les fichiers
requirements.txtetLOSC_Event_tutorial.pydans le répertoirelocal_build. -
Modifier le
Dockerfile.apppour qu’il puisse exécuter le script PythonLOSC_Event_tutorial.py(modifier/rajouter les instructionsCOPY,ENTRYPOINTetCOMMAND). -
Construire une image de l’application et la lancer avec le volume des données LIGO monté dans le conteneur.
numpy==1.17.2 scipy==1.3.1 h5py==2.9.0 simplejson==3.16.0 matplotlib==3.1.1 ipython==7.8.0 ipython-genutils==0.2.0
WORKDIR /app COPY . /app/ RUN pip install --no-cache-dir -r requirements.txt ENTRYPOINT ["python"] CMD ["LOSC_Event_tutorial.py"]
$ cp ../local_work/LOSC_Event_tutorial/LOSC_Event_tutorial.py . $ docker build -t myapp -f Dockerfile.app . $ docker images myapp latest 208c47af0787 3 days ago 1.15GB $ docker run -v $user_path/LOSC_Event_tutorial:/app myapp $ ls -lrt ../local_work/LOSC_Event_tutorial GW150914_strain.png ...
Gestion des images
Docker Hub
Explorer le Docker Hub (Store, https://hub.docker.com) dans le but de trouver l’image Python utilisée précédemment et son Dockerfile.
Docker Registry
Mettre en place un registre local et pousser une image dans ce gestionnaire d’image :
-
Récupérer l’image Registry et lancer le service correspondant.
-
Tagger l’image myapp et la pousser sur le registre.
-
Options : restart always - always restart container in case of failure.
$ docker run -d -p 5000:5000 --restart always --name registry registry:2 $ docker tag myapp localhost:5000/myapp $ docker images localhost:5000/myapp latest 88280d4a85ec 9 days ago 1.15GB $ docker push localhost:5000/myapp $ docker exec registry ls /var/lib/registry/docker/registry/v2/repositories
GitLab-CI
Réutiliser le projet en Python myapp et utiliser l’intégration continue pour permettre la construction automatique d’une image Docker accessible via le registre GitLab :
-
Copier le fichier d’intégration continue
.gitlab-ci.yaml.exampledanslocal_build/.gitlab-ci.yaml -
Pousser le contenu du répertoire
local_builddans un projet de GitLab. -
Vérifier l’éxécution du pipeline de CI sur l’interface graphique de GitLab (
/projet/pipelines). -
Vérifier la construction de l’image Docker sur l’interface graphique de GitLab (
/projet/container_registry).
variables:
DOCKER_DRIVER: overlay2
stages:
- build
build:
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
stage: build
script:
- export IMAGE_TAG=$(echo -en $CI_BUILD_REF_NAME | tr -c '[:alnum:]_.-' '-')
- docker build --pull -t "$CI_REGISTRY_IMAGE:$IMAGE_TAG" .
- docker push "$CI_REGISTRY_IMAGE:$IMAGE_TAG"
- echo 'pushed on registry'
$ ls -la .dockerignore .gitlab-ci.yml Dockerfile LOSC_Event_tutorial.py requirements.txt $ git init $ git remote add origin git@gitlab.fr:projet/myapp.git $ git add . $ git commit -m "Initial commit" $ git push -u origin master
Utiliser la nouvelle image Docker de votre projet qui a été construite automatiquement :
$ docker login https://gitlab-registry.fr $ cat ~/.docker/config.json $ docker pull gitlab-registry.fr/user/projet:latest $ docker run -v $user_path/LOSC_Event_tutorial:/app gitlab-registry.fr/user/projet:latest
Déploiement de conteneurs avec Docker Compose
| Permet de lancer plusieurs conteneurs en interaction avec une seule commande. |
Ma première application composée
Lancer une application de micro-service via Docker Compose :
-
Copier le fichier
docker-compose.ymlqui permet de lancer un seul service (le Jupyter serveur). -
Exporter la variable d’environnement
LOCAL_PATH. -
Exécuter le fichier YAML avec Docker Compose.
-
Options : le mot clé version 3 correspond à la dernière version de Docker Compose compatible avec la version 2 et Docker Swarm.
version: "3"
services:
jupyter:
image: jupyter/scipy-notebook
container_name: jupyter
volumes:
- $LOCAL_PATH:/home/jovyan/work/local
ports:
- "8888:8888"
volumes:
workspace:
$ export LOCAL_PATH=`pwd` $ docker-compose up -d Creating jupyter ... done $ docker-compose ps Name Command State Ports ------------------------------------------------ jupyter tini... Up 0.0.0.0:8888->8888/tcp $ docker-compose logs jupyter $ docker-compose exec jupyter $ docker-compose down
Création de Machines Virtuelles avec Docker Machine
| Permet de créer des MV locales ou sur le cloud avec Docker installé et configuré. |
Lancer une MV via Docker Machine :
-
en local si vous avez VirtualBox installé.
-
sur une infrastructure de cloud computing (OpenStack) si vous avez un compte sur ce type de ressources. Il est nécessaire de sourcer d’abord les identifiants du compte.
$ docker-machine create --driver virtualbox --virtualbox-memory 2048 --virtualbox-cpu-count "2" --virtualbox-disk-size "2000" default $ docker-machine ls $ docker-machine ssh default $ docker-machine rm -f default
$ source ~/.novacreds/novarc.sh $ docker-machine create --driver openstack --openstack-flavor-name "m1.small" --openstack-image-name centos-7 --openstack-domain-name default --openstack-net-name cloud-net --openstack-floatingip-pool ext-net --openstack-keypair-name cloudkey --openstack-private-key-file ~/.novacreds/cloudkey --openstack-ssh-user centos test