Docker : premiers pas - créer une app

https://docs.docker.com/get-started/part2/

Pour créer une application, on va commencer par le bas de :

  • Stack : définition des interactions des services
  • Services : comment le container se comporte en prod
  • Container (on est là)

 


Le fichier Dockerfile

définit ce qui se passe dans l'env dans le conteneur (car quand on est dans un container, accéder à son nom retourne l'ID du container) :
           FROM (un run time officiel) ; WORKDIR /app ; ADD . /app ; RUN ... ; EXPOSE 80 (port 80 dispo) ...

Sur son ordi, créer un dossier, avec dedans, les 3 fichiers zippées en PJ (dont le fichier Dockerfile), etre dans ce dossier (cd PATH) et (construit une image "coucou")   docker build -t coucou .

Un   docker image ls     va montrer coucou  (en colonne REPOSITORY, avec le TAG latest, ID de l'image, idée d'age et taille). On peux alors :

  • docker run -p 4000:80 coucou lancer (sur le :4000 de son pc, 80 exposé du contener).
                  Est affiché via python le message à "http://0.0.0.0:80" (mais en fait pour nous à http://localhost:4000/). On peux trouver ip avec docker-machine ip
  • docker run -d -p 4000:80         lancer en background, en mode détaché
    docker container ls
  • docker container stop ID

enlightenedA chaque fois, le Hostname affiché est différent - c'est le CONTAINER ID 

$ docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
d3cd31c2004d        coucou              "python app.py"     2 minutes ago       Up 2 minutes        0.0.0.0:4000->80/tcp   dazzling_jepsen

Donc ici :  docker container stop d3cd31c2004d

Publication (sur un repository)

docker login
# Def tag : docker tag image username/repository:tag
docker tag coucou username/get-started:part2
docker push username/repository:tag

De n'importe quelle machine, on peux maintenant faire (si l'image n'est pas en local, docker ira la chercher):   docker run -p 4000:80 username/get-started:part2

 

 


 

 

Services

https://docs.docker.com/get-started/part3/

On va ici activer le load-balancing.
Les services sont des conteneurs, un service lance une seule image en la controlant (ports utilisés, nb replicas...). On va ici changer le nb d'instances de tel contener etc...

docker-compose.yml

définit comment le conteneur (service) doit se comporter. Celui ci :

version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: username/repo:tag
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "80:80"
    networks:
      - webnet
networks:
  webnet:
  • dl du registre l'image qu'on avait envoyée
  • lance sur un service nommé web : 5 instance de cette image (replicas: 5) - en limitant la charge (10% cpu, 50 M ram avec resources: et limits:)
  • relance de suite un container qui tomberait (restart_policy:   condition: on-failure)
  • map des ports : 80:80
  • indique aux containers de web qu'il faut partager le :80 via le réseau load-balanced nommé webnet
  • et définit le réseau webnet avec les paramètres par défaut

Avant de pouvoir faire un 1er  stack deploy  il faut d'abord lancer un docker swarm init
Pour la lancer, il faut lui donner un nom, ici getstartedlab =>  docker stack deploy -c docker-compose.yml getstartedlab

Un container qui fait tourner un service est une tâche ou task. Les tâches ont un ID unique (qui s'incrémente), jusqu'au nb de replicas qu'on a indiqué dans le docker-compose.yml.
Pour voir les tasks de son service: docker service ps getstartedlab_web

 

yes On les voit quand on liste les containeurs, à moins d'utiliser un filtre sur les services  :  docker container ls -q

Voir sur un navigateur ou en ligne (curl -4 http://localhost ) le résultat pour voir l'ID du conteneur changer (affiché après le hostname) et le load-balancing fonctionner.

Changer les paramètres dans docker-compose.yml et redéployer avec docker stack deploy -c docker-compose.yml getstartedlab

Pour voir le résultat : docker container ls -q

On arrete

pour l'appli : docker stack rm getstartedlab
pour le swarm : docker swarm leave --force

Les clusters Swarm, manager swarm et nodes

https://docs.docker.com/get-started/part4/

Un swarm (essaim) est un groupe de machines  (physiques ou vm, on les appelle nodes) qui executent Docker et qui sont dans un cluster. A partir de maintenant les commandes dockers habituelles sont lancées sur un cluster par le manager swarm.
Les managers swarm peuvent utiliser plusieurs stratégies (fichier Compose) pour faire tourner les containers - citons :

  • “emptiest node” : remplir les machines les moins utilisées
  • "global" : chaque machine a exactement une instance d'un contener spécifié

Les managers Swarw sont les seules machines qui peuvent exe vos commandes, ou authoriser d'autres machines à joindre le swarw en tant que workers. Le port du management swarm est 2377.
Quand le mode swarm est activé, c'est la machine qui l'active qui devient automatiquement le manager swarm.

Définir son swarm : docker swarm init

sur les autres machines (qui seront des workers): docker swarm join
Pour quitter un swarm (quand on est dans un node) : docker swarm leave

créer un cluster (avec une vm) en créant des vm virtualbox (vb) nommées myvm1 et myvm2
docker-machine create --driver virtualbox myvm1
docker-machine create --driver virtualbox myvm2

Voir machines et leurs ip : docker-machine ls

ini swarm et ajout nodes

(rappel : la 1ere machine est le manager, la seconde est worker)
On peux envoyer des commandes aux vm avec docker-machine ssh. Ici, on a dire à myvm1 d'être le manager swarm (avec un docker swarm init)

$ docker-machine ssh myvm1 "docker swarm init --advertise-addr <myvm1 ip>"
Swarm initialized: current node <node ID> is now a manager.

To add a worker to this swarm, run the following command:
  docker swarm join \
  --token <token> \
  <myvm ip>:<port>

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

enlightenedIl faut toujours lancer swarm init et swarm join sur :2377, ou sans préciser de port (conf par défaut). Le :2376 est le port réservé du dockerd. En cas de soucis ssh quand on envoi des commandes au manager swarm, tenter docker-machine --native-ssh ssh myvm1 ...

Le docker swarm init a lancé automatiquement un docker swarm join  préconfiguré à lancer sur les nodes qu'on voudrait ajouter (copier cette commande, la coller en adaptant). Ici, on ajouter myvm2 en worker :

$ docker-machine ssh myvm2 "docker swarm join \
--token <token> \
<ip>:2377"

This node joined a swarm as a worker.

Sur le manager (myvm1), lancer docker node ls  pour voir les nodes de ce swarm : 

$ docker-machine ssh myvm1 "docker node ls"
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
brtu9urxwfd5j0zrmkubhpkbd     myvm2               Ready               Active
rihwohkh3ph38fhillhhb84sk *   myvm1               Ready               Active              Leader

 

Déployer son app sur un cluster swarm

En gros, on va répéter les actions de la partie "service" (docker stack deploy -c docker-compose.yml getstartedlab)

On a utilisé docker-machine ssh  pour parle aux vm. On peux aussi configurer son shell "docker-machine" via  docker-machine env <machine> qui indique à son shell qu'il faut parler au daemon Docker qui tourne sur une vm. C'est ici ce que l'on va faire, car cela nous facilite l'action suivante (car cela va nous permettre d'utiliser le fichier local docker-compose.yml pour déployer l'application à distance, sans avoir à copier ce fichier nulle part).

Faire un docker-machine env myvm1 -> la dernière ligne affiche ce qu'il nous faut pour parler au manager swarm (à copier/coller et lancer) :

$ docker-machine env myvm1
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/sam/.docker/machine/machines/myvm1"
export DOCKER_MACHINE_NAME="myvm1"
# Run this command to configure your shell:
# eval $(docker-machine env myvm1)

Vérification :

$ docker-machine ls
NAME    ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
myvm1   *        virtualbox   Running   tcp://192.168.99.100:2376           v17.06.2-ce   
myvm2   -        virtualbox   Running   tcp://192.168.99.101:2376           v17.06.2-ce   

myvm1 est le manager swarm, on a localement le fichier docker-compose.yml, et myvm1 va déployer notre appli (ce qui prend un certain temps).
Sur le manager swarm on peux vérifier que tous les services ont été déployés avec docker service ps <service_name>

Etre dans le dossier où est le docker-compose.yml et déployer l'appli sur myvm1 avec docker stack deploy -c docker-compose.yml getstartedlab

cool Si l'image est sur un registre privé et non sur le Hub Docker, se loguer  (docker login reg.ex.com) et ajouter --with-registry-auth : docker stack deploy --with-registry-auth -c docker-compose.yml getstartedlab
Ca envoie le token de login de son client local vers les nodes du swarm où le service est déployé, en utilisant les logs WAL cryptés. Avec cette info, les nodes peuvent mettre leurs logs dans le registre et pull/récupérer l'image.

Ici, il est conseiller de relire et refaire la partie 3 (services).

$ docker stack ps getstartedlab

ID            NAME                  IMAGE                   NODE   DESIRED STATE
jq2g3qp8nzwx  getstartedlab_web.1   john/get-started:part2  myvm1  Running
88wgshobzoxl  getstartedlab_web.2   john/get-started:part2  myvm2  Running
vbb1qbkb0o2z  getstartedlab_web.3   john/get-started:part2  myvm2  Running
ghii74p9budx  getstartedlab_web.4   john/get-started:part2  myvm1  Running
0prmarhavs87  getstartedlab_web.5   john/get-started:part2  myvm2  Running

Parler aux vm avec docker-machine env et docker-machine ssh

Voir les ip des vm docker-machine ls

Pour parler à vm2 :

  • docker-machine env myvm2 et lancer la commande affichée. Ca ne marche que dans le shell où on a lancé la commande. Un docker-machine ls montre état, IP, et à avec qui on parle (si on est connecté à une machine).
  • docker-machine ssh <machine> "<command>" on se logue sur une vm (on n'a plus accès aux fichiers locaux de son poste)
  • docker-machine scp <file> <machine>:~  pour copier des fichiers sur des machines

Accéder à son cluster (navigateur ou curl) : via l'IP, myvm1 ou myvm2 - on a bien 5 ID de containers affichés, en mode aléatoire. Il y a un routage d'entrée routing mesh, qui assure que pour un service déployé dans un swarm, le port réfère toujours lui-meme, quelque soit le node qui execute le contener.

enlightenedsoucis réseau ? pour que le routage fonctionne dans un swarm, il faut que les nodes écoutent tous 7946 sur tcp/udp (découverte réseau du contener) et 1789 udp (entrée du réseau du contener) avant d'activer le mode swarm.

Utiliser le .yml pour modifier l'appli, pratiquer les part 2 et part 3.

Nettoyage et reboot

Stacks et swarms

Casser le stack docker stack rm getstartedlab

La partie 5 a besoin du swarm. Sinon, pour l'effacer (sur workers et le manager vm2):
docker-machine ssh myvm2 "docker swarm leave"   ;   docker-machine ssh myvm1 "docker swarm leave --force

Défaire la conf du shell (et déconnecte le shell de la vm) :  eval $(docker-machine env -u)
Plus à https://docs.docker.com/machine/get-started/#unset-environment-variables...

Relancer les machines docker : docker-machine start <machine-name>

 

 

 


Stack (pile)

https://docs.docker.com/get-started/part5/

Ajout d'un service (sans dépendance) et redeploy

Pour voir comment notre swarm gère les conteners, ouvrir le fichier docker-compose.yml et remplacer son contenu par

version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: username/repo:tag
    deploy:
      replicas: 5
      restart_policy:
        condition: on-failure
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
    ports:
      - "80:80"
    networks:
      - webnet
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
networks:
  webnet:

Y est ajouté un service lié à web, nommé visualizer : volumes est une clef, donnant au visionneur accès à docker au fichier socket de l'hote + placement, qui assure que ce service ne tournera que sur le manager - jamais sur un worker.

S'assurer que l'environnement est ok, que son shell parle au manager (* sur vm1 sur la sortie d'un docker-machine ls sinon ) ; si ok alors relancer sur le manager docker stack deploy ... Le visionneur est dispo à IP:8080 (pour trouver ip d'un node : docker-machine ls), à comparer avec le résultat de 

docker stack ps getstartedlab

Ce service fonctionne tout seul, on peux le lancer dans toute appli qui l'inclut dans la pile (stack). On va maintenant créer un service qui a une dépendance : le service Redis, qui a un compteur de visite.

 

 

 

 

Ajout d'une db Redis (avec dépendance)

Cette db va garder les données de l'appli. Le fichier complet en en PJ, on ne montre ici que les ajouts :

  redis:
    image: redis
    ports:
      - "6379:6379"
    volumes:
      - "/home/docker/data:/data"
    deploy:
      placement:
        constraints: [node.role == manager]
    command: redis-server --appendonly yes

Les 1eres lignes sont liées à l'image, ce qui est important est la persistance des données de cette pile :

  • redis tourne toujours sur le manager et donc utilise toujours le meme fs
  • redis accède à un dossier dans le fs de l'hote en tant que /data (de l'interieur du conteneur), c'est là où redis stocke les données

Ensemble, ces lignes créent pour la db Redis un endroit sécure pour y stocker ses données. Sans, redis stocke les données dans le /data du fs du conteneur - qui est effacé si on redeploy par la suite.

Il ne reste qu'à créer le dossier sur le manager : docker-machine ssh myvm1 "mkdir ./data"

S'assurer que son shell parle bien au manager myvm1 et docker stack deploy -c docker-compose.yml getstartedlab
s'assurer que les 3 services tournent avec

$ docker service ls
ID                  NAME                       MODE                REPLICAS            IMAGE                             PORTS
x7uij6xb4foj        getstartedlab_redis        replicated          1/1                 redis:latest                      *:6379->6379/tcp
n5rvhm52ykq7        getstartedlab_visualizer   replicated          1/1                 dockersamples/visualizer:stable   *:8080->8080/tcp
mifd433bti1d        getstartedlab_web          replicated          5/5                 orangesnap/getstarted:latest    *:80->80/tcp

Naviguer sur quelques pages avec la visioneuse sur une des ip :8080

Déployer son appli

https://docs.docker.com/get-started/part6/

Pour la partie 6, on choisi Docker CE avec Docker Cloud (vers AWS Amazon Web Services, DigitalOcean, et Microsoft Azure).

Pour configurer et déployer, 3 points:

  1. relier Docker Cloud avec son fournisseur préféré (plusieurs possibilités), en donnant la perm à Docker Cloud d'aprovisionner automatiquement et de dockeriser les vm à notre place
  2. utiliser Docker Cloud pour créer ses ressources et créer son swarm
  3. déployer son appli

Le Docker Cloud a 2 modes : le mode swarm (qui est maintenant le mode par défaut) et standard.

Quand on est pret à créer son swarm (le cas en mode swarm) : créer ses nodes (https://docs.docker.com/docker-cloud/getting-started/your_first_node/). Cliquer sur Launch node cluster  (attendre) pour provisionner ce node de cluster. Pour voir la progression : clic node, puis Timeline et ouvrir Node Cluster Deploy

Via la vue détaillée Node cluster : voir les statut des nodes, del un node ou tout le cluster, upgrade d'un node, modif le cluster de 1 à 10 nodes.

Une fois déployé (au moins) un node, on peux déployer son 1er service (groupe de conteneurs qui utilisent le meme conteneur image).

 


 

Docker c'est :

  • une plateforme (isolation...),
  • Docker Engine : appli client/server à 3 composants majeurs :
    • dockerd (crée et gère les objets : images, conteners, networks, volumes),
    • une API REST (quelles interfaces les programmes utilisent pour parler au daemon et lui dire quoi faire) et
    • un client CLI "docker" (qui utilise l'api pour controler dockerd)

https://docs.docker.com/engine/docker-overview/#docker-architecture

 


 

https://docs.docker.com/machine/get-started/#unset-environment-variables...

Routage d'entrée, port 8080, dans un swarm à 3 nodes
Docker Engine  Docker Engine is a client-server application with 3 major components