Thématiques principales

mardi 28 avril 2020

Network, VM et IaC avec Vagrant

Introduction

Qui n'a jamais eut besoin de faire des tests dans un environnement sain et isolé du poste de développement? Personne je crois en tout cas si ce n'est pas le cas, vous y viendrais un jour, c'est sur car a un moment et si vous utiliser pas Docker, il va falloir confronter vos exe a l'environnement d’exécution de la Prod!

Deux approches s'offrent généralement:
  • bénéficier d'un environnement de test dédié, c'est a dire avoir une machine physique [bare-metal], pré-installé comme en prod sur laquelle il est possible de déployer votre application et exécuter des tests dessus. on se doute que cette approche est coûteuse en matériel et en maintenance (temps de nettoyage/ réinstallation des machine etc...)
  • utiliser des machines virtuelles [machine-virtuelle].

La virtualisation

Cette deuxième approche [machine-virtuelle], que nous allons un peu plus détailler, offre de nombreux avantages car elle virtualise d'une part le matériel, donc pas de ressources physique a gérer mais elle permet de disposer d'environnement iso, réutilisable, ajustable et jetable rapidement. On pourra du coup évoquer bien sur le cas extrême de cette démarche par l'utilisation de Docker [Docker]. Pourtant il est important de ne pas confondre les deux outils et leurs objectifs respectifs. Le container isole un processus, une machine virtuelle isole un environnement. Cette dichotomie est importante car elle pousse a réfléchir a ce que l'on souhaite mettre en œuvre et pas faire un choix dogmatiquement.

Ainsi pour en revenir aux machines virtuelles, leur intérêt est donc par l'abstraction de l’environnement d’exécution de permettre de disposer a la demande de cet environnement dans un état de configuration maîtrisé.

Jusque ici l'utilisation des machines passe généralement par le choix d'un hyperviseur, en gros une couche logicielle permettant d’allouer sur la stack physique de l'OS de la machine des ressources simulées. Cette démarche permet de créer des CPU virtuelle, de la mémoire virtuelle, du stockage virtuel ou même encore du réseau virtuel (nous reviendrons sur cette partie dans un autre article car c'est un sujet en soit).

L’inconvenant de l'utilisation d'un superviseur, c'est qu'il faut faire un choix. Selon le système d'exploitation qui est utiliser, on ne disposera pas des mêmes. De façon général, on notera malgré tout que l'offre est riche: qemu-KVM/libvirt [qemu], [virtualbox], hyper-v [hyper-v] ou encore vmware sont les plus connu. Pourtant et malgré des années d’existences, ces derniers n'offrent toujours pas d'API homogènes rendant leur utilisation au sein d'un même contexte compliqué car il faudra alors prendre en considération les spécificités de chacun d'eux.

Ainsi non seulement, souvent ces machines sont utilisé a la main mais lorsqu'il s'agit de gérer logiciellement le cycle de vie des VM et l'automatiser dans une démarche IaC (infrastructure as a code [IaC]), alors il faudra se limiter. Le quoi? l'IaC? Ce n'est pas important, nous y reviendrons!

Vagrant

Une solution est pourtant possible! Vagrant [vagrant]! Bon ce n'est pas une solution miracle, mais en terme de provisionning de machine virtuel, cet outil permet d'abstraire bon nombre de caracteristique propres aux hyperviseurs (en dehors de son choix propre mais cela reste variabilisable).

Vagrant a surtout pour interet d'etre extremement simple d'emploi pour des actions basiques sur le cycle de vie d'une VM. En gros construire la VM, la lancer, l'arreter, ou encore la detruire se realise en juste quelques commandes. Bien sur qu'il permet d'ee faire plus mais globalement ca sera pour des utilisations en marge de celle utile au quotidien.

Ainsi pour realiser une VM, il va falloir en premier lieu la definir. Pour cela, on va realiser un fichier vagrantfile. Ce fichier s'appuie sur le language Ruby. sans etre un grand expert de Ruby, en fait ce fichier va etre essentiellement descriptif: Il va contenir un bloc "do" permettant de specifier la version vagrant utilisé. Dans ce bloc il va ensuite falloir decrire la VM en specifiant:
  • son image de base qui sera issu d'une bibliotheque d'image hebergé par vagrant [vagrant-images].
  • un nom qui servira de hostname,
  • une config reseau selon 3 modes possibles:
    • en port mapping permettant de router les paquet arrivant sur un port de la machine hote sur un port de la machine virtuelle
    • avec un reseau privé, c'est a dire qu'un reseau virtuel sera construit dans laquelle la machine virtuelle aura une adressse IP. Ce reseau sera accessible alors par la machine hote et seulement celle ci (la machine host disposera alors d'un nouvelle interface avec une IP dans le reseau virtuel)
    • avec un reseau publique, c'est a dire qu'une interface sera creer dans la machine virtuelle mais celle ci sera bridgé sur la machine hote dans le meme reseau que celle ci.
  • un provider c'est a dire l'hyperviseur employé, et on pourra alors preciser le nombre de CPU virtuel et de memoire que l'on souhaite lui allouer.

Pour exemple, voici une allocation de VM possible:


1
2
3
4
5
6
7
8
9
Vagrant.configure("2") do |config|
  config.vm.box = "generic/ubuntu1804"
  config.vm.hostname = "myvmtest"
  config.vm.network "public_network", :dev => "eno2", :mode => 'bridge', mac: "52:54:00:B2:14:8E", use_dhcp_assigned_default_route: true
  config.vm.provider "libvirt" do |vb|
    vb.memory = "1000"
    vb.cpus = "1"
  end
end

Pour lancer cette VM, rien de plus simple:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$ vagrant up
Bringing machine 'default' up with 'libvirt' provider...
==> default: Checking if box 'generic/ubuntu1804' is up to date...
==> default: Creating image (snapshot of base box volume).
==> default: Creating domain with the following settings...
==> default:  -- Name:              vagrant-template_default
==> default:  -- Domain type:       kvm
==> default:  -- Cpus:              1
==> default: 
==> default:  -- Feature:           acpi
==> default:  -- Feature:           apic
==> default:  -- Feature:           pae
==> default:  -- Memory:            1000M
==> default:  -- Management MAC:    
==> default:  -- Loader:            
==> default:  -- Base box:          generic/ubuntu1804
==> default:  -- Storage pool:      default
==> default:  -- Image:             /var/lib/libvirt/images/vagrant-template_default.img (32G)
==> default:  -- Volume Cache:      default
==> default:  -- Kernel:            
==> default:  -- Initrd:            
==> default:  -- Graphics Type:     vnc
==> default:  -- Graphics Port:     -1
==> default:  -- Graphics IP:       127.0.0.1
==> default:  -- Graphics Password: Not defined
==> default:  -- Video Type:        cirrus
==> default:  -- Video VRAM:        256
==> default:  -- Sound Type:
==> default:  -- Keymap:            en-us
==> default:  -- TPM Path:          
==> default:  -- INPUT:             type=mouse, bus=ps2
==> default: Creating shared folders metadata...
==> default: Starting domain.
==> default: Waiting for domain to get an IP address...
==> default: Waiting for SSH to become available...
    default: 
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default: 
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Setting hostname...
==> default: Configuring and enabling network interfaces...

Cela va avoir pour consequence de provisionner la VM les ressources, faire l'allocation de l'IP via le DHCP et de fournir une interface en plus pour la maintenance.

Networking

Aisni, du coté host, on a un certain nombre d'interfaces reseaux "mysterieuse" qui ont ete crée, virbr0, vnet, macvtap0@eno2 on va revenir dessus:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ ip a
1: lo: [...]
2: eno2: <broadcast> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 04:92:26:1d:b2:e8 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.57/24 brd 192.168.0.255 scope global dynamic noprefixroute eno2
       valid_lft 36031sec preferred_lft 36031sec
3: wlo1: [...]
41: virbr0: <broadcast> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 52:54:00:d7:c3:3c brd ff:ff:ff:ff:ff:ff
    inet 192.168.121.1/24 brd 192.168.121.255 scope global virbr0
       valid_lft forever preferred_lft forever
42: virbr0-nic: <broadcast> mtu 1500 qdisc fq_codel master virbr0 state DOWN group default qlen 1000
    link/ether 52:54:00:d7:c3:3c brd ff:ff:ff:ff:ff:ff
71: vnet0: <broadcast> mtu 1500 qdisc fq_codel master virbr0 state UNKNOWN group default qlen 1000
    link/ether fe:54:00:51:d8:29 brd ff:ff:ff:ff:ff:ff
72: macvtap0@eno2: <broadcast> mtu 1500 qdisc fq_codel state UP group default qlen 500
    link/ether 52:54:00:b2:14:8e brd ff:ff:ff:ff:ff:ff

Mais dans la VM, on a que deux interfaces:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ vagrant ssh 
$ ip a
1: lo: [...]
2: eth0: <broadcast> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:51:d8:29 brd ff:ff:ff:ff:ff:ff
    inet 192.168.121.245/24 brd 192.168.121.255 scope global dynamic eth0
       valid_lft 1943sec preferred_lft 1943sec
3: eth1: <broadcast> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:b2:14:8e brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.110/24 brd 192.168.0.255 scope global dynamic eth1
       valid_lft 41543sec preferred_lft 41543sec

Pour expliquer un peu tout cela. Lors de la creation de la VM, vagrant va construire 2 interfaces, l'une pour la maintenance est utilisée lorsque l'on realise "vagrant ssh" (eth0) et l'autre est celle qu'on lui a demandé de creer dans le vagrantfile (eth0).

Du coté du host c'est un peu plus compliqué. On sait que l'interface que nous avons demandé de constuire a vagrant est une interface public mais par defaut, celle qu'il construit pour lui, ou celle de maintenance, est une interface privé.
On a donc deux approches differentes et forcement deux solutions (avant cela, je vous invite a aller relire l'article sur l'adressage [addressage], ca peut aider).

Reseau Privé


Pour les reseau privé, vagrant va constuire un network virtuel. Pour cela il va creer une interface associé present dans la VM (ici vnet0), de meme, il va creer une interface pour le host (ici virbr0-nic). Enfin, vagrant va construire un bridge [bridge] (ici virbr0) ou pont permettant d'alluer une ip au host, dans un plan d'addressage specifique.

C'est cette manipualtion qui va permettre la creation de ce reseau privé entre le host et la machien virtuelle permettant aux deux de communiquer ensemble. On peu le verifier en utilisant les commande suivante:


1
2
3
4
$ brctl show 
bridge name bridge id  STP enabled interfaces
virbr0  8000.525400d7c33c yes  virbr0-nic
       vnet0

La commande brctl n'etant plus officiellement supporté sous certains OS, l'alternative est:


1
2
3
4
5
6
7
8
$ ip link show type bridge_slave
42: virbr0-nic: <broadcast> mtu 1500 qdisc fq_codel master virbr0 state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:54:00:d7:c3:3c brd ff:ff:ff:ff:ff:ff
73: vnet0: <broadcast> mtu 1500 qdisc fq_codel master virbr0 state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether fe:54:00:20:a2:a1 brd ff:ff:ff:ff:ff:ff
$ ip link show type bridge
41: virbr0: <broadcast> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:d7:c3:3c brd ff:ff:ff:ff:ff:ff

Reseau Publique


Concernant l'interface publique, c'est plus simple car il existe deja une interface dans le reseau public, c'est eno2. Du coup au lieu de construire un bridge comme precedement, ici dans le host, vagrant va en construire une autre sorte, le macvtap, entre l'interface reseau de la VM identifié par son adresse mac (qui sera alors transposé sur le macvtap) et l'interface en02 de la machine host.

On peut le voir grace a la commande suivante:


1
2
3
ip link show type macvtap
74: macvtap0@eno2: <broadcast> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 500
    link/ether 52:54:00:b2:14:8e brd ff:ff:ff:ff:ff:ff

L'interet ici contrairement a l'interface public, c'est que l'adresse mac de la VM est visible depuis le reseau publique et donc qu'elle peut etre gerer par un service DHCP.

En resumé, tout cela donne le reseau suivant:



Il y aurait encore beaucoup a dire sur les aspects reseaux (le vlan par exemple, etc..) ou sur vagrant qui par le biais de plugin va permettre le provision automatique du contenu logiciel de la VM ainsi creer (via Ansible par exemple).

Ceci est un autre probleme que nous traiterons dans d'autres articles.

Références

  • [bare-metal] https://www.ionos.fr/digitalguide/serveur/know-how/serveur-bare-metal-definition-et-structure/
  • [machine-virtuelle] https://fr.wikipedia.org/wiki/Machine_virtuelle
  • [Docker] https://www.docker.com/
  • [qemu] https://www.qemu.org/
  • [virtualbox] https://www.virtualbox.org/
  • [hyper-v] https://docs.microsoft.com/fr-fr/virtualization/hyper-v-on-windows/about/
  • [vmware] https://www.vmware.com/fr.html
  • [IaC] https://www.lebigdata.fr/infrastructure-as-code-definition
  • [vagrant] https://www.vagrantup.com
  • [vagrant-images] https://app.vagrantup.com/boxes/search
  • [ip-addr] https://memo-linux.com/ip-la-commande-linux-pour-gerer-son-interface-reseau/
  • [addressage] https://un-est-tout-et-tout-est-un.blogspot.com/2020/04/networking-adressage.html
  • [bridge] https://seravo.fi/2012/virtualized-bridged-networking-with-macvtap

samedi 25 avril 2020

Developpeur super-hero ou developpeur fou?

Ce n'est pas souvent que j’écris des billets d'humeur généralement deux ou trois par ans, je pense mais ce mois-ci, avec celui sur le Gain de Maturité, et bien ça en fera deux en un seul mois!.

Ce coup-ci ce n'est pas vraiment un billet positif que je vais écrire mais mais une forme de coup de gueule suite à une réflexion sur l’évolution (ou pas) des mentalités professionnelles dans le développement logiciel.

Naissance d'un métier


Nous avions un peu évoqué lorsque l'on traitait un peu plus de machine learning des origines de l'informatique. Ce qu'il faut surtout en retenir, c'est que l'informatique moderne a réellement explosé a la suite de la seconde guerre, l'apparition des transistor et bien sur des premiers langages de programmation.

Nous n'allons pas nous intéresser a cela dans ce billet mais aux humains qui ont "jalonnés" le monde de l'informatique jusqu’à aujourd'hui... Pas des humains en particulier mais au contraire ceux qui ont commencés par bidouiller dans leur garage dans les années 70, façonnés les premiers langages, outils logiciels (traitement de texte par exemple) ou jeux vidéos.

Nostalgie


Dans la culture actuelle, cette époque est teintée d'une forme de belle époque ou seuls des boutonneux talentueux ont su comme lors de la conquête spatiale, poser un pied sur la lune et créer le monde de l'informatique moderne. On passera bien évidement sur tous ces gens aussi talentueux qui se sont planté dans leur entreprise a l’époque (bien sur on les a oublié...) mais ce qu'il en reste est cette image idyllique dans l'inconscient que tous ces gens étaient des super intello un peu autiste mais toujours sympa, que l'on comprenait pas vraiment, forcement harcelé a l’école, n'ayant pas de copine (je precise qu'en plus ce sont des garçons), et généralement seul ou avec une bande d'amis geek aussi... enfin vous voyez le tableau...

Cette image qui finalement place l'informaticien en mec bizarre mais quand même sympa et en plus vachement futé a donné quand même beaucoup envie a des gamins de se mettre devant un clavier. A l'image du personnage de Jerry Steiner dans Parker Lewis, effectivement, malgré tout, avec les moyen du bord, il fallait de la motivation a l’époque quand les programmes étaient encore enregistrer sur des cassettes audio (pour ceux ayant connu le MO5) et que pour en charger un il fallait parfois une bonne demi heure de lecture (tout ca pour charger quelques Ko en mémoire vive)

La vraie vie


Les choses ont changé, s'il est certain que être informaticien est un métier complexe et nécessitant de nombreuses compétences, il ne s'agit plus (si ça a été vrai un jour d’ailleurs) de simplement connaître un langage de programmation, écrire du code qui marche et op balancer ça joyeusement en production en disant: Sur mon poste, ça marche!

Non le métier d’aujourd’hui, s'est professionnalisé et heureusement. Les outils du développeur ne sont plus des simples traitement de texte permettant de faire de la compilation du code, non ces outils intègrent des environnement complet, prés pour le développement sur de multiples langages en même temps, ayant des usages différents permettant des tests a des niveaux d'abstractions variables, facilitant l’intégration, améliorant la modélisation des systèmes, le monitoring et la collaboration.

A cela, s'ajoute écosystème dans lequel le développeur aura fait le choix de se spécialiser  impliquant une compréhension des métiers associés a cet écosystème. Aujourd'hui, beaucoup d'application de gestion sont produite en Java mais si vous allez voir des applications embarqués, il y a peu de chance que Java soit un premier choix!

Ceci n'est encore que la composante technique du métier informaticien (et la plus plaisante a priori peut être mais...), car il ne faut pas oublier deux aspects: le contexte économique, c'est a dire les enjeux propre a l'entreprise et les processus qu'elle souhaite mettre en place pour faire de l'argent (oui forcement a un moment le salaire, il vient de quelque part) et enfin le caractère humain, c'est a dire la aussi être capable de communiquer, comprendre, expliquer et léguer.

A titre personnel je considère même ce dernier point comme étant le plus complexe a appréhender. Autant la technique, ce n'est que de la technique, par le travail, rien n'est incompréhensible ni inaccessible, la composante politique et économique, la comprendre permet de mieux saisir les enjeux, certes, mais notre impacts sur cet axe est faible. Par contre le caractère relationnel du métier, c'est un vrai défi qui au fils des années m’apparaît comme étant de plus en plus majeur a la réussite des projets! Car non seulement le travail qui est réalisé nécessite de la collaboration et du dialogue, de la pédagogie mais elle nécessite une vraie prise de conscience sur notre rapport au code, la manière de le réaliser, de le penser, de l’écrire.

Les comportements toxiques


Et c'est la que nous arrivons au cœur du problème de cette image du développeur super héros, elle nous dessers! Bien sur au delà des cliché s pseudo positif que cela entraîne, il en ressort en fait beaucoup de machisme et d'immaturité. (Je ne traiterai pas du sujet du machisme dans cette bataille mais c'est un sujet a part entière qui demande plus de recul que je n'ai en l’état actuel des choses...)

Cette immaturité, on la rencontre encore souvent chez ces profils restés dans cette vieille image. Souvent il s'agit de développeur vraiment très compétant sur leur sujet, qui peuvent être touche a tout techniquement mais qui s'en cognent joyeusement des principes du clean code... parce-que oui ce type de profil sait tellement bien faire son travail, que si son code n'est pas maintenable ou testé, ce n'est pas grave car il marche sur son poste ou que les autres ne sont pas assez bon pour comprendre son code et toute la subtilité qu'il a su y mettre quitte a revisiter les design pattern selon sa propre vision des choses.

Généralement, ces profils sont une plaie, leur code n'est souvent pas documenté (de toute facon la doc c'est pour les faibles) et les tests se limitent a des cas passant quand on a de la chance. Alors il est certain que dans les principes du clean code, la doc, on évite surtout le commentaire (on en reparlera quand on abordera le sujet clean code) car le code est sensé se suffire a lui même. Mais non la nous avons un super hero donc le code ne peut, que dis je, ne dois pas être simple! Pour ce type de développeur, il est forcement nécessaire de déployer des monstres de généricité pour résoudre tous les problèmes ... ba oui au cas ou quoi! Et la encore une fois on passe a coté de l'utilité même du code! Sans compter le caractère souvent immaintenable de ce type de code qui s'il faut le reconnaître est souvent très pointu, n'est jamais accessible a des débutants qui aurait pu espérer ne pas se sentir très null.

Le plus amusant c'est qu'avec le temps, ce genre de développeur prennent la grosse tête. Ils sont souvent vu comme fort et compétant (ba oui personne ne les comprennent!) et cela enrichi cette vision positive de super héro développeur qu'ils ont.

Et la c'est le drame, car leur compréhension de leur technique leur permettent de déroger aux règles fondamentales de la programmation et se permettent divers entorses (qu'il auraient critiqués en d'autres temps mais bon la ils sont fort donc ça va...) Et personnellement, j'en ai vu passer du code avec des "return null" en pagaille... DEPUIS QUAND NULL EST IL UNE VALEUR!!!!

Et c'est comme ça que après le passage de ces Heros, des équipes se tirent les cheveux à maintenir un code incompréhensible et non testé qui marche mais qui crash au moindre changement.... et forcement c'est la faute du développeur mainteneur, pas celui qui a littéralement (je me permet de le dire car vraiment c'est insupportable) chier dans la base code.

On peut encore trop en croiser de ce type de profil de développeur élevé dans cette culture du Super-hero qui n'ont pas pris la mesure de l’évolution du métier qui passe dans un projet, passe pour un génie et se barre en laissant derrière eux une ardoise que les suivant peineront a effacer mais devront assumer.

Voila du coup c’était mon coup de gueule. Et bien sur ce que j'ai décris au dessus c’était moi avant que je rencontre un autre moi en pire qui m'a fait prendre conscience que le code que nous écrivons, il n'est pas fait pour la machine, mais en réalité, il est fait pour nous.

Ce langage de programmation que nous utilisons et ce code que nous produisons, il faut etre lucide, ils ne sont que en fait qu'une sorte d'IHM pour le développeur et il ne sera pas seul a l'utiliser. D'autres passerons dessus et il doit être aussi accessible pour un autre que pour soit même et ce meme dans 5 ans!

Enfin voila tout ça, ça va être l'opportunité d'introduire au passage quelques sujets supplémentaires pour de prochains articles. Entre autre, je tacherai d'élargir ce blog à ces composantes qui sortent un peu du monde propre de l'informatique mais qui y ont une importance majeur pour que les projets se mènent aux mieux.

On tachera donc de parler un peu plus de Clean Code, et d'Egoless Programming, de CNV (Communication non violente) et comment elle peut nous aider a mieux travailler en équipe et aussi de regarder le code différemment et enfin on parlera aussi des biais cognitif, sujet passionnant qui nous emmènent souvent dans des travers de jugement qui peuvent nuire aux autres, a nous même et a la qualité de ce que l'on produit.

mercredi 22 avril 2020

Maintenance Raid

On avait vu comment monter des disques en Raid [raid]. Mais je n'avais pas évoqué la question de comment reprendre un disque défaillant.

Data pas de panique, un disque peu très bien avoir eut un soucis de connexion et le raid l'a détecté et l'a donc placer en erreur.

Identification


Pour savoir si un disque est ko, il faut utiliser l'utilitaire mdadm:

1
$ mdadm --detail /dev/md0

Le récapitulatif qui vous sera fourni vous donnera alors l’état des disques faisant parti du Raid.

En suite une fois identifié le problème, et dans la mesure ou le disque est recupérable alors il faudra identifier le disque en question pour ensuite le réintroduire dans le raid.

Pour cela un simple!:

1
$ fdisk -l

Réparation 


Puis pour réintroduire le disque:

1
$ mdadm --manage /dev/md0 --add /dev/sdd1

(Si c'est le disque sdd1 qui était initialement dans le raid)

Alors le disque va etre resynchroniser (car peut être qu'il n'a pas ete mise a jour des dernieres infos.

Pour voir l’état de la resynhro, il suffit d'observer le fichier mdstat avec

1
$ watch cat /proc/mdstat

Et la vous aurez votre raid de nouveau opérationnel.

Références:


[raid] https://un-est-tout-et-tout-est-un.blogspot.com/2020/03/montage-raid.html
[mdadm] https://doc.ubuntu-fr.org/raid_logiciel

dimanche 19 avril 2020

Le gain en maturité

Un petit billet d'humeur aujourd'hui suite à un constat. Quand j'ai commencé ce blog, j'avais la résolution de retrouver un rythme. J'en avais rapidement parler dans [donc-ca] sans vraiment être rentré dans le détail ensuite a l'occasion d'un bilan [autobio], la j'ai expliqué un peu mon parcours et pourquoi j'avais décidé de tenir ce blog.

Ecrire un blog


Sur le fond au delà des raisons personnelles, si l'on souhaite être pragmatique, tenir un blog ça permet en premier lieu de faire une veille techno réaliste. Comme je l'expliquais dans [veille], a mon sens on peut bien lire tout les articles que l'on veut ou tous les tutoriaux du monde, le monde de l'informatique est vaste et très hétérogène et retenir quelque chose d'une lecture au delà de quelques semaines permet au mieux de pouvoir dire, "oui j'ai vu ou entendu parler", mais clairement celui qui prêtent dire "oui je connais" est  un menteur.

De la veille


Sans revenir sur le contenu de cet article [veille], prendre la mesure d'un outils ou d'un concept en informatique, cela nécessite au moins de manipuler. Cela permet de se confronter (un peu) aux limites, aux écueils, aux trucs fun d'une techno mais cela permet aussi de mieux la situer dans son écosystème technique.

Par expérience, la encore, (et cela me relève de mon opinion et peut être de mon fonctionnement, se rassurer, consolider, se prouver etc...) a mon sens il faut aussi aller au delà et écrire un billet sur ce que l'on voit, cela permet de consolider et de garder une trace de ce que l'on a fait.... car il faut pas se leurrer: on oubli!

Oui on oubli! Aussi bon soit votre mémoire, elle a une limite et un temps d’accès ou un temps de recontextualisation (vous savez le truc que vous savez mais vous savez plus pourquoi comment ni comme ça s'y rattache...)

Et la encore, mettre noir sur blanc (ou 1 sur 0) permet de fixer les choses, de mieux mémoriser et cerise sur le gâteau, vérifier si notre vision de quelques a du sens! Je ne compte plus aujourd'hui les fois ou lors de la rédaction d'un article je me suis rendu compte d'une faille dans ma compréhension des choses. Et parfois cela a même pus complètement remettre en question l'article!

Mais pas que


Aujourd'hui, après 3 ans de rédaction plus ou moins suivi et prés de 170 publiés j'ai découvert un denier point intéressant a la rédaction d'articles. Non cela n’améliore pas l'orthographe désolé ! (même si la capacité rédactionnelle est quand même notablement amélioré) non mais la rédaction de tous ces articles permet a terme d'avoir son parcours en perspective.

Je ne parle pas forcement de pouvoir utiliser cela comme un outil du genre CV même si ce la peut y trouver du sens (jusqu’à un certain point) mais de simplement permettre de regarder son parcours, ce que l'on a appris, les choix que l'on a fait (ces derniers étant contextualisable avec parfois peut être des besoins, d'autres par goût personnel) et aussi de voir son évolution sur les sujets.

Quand je relis certains de mes articles (car oui ça m'arrive pas de façon narcissique mais parce que parfois c'est utile de les utiliser comme aide mémoire) je me rend compte que autant parfois j'ai pu être pertinent sur certains sujet parfois pas du tout. Pour tout dire, je me suis même demandé parfois si je ne devais pas retirer certains de mes anciens articles car je les juge aujourd'hui insuffisant....

Bien sur je ne ferai pas ça, car en fait ces articles démontrent une évolution, si leur contenu n'est pas pertinent, leur présence au milieu des autres faits états des tentatives pour avancer et construire. Bien sur parfois c'est léger et parfois il y a des bêtises de dites mais c'est la aussi que l'on apprend et que l'on se rend compte justement que l'on avance!

Donc voila un autre point qui devrais donner envie d’écrire: le droit de se tromper, la possibilité de prendre du recul, la joie de se voir évoluer et de gagner en maturité!

Références


[donc-ca] https://un-est-tout-et-tout-est-un.blogspot.com/2017/09/donc-ca.html
[veille] https://un-est-tout-et-tout-est-un.blogspot.com/search?q=veille
[autobio] https://un-est-tout-et-tout-est-un.blogspot.com/2018/09/100-un-peu-dautobio.html

jeudi 16 avril 2020

Networking: adressage

Networking : l’adressage

1. Introduction

Souvent je me dis qu’avoir un article récapitulatif des principes sous-jacents aux outils réseaux ne serait pas un luxe car on est régulièrement confronté à manipuler des flux entre des VM ou des conteneurs et parfois avoir les bon outils et bonnes connaissances pour bidouiller c’est pas de trop, (et ceux ayant lu les articles sur Iptable seront de mon avis, je pense …​) Surtout que par expérience on oublie vite! Pour avoir fait pas mal de réseau à une époque aujourd’hui j’ai un peu l’impression d’en avoir oublié la moitié.
Donc avec cet article, on va essayer de refaire un tour des concepts principaux du networking, une adresse, un masque, un réseau, un bridge, un dns ou dhcp, on va essayer de revoir un peu tout ça avec les outils permettant de les mettre en oeuvre.
Bon je ne garanti pas que ça se fera qu’en un seul article…​.

2. Concepts principaux

2.1. Réseau

Un réseau, déjà qu’est ce que c’est? C’est tout simplement un ensemble de machines interconnectées. Bon jusque la je ne prend personne en traite. Seulement pour que ces machine communique entres elles, il est nécessaire qu’elles puissent s’identifier, c’est la que va intervenir l’adressage.
Pour ceux à qui OSI parle, nous nous trouvons alors dans la couche 3 celle que l’on nomme (étrangement) la couche réseau. A partir d’ici on évoluera assez peu dans les couches supérieur qui correspondent aux couches protocoles de transport et qui sont plus d’ordre logiciel. Par contre dans les couches inférieurs, nous trouverons le support de l’interconnexion réseau: l’interface réseau (identifiable matériellement par une adresse mac, celle ci est propre à l’interface) qui représente matériellement ou virtuellement le point de connections de la machine avec le ou les réseaux. Dans ce réseau, alors l’interface sera identifié via une adresse qui lui sera assignée, entre autre une adresse IP.
Quoi deux adresses? pourquoi une adresse mac et une adresse IP? Il faut se dire que les deux types d’adresses ne servent pas à la même chose. La premier sert à identifier physiquement une interface et donc une machine, pas la localiser alors que l’IP (nous le verrons plus tard) permet aussi la localisation de le cette machine dans le réseau. D’autre part, pour une même interface, il n’est pas exclu que celle ci puisse être dans deux réseaux différents. Ainsi, elle aura deux IP mais toujours qu’une adresse mac. Nous verrons plus en détails cela par la suite.
De façon général donc un réseau cela va être un espace sur lequel seront connecté des machines portant une adresse mac et une ou plusieurs adresses IP
Mais pour que cela soit plus concret, on peut représenter cela avec un routeur qui aura la charge d’enregistrer les machines connectées sur le réseau et de leur permettre d’interagir entre elles (un switch pourra faire globalement le même taff, au broadcast prés…​).
Si l’on peut faire une analogie, lorsque vous souhaitez envoyer un courrier à la poste, vous envoyez votre avec l’adresse du destinataire et la poste (ici le routeur) se charge de pousser ce message dans la bonne direction et au bon endroit.
Bon voila nous avons vu l’essentiel! non je rigole, enfin quoique car finalement il ne s’agit que de ça, du routage de ce que l’on appelle paquet.

2.2. IP

Mais non quand même pas c’est pas si simple. Car plein de question devrait arriver: * comment les machines s’identifient dans le réseau ? * comment sont définis les IP, qui les donne ? * comment définir des réseaux différents sans prendre le risque qu’ils puissent se parler ? * pourquoi les IP sont construites sur 4 digits? * etc…​
On va essayer de répondre à tout ça en entrant plus dans le détail de ce qu’est une IP.
On vient de le dire finalement, une IP c’est une adresse encodé sur 4 digits, en fait c’est ce que l’on appelle une IPv4. Vous en avez sûrement entendu parler, il existe aussi des IPv6, la différence est les nombre d’adresse que l’on va pouvoir construire avec les digits mais globalement c’est transposable. On gardera quand même nos explications sur IPv4, car nous allons le voir ça sera plus simple "visuellement".
Donc une IP (IPv4) c’est 4 digit allant de 0 à 255. Par exemple, 192.168.0.10 est une IPv4. De cette façon, on va pouvoir construire 4 milliards d’adresses…​ (ça fait beaucoup mais…​ en fait aujourd’hui ça pose problème: pc + serveurs + Iot etc…​ en fait on les a exploser d’où l’apparition de IPv6 mais c’est une autre histoire)
Par contre on s’est rendu compte que l’on ne pouvait pas considérer que l’on puisse adresse tout internet sur la base brute de ces 4 milliard d’adresses possibles. D’une part, à gérer cela aurait été trop gros et d’autre par, il est apparu important de pouvoir segmenter les réseaux, de façon à les isoler. Différentes topologie ont donc du être considéré: les petits réseaux qui finalement n’avait pas besoin de beaucoup d’adresse possible et les grands pour qui c’est l’inverse.
On a donc créer des classes de réseaux identifiables via du masquage d’adresse.

2.3. Masquage réseau

Le masquage consiste à définir un pattern permettant de contextualiser une adresse IP. En utilisant un masque, l’adresse fournira alors deux type d’information, celle identifiant la machine, et celle identifiant le plan d’adressage du réseau dans lequel cette machine se trouve.
Par exemple, considérons l’IP : 192.168.0.25. En l’état la seul chose que l’on puisse dire c’est qu’il n’existe d’un réseau et cette IP est associé à la machine numéro 192.168.0.25.
Pas contre l’utilisation d’un masque spécifiant par exemple 255.255.255.0 (/24). Nous permet de dire qu’en fait cette machine fait parti du réseau 192.168.0.0 et qu’elle est la machine numéro 25.
La notion de masque à été standardisé au travers des classes A,B,C,D et E…​ [classe-IP] Ici nous ne nous y intéresserons pas.
Le principe du masquage nous permet ici d’avoir un réseau restreint contenant que 255 machine possible. L’intérêt par contre est que ce plan d’adressage en 192.168.0.0 est réutilisable dans un autre réseau qui serait isolé et indépendant de celui-ci car aucune des machines ne pourrait se connaître et on pourrait alors avoir dans chacun de ces deux réseaux une machine portant la mémé adresse. Comme ci dessous.
Ici on a deux réseaux avec un plan d’adressage identique mais qui sont interconnectés via un troisième réseau qui lui les identifie dans un plan d’adressage diffèrent (on y viendra mais alors il faudra penser à utiliser des routeurs afin de permettre à toutes ces machines de parler entre elle, on verra cela lors du routage).
Un autre solution à la topologie précédente est d’utiliser un sous masque réseau sur la base d’un masque réseau plus large. Ainsi on crée des réseaux dans le plan d’adressage initial permettant d’avoir une décomposition logique et minimiser le nombre de routeurs à déployer

3. Exemple

C’est bien tout ça mais dans la vraie vie comme ça se présente? Pour faire simple, et visualiser cela depuis sa machine, deux outils peuvent être employé.
Le très célèbre ifconfig (ipconfig sous windows) [ifconfig] qui nous restituera l’ensemble des interfaces de notre machine avec les informations dont nous venons de parler:
IfConfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ ifconfig
eno2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.57  netmask 255.255.255.0  broadcast 192.168.0.255
        ether 04:56:26:1d:b2:96  txqueuelen 1000  (Ethernet)
        RX packets 8229590  bytes 7371495080 (7.3 GB)
        RX errors 0  dropped 184  overruns 0  frame 0
        TX packets 7627831  bytes 1670924458 (1.6 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Boucle locale)
        RX packets 459205  bytes 108586619 (108.5 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 459205  bytes 108586619 (108.5 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlo1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.43  netmask 255.255.255.0  broadcast 192.168.0.255
        ether 48:14:7f:86:2e:69  txqueuelen 1000  (Ethernet)
        RX packets 148857  bytes 23021004 (23.0 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 48859  bytes 5284481 (5.2 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
On y retrouve l’interface filaire eno2 et l’interface wifi wlo1. A noter lo qui est ce que l’on appelle la loopback qui est en 127.0.0.1 qui permet à la machine de se parler à elle même sans préjuger du réseau dans lequel elle se trouve.
L’autre outil est plus récent que ifconfig il s’agit de ip [ip-tool], un outil générique pour la manipulation des concepts réseaux, nous reviendrons souvent dessus.
IfConfig
1
2
3
4
5
6
7
8
9
10
11
12
13
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 04:92:26:de:b2:e8 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.57/24 brd 192.168.0.255 scope global dynamic noprefixroute eno2
       valid_lft 32728sec preferred_lft 32728sec
3: wlo1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 48:de:7f:09:2e:69 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.43/24 brd 192.168.0.255 scope global dynamic noprefixroute wlo1
       valid_lft 37450sec preferred_lft 37450sec
Enfin , maintenant que nos machines sont identifiables dans le réseau, il va falloir définir comment leur donner ces adresses!

4. DHCP, passerelle et DNS

La ça va être le rôle du DHCP (Dynamic Host Configuration Protocole) [dhcp]. En effet, il est toujours possible d’allouer une adresse ip manuellement à une machine typiquement on ferai comme ceci:
Ip manuelle
1
$ sudo ip addr add 192.168.0.125 dev eno2
Mais honnêtement si votre parc de machine ou serveur comporte 200 équipements réseaux dont la plupart ont des interfaces réseaux redonnées, alors je vous souhaite bien du courage!
Non le plus simple est de déléguer ça à un gestionnaire d’adresse réseaux qu’est le DHCP. Ainsi lorsqu’une machine n’a pas d’IP, elle va aller en demander une en broadcastant une requête sur le réseaux. Le serveur DHCP va y répondre et lui allouer une ip (parmi celle disponible en fonction de l’adresse réseau, du masque et des adresses déjà allouées) mais aussi lui donner l’adresse de la passerelle par défaut et l’adresse du DNS.
Ou-la, qu’est ce que c’est que ça encore! Oui nous n’en avons pas encore parler mais une machine du réseaux, si elle souhaite parler à une autre machine du même réseau, alors pas de soucis, le routage des paquets est direct. Par contre si cette machine est en dehors du réseau alors, il faudra qu’elle s’adresse à la passerelle pour que celle ci puisse relayer les messages vers un réseau plus compétant dans la résolution de l’IP (qui lui même fera pareil le cas échéant)…​ il s’agit du même mécanisme que celui que nous avions évoqué dans l’article sur Iptable et le routage [iptable].
Ce qu’il faut retenir c’est qu’une passerelle c’est comme votre box internet, quand vous allez sur internet ça passe par elle (elle a donc une ip dans votre réseau) et quand les réponses reviennent, cela passe par une ip externe qu’elle expose de façon à être identifié dans le réseau externe.
De même un serveur DNS est un serveur chargé de résoudre les noms de domaine et de machine et vous les traduire en adresse IP pour que vous puissiez contacter la machine en question.
Ainsi par exemple, vous voulez accéder au site www.google.fr . Ceci est un nom de domaine, pas une ip, donc vous allez devoir vous adresser au serveur DNS que le serveur DHCP. Ce que vous avez du DNS c’est son adresse IP et celle ci est un autre réseau que vous. Vous allez don envoyer votre requête à la passerelle qui poussera la demande au DNS. Le DNS répondra alors à la passerelle qui vous retransmettra le message Comportant l’IP du site web de google. Pour l’interroger, rebelotte, la requête est envoyé à la passerelle (oui je doute que votre réseau local contienne les serveur de google) qui la renverra sur l’IP de chez google.
A noter, que l’IP de google est probablement d’une passerelle également et que ses flux sont envoyé en interne dans d’autre sous réseau dont on a pas connaissance.

5. Conclusion

Voila, nous avons vu l’essentiel du réseau, les IP, les masques, quelques notions de routage et de résolutions de nom. Maintenant nous allons pouvoir aborder des choses plus intéressants: les réseaux virtuels et les bridges

samedi 4 avril 2020

Docker : Swarm

Introduction

Problématique Microservices

Dans le contexte des infrastructures microservices, docker [docker] est la reference! Jusqu’a maintenant nous avions surotut vu son utilisation dans le cadre du processus de developpement voir d’integration, mais nous ne sommes pas allé sur le terrain de la mise en production.

Qu’est ce que je veux dire? Ce que je veux dire, c’est qu’une architecture microservice necessite forcement plusieurs micorservice et c’est pour cela d’ailleur que nous avons vite utilisé [docker-compose] afin de nous faciliter la vie en lancant l’ensemble de ces microservices ensemble, pour ainsi dire "orchestrer".
Pourtant docker-compose n’est pas suffisant, en effet celui ci nous permet de mettre en place une deployement cible de nos microservices mais ces derniers n’evolent alors que dans la machine dans laquelle docker-compose a ete invoqué!
Dans le cas ou nous souhaiterions deployer l’ensemble de nos microservice selon des regles specifique de deploiement, (par exemple les composants front ensemble, les back ensemble etc…​) alors il nous faut d’une part etre capable de deploier dans un ensemble de machine de facon transparente mais en plus de pouvoir facilement administrer ce deploiement!
La solution a cette problematique c’est le sujet de cet article, docker-swarm [docker-swarm]

Architecture

Docker swarm [docker-swarm-concepts] est un outil d’orchestration inclu dans docker engine. Un Swarm est un ensemble machine contenant docker et fonctionnant en mode swarm Danse ce cluster, on trouvera alors un manager (ou n selon la redondance souhaité) et des worker (le manager pouvant aussi cumuler le rôle de worker).




Comme dans docker-compose, on déclare des services correspondant a un etat descriptif de la configuration souhaitée auprès du manager qui va produire des taches de déploiement dans les workers.

Fonctionnalités

Docker Swarm permet:
  • de gérer un cluster de nœud définit dans un réseau de machine potentiellement distribué et heterogene.
  • de fournir une description du déploiement orienté service comme docker compose
  • de scaler les instances pour ajouter de la redondance logique
  • de faire du monitoring et de la réconciliation: en cas de crash, swarm sera capable de détecter les instances éventuellement manquante et se chargera de les redémarrer
  • de faire des mise a jour a chaud pour realiser des modifications sur la configuration de déploiement comme des mise a jour applicative et docker se chargera de réconcilier l’état reel avec l’etat voulu.
  • de loadbalancer la charge des flux sur les n instances (les replicas que nous verrons plus loin)

Creation du cluster swarm

Architecture cible





Dans notre archi, on va jouer avec 1 manager principal redondé une fois et 5 workers (incluant les 2 managers).

On va vouloir faire un server de fichier via http (avec [nginx]) dont les données de configuration sont partagées via un partage [nfs] global au cluster. Par contre dans notre exemple nous considererons que les données a exposer ne sont disponible que sur manager et node1.

Nos instances nginx devront donc se trouver sur l’une ou ces deux workers.
Process

Pour creer le swarm, on va suivre la doc! [create-swarm]

On va sur la machine qui sera le manager et on execute la commande:

1
$docker swarm init --advertise-addr 192.168.0.60

On obtient une reponse de la forme:

1
$docker swarm join --token SWMTKN-1- 192.168.0.60:2377

Cette commande il faudra aller l’exécuter sur chaque machine ou est installé docker-engine. Avec la commande suivante il est possible de verifier que les noeuds ont bien eté ajouté:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
  $ docker info
  Client:
  Debug Mode: false

  Server:
  Containers: 5
    Running: 0
    Paused: 0
    Stopped: 5
  Images: 21
  Server Version: 19.03.6
  [...]
  Swarm: active
    NodeID: tntgi3hb72z9ly8rgir8p1j9p
    Is Manager: true
    ClusterID: wr0n081vcbdyxaabz40y3k3n8
    Managers: 1
    Nodes: 4
    Default Address Pool: 10.0.0.0/8  
    SubnetSize: 24
    Data Path Port: 4789
    [...]

Pour redonder le manager il faut s’ajouter dans cluster comme noeud manager secondaire pour rendre possible l’execution des commandes en local (le poste de dev en fait) et non devoir les executer sur le manger en remote.

Sur le poste de dev, on execute la commande d’ajout d’un noeud classique:

1
$ docker swarm join --token SWMTKN-1-<token-value> 192.168.0.60:2377

Et sur la machine manager on realise une promotion a la machine de dev (dev etant le nom hostname de la machine):

1
$docker node promote dev

Pour obtenir des informations sur les noeuds:

1
2
3
4
5
6
7
  $ docker node ls
  ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
  tntgi3hb72z9ly8rgir8p1j9p *   manager            Ready               Active              Leader              19.03.6
  xbaxr3icsfc08a3liv4dr3v7p     node1              Ready               Active                                  19.03.8
  fyvyl153mrly3jz12xt0bblb3     node2              Ready               Active                                  19.03.8
  vgqfp4qxuguma7u11ghyw847i     node3              Ready               Active                                  19.03.8
  s4h7oyar5tnothrwp0p6ukews *   dev                Ready               Active              Reachable           19.03.5

En preparation et pour respecter la typologie a venir, on va ajouter un label a nos noeuds [add-label]. Nous verons plus tard pourquoi et comment cela va impacter le deploiement.

1
2
$docker node update --label-add http=active manager
$docker node update --label-add http=active node1

Deploiement d’un service dans le swarm

Process

Pour deploier nos service nginx, on va definir un ficheir docker-compose un peu booster et integrant quelques specifications supplementaire [deploy-swarm].

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  tc-ngnix:
    image: nginx:1.17.2-alpine
    volumes:
      - "/media/nfs_storage/tc-nginx/conf:/etc/nginx:ro"
      - "/mnt/raid/data:/usr/share/nginx/html/data:ro"
    ports:
      - 80:80
    deploy:
      replicas: 2
      placement:
        constraints:
          - "node.labels.http==active"

Ce fichier va s’appuyer sur une image nginx evidemement, declarer les points de montage de conf et de data et definir :
  • le nombre de replicas c’est a dire le nombre d’instance souhaité du container
  • la strategie de placement via une contrainte permetant de n’utiliser que les nodes sur lesquels on a mis le label http
Pour deployer le service http-services (son petit nom a nous):

1
$docker stack deploy --compose-file docker-compose.yml http-services

Pour consulter le service

1
2
3
  $ docker stack services http-services
  ID                  NAME                        MODE                REPLICAS            IMAGE                               PORTS
  d0g78u03joll        tc-infra-base_tc-ngnix      replicated          2/2                 nginx:1.17.2-alpine   *:80->80/tcp

Nous dit que nous avons bien deployer nos instances. Pour savoir ou? nous allons demander directement a docker avec un docker ps sur le manager:

1
2
3
  $ docker ps -a
  CONTAINER ID        IMAGE                          COMMAND                  CREATED              STATUS                      PORTS               NAMES
  e7e989c8b5f5        nginx:1.17.2-alpine            "nginx -g 'daemon of…"   About a minute ago   Up About a minute           80/tcp              http-services_tc-ngnix.1.xjww2x4g3ic3fs0h156vxneg0

Il en manque un! mais non il est sur le node1:


1
2
3
  $ docker ps -a
  CONTAINER ID        IMAGE                          COMMAND                  CREATED              STATUS                      PORTS               NAMES
  a1e06407c418        nginx:1.17.2-alpine            "nginx -g 'daemon of…"   About a minute ago   Up About a minute           80/tcp              http-services_tc-ngnix.2.ej3w74okhms3ir3gufbnockz7

Le plus simpa avec ca du coup c’est que notre server est accessible que ce soit:
  • http://node1
  • http://manager
mais aussi en:
  • http://dev
  • http://node2
  • http://node3
Parfait nous voila avec un server nginx up en double instance, loadbalancé et accessible via tous les noeuds du cluster!

Point de vigilance

Je n’entre pas dans le detail mais sur certains points quelques interrogation peuvent etre soulevé, concernant le partage de la conf et des datas a nginx via un point de montage [nfs]. Ce n’est pas une solution ideale mais elle a le merite d’etre rapide et simple a mettre en oeuvre mais attention alors a la securité…​.

Pour aller un peu plus loin…​

Pour voir un exemple similaire avec quelques manip en plus genre la mise a jour a chaud ou le scaling horizontal aller voir cet article [swarm-fun]

Ensuite si vous voulez entrer dans la partie monitoring de vos containeurs et service avec des outils comme Prometheus ou Grafana, vous pouvez consulter [swarm-monitoring]

References

  • [docker-swarm-concepts] https://docs.docker.com/engine/swarm/key-concepts/
  • [docker-swarm] https://docs.docker.com/engine/swarm/
  • [create-swarm] https://docs.docker.com/engine/swarm/swarm-tutorial/create-swarm/
  • [deploy-swarm] https://docs.docker.com/engine/swarm/stack-deploy/
  • [swarm-mode] https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/#replicated-and-global-services
  • [add-label] https://docs.docker.com/engine/reference/commandline/node_update/#add-label-metadata-to-a-node
  • [docker] https://docs.docker.com/
  • [docker-compose] https://docs.docker.com/compose/
  • [nfs] https://doc.ubuntu-fr.org/nfs
  • [nginx] https://www.nginx.com/
  • [swarm-fun] https://dzone.com/articles/fun-with-docker-swarm?edition=334876&utm_source=Daily%20Digest&utm_medium=email&utm_campaign=Daily%20Digest%202017-11-15
  • [swarm-monitoring] https://dzone.com/articles/monitoring-docker-swarm?edition=451233&utm_source=Daily%20Digest&utm_medium=email&utm_campaign=Daily%20Digest%202019-02-11