Formation DevOps : Docker et Kubernetes
Formation DevOps : Docker et Kubernetes
Retour au site
Uptime Formation - Docker - Avril 2021
Supports de formation : Elie Gavoty et Hadrien Pélissier Conçus initialement dans le cadre d'un cursus
Uptime Formation. Sous licence CC-BY-NC-SA - Docker - Avril 2021
[Link] 1/181
30/01/2024 23:20 Exporter tout le contenu
Introduction
Introduction
DevOps
Le nouveau paradigme de l’informatique
Introduction au DevOps
La culture et la pratique du DevOps
A propos de moi
Hadrien Pélissier
A propos de vous
“Profil” : votre environnement technique initial
Besoins : ce que vous aimeriez faire, avez besoin de savoir faire
Attentes de cette formation
DevOps : définition
“Le DevOps est un mouvement qui s’attaque au conflit existant structurellement entre le
développement de logiciels et les opérations. Ce conflit résulte d’objectifs et de
motivations divergents. Le DevOps améliore la collaboration entre les départements du
développement et des opérations et rationalise l’ensemble de l’organisation. (Citation de
Hütterman 2012 - Devops for developers)”
[Link] 2/181
30/01/2024 23:20 Exporter tout le contenu
L’agilité en informatique
Traditionnellement la qualité logicielle provient :
Exemple : Netflix ou Spotify ou Facebook etc. déploient une nouvelle version mineure de
leur logiciel par jour.
Dans un DSI (département de service informatique) on organise ces activités d’admin sys
en opérations:
La difficulté principale pour les Ops c’est qu’un système informatique est:
[Link] 3/181
30/01/2024 23:20 Exporter tout le contenu
On peut donc constater que les opérations traditionnelles implique une culture de la
prudence
On s’organise à l’avance.
On vérifie plusieurs fois chaque chose.
On ne fait pas confiance au code que nous donnent les développeur·euses.
On suit des procédures pour limiter les risques.
On surveille l’état du système (on parle de monitoring)
Et on reçoit même des SMS la nuit si ya un problème :S
Bilan
Les opérations “traditionnelles”:
Peuvent pas aller trop vite car il faut marcher sur des oeufs.
Les Ops veulent pas déployer de nouvelles versions trop souvent car ça fait plein de
boulot et ils prennent des risques (bugs / incompatilibités).
Quand c’est mal organisé ou qu’on va trop vite il y a des catastrophes possibles.
[Link] 4/181
30/01/2024 23:20 Exporter tout le contenu
Mais pour que ça fonctionne il faut résoudre des défi techniques nouveau => innovations
Renforcer la collaboration
Équipes transversales
Dans le cadre d’un produit logiciel, les administrateurs systèmes sont rassemblées avec le
développement et le chef produit : tout le monde fait les réunions ensemble pour se
parler et se comprendre.
Culture de la polyvalence
Les développeur·euses peuvent plus facilement créer un environnement réaliste pour
jouer avec et comprendre comment fonctionne l’infrastructure de production (ils
progressent dans l’administration système et la compréhension des enjeux
opérationnels).
Les adminsys apprennent à programmer leurs opérations de façon puissante il
deviennent donc plus proche de la logique des développeur·euses. (grace à
l’Infrastructure as Code)
Le profil DevOps
Par abus de langage on dit un ou une DevOps pour parler d’un métier spécifique dans
une entreprise. Je dis que je suis DevOps sur mon CV par exemple.
[Link] 5/181
30/01/2024 23:20 Exporter tout le contenu
Le profil DevOps
Il faut être polyvalent : bien connaître l’administration système Linux mais aussi un peu la
programmation et le développement.
Il faut connaître les nouvelles bonnes pratiques et les nouveaux outils cités
précédemment.
En résumé
Un profil ? Un hybride de dev et d’ops…
Une méthode ? Infra-as-Code, continuous integration and delivery (CI/CD),
conteneurisation
Une façon de virer des adminsys… ?
Solutions techniques
Le cloud
Plutôt que d'installer manuellement de nouveaux serveurs linux pour faire tourner des
logiciels on peut utiliser des outils pour faire apparaître de nouveaux serveurs à la
demande.
[Link] 6/181
30/01/2024 23:20 Exporter tout le contenu
Du coup on peut agrandir sans effort l’infrastructure de production pour délivrer une
nouvelle version
CI / CD
Infrastructure as code
Permet de régler un problème de l’administration système : Difficultée l’état du
système à un instant T ce qui augmente les risques.
Plutôt que d’appliquer des commandes puis d’oublier si on les a appliqué, On décrit
le système d’exploitation (l’état du linux) dans un fichier et on utilise un système qui
applique cette configuration explicite à tout moment.
Permet aux Ops/AdminSys de travailler comme des développeur·euses (avec une
usine logicielle et ses outils)
Infrastructure As Code
Un mouvement d’informatique lié au DevOps et au cloud :
[Link] 7/181
30/01/2024 23:20 Exporter tout le contenu
Une façon de définir une infrastructure dans un fichier descriptif et ainsi de créer
dynamiquement des services.
Avantages :
Descriptif : on peut lire facilement l'état actuel de l’infra
Git ! Gérer les versions de l’infrastructure et collaborer facilement comme avec du
code.
Tester les instrastructure pour éviter les régressions/bugs
Facilite l’intégration et le déploiement continus = vélocité = versions testées puis
mises en prod' progressivement et automatiquement dans le cycle DevOps
Pas de surprise = possibilité d’agrandir les clusters sans souci !
On peut multiplier les machines (une machine ou 100 machines identiques c’est
pareil).
Infrastructure As Code
Concepts proches
Infrastructure as a Service (commercial et logiciel)
L’infrastructure as code
Il s’agit comme son nom l’indique de gérer les infrastructures en tant que code c’est-à-
dire des fichiers textes avec une logique algorithmique/de données et suivis grâce à un
gestionnaire de version (git).
Multiplier les serveurs identiques est difficile si leur état est le résultat d’un processus
manuel partiellement documenté.
Difficulté à reproduire/simuler l’état précis de l’infrastructure de production dans les
contextes de tests logiciels.
3. Difficultés du travail collaboratif dans de grandes équipes avec plusieurs culture (Dev
vs Ops) lorsque les rythmes et les modes de travail diffèrent
Containerisation
Les conteneurs (Docker et Kubernetes)
Faire des boîtes isolées avec nos logiciels:
[Link] 9/181
30/01/2024 23:20 Exporter tout le contenu
Containerisation - Pourquoi ?
L’isolation des containers permet d’éviter que les logiciels s’emmêlent entre
eux. (Les dépendances ne rentrent pas en conflit)
Les conteneurs non modifiables permettent de savoir exactement l’état de ce qu’on
exécute sur l’ordinateur
Préparation
Un peu de logistique
Les supports de présentation et les TD sont disponibles à l’adresse
[Link]
Pour exporter les TD utilisez la fonction d’impression pdf de google chrome.
[Link] 10/181
30/01/2024 23:20 Exporter tout le contenu
Ansible
Module 1
Ansible
Découvrir le couteau suisse de l’automatisation et de l’infrastructure as code.
Plan
configurer ansible
/etc ou [Link]
configuration de la connexion
connexion SSH et autres plugins de connection
versions de Python et d’Ansible
L’inventaire ansible
gérer des groupes de machines
L’inventaire est la source d’information principale pour Ansible
[Link] 11/181
30/01/2024 23:20 Exporter tout le contenu
debugging de playbook
verbosite
directive de debug
gestion des erreurs à l’exécution
Les rôles
Ansible Galaxy pour installer des rôles.
Architecture d’un rôle et bonnes pratiques de gestion des rôles.
Orchestration
Stratégies : Parallélisme de l’exécution
Délégation de tâche
Réalisation d’un rolling upgrade de notre application web grace à Ansible
Inverser des tâches Ansible - stratégies de rollback
Exécution personnalisée avec des tags
Sécurité
Ansible Vault : gestion des secrets pour l’infrastructure as code
desctiver les logs des tâches sensibles
Renforcer le mode de connexion ansible avec un bastion SSH
Cours 1 - Présentation
Présentation d’Ansible
Ansible
Ansible est un gestionnaire de configuration et un outil de déploiement et
d’orchestration très populaire et central dans le monde de l'infrastructure as code
(IaC).
[Link] 13/181
30/01/2024 23:20 Exporter tout le contenu
Il fait donc également partie de façon centrale du mouvement DevOps car il s’apparente à
un véritable couteau suisse de l’automatisation des infrastructures.
Histoire
Ansible a été créé en 2012 (plus récent que ses concurrents Puppet et Chef) autour d’une
recherche de simplicité et du principe de configuration agentless.
Red Hat rachète Ansible en 2015 et développe un certain nombre de produits autour
(Ansible Tower, Ansible container avec Openshift).
Ansible est agentless c’est à dire qu’il ne nécessite aucun service/daemon spécifique sur
les machines à configurer.
La simplicité d’Ansible provient également du fait qu’il s’appuie sur des technologies linux
omniprésentes et devenues universelles.
ssh : connexion et authentification classique avec les comptes présents sur les
machines.
python : multiplateforme, un classique sous linux, adapté à l’admin sys et à tous les
usages.
De fait Ansible fonctionne efficacement sur toutes les distributions linux, debian, centos,
ubuntu en particulier (et maintenant également sur Windows).
[Link] 14/181
30/01/2024 23:20 Exporter tout le contenu
petit:
… un petit playbook (~script) fournit avec le code d’un logiciel pour déployer en
mode test.
… la configuration d’une machine de travail personnelle.
etc.
moyen:
Ansible et Docker
Ansible est très complémentaire à docker:
Plus récemment avec l’arrivé d' Ansible container il est possible de construire et
déployer des conteneurs docker avec du code ansible. Cette solution fait partie de la stack
Red Hat Openshift. Concrêtement le langage ansible remplace (avantageusement ?) le
langage Dockerfile pour la construction des images Docker.
Pour tester la connexion aux serveurs on utilise la commande ad hoc suivante. ansible
all -m ping
Classées par groupe et sous groupes pour être désignables collectivement (exp
executer telle opération sur)
La méthode connexion est précisée soit globalement soit pour chaque machine.
Des variables peuvent être définies pour chaque machine ou groupe pour contrôler
dynamiquement par la suite la configuration ansible.
Exemple :
[all:vars]
ansible_ssh_user=elie
ansible_python_interpreter=/usr/bin/python3
[awx_nodes]
awxnode1 node_state=started ansible_host=[Link] container_image=cent
[dbservers]
pgnode1 node_state=started ansible_host=[Link] container_image=cento
pgnode2 node_state=started ansible_host=[Link] container_image=cento
[appservers]
appnode1 node_state=started ansible_host=[Link] container_image=cent
appnode2 node_state=started ansible_host=[Link] container_image=cent
[Link] 16/181
30/01/2024 23:20 Exporter tout le contenu
Les inventaires peuvent également être au format YAML (plus lisible mais pas toujours
intuitif) ou JSON (pour les machines).
Configuration
Ansible se configure classiquement au niveau global dans le dossier /etc/ansible/
dans lequel on retrouve en autre l’inventaire par défaut et des paramètre de
configuration.
Ansible est très fortement configurable pour s’adapter à des environnement contraints.
Liste des paramètre de configuration:
La commande ansible
version minimale : ansible <groupe_machine> -m <module> -a
<arguments_module>
ansible all -m ping : Permet de tester si les hotes sont joignables et ansible
utilisable (SSH et python sont présents et configurés).
version plus complète : ansible <groupe_machine> --inventory
<fichier_inventaire> --become -m <module> -a <arguments_module>
Il en existe pour un peu toute les tâches raisonnablement courantes : un slogan Ansible
“Batteries included” ! Plus de 1300 modules sont intégrés par défaut.
ping : un module de test Ansible (pas seulement réseau comme la commande ping)
yum/apt : pour gérer les paquets sur les distributions basées respectivement sur
Red Hat ou Debian.
systemd (ou plus générique service ): gérer les services/daemons d’un système.
cela permet de garder les appel de modules très succints pour les tâches par défaut
il est également possible de rendre des paramètres par défaut explicites pour
augmenter la clarté du code.
Exemple et bonne pratique: toujours préciser state: present même si cette valeur est
presque toujours le défaut implicite.
Commençons le TP1
Le playbook est une sorte de script Ansible, c’est-à-dire du code. Le nom provient du
football américain : il s’agit d’un ensemble de stratégies qu’une équipe a travaillé pour
répondre aux situations du match. Elle insiste sur la versatilité de l’outil.
Syntaxe YAML
Les playbooks ansible sont écrits au format YAML.
YAML est basé sur les identations à base d’espaces (2 espaces par indentation en
général). Comme le langage python.
C’est un format assez lisible et simple à écrire bien que les indentations soient parfois
difficiles à lire.
C’est un format assez flexible avec des types liste et dictionnaires qui peuvent
s’imbriquer.
[Link] 18/181
30/01/2024 23:20 Exporter tout le contenu
Le YAML est assez proche du JSON (leur structures arborescentes typées sont dites
isomorphes, en gros faciles à convertir de l’un vers l’autre) mais plus facile à écrire.
A quoi ça ressemble ?
Une liste
- 1
- Poire
- "Message à caractère informatif"
Un dictionnaire
clé1: valeur1
clé2: valeur2
clé3: 3
- potiron
# fin du dictionnaire global
Pour mieux visualiser l’imbrication des dictionnaires et des listes en YAML on peut utiliser
un convertisseur YAML -> JSON : [Link]
{
"marché": {
"lieu": "Crimée Curial",
"jour": "dimanche",
[Link] 19/181
30/01/2024 23:20 Exporter tout le contenu
"horaire": {
"unité": "heure",
"min": 9,
"max": 14
},
"fruits": [
{
"nom": "pomme",
"couleur": "verte",
"pesticide": "avec"
},
{
"nom": "poires",
"couleur": "jaune",
"pesticide": "sans"
}
],
"légumes": [
"courgettes",
"salade",
"potiron"
]
}
}
Observez en particulier la syntaxe assez condensée de la liste “fruits” en YAML qui est une
liste de dictionnaires.
vars:
logfile_name: "[Link]"
var_files:
- [Link]
pre_tasks:
- name: dynamic variable
set_fact:
mavariable: "{{ inventory_hostname + 'prod' }}" #guillemets obligato
rôles:
- flaskapp
tasks:
- name: installer le serveur nginx
apt: name=nginx state=present # syntaxe concise proche des commandes a
[Link] 20/181
30/01/2024 23:20 Exporter tout le contenu
- import_tasks: [Link]
handlers:
- systemd:
name: nginx
state: "reloaded"
Les handlers sont des tâches conditionnelles qui s’exécutent à la fin (post
traitements conditionnels comme le redémarrage d’un service)
Ordre d’exécution
1. pre_tasks
2. roles
3. tasks
4. post_tasks
5. handlers
Les rôles ne sont pas des tâches à proprement parler mais un ensemble de tâches et
ressources regroupées dans un module, un peu comme une librairie dans le
développement. Nous explorerons les rôles au cours 3.
[Link] 21/181
30/01/2024 23:20 Exporter tout le contenu
Utiliser les arguments au format YAML (sur plusieurs lignes) pour la lisibilité, sauf s’il
y a peu d’arguments
Pour valider la syntaxe il est possible d’installer et utiliser ansible-linter sur les
fichiers YAML.
Élévation de privilège
L’élévation de privilège est nécessaire lorsqu’on a besoin d’être root pour exécuter une
commande ou plus généralement qu’on a besoin d’exécuter une commande avec un
utilisateur différent de celui utilisé pour la connexion on peut utiliser:
au début du play (après hosts ) : toutes les tâches seront executée avec cette
élévation par défaut.
après n’importe quelle tâche : l’élévation concerne uniquement la tâche cible.
Pour executer une tâche avec un autre utilisateur que root (become simple) ou celui
de connexion (sans become) on le précise en ajoutant à become: yes ,
become_user: username
Variables Ansible
Ansible utilise en arrière plan un dictionnaire contenant de nombreuses variables.
Ce moteur permet de créer des valeurs dynamiques dans le code des playbooks, des
rôles, et des fichiers de configuration.
Les variables écrites au format {{ mavariable }} sont remplacées par leur valeur
provenant du dictionnaire d’exécution d’Ansible.
[Link] 22/181
30/01/2024 23:20 Exporter tout le contenu
Lorsque définies plusieurs fois, les variables ont des priorités en fonction de l’endroit de
définition. L’ordre de priorité est plutôt complexe:
[Link]
precedence-where-should-i-put-a-variable
En résumé la règle peut être exprimée comme suit: les variables de runtime sont
prioritaires sur les variables dans un playbook qui sont prioritaires sur les variables de
l’inventaire qui sont prioritaires sur les variables par défaut d’un rôle.
Bonne pratique: limiter les redéfinitions de variables en cascade (au maximum une
valeur par défaut, une valeur contextuelle et une valeur runtime) pour éviter que le
playbook soit trop complexe et difficilement compréhensible et donc maintenable.
Remarques de syntaxe
[Link] et groups['all'] sont deux syntaxes équivalentes pour désigner les
éléments d’un dictionnaire.
Variables spéciales
[Link]
[Link] 23/181
30/01/2024 23:20 Exporter tout le contenu
Pour explorer chacune de ces variables vous pouvez utiliser le module debug en mode
adhoc ou dans un playbook:
ou encore:
Facts
Les facts sont des valeurs de variables récupérées au début de l’exécution durant l’étape
gather_facts et qui décrivent l’état courant de chaque machine.
! Lors d’une commande adhoc ansible les facts ne sont pas récupérés : la variable
ansible_os_family ne sera pas disponible.
La liste des facts peut être trouvée dans la documentation et dépend des plugins utilisés
pour les récupérés:
[Link]
La directive loop:
Cette directive permet d’executer une tâche plusieurs fois basée sur une liste de valeur:
[Link]
[Link] 24/181
30/01/2024 23:20 Exporter tout le contenu
exemple:
- hosts: localhost
tasks:
- name: exemple de boucle
debug:
msg: "{{ item }}"
loop:
- message1
- message2
- message3
- hosts: localhost
vars:
messages:
- message1
- message2
- message3
tasks:
- name: exemple de boucle
debug:
msg: "message numero {{ num }} : {{ message }}"
loop: "{{ messages }}"
loop_control:
loop_var: message
index_var: num
Filtres Jinja
Pour transformer la valeur des variables à la volée lors de leur appel on peut utiliser des
filtres (jinja2) :
par exemple on peut fournir une valeur par défaut pour une variable avec filtre
default: {{ hostname | default('localhost') }}
Un autre usage courant des filtres est de reformater et filtrer des listes et
dictionnaires de paramètre. Ces syntaxes sont peut intuitives. Vous pouvez vous
entrainer en regardant ces tutoriels:
[Link]
[Link]
[Link] 25/181
30/01/2024 23:20 Exporter tout le contenu
Debugger un playbook.
Avec Ansible on dispose d’au moins trois manières de debugger un playbook:
group_vars/
[Link] # here we assign variables to particular groups
[Link]
host_vars/
[Link] # here we assign variables to particular systems
[Link]
roles/
common/ # this hierarchy represents a "role"
... # role code
Plusieurs remarques:
[Link] 26/181
30/01/2024 23:20 Exporter tout le contenu
production .
Chaque groupe de serveurs (tier) dispose de son playbook
qui s’applique sur le groupe en question.
éventuellement définit quelques variables spécifiques (mais il vaut mieux les
mettre dans l’inventaire ou les dossiers cf suite).
Idéalement contient un minimum de tâches et plutôt des rôles
Pour limiter la taille de l’inventaire principal on range les variables communes dans
des dossiers group_vars et host_vars . On met à l’intérieur un fichier
<nom_du_groupe>.yml qui contient un dictionnaire de variables.
On cherche à modulariser au maximum la configuration dans des rôles, c’est-à-dire
des groupes de tâches rendues génériques et specifiques à un objectif de
configuration.
Ce modèle d’organisation correspond plutôt à la configuration de base d’une
infrastructure (playbooks à exécuter régulièrement) qu’à l’usage de playbooks
ponctuels comme pour le déploiement. Mais, bien sûr, on peut ajouter un dossier
playbooks ou operations pour certaines opérations ponctuelles. (cf cours 4)
Si les modules de Ansible (complétés par les commandes bash) ne suffisent pas on
peut développer ses propres modules Ansible.
Rôles Ansible
Objectif:
Découper les tâches de configuration en sous-ensembles réutilisables (une suite
d’étapes de configuration).
Ansible est une sorte de langage de programmation et l’intérêt du code est de
pouvoir créer des fonctions regroupées en librairies et les composer. Les rôles sont
les “librairies” Ansible en quelque sorte.
[Link] 27/181
30/01/2024 23:20 Exporter tout le contenu
Comme une fonction, un rôle prend généralement des paramètres qui permettent de
personnaliser son comportement.
Tout le nécessaire doit y être (fichiers de configurations, archives et binaires à
déployer, modules personnels dans library etc.)
Remarque : ne pas confondre modules et roles. file est un module,
[Link] est un rôle. On doit écrire des rôles pour coder correctement
en Ansible, on peut écrire des modules mais c’est largement facultatif car la plupart
des actions existent déjà.
Présentation d’un exemple de rôle : [Link]
docker
roles/
my_role/ # hiérarchie du rôle "my_role"
tasks/ #
[Link] # <-- le fichier de tâches exécuté par défaut
handlers/ #
[Link] # <-- les handlers
templates/ # <-- dossier des templates
[Link].j2 # <------- les templates finissent par .j2
files/ #
[Link] # <-- d'autres fichiers si nécessaire
vars/ #
[Link] # <-- variables internes du rôle
defaults/ #
[Link] # <-- variables par défaut pour le rôle
meta/ #
[Link] # <-- informations sur le rôle
[Link] 28/181
30/01/2024 23:20 Exporter tout le contenu
On constate que les noms des sous-dossiers correspondent souvent à des sections du
playbook. En fait le principe de base est d’extraire les différentes listes de tâches ou de
variables dans des sous-dossiers.
[Link]
licence
compatibilité
version
dépendances à d’autres rôles.
Le dossier files contient les fichiers qui ne sont pas des templates (pour les
module copy ou sync , script etc).
Ansible Galaxy
C’est le store de rôles officiel d’Ansible : [Link]
C’est également le nom d’une commande ansible-galaxy qui permet d’installer des
rôles et leurs dépendances depuis internet. Un sorte de gestionnaire de paquets pour
Ansible.
Tous les rôles Ansible sont communautaires (pas de rôles officiels) et généralement
stockés sur Github ou Gitlab.
Mais on peut voir la popularité (étoiles Github), et la présence de tests (avec un outil
Ansible appelé Molecule), qui garantissement la plus ou moins grande fiabilité et qualité
du rôle.
Il existe des rôles pour installer un peu n’importe quelle application serveur courante
aujourd’hui. Passez du temps à explorer le web avant de développer quelque chose avec
Ansible.
[Link] 29/181
30/01/2024 23:20 Exporter tout le contenu
- src: [Link]-epel
- src: [Link]
- src: [Link]
# from GitHub, overriding the name and specifying a specific tag
- src: [Link]
version: master
name: nginx_role
Imports et includes
Il est possible d’importer le contenu d’autres fichiers dans un playbook:
Les deux instructions précédentes désignent un import statique qui est résolu avant
l’exécution.
Par exemple :
vars:
apps:
- app1
- app2
- app3
tasks:
- include_tasks: install_app.yml
loop: "{{ apps }}"
Ce code indique à Ansible d’exécuter une série de tâches pour chaque application de la
liste. On pourrait remplacer cette liste par une liste dynamique. Comme le nombre
d’imports ne peut pas facilement être connu à l’avance on doit utiliser include_tasks .
Savoir si on doit utiliser include ou import se fait selon les cas et avec tâtonnement le
plus souvent.
Les problématiques de sécurité Linux ne sont pas du tout résolues magiquement par
Ansible. Tous le travail de réflexion et de sécurisation reste identique mais peut, comme le
reste, être mieux controllé grâce à l’approche déclarative de l’infrastructure as code.
Si cette problématique des liens entre Ansible et sécurité vous intéresse, il existe un livre
appelé Security automation with Ansible .
Il est à noter tout de même qu’Ansible est généralement apprécié d’un point de vue
sécurité car il n’augmente pas (vraiment) la surface d’attaque de vos infrastructures : il est
basé sur ssh qui est éprouvé et ne nécessite généralement pas de réorganisation des
infrastructures.
Pour les cas plus spécifiques, Ansible est relativement agnostique du mode de connexion
grâce aux plugins de connexions (voir ci-dessous).
Authentification et SSH
Un bonne pratique : changer le port de connexion ssh pour un port atypique. Vous
pourrez ajouter la variable ansible_ssh_port=17728 dans l’inventaire.
Il faut idéalement éviter de créer un seul compte Ansible de connexion pour toutes les
machines :
difficile à bouger
responsabilité des connexions pas auditable ([Link] + syslog)
Il faut utiliser comme nous avons fait dans les TP des logins ssh avec des utilisateurs aux
noms correspondant aux usages ou aux humains derrière, et des clés ssh. C’est-à-dire le
même modèle d’authentification que l’administration traditionnelle.
Variables et secrets
[Link] 31/181
30/01/2024 23:20 Exporter tout le contenu
Attention : les dépôts git peuvent cacher des secrets dans leur historique. Pour nettoyer un
secret dans un dépôt Git, l’outil le plus courant est BFG : [Link]
cleaner/
Par exemple, si une tâche change une entrée en base qui contient un mot de passe,
no_log: yes est tout indiqué.
Ansible Vault
Pour éviter de divulguer des secrets par inadvertance, il est possible de gérer les secrets
avec des variables d’environnement ou avec un fichier variable externe au projet qui
échappera au versionning git, mais ce n’est pas idéal.
Ansible intègre un trousseau de secrets appelé Ansible Vault. Il permet de chiffrer des
valeurs variables par variables ou via des fichiers complets. Les valeurs stockées dans
le trousseau sont déchiffrées à l’exécution après déverrouillage du trousseau.
Il existe également un mode pour gérer plusieurs mots de passe associés à des
identifiants.
[Link] 32/181
30/01/2024 23:20 Exporter tout le contenu
Il existe de nombreuses solutions pour intégrer Ansible avec les principaux providers de
cloud (modules Ansible, plugins d’API, intégration avec d’autre outils d’Infrastructure-as-
Code cloud comme Terraform ou Cloudformation).
Inventaires dynamiques
Les inventaires que nous avons utilisés jusqu’ici implique d’affecter à la main les adresses
IP des différents noeuds de notre infrastructure. Cela devient vite ingérable si celle-ci
change souvent.
La solution Ansible pour ne pas gérer les IP et les groupes à la main est appelée inventaire
dynamique ou inventory plugin . Un inventaire dynamique est simplement un
programme qui renvoie un JSON respectant le format d’inventaire JSON Ansible,
généralement en contactant l’API du cloud provider ou une autre source.
$ ./inventory_terraform.py
{
"_meta": {
"hostvars": {
"balancer0": {
"ansible_host": "[Link]"
},
"balancer1": {
"ansible_host": "[Link]"
},
"awx0": {
"ansible_host": "[Link]"
},
"appserver0": {
"ansible_host": "[Link]"
}
}
},
"all": {
"children": [],
"hosts": [
"appserver0",
"awx0",
"balancer0",
"balancer1"
],
"vars": {}
},
"appservers": {
"children": [],
"hosts": [
"balancer0",
"balancer1"
],
"vars": {}
},
[Link] 33/181
30/01/2024 23:20 Exporter tout le contenu
"awxnodes": {
"children": [],
"hosts": [
"awx0"
],
"vars": {}
},
"balancers": {
"children": [],
"hosts": [
"appserver0"
],
"vars": {}
}
}%
[Link]
Exemple:
[Link] 34/181
30/01/2024 23:20 Exporter tout le contenu
{{ postconf_d | combine(dict([ [Link]('=')[::2]map'trim
loop: postconf_result.stdout_lines
On peut explorer plus facilement la hiérarchie d’un inventaire statique ou dynamique avec
la commande:
Ansible modules
Inventory plugins
Connection plugins
Possibilité 2 : Laisser le contrôle à Nagios et utiliser un plugin pour que Nagios puisse
lancer des plays Ansible en réponse à des évènements sur les sondes.
[Link] 35/181
30/01/2024 23:20 Exporter tout le contenu
$ sudo apt-add-repository --yes --update ppa:ansible/ansible
$ sudo apt install ansible
ansible --version
=> 2.8.x
Réponse :
Réponse :
Utilisez en plus l’option -vvv pour mettre en mode très verbeux. Ce mode est très
efficace pour debugger lorsqu’une erreur inconnue se présente. Que se passe-t-il
avec l’inventaire ?
Réponse :
Réponse :
Réponse :
Explorer LXD
LXD est une technologie de conteneurs actuellement promue par canonical (ubuntu) qui
permet de faire des conteneur linux orientés systèmes plutôt qu’application. Par exemple
systemd est disponible à l’intérieur des conteneurs contrairement aux conteneurs
Docker.
LXD est déjà installé et initialisé sur notre ubuntu (sinon apt install snapd + snap
install lxd + ajouter votre utilisateur courant au group unix lxd ).
Ce conteneur est un centos minimal et n’a donc pas de serveur SSH pour se
connecter. Pour lancez des commandes dans le conteneur on utilise une commande
LXC pour s’y connecter lxc exec <non_conteneur> -- <commande> . Dans notre cas
nous voulons lancer bash pour ouvrir un shell dans le conteneur : lxc exec centos1
-- bash .
Nous pouvons installer des logiciels dans le conteneur comme dans une VM. Pour
sortir du conteneur on peut simplement utiliser exit .
Un peu comme avec Docker, LXC utilise des images modèles pour créer des
conteneurs. Affichez la liste des images avec lxc image list . Trois images sont
disponibles l’image centos vide téléchargée et utilisée pour créer centos1 et deux
autres images préconfigurée ubuntu_ansible et centos_ansible . Ces images
contiennent déjà la configuration nécessaire pour être utilisée avec ansible (SSH +
Python + Un utilisateur + une clé SSH).
Supprimez la machine centos1 avec lxc stop centos1 && lxc delete centos1
bash /opt/[Link]
Pour se connecter en SSH nous allons donc utiliser une clé SSH appelée
id_stagiaire qui devrait être présente dans votre dossier ~/.ssh/ . Vérifiez cela
en lançant ls -l /home/stagiaire/.ssh .
Déverrouillez cette clé ssh avec ssh-add ~/.ssh/id_stagiaire et le mot de passe
devops101 (le ssh-agent doit être démarré dans le shell pour que cette commande
fonctionne si ce n’est pas le cas eval $(ssh-agent) ).
Essayez de vous connecter à ubu1 et centos1 en ssh pour vérifier que la clé ssh
est bien configurée et vérifiez dans chaque machine que le sudo est configuré sans
mot de passe avec sudo -i .
[Link] 37/181
30/01/2024 23:20 Exporter tout le contenu
Ajouter tous les paramètres nécessaires dans un dossier pour être au plus proche du
code. Par exemple utiliser un inventaire [Link] ou hosts et une
configuration locale au projet [Link]
Facultatif :
[defaults]
inventory = ./[Link]
roles_path = ./roles
host_key_checking = false # nécessaire pour les labs où l'on créé et supprim
ubu1 ansible_host=<ip>
[all:vars]
ansible_user=<votre_user>
Dans le dossier du projet, essayez de relancer la commande ad-hoc ping sur cette
machine.
Ansible implique le cas échéant (login avec clé ssh) de déverrouiller la clé ssh pour se
connecter à chaque hôte. Lorsqu’on en a plusieurs il est donc nécessaire de la
déverrouiller en amont avec l’agent ssh pour ne pas perturber l’exécution des
commandes ansible. Pour cela : ssh-add .
Créez un groupe adhoc_lab et ajoutez les deux machines ubu1 et centos1 .
Réponse :
[Link] 38/181
30/01/2024 23:20 Exporter tout le contenu
Réponse :
Nous avons jusqu’à présent utilisé une connexion ssh par clé et précisé l’utilisateur
de connexion dans le fichier [Link] . Cependant on peut aussi utiliser une
connexion par mot de passe et préciser l’utilisateur et le mot de passe dans
l’inventaire ou en lançant la commande.
En précisant les paramètres de connexion dans le playbook il et aussi possible d’avoir des
modes de connexion différents pour chaque machine.
[all:vars]
ansible_user=<votre_user>
[ubuntu_hosts]
ubu1 ansible_host=<ip>
[centos_hosts]
centos1 ansible_host=<ip>
[adhoc_lab:children]
ubuntu_hosts
centos_hosts
Dans un inventaire ansible on commence toujours par créer les plus petits sous groupes
puis on les rassemble en plus grands groupes.
Nous allons maintenant installer nginx sur les 2 machines. Il y a plusieurs façons
d’installer des logiciels grâce à Ansible: en utilisant le gestionnaire de paquets de la
distribution ou un gestionnaire spécifique comme pip ou npm . Chaque méthode
dispose d’un module ansible spécifique.
Si nous voulions installer nginx avec la même commande sur des machines centos et
ubuntu à la fois impossible d’utiliser apt car centos utilise yum . Pour éviter ce
problème on peut utiliser le module package qui permet d’uniformiser l’installation
(pour les cas simples).
Allez voir la documentation de ce module
utilisez --become pour devenir root avant d’exécuter la commande (cf
élévation de privilège dans le cours2)
Utilisez le pour installer nginx
[Link] 39/181
30/01/2024 23:20 Exporter tout le contenu
Réponse :
Réponse :
Réponse :
Réponse :
L’option --check à vérifier l’état des ressources sur les machines mais sans
modifier la configuration`. Relancez la commande précédente pour le vérifier.
Normalement le retour de la commande est le même (l’ordre peu varier).
Lancez la commande avec state=stopped : le retour est inversé.
Enlevez le --check pour vous assurer que le service est démarré sur chacune des
machines.
Visitez dans un navigateur l’ip d’un des hôtes pour voir la page d’accueil nginx.
[defaults]
inventory = ./[Link]
roles_path = ./roles
host_key_checking = false
[all:vars]
ansible_user=<user>
[appservers]
app1 ansible_host=10.x.y.z
app2 ansible_host=10.x.y.z
Facultatif :
[Link] 41/181
30/01/2024 23:20 Exporter tout le contenu
- hosts: <hotes_cible>
tasks:
- name: ping
ping:
Ajoutez une tâche pour créer un utilisateur flask et l’ajouter au groupe www-data .
Utilisez bien le paramètre append: yes pour éviter de supprimer des groupes à
l’utilisateur.
[Link] 42/181
30/01/2024 23:20 Exporter tout le contenu
Télécharger le code dans notre projet et le copier sur chaque serveur avec le
module sync qui fait une copie rsync.
Utiliser le module git .
Nous allons utiliser la deuxième option ( git ) qui est plus cohérente pour le
déploiement et la gestion des versions logicielles. Allez voir la documentation
comment utiliser ce module.
Utilisez le pour télécharger le code source de l’application (branche master ) dans le
dossier /home/flask/hello mais en désactivant la mise à jour (au cas ou le code
change).
Lancez votre playbook et allez vérifier sur une machine en ssh que le code est bien
téléchargé.
[Link] 43/181
30/01/2024 23:20 Exporter tout le contenu
Réponse :
Créez une tâche file qui change le propriétaire du dossier de façon récursive.
[Unit]
Description=Gunicorn instance to serve hello
After=[Link]
[Service]
User=flask
Group=www-data
WorkingDirectory=/home/flask/hello
Environment="PATH=/home/flask/hello/venv/bin"
ExecStart=/home/flask/hello/venv/bin/gunicorn --workers 3 --bind unix:hello
[Install]
WantedBy=[Link]
Pour gérer les fichier de configuration on utilise généralement le module template qui
permet à partir d’un fichier modèle situé dans le projet ansible de créer dynamiquement
un fichier de configuration adapté sur la machine distante.
[Link] 44/181
30/01/2024 23:20 Exporter tout le contenu
Configurer nginx
Comme précédemment créez un fichier de configuration [Link] dans le
dossier /etc/nginx/sites-available à partir du fichier modèle:
[Link].j2
server {
listen 80;
server_name [Link];
location / {
include proxy_params;
proxy_pass [Link]
}
}
Correction intermédiaire
flaskhello_deploy.yml
Code de correction :
Facultatif :
[Link] 45/181
30/01/2024 23:20 Exporter tout le contenu
app:
name: hello
user: flask
domain: [Link]
Facultatif :
Le dépôt contient également les corrigés du TP3 et TP4 dans d’autre branches.
[Link] 46/181
30/01/2024 23:20 Exporter tout le contenu
...
handlers:
- name: reload nginx
systemd:
name: "nginx"
state: reloaded
Identifiez dans le playbook précédent les tâches qui sont exactement communes aux
deux installations.
Réponse :
Créez un nouveau fichier deploy_app_tasks.yml et copier à l’intérieur la liste de
toutes les autres tâches mais sans les handlers que vous laisserez à la fin du
playbook.
Réponse :
Ce nouveau fichier n’est pas à proprement parler un playbook mais une liste de
tâches. utilisez include_tasks: pour importer cette liste de tâche à l’endroit ou
vous les avez supprimées.
Vérifiez que le playbook fonctionne et est toujours idempotent.
Ajoutez une tâche debug: msg={{ app }} au début du playbook pour visualiser le
contenu de la variable.
Ensuite remplacez la variable app par une liste flask_apps de deux dictionnaires
(avec name , domain , user différents les deux dictionnaires et repository et
version identiques).
flask_apps:
- name: hello
domain: "[Link]"
user: "flask1"
version: master
repository: [Link]
- name: hello2
domain: "[Link]"
[Link] 47/181
30/01/2024 23:20 Exporter tout le contenu
user: "flask2"
version: master
repository: [Link]
Correction
Pour la correction clonez le dépôt de base à l’adresse [Link]
lie/ansible_tp_corrections.
Renommez le clone en tp2.
ouvrez le projet avec VSCode.
Activez la branche tp2_correction avec git checkout tp2_correction .
Le dépôt contient également les corrigés du TP3 et TP4 dans d’autre branches.
Bonus
Pour ceux ou celles qui sont allé-es vite, vous pouvez tenter de créer une nouvelle version
de votre playbook portable entre CentOS et ubuntu. Pour cela utilisez la directive when:
ansible_os_family == 'Debian' ou RedHat .
Il s’agit de l’application construite au fur et à mesure dans un super tutoriel Python sur
Flask. Ce chapitre indique comment déployer l’application sur linux.
[Link] 48/181
30/01/2024 23:20 Exporter tout le contenu
Dans notre infra virtuelle, nous avons trois machines dans deux groupes. Quand notre lab
d’infra grossit il devient laborieux de créer les machines et affecter les ip à la main. En
particulier détruire le lab et le reconstruire est pénible. Nous allons pour cela introduire un
playbook de provisionning qui va créer les conteneurs lxd en définissant leur ip à partir de
l’inventaire.
[all:vars]
ansible_user=<votre_user>
[appservers]
app1 ansible_host=10.x.y.121 container_image=ubuntu_ansible node_state=start
app2 ansible_host=10.x.y.122 container_image=ubuntu_ansible node_state=start
[dbservers]
db1 ansible_host=10.x.y.131 container_image=ubuntu_ansible node_state=starte
Remplacez x et y dans l’adresse IP par celle fournies par votre réseau virtuel lxd
(faites lxc list et copier simplement les deux chiffres du milieu des adresses IP)
Ajoutez un playbook provision_lxd_infra.yml dans un dossier provisionners
contenant:
- hosts: localhost
connection: local
tasks:
- name: Setup linux containers for the infrastructure simulation
lxd_container:
name: "{{ item }}"
state: "{{ hostvars[item]['node_state'] }}"
source:
type: image
alias: "{{ hostvars[item]['container_image'] }}"
profiles: ["default"]
config:
[Link]: 'true'
[Link]: 'false'
devices:
# configure network interface
eth0:
type: nic
nictype: bridged
parent: lxdbr0
# get ip address from inventory
[Link]: "{{ hostvars[item].ansible_host }}"
[Link] 49/181
30/01/2024 23:20 Exporter tout le contenu
# Comment following line if you installed lxd using apt
url: unix:/var/snap/lxd/common/lxd/[Link]
wait_for_ipv4_addresses: true
timeout: 600
register: containers
loop: "{{ groups['all'] }}"
flaskapp
├── defaults
│ └── [Link]
├── handlers
│ └── [Link]
├── tasks
│ ├── deploy_app_tasks.yml
│ └── [Link]
└── templates
[Link] 50/181
30/01/2024 23:20 Exporter tout le contenu
├── [Link].j2
└── [Link].j2
Les templates et les listes de handlers/tasks sont à mettre dans les fichiers
correspondants (voir plus bas)
Le fichier defaults/[Link] permet de définir des valeurs par défaut pour les
variables du rôle. Mettez à l’intérieur une application par défaut :
flask_apps:
- name: defaultflask
domain: [Link]
repository: [Link]
version: master
user: defaultflask
Ces valeurs seront écrasées par celles fournies dans le dossier group_vars (la liste de
deux applications du TP2). Elle est présente pour que le rôle fonctionne même en
l’absence de variable (valeurs de fallback).
Copiez les tâches (juste la liste de tirets sans l’intitulé de section tasks: ) contenues
dans le playbook appservers dans le fichier tasks/[Link] .
De la même façon, copiez le handler dans handlers/[Link] sans l’intitulé
handlers: .
roles:
- flaskapp
Votre rôle est prêt : lancez [Link] et debuggez le résultat le cas échéant.
Correction
Pour la correction, clonez le dépôt de base à l’adresse [Link]
lie/ansible_tp_corrections.
Renommez le clone en tp3.
Ouvrez le projet avec VSCode.
Activez la branche tp3_correction avec git checkout tp3_correction .
[Link] 51/181
30/01/2024 23:20 Exporter tout le contenu
Bonus
Essayez différents exemples de projets de Geerlingguy accessibles sur GitHub à l’adresse
[Link]
[Link] 52/181
30/01/2024 23:20 Exporter tout le contenu
Rechargez la page: vous constatez que c’est l’autre backend qui a pris le relais.
Nous allons maintenant mettre à jour
Bibliographie
[Link] 53/181
30/01/2024 23:20 Exporter tout le contenu
Ansible
Jeff Geerling - Ansible for DevOps - Leanpub
Cheatsheet
[Link]
sheet-guide
Docker
Module 2
Docker
Créer et manipuler des conteneurs
0 - Introduction à Docker
1 - Manipulation des conteneurs
TP 1 - Installer Docker et jouer avec
2 - Images et conteneurs
TP 2 - Images et conteneurs
3 - Volumes et réseaux
TP 3 - Réseaux
TP 3bis - Volumes
4 - Créer une application multiconteneur
TP 4 - Créer une application multiconteneur
5 - Orchestration et clustering
TP 5 - Orchestration et clustering
Conclusion
TP 6 (bonus) - Intégration continue avec Gitlab
TP 7 (bonus) - Docker et les reverse proxies
[Link] 54/181
30/01/2024 23:20 Exporter tout le contenu
QCM Docker
0 - Introduction à Docker
Modularisez et maîtrisez vos applications
Introduction
La métaphore docker : “box it, ship it”
Une abstraction qui ouvre de nouvelles possibilités pour la manipulation logicielle.
Permet de standardiser et de contrôler la livraison et le déploiement.
[Link] 55/181
30/01/2024 23:20 Exporter tout le contenu
Les deux technologies peuvent utiliser un système de quotas pour l’accès aux ressources
matérielles (accès en lecture/écriture sur le disque, sollicitation de la carte réseau, du
processeur)
L’imaginer comme une “boîte” est donc une allégorie un peu trompeuse, car ce n’est pas
de la virtualisation (= isolation au niveau matériel).
chroot
Implémenté principalement par le programme chroot [change root : changer de
racine], présent dans les systèmes UNIX depuis longtemps (1979 !) :
“Comme tout est fichier, changer la racine d’un processus, c’est comme le
faire changer de système”.
jail
jail est introduit par FreeBSD en 2002 pour compléter chroot et qui permet
pour la première fois une isolation réelle (et sécurisée) des processus.
chroot ne s’occupait que de l’isolation d’un process par rapport au système de
fichiers :
[Link] 56/181
30/01/2024 23:20 Exporter tout le contenu
En 2005, Sun introduit les conteneurs Solaris décrits comme un « chroot sous
stéroïdes » : comme les jails de FreeBSD
Pour Linux, ce concept est repris via la mise en place de namespaces Linux
usage de la mémoire
du disque
du réseau
des appels système
[Link] 57/181
30/01/2024 23:20 Exporter tout le contenu
du processeur (CPU)
En 2005, Google commence le développement des cgroups : une façon de tagger les
demandes de processeur et les appels systèmes pour les grouper et les isoler.
:(){ : | :& }; :
Ceci est une fork bomb. Dans un conteneur non privilégié, on bloque tout Docker, voire
tout le système sous-jacent, en l’empêchant de créer de nouveaux processus.
Pour éviter cela il faudrait limiter la création de processus via une option kernel.
les cgroups
le chroot
les namespaces.
Originellement, Docker était basé sur LXC. Il a depuis développé son propre
assemblage de ces 3 mécanismes.
[Link] 58/181
30/01/2024 23:20 Exporter tout le contenu
Docker et LXC
En 2013, Docker commence à proposer une meilleure finition et une interface simple
qui facilite l’utilisation des conteneurs LXC.
Puis il propose aussi son cloud, le Docker Hub pour faciliter la gestion d’images
toutes faites de conteneurs.
Au fur et à mesure, Docker abandonne le code de LXC (mais continue d’utiliser le
chroot, les cgroups et namespaces).
Le code de base de Docker (notamment runC) est open source : l'Open Container
Initiative vise à standardiser et rendre robuste l’utilisation de containers.
Vitesse d’exécution.
Flexibilité sur les ressources (mémoire partagée).
Moins complexe que la virtualisation
Plus standard que les multiples hyperviseurs
notamment moins de bugs d’interaction entre l’hyperviseur et le noyau
[Link] 59/181
30/01/2024 23:20 Exporter tout le contenu
Infrastructure as Code
Résumé
on décrit en mode code un état du système. Avantages :
pas de dérive de la configuration et du système (immutabilité)
on peut connaître de façon fiable l’état des composants du système
on peut travailler en collaboration plus facilement (grâce à Git notamment)
on peut faire des tests
[Link] 60/181
30/01/2024 23:20 Exporter tout le contenu
[Link] 61/181
30/01/2024 23:20 Exporter tout le contenu
L’écosystème Docker
Docker Compose : Un outil pour décrire des applications multiconteneurs.
Docker Machine : Un outil pour gérer le déploiement Docker sur plusieurs
machines depuis un hôte.
Docker Hub : Le service d’hébergement d’images proposé par Docker Inc. (le
registry officiel)
L’environnement de développement
Docker Engine pour lancer des commandes docker
Docker Compose pour lancer des application multiconteneurs
Portainer, un GUI Docker
VirtualBox pour avoir une VM Linux quand on est sur Windows
[Link] 62/181
30/01/2024 23:20 Exporter tout le contenu
Fonctionne avec Windows Subsystem for Linux : c’est une VM Linux très bien
intégrée à Windows
Le meilleur des deux mondes ?
Workflow similaire à celui d’un serveur Linux
Solution Windows : on utilise Docker Desktop for Windows:
On peut l’installer avec le gestionnaire de paquets de l’OS mais cette version peut
être trop ancienne.
Sur Ubuntu ou CentOS la méthode conseillée est d’utiliser les paquets fournis dans
le dépôt officiel Docker (vous pouvez avoir des surprises avec la version snap
d’Ubuntu).
[Link] 63/181
30/01/2024 23:20 Exporter tout le contenu
on peut la voir un peu comme une boîte “modèle” : on peut l’utiliser plusieurs
fois comme base de création de containers identiques, similaires ou différents.
docker images
docker image ls
Les conteneurs
Un conteneur est une instance en cours de fonctionnement (“vivante”) d’une image.
un conteneur en cours de fonctionnement est un processus (et ses processus
enfants) qui tourne dans le Linux hôte (mais qui est isolé de celui-ci)
Commandes Docker
Docker fonctionne avec des sous-commandes et propose de grandes quantités d’options
pour chaque commande.
[Link] 64/181
30/01/2024 23:20 Exporter tout le contenu
docker info # affiche plein d'information sur l'engine avec lequel vous ête
docker ps # affiche les conteneurs en train de tourner
docker ps -a # affiche également les conteneurs arrêtés
Docker Engine
Linux
Images
alpine hello-world
[Link] 65/181
30/01/2024 23:20 Exporter tout le contenu
-it permet de lancer une commande en mode interactif (un terminal comme
bash ).
-a (ou --attach ) permet de se connecter à l’entrée-sortie du processus dans
le container.
Commandes Docker
Le démarrage d’un conteneur est lié à une commande.
Si le conteneur n’a pas de commande, il s’arrête dès qu’il a fini de démarrer
docker run debian echo 'attendre 10s' && sleep 10 # s'arrête après 10s
[Link] 66/181
30/01/2024 23:20 Exporter tout le contenu
Les utilisateurs Unix à l’intérieur du conteneur ont des UID et GID qui existent
classiquement sur l’hôte mais ils peuvent correspondre à un utilisateur Unix sans
droits sur l’hôte si on utilise les user namespaces.
Introspection de conteneur
La commande docker exec permet d’exécuter une commande à l’intérieur du
conteneur s’il est lancé.
Une utilisation typique est d’introspecter un conteneur en lançant bash (ou sh ).
Dans ce contexte un élément qui a fait le succès de Docker est le Docker Hub :
[Link]
Il s’agit d’un répertoire public et souvent gratuit d’images (officielles ou non) pour des
milliers d’applications pré-configurées.
Docker Hub:
On peut y chercher et trouver presque n’importe quel logiciel au format d’image
Docker.
Il suffit pour cela de chercher l’identifiant et la version de l’image désirée.
Puis utiliser docker run [<compte>/]<id_image>:<version>
La partie compte est le compte de la personne qui a poussé ses images sur le
Docker Hub. Les images Docker officielles ( ubuntu par exemple) ne sont pas liées à
un compte : on peut écrire simplement ubuntu:focal .
On peut aussi juste télécharger l’image : docker pull <image>
On peut également y créer un compte gratuit pour pousser et distribuer ses propres
images, ou installer son propre serveur de distribution d’images privé ou public, appelé
registry.
En résumé
[Link] 67/181
30/01/2024 23:20 Exporter tout le contenu
Pour installer Docker, suivez la documentation officielle pour installer Docker sur
Ubuntu, depuis “Install using the repository” jusqu’aux deux commandes sudo apt-
get update et sudo apt-get install docker-ce docker-ce-cli [Link] .
Docker nous propose aussi une installation en une ligne (one-liner), moins
sécurisée : curl -sSL [Link] | sudo sh
Lancez sudo docker run hello-world . Bien lire le message renvoyé (le traduire
sur Deepl si nécessaire). Que s’est-il passé ?
Il manque les droits pour exécuter Docker sans passer par sudo à chaque fois.
Autocomplétion
[Link] 68/181
30/01/2024 23:20 Exporter tout le contenu
Pour vous faciliter la vie, ajoutez le plugin autocomplete pour Docker et Docker
Compose à bash en copiant les commandes suivantes :
Important: Vous pouvez désormais appuyer sur la touche pour utiliser l’autocomplétion
quand vous écrivez des commandes Docker
docker info # affiche plein d'information sur l'engine avec lequel vous ête
docker ps # affiche les conteneurs en train de tourner
docker ps -a # affiche également les conteneurs arrêtés
Manipuler un conteneur
Commandes utiles : [Link]
Documentation docker run : [Link]
[Link] 69/181
30/01/2024 23:20 Exporter tout le contenu
Avec l’aide du support et de --help , et en notant sur une feuille ou dans un fichier texte
les commandes utilisées :
Résultat :
Lancez un conteneur Debian ( docker run puis les arguments nécessaires, cf. l’aide
--help ) en mode détaché avec la commande echo "Debian container" . Rien
n’apparaît. En effet en mode détaché la sortie standard n’est pas connectée au
terminal.
Lancez docker logs avec le nom ou l’id du conteneur. Vous devriez voir le résultat
de la commande echo précédente.
Résultat :
Solution :
Solution :
[Link] 70/181
30/01/2024 23:20 Exporter tout le contenu
NB: On peut désigner un conteneur soit par le nom qu’on lui a donné, soit par le nom
généré automatiquement, soit par son empreinte (toutes ces informations sont indiquées
dans un docker ps ou docker ps -a ). L’autocomplétion fonctionne avec les deux
noms.
Solution :
Solution :
Le nom d’un conteneur doit être unique (à ne pas confondre avec le nom de l’image qui
est le modèle utilisé à partir duquel est créé le conteneur).
Lancez un conteneur Nginx. Notez que lorsque l’image est déjà téléchargée le
lancement d’un conteneur est quasi instantané.
Ce conteneur n’est pas très utile, car on a oublié de configurer un port ouvert.
Trouvez un moyen d’accéder quand même au Nginx à partir de l’hôte Docker (indice :
quelle adresse IP le conteneur possède-t-il ?).
Solution :
[Link] 71/181
30/01/2024 23:20 Exporter tout le contenu
En visitant l’adresse et le port associé au conteneur Nginx, on doit voir apparaître des
logs Nginx dans son terminal car on a lancé le conteneur en mode attached.
Supprimez ce conteneur. NB : On doit arrêter un conteneur avant de le supprimer,
sauf si on utilise l’option “-f”.
On peut lancer des logiciels plus ambitieux, comme par exemple Funkwhale, une sorte
d’iTunes en web qui fait aussi réseau social :
Vous pouvez visiter ensuite ce conteneur Funkwhale sur le port 80 (après quelques
secondes à suivre le lancement de l’application dans les logs) ! Mais il n’y aura hélas pas
de musique dedans :(
Attention à ne jamais lancer deux containers connectés au même port sur l’hôte, sinon
cela échouera !
Supprimons ce conteneur :
docker rm -f funky_conteneur
Nous pouvons accéder au Wordpress, mais il n’a pas encore de base MySQL configurée.
Ce serait un peu dommage de configurer cette base de données à la main. Nous allons
configurer cela à partir de variables d’environnement et d’un deuxième conteneur créé à
partir de l’image mysql .
Depuis Ubuntu:
Il va falloir mettre ces deux conteneurs dans le même réseau (nous verrons plus tarde
ce que cela implique), créons ce réseau :
[Link] 72/181
30/01/2024 23:20 Exporter tout le contenu
Résultat :
Solution :
Faire du ménage
Lancez la commande docker ps -aq -f status=exited . Que fait-elle ?
Combinez cette commande avec docker rm pour supprimer tous les conteneurs
arrêtés (indice : en Bash, une commande entre les parenthèses de “ $() ” est
exécutée avant et utilisée comme chaîne de caractère dans la commande principale)
Solution :
Décortiquer un conteneur
En utilisant la commande docker export votre_conteneur -o [Link] ,
puis tar -C conteneur_decompresse -xvf [Link] pour décompresser un
conteneur Docker, explorez (avec l’explorateur de fichiers par exemple) jusqu’à
trouver l’exécutable principal contenu dans le conteneur.
[Link] 73/181
30/01/2024 23:20 Exporter tout le contenu
Portainer
Portainer est un portail web pour gérer une installation Docker via une interface
graphique. Il va nous faciliter la vie.
2 - Images et conteneurs
Créer une image en utilisant un Dockerfile
Jusqu’ici nous avons utilisé des images toutes prêtes.
Une des fonctionnalités principales de Docker est de pouvoir facilement construire
des images à partir d’un simple fichier texte : le Dockerfile.
[Link] 74/181
30/01/2024 23:20 Exporter tout le contenu
Chaque nouveau build génère une nouvelle image dans le répertoire des images
( /var/lib/docker/images ) (attention ça peut vite prendre énormément de place)
On construit les images à partir d’un fichier Dockerfile en décrivant
procéduralement (étape par étape) la construction.
Dockerfiles
Dock erfile: FROM alpine
RUN apk update && apk add nodejs
COPY . /app
WORKDIR /app
CMD ["node","[Link]"]
WORKDIR /app
FROM alpine RUN apk COPY . /app CMD "node" "[Link]"
+ + +
apk update host/[Link] --> $ cd /app
apk add nodejs container/app $ node [Link]
alpine
hello:v0.1
Exemple de Dockerfile :
FROM debian:latest
[Link] 75/181
30/01/2024 23:20 Exporter tout le contenu
# upgrade pip
RUN pip install --upgrade pip
Instruction FROM
L’image de base à partir de laquelle est construite l’image actuelle.
Instruction RUN
Permet de lancer une commande shell (installation, configuration).
Instruction ADD
Permet d’ajouter des fichier depuis le contexte de build à l’intérieur du conteneur.
Généralement utilisé pour ajouter le code du logiciel en cours de développement et
sa configuration au conteneur.
Instruction CMD
Généralement à la fin du Dockerfile : elle permet de préciser la commande par
défaut lancée à la création d’une instance du conteneur avec docker run . on
l’utilise avec une liste de paramètres
Instruction ENTRYPOINT
Précise le programme de base avec lequel sera lancé la commande
[Link] 76/181
30/01/2024 23:20 Exporter tout le contenu
ENTRYPOINT ["/usr/bin/python3"]
CMD et ENTRYPOINT
Ne surtout pas confondre avec RUN qui exécute une commande Bash uniquement
pendant la construction de l’image.
Si l’on souhaite que notre container lance le même exécutable à chaque fois, alors on peut
opter pour l’usage d' ENTRYPOINT en combination avec CMD .
Instruction ENV
Une façon recommandée de configurer vos applications Docker est d’utiliser les
variables d’environnement UNIX, ce qui permet une configuration “au runtime”.
Instruction HEALTHCHECK
HEALTHCHECK permet de vérifier si l’app contenue dans un conteneur est en bonne santé.
Les variables
On peut utiliser des variables d’environnement dans les Dockerfiles. La syntaxe est
${...} . Exemple :
FROM busybox
ENV FOO=/bar
WORKDIR ${FOO} # WORKDIR /bar
ADD . $FOO # ADD . /bar
COPY \$FOO /quux # COPY $FOO /quux
Documentation
[Link] 77/181
30/01/2024 23:20 Exporter tout le contenu
Lancer la construction
La commande pour lancer la construction d’une image est :
[Link] 78/181
30/01/2024 23:20 Exporter tout le contenu
Les images Docker ont souvent une taille de plusieurs centaines de mégaoctets
voire parfois gigaoctets. docker image ls permet de voir la taille des images.
Or, on construit souvent plusieurs dizaines de versions d’une application par jour
(souvent automatiquement sur les serveurs d’intégration continue).
Une image ubuntu complète pèse déjà presque une soixantaine de mégaoctets.
mais une image trop rudimentaire ( busybox ) est difficile à débugger et peu
bloquer pour certaines tâches à cause de binaires ou de bibliothèques logicielles
qui manquent (compilation par exemple).
Souvent on utilise des images de base construites à partir de alpine qui est un
bon compromis (6 mégaoctets seulement et un gestionnaire de paquets apk ).
Par exemple python3 est fourni en version python:alpine (99 Mo),
python:3-slim (179 Mo) et python:latest (918 Mo).
Avec les multi-stage builds, on peut utiliser plusieurs instructions FROM dans un
Dockerfile. Chaque instruction FROM utilise une base différente. On sélectionne ensuite
les fichiers intéressants (des fichiers compilés par exemple) en les copiant d’un stage à un
autre.
[Link] 79/181
30/01/2024 23:20 Exporter tout le contenu
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/[Link]/alexellis/href-counter/app .
CMD ["./app"]
Gitlab fournit un registry très intéressant car intégré dans leur workflow
DevOps.
[Link] 80/181
30/01/2024 23:20 Exporter tout le contenu
TP 2 - Images et conteneurs
Découverte d’une application web flask
Récupérez d’abord une application Flask exemple en la clonant :
Passons à Docker
Déployer une application Flask manuellement à chaque fois est relativement pénible. Pour
que les dépendances de deux projets Python ne se perturbent pas, il faut normalement
utiliser un environnement virtuel virtualenv pour séparer ces deux apps. Avec Docker,
les projets sont déjà isolés dans des conteneurs. Nous allons donc construire une image
de conteneur pour empaqueter l’application et la manipuler plus facilement. Assurez-vous
que Docker est installé.
Pour connaître la liste des instructions des Dockerfiles et leur usage, se référer au manuel
de référence sur les Dockerfiles.
COPY ./ /microblog
WORKDIR /microblog
Cette première ligne indique de copier tout le contenu du dossier courant sur l’hôte dans
un dossier /microblog à l’intérieur du conteneur. Nous n’avons pas copié les
requirements en même temps pour pouvoir tirer partie des fonctionnalités de cache de
Docker, et ne pas avoir à retélécharger les dépendances de l’application à chaque fois que
l’on modifie le contenu de l’app.
CMD ["./[Link]"]
[Link] 82/181
30/01/2024 23:20 Exporter tout le contenu
Docker Hub
Avec docker login , docker tag et docker push , poussez l’image microblog
sur le Docker Hub. Créez un compte sur le Docker Hub le cas échéant.
Solution :
Améliorer le Dockerfile
Pour démarrer l’application, nous avons fait appel à un script de boot [Link] avec à
l’intérieur :
#!/bin/bash
# ...
set -e
if [ "$APP_ENVIRONMENT" = 'DEV' ]; then
echo "Running Development Server"
exec flask run -h [Link]
else
echo "Running Production Server"
exec gunicorn -b :5000 --access-logfile - --error-logfile - app_name:ap
fi
[Link] 83/181
30/01/2024 23:20 Exporter tout le contenu
Exposer le port
Ajoutons l’instruction EXPOSE 5000 pour indiquer à Docker que cette app est censée
être accédée via son port 5000 .
NB : Publier le port grâce à l’option -p port_de_l-hote:port_du_container reste
nécessaire, l’instruction EXPOSE n’est là qu’à titre de documentation de l’image.
Dockerfile amélioré
`Dockerfile` final :
L’instruction HEALTHCHECK
HEALTHCHECK permet de vérifier si l’app contenue dans un conteneur est en bonne santé.
FROM python:alpine
healthy = True
app = Flask(__name__)
@[Link]('/health')
def health():
[Link] 84/181
30/01/2024 23:20 Exporter tout le contenu
global healthy
if healthy:
return 'OK', 200
else:
return 'NOT OK', 500
@[Link]('/kill')
def kill():
global healthy
healthy = False
return 'You have killed your app.', 200
if __name__ == "__main__":
[Link](host="[Link]")
On y trouve une sorte de base de données de tous les layers d’images avec leurs
ancêtres.
Il s’agit d’une arborescence.
Vous pouvez aussi utiliser la commande docker save votre_image -o [Link] ,
et utiliser tar -C image_decompressee/ -xvf [Link] pour décompresser une
image Docker puis explorer les différents layers de l’image.
Pour explorer la hiérarchie des images vous pouvez installer
[Link]
Solution :
Solution :
3 - Volumes et réseaux
Cycle de vie d’un conteneur
[Link] 86/181
30/01/2024 23:20 Exporter tout le contenu
Un conteneur a un cycle de vie très court: il doit pouvoir être créé et supprimé
rapidement même en contexte de production.
Conséquences :
Solutions :
Des réseaux dynamiques par défaut automatiques (DHCP mais surtout DNS
automatiques)
Des volumes (partagés ou non, distribués ou non) montés dans les conteneurs
Réseau
Bridge et overlay
Un réseau bridge est une façon de créer un pont entre deux carte réseaux pour
construire un réseau à partir de deux.
Par défaut les réseaux docker fonctionne en bridge (le réseau de chaque conteneur
est bridgé à un réseau virtuel docker)
par défaut les adresses sont en [Link]/8, typiquement chaque hôte définit le bloc
d’IP [Link]/16 configuré avec DHCP.
Un réseau overlay est un réseau virtuel privé déployé par dessus un réseau existant
(typiquement public). Pour par exemple faire un cloud multi-datacenters.
Mais ne pas avoir peur d’aller voir comment on perçoit le réseau de l’intérieur.
Nécessaire pour bien contrôler le réseau.
ingress : un loadbalancer automatiquement connecté aux nœuds d’un Swarm. Voir
la doc sur les réseaux overlay.
Plugins réseaux
Il existe :
Volumes
docker volume rm
Bind mounting
[Link] 88/181
30/01/2024 23:20 Exporter tout le contenu
Lorsqu’un répertoire hôte spécifique est utilisé dans un volume (la syntaxe -v
HOST_DIR:CONTAINER_DIR ), elle est souvent appelée bind mounting (“montage lié”).
C’est quelque peu trompeur, car tous les volumes sont techniquement “bind mounted”. La
particularité, c’est que le point de montage sur l’hôte est explicite plutôt que caché dans
un répertoire appartenant à Docker.
Exemple :
cd /data/
touch testfile
exit
ls /tmp/data/
Plugins de volumes
On peut utiliser d’autres systèmes de stockage en installant de nouveau plugins de driver
de volume. Par exemple, le plugin vieux/sshfs permet de piloter un volume distant via
SSH.
Exemples:
[Link] 89/181
30/01/2024 23:20 Exporter tout le contenu
Ou via docker-compose :
volumes:
sshfsdata:
driver: vieux/sshfs:latest
driver_opts:
sshcmd: "username@server:/location/on/the/server"
allow_other: ""
Permissions
Un volume est créé avec les permissions du dossier préexistant.
FROM debian
RUN groupadd -r graphite && useradd -r -g graphite graphite
RUN mkdir -p /data/graphite && chown -R graphite:graphite /data/graphite
VOLUME /data/graphite
USER graphite
CMD ["echo", "Data container for graphite"]
Backups de volumes
Pour effectuer un backup la méthode recommandée est d’utiliser un conteneur
suplémentaire dédié
qui accède au volume avec --volume-from
qui est identique aux autres et donc normalement avec les mêmes
UID/GID/permissions.
permet de ne pas perdre bêtement le volume lors d’un prune car il reste un
conteneur qui y est lié
[Link] 90/181
30/01/2024 23:20 Exporter tout le contenu
TP 3 - Réseaux
Portainer
Si vous aviez déjà créé le conteneur Portainer, vous pouvez le relancer en faisant docker
start portainer , sinon créez-le comme suit :
Docker implémente ces réseaux virtuels en créant des interfaces. Lancez la commande ip
a | tee /tmp/interfaces_apres.txt et comparez ( diff /tmp/interfaces_avant.txt
/tmp/interfaces_apres.txt ). Qu’est-ce qui a changé ?
[Link] 91/181
30/01/2024 23:20 Exporter tout le contenu
var host = opts.redis_host || [Link].USE_REDIS_HOST || "redis";
En résumé par défaut, notre application se connecte sur l’hôte redis avec le port 6379
Vous ne pouvez pas avoir deux conteneurs avec les mêmes noms, comme nous l’avons
déjà découvert. Par contre, notre deuxième réseau fonctionne complètement isolé de
notre premier réseau, ce qui signifie que nous pouvons toujours utiliser le nom de
domaine redis . Pour ce faire, nous devons spécifier l’option --network-alias :
Créons un deuxième redis avec le même domaine: docker run -d --name redis2 -
-network moby-network2 --network-alias redis redis:alpine
Lorsque vous pingez redis depuis cette nouvelle instance de l’application, quelle IP
obtenez-vous ?
Récupérez comme auparavant l’adresse IP du nameserver local pour moby-
counter2 .
[Link] 92/181
30/01/2024 23:20 Exporter tout le contenu
De même docker network prune permet de faire le ménage des réseaux qui ne
sont plus utilisés par aucun conteneur.
TP 3bis - Volumes
Portainer
Si vous aviez déjà créé le conteneur Portainer, vous pouvez le relancer en faisant docker
start portainer , sinon créez-le comme suit :
cd /data/
touch testfile
exit
Après être sorti·e du conteneur, listons le contenu du dossier sur l’hôte avec la
commande suivante ou avec le navigateur de fichiers d’Ubuntu :
ls /tmp/data/
[Link] 93/181
30/01/2024 23:20 Exporter tout le contenu
Le fichier testfile a été crée par le conteneur au dossier que l’on avait connecté grâce
à -v /tmp/data:/data
Stoppez tous les conteneurs redis et moby-counter avec docker stop ou avec
Portainer.
Supprimez les conteneurs arrêtés avec docker container prune
Lancez docker volume prune pour faire le ménage de volume éventuellement
créés dans les TPs précédent
Lancez aussi docker network prune pour nettoyer les réseaux inutilisés
FROM alpine:3.5
[Link] 94/181
30/01/2024 23:20 Exporter tout le contenu
&& wget -O [Link] "$REDIS_DOWNLOAD_URL" \
&& echo "$REDIS_DOWNLOAD_SHA *[Link]" | sha1sum -c - \
&& mkdir -p /usr/src/redis \
&& tar -xzf [Link] -C /usr/src/redis --strip-components=1 \
&& rm [Link] \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -r /usr/src/redis \
&& apk del .build-deps
Notez que, vers la fin du fichier, il y a une instruction VOLUME ; cela signifie que lorque
notre conteneur a été lancé, un volume “caché” a effectivement été créé par Docker.
Beaucoup de conteneurs Docker sont des applications stateful, c’est-à-dire qui stockent
des données. Automatiquement ces conteneurs créent des volument anonymes en arrière
plan qu’il faut ensuite supprimer manuellement (avec rm ou prune).
Inspectez la liste des volumes (par exemple avec Portainer) pour retrouver
l’identifiant du volume caché. Normalement il devrait y avoir un volume
portainer_data (si vous utilisez Portainer) et un volume anonyme avec un hash.
Créez un nouveau conteneur redis en le rattachant au volume redis “caché” que vous
avez retrouvé (en copiant l’id du volume anonyme) : docker container run -d --
name redis -v <volume_id>:/data --network moby-network redis:alpine
Bind mounting
Finalement, nous allons recréer un conteneur avec un volume qui n’est pas anonyme.
En effet, la bonne façon de créer des volumes consiste à les créer manuellement (volumes
nommés) : docker volume create redis_data .
Lorsqu’un répertoire hôte spécifique est utilisé dans un volume (la syntaxe -v
HOST_DIR:CONTAINER_DIR ), elle est souvent appelée bind mounting. C’est quelque peu
[Link] 95/181
30/01/2024 23:20 Exporter tout le contenu
trompeur, car tous les volumes sont techniquement “bind mounted”. La différence, c’est
que le point de montage est explicite plutôt que caché dans un répertoire géré par Docker.
Lancez la fonction prune pour les conteneurs d’abord, puis pour les réseaux, et
enfin pour les volumes.
ENV DATABASE_URL=sqlite:////data/[Link]
Indice :
Solution :
[Link] 96/181
30/01/2024 23:20 Exporter tout le contenu
- nom: poires
couleur: jaune
pesticide: sans
légumes:
[Link] 97/181
30/01/2024 23:20 Exporter tout le contenu
- courgettes
- salade
- potiron
Syntaxe
Alignement ! (2 espaces !!)
ALIGNEMENT !! (comme en python)
ALIGNEMENT !!! (le défaut du YAML, pas de correcteur syntaxique automatique,
c’est bête mais vous y perdrez forcément quelques heures !
des listes (tirets)
des paires clé: valeur
Un peu comme du JSON, avec cette grosse différence que le JSON se fiche de
l’alignement et met des accolades et des points-virgules
les extensions Docker et YAML dans VSCode vous aident à repérer des erreurs
services:
postgres:
image: postgres:10
environment:
POSTGRES_USER: rails_user
POSTGRES_PASSWORD: rails_password
POSTGRES_DB: rails_db
networks:
- back_end
redis:
image: redis:3.2-alpine
networks:
- back_end
rails:
build: .
depends_on:
- postgres
- redis
environment:
DATABASE_URL: "postgres://rails_user:rails_password@postgres:5432/rai
REDIS_HOST: "redis:6379"
networks:
- front_end
- back_end
volumes:
- .:/app
[Link] 98/181
30/01/2024 23:20 Exporter tout le contenu
nginx:
image: nginx:latest
networks:
- front_end
ports:
- 3000:80
volumes:
- ./[Link]:/etc/nginx/conf.d/[Link]:ro
networks:
front_end:
back_end:
Un deuxième exemple :
version: "3.3"
services:
mysql:
container_name: mysqlpourwordpress
environment:
- MYSQL_ROOT_PASSWORD=motdepasseroot
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=monwordpress
networks:
- wordpress
image: "mysql:5.7"
wordpress:
depends_on:
- mysql
container_name: wordpressavecmysql
environment:
- "WORDPRESS_DB_HOST=mysqlpourwordpress:3306"
- WORDPRESS_DB_PASSWORD=monwordpress
- WORDPRESS_DB_USER=wordpress
networks:
- wordpress
ports:
- "80:80"
image: wordpress
volumes:
- wordpress_config:/var/www/html/
networks:
wordpress:
volumes:
wordpress_config:
[Link] 99/181
30/01/2024 23:20 Exporter tout le contenu
up démarre tous les conteneurs définis dans le fichier compose et agrège la sortie
des logs. Normalement, vous voudrez utiliser l’argument -d pour exécuter
Compose en arrière-plan.
build reconstruit toutes les images créées à partir de Dockerfiles. La commande up
ne construira pas une image à moins qu’elle n’existe pas, donc utilisez cette
commande à chaque fois que vous avez besoin de mettre à jour une image (quand
vous avez édité un Dockerfile). On peut aussi faire docker-compose up --build
ps fournit des informations sur le statut des conteneurs gérés par Compose.
run fait tourner un conteneur pour exécuter une commande unique. Cela aura aussi
pour effet de faire tourner tout conteneur décrit dans depends_on , à moins que
l’argument --no-deps ne soit donné.
logs affiche les logs. De façon générale la sortie des logs est colorée et agrégée
pour les conteneurs gérés par Compose.
stop arrête les conteneurs sans les enlever.
[Link] 100/181
30/01/2024 23:20 Exporter tout le contenu
app = Flask(__name__)
cache = [Link](host='redis', port=6379, db=0)
salt = "UNIQUE_SALT"
default_name = 'Joe Bloggs'
name = default_name
if [Link] == 'POST':
name = [Link]['name']
@[Link]('/monster/<name>')
[Link] 101/181
30/01/2024 23:20 Exporter tout le contenu
def get_identicon(name):
image = [Link](name)
if image is None:
print ("Cache miss", flush=True)
r = [Link]('[Link] + name + '?size=80
image = [Link]
[Link](name, image)
if __name__ == '__main__':
[Link](debug=True, host='[Link]', port=9090)
uWSGI est un serveur python de production très adapté pour servir notre serveur
intégré Flask, nous allons l’utiliser.
Dockerisons maintenant cette nouvelle application avec le Dockerfile suivant :
FROM python:3.7
Observons le code du Dockerfile ensemble s’il n’est pas clair pour vous. Juste avant
de lancer l’application, nous avons changé d’utilisateur avec l’instruction USER ,
pourquoi ?.
Construire l’application, pour l’instant avec docker build , la lancer et vérifier avec
docker exec , whoami et id l’utilisateur avec lequel tourne le conteneur.
Réponse :
version: "3.7"
services:
identidock:
build: .
[Link] 102/181
30/01/2024 23:20 Exporter tout le contenu
ports:
- "9090:9090"
Plusieurs remarques :
dnmonster:
image: amouat/dnmonster:1.0
version: "3.7"
services:
identidock:
build: .
ports:
- "9090:9090"
dnmonster:
image: amouat/dnmonster:1.0
Enfin, nous déclarons aussi un réseau appelé identinet pour y mettre les deux
conteneurs de notre application.
Il faut déclarer ce réseau à la fin du fichier (notez que l’on doit spécifier le driver
réseau) :
networks:
identinet:
driver: bridge
Il faut aussi mettre nos deux services identidock et dnmonster sur le même
réseau en ajoutant deux fois ce bout de code où c’est nécessaire (attention aux
indentations !) :
[Link] 103/181
30/01/2024 23:20 Exporter tout le contenu
networks:
- identinet
redis:
image: redis
networks:
- identinet
[Link] final :
version: "3.7"
services:
identidock:
build: .
ports:
- "9090:9090"
networks:
- identinet
dnmonster:
image: amouat/dnmonster:1.0
networks:
- identinet
redis:
image: redis
networks:
- identinet
networks:
identinet:
driver: bridge
D’autres services
[Link] 104/181
30/01/2024 23:20 Exporter tout le contenu
curl -L -O [Link]
Renommons cette configuration et rectifions qui possède ce fichier pour satisfaire une
contrainte de sécurité de Filebeat :
mv [Link] [Link]
sudo chown root [Link]
version: "3"
services:
elasticsearch:
image: [Link]/elasticsearch/elasticsearch:7.5.0
environment:
- [Link]=single-node
- [Link]=false
networks:
- logging-network
filebeat:
image: [Link]/beats/filebeat:7.5.0
user: root
depends_on:
- elasticsearch
volumes:
- ./[Link]:/usr/share/filebeat/[Link]:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/[Link]:/var/run/[Link]:ro
networks:
- logging-network
environment:
- -[Link]=false
[Link] 105/181
30/01/2024 23:20 Exporter tout le contenu
kibana:
image: [Link]/kibana/kibana:7.5.0
depends_on:
- elasticsearch
ports:
- 5601:5601
networks:
- logging-network
networks:
logging-network:
driver: bridge
Il suffit ensuite de se rendre sur Kibana (port 5601 ) et de configurer l’index en tapant *
dans le champ indiqué, de valider et de sélectionner le champ @timestamp , puis de
valider. L’index nécessaire à Kibana est créé, vous pouvez vous rendre dans la partie
Discover à gauche (l’icône boussole 🧭) pour lire vos logs.
5 - Orchestration et clustering
Orchestration
Un des intérêts principaux de Docker et des conteneurs en général est de :
Les nœuds d’un cluster sont les machines (serveurs physiques, machines virtuelles, etc.)
qui font tourner vos applications (composées de conteneurs).
[Link] 106/181
30/01/2024 23:20 Exporter tout le contenu
Docker Swarm
Swarm est l'outil de clustering et d’orchestration natif de Docker (développé par
Docker Inc.).
Il s’intègre très bien avec les autres commandes docker (on a même pas l’impression
de faire du clustering).
Il permet de gérer de très grosses productions Docker.
Swarm utilise l’API standard du Docker Engine (sur le port 2376) et sa propre API de
management Swarm (sur le port 2377).
Il a perdu un peu en popularité face à Kubernetes mais c’est très relatif (voir
comparaison plus loin).
Les nœuds managers sont en fait aussi des workers et font tourner des conteneurs,
c’est leur rôles qui varient.
[Link] 107/181
30/01/2024 23:20 Exporter tout le contenu
version: "3"
services:
web:
image: username/repo
deploy:
replicas: 5
resources:
limits:
cpus: "0.1"
memory: 50M
restart_policy:
condition: on-failure
ports:
- "4000:80"
networks:
- webnet
networks:
webnet:
Sous-commandes Swarm
swarm init : Activer Swarm et devenir manager d’un cluster d’un seul nœud
swarm join : Rejoindre un cluster Swarm en tant que nœud manager ou worker
docker stack deploy : Déploie une stack (= fichier Docker compose) ou update
une stack existante
docker stack ls : Liste les stacks
docker stack ps : Liste l’état du déploiement d’une stack
Éviter la surcharge : les requêtes sont réparties sur différents backends pour
éviter de les saturer.
Haute disponibilité : on veut que notre service soit toujours disponible, même en cas
de panne (partielle) ou de maintenance.
[Link] 109/181
30/01/2024 23:20 Exporter tout le contenu
Docker Machine
C’est l’outil de gestion d’hôtes Docker
Il est capable de créer des serveurs Docker “à la volée”
[Link] 110/181
30/01/2024 23:20 Exporter tout le contenu
Exemple :
Présentation de Kubernetes
Les deployments sont une abstraction pour scaler ou mettre à jours des groupes de
pods (un peu comme les tasks dans Swarm).
Présentation de Kubernetes
Une autre solution très à la mode depuis 4 ans. Un buzz word du DevOps en France :)
Une solution robuste, structurante et open source d’orchestration Docker.
Au cœur du consortium Cloud Native Computing Foundation très influent dans
le monde de l’informatique.
[Link] 111/181
30/01/2024 23:20 Exporter tout le contenu
Swarm est beaucoup plus simple à mettre en œuvre qu’une stack Kubernetes.
Swarm serait donc mieux pour les clusters moyen et Kubernetes pour les très gros
TP 5 - Orchestration et clustering
Introduction à Swarm
Initialisez Swarm avec docker swarm init .
Créer un service
A l’aide de docker service create , créer un service à partir de l’image
traefik/whoami accessible sur le port 9999 et connecté au port 80 et avec 5
répliques.
Solution :
Accédez à votre service et actualisez plusieurs fois la page. Les informations affichées
changent. Pourquoi ?
[Link] 112/181
30/01/2024 23:20 Exporter tout le contenu
La stack example-voting-app
Cloner l’application example-voting-app ici :
[Link]
Lire le schéma d’architecture de l’app example-voting-app sur Github. A noter que
le service worker existe en deux versions utilisant un langage de programmation
différent (Java ou .NET), et que tous les services possèdent des images pour
conteneurs Windows et pour conteneurs Linux. Ces versions peuvent être déployées
de manière interchangeable et ne modifient pas le fonctionnement de l’application
multi-conteneur. C’est une démonstration de l’utilité du paradigme de la
conteneurisation et de l’architecture dite “micro-service”.
Lire attentivement les fichiers [Link] , [Link] ,
[Link] et [Link] . Ce sont tous des fichiers Docker
Compose classiques avec différentes options liées à un déploiement via Swarm.
Quelles options semblent spécifiques à Docker Swarm ? Ces options permettent de
configurer des fonctionnalités d'orchestration.
Dessiner rapidement le schéma d’architecture associé au fichier docker-compose-
[Link] , puis celui associé à [Link] en indiquant bien à quel
réseau quel service appartient.
Avec docker swarm init , transformer son installation Docker en une installation
Docker compatible avec Swarm. Lisez attentivement le message qui vous est renvoyé.
Déployer la stack du fichier [Link] : docker stack deploy --
compose-file [Link] vote
docker stack ls indique 6 services pour la stack vote . Observer également
l’output de docker stack ps vote et de docker stack services vote . Qu’est-ce
qu’un service dans la terminologie de Swarm ?
Accéder aux différents front-ends de la stack grâce aux informations contenues dans
les commandes précédentes. Sur le front-end lié au vote, actualiser plusieurs fois la
page. Que signifie la ligne Processed by container ID […] ? Pourquoi varie-t-elle
?
Scaler la stack en ajoutant des replicas du front-end lié au vote avec l’aide de docker
service --help . Accédez à ce front-end et vérifier que cela a bien fonctionné en
actualisant plusieurs fois.
Avec un service
Se grouper par 2 ou 3 pour créer un cluster à partir de vos VM respectives (il faut
utiliser une commande Swarm pour récupérer les instructions nécessaires).
Si grouper plusieurs des VM n’est pas possible, vous pouvez créer un cluster multi-
nodes très simplement avec l’interface du site Play With Docker, il faut s’y connecter
avec vos identifiants Docker Hub.
Vous pouvez faire docker swarm --help pour obtenir des infos manquantes, ou
faire docker swarm leave --force pour réinitialiser votre configuration Docker
Swarm si besoin.
[Link] 113/181
30/01/2024 23:20 Exporter tout le contenu
N’hésitez pas à regarder dans les logs avec systemctl status docker comment se
passe l’élection du nœud leader, à partir du moment où vous avez plus d’un
manager.
Lancez le service suivant : docker service create --name whoami --replicas 5 -
-publish published=80,target=80 traefik/whoami
Accédez au service depuis un node, et depuis l’autre. Actualisez plusieurs fois la page.
Les informations affichées changent. Lesquelles, et pourquoi ?
Indice 1 :
Indice 2 :
Indice 3 :
Solution / explications :
Introduction à Kubernetes
Le fichier [Link] de l’app example-voting-app décrit la même app
pour un déploiement dans Kubernetes plutôt que dans Docker Compose ou Docker
Swarm. Tentez de retrouver quelques équivalences entre Docker Compose / Swarm et
Kubernetes en lisant attentivement ce fichier qui décrit un déploiement Kubernetes.
Vous pouvez désormais faire l’exercice 2 du TP 7 pour configurer un serveur web qui
permet d’accéder à vos services Swarm via des domaines spécifiques.
Conclusion
[Link] 115/181
30/01/2024 23:20 Exporter tout le contenu
Sécurité / durcissement
un conteneur privilégié est root sur la machine !
des cgroups correct : ulimit -a
par défaut les user namespaces ne sont pas utilisés !
Limites de Docker
Stateful
[Link] 116/181
30/01/2024 23:20 Exporter tout le contenu
les conteneurs stateless c’est bien beau mais avec une base de données, ça ne se gère
pas magiquement du tout
Volumes distribués
problème des volumes partagés / répliqués
Retours
[Link] 117/181
30/01/2024 23:20 Exporter tout le contenu
Ressources
La section Quick Start de la documentation Gitlab-CI
Vous pouvez trouver des exemples de CI dans la documentation Gitlab.
La section dédiée à docker build de la documentation Gitlab
La section de la documentation dédiée au Container Registry
Avec BitBucket
BitBucket propose aussi son outil de pipeline, à la différence qu’il n’a pas de registry
intégré, le template par défaut propose donc de pousser son image sur le registry Docker
Hub.
Il suffit de créer un repo BitBucket puis d’y ajouter le template de CI Docker proposé
(le template est caché derrière un bouton See more).
[Link] 118/181
30/01/2024 23:20 Exporter tout le contenu
Ensuite, il faut ajouter des Repository variables avec ses identifiants Docker Hub.
Dans le template, ce sont les variables DOCKERHUB_USERNAME , DOCKERHUB_PASSWORD
et DOCKERHUB_NAMESPACE (identique à l’username ici).
Ressources
[Link]
bitbucket-pipelines/
Conclusion
Avec l’aide de la documentation Traefik, ajoutez une section pour le reverse proxy
Traefik pour dans un fichier Docker Compose de votre choix.
Solution :
Explorez le dashboard Traefik accessible sur le port indiqué dans le fichier Docker
Compose.
Ajouter des labels à l’app web que vous souhaitez desservir grâce à Traefik à partir de
l’exemple de la doc Traefik, grâce aux labels ajoutés dans le [Link]
(attention à l’indentation).
Solution :
Avec l’aide de la documentation Traefik sur Let’s Encrypt et Docker Compose,
configurez Traefik pour qu’il crée un certificat Let’s Encrypt pour votre container.
[Link] 119/181
30/01/2024 23:20 Exporter tout le contenu
Si vous avez une IP publique mais pas de domaine, vous pouvez utiliser le service
gratuit [[Link]] qui vous fournira un domaine en *.[Link] .
Vous aurez aussi besoin de configurer des DNS via [Link] si vous voulez
vérifier des sous-domaines (et non votre domaine principal) auprès de Let’s Encrypt
(de plus, si vous voulez un certificat avec wildcard pour tous vos sous-domaines, il
faudra résoudre le dnsChallenge de Let’s Encrypt de manière manuelle).
Solution :
Solution :
QCM Docker
Entourez la bonne réponse
Question 1
Quelle est la principale différence entre une machine virtuelle (VM) et un conteneur ?
1. Un conteneur est une boîte qui contient un logiciel Windows alors qu’une VM
fonctionne généralement sous Linux.
2. Un conteneur permet de faire des applications distribuées dans le cloud
contrairement aux machines virtuelles.
3. Un conteneur partage le noyau du système hôte alors qu’une machine virtuelle
virtualise son propre noyau indépendant.
Question 2
En quoi Docker permet de faire de l'Infrastructure as Code ?
Question 3
Quels sont les principaux atouts de Docker ?
[Link] 120/181
30/01/2024 23:20 Exporter tout le contenu
1. Il permet de rendre compatible tous les logiciels avec le cloud (AWS, etc.) et facilite
l’IoT.
2. Il utilise le langage Go qui est de plus en plus populaire et accélère les logiciels qui
l’utilise.
3. Il permet d’uniformiser les déploiements logiciels et facilite la construction
d’application distribuées.
Question 4
Pour créer un conteneur Docker à partir du code d’un logiciel il faut d’abord :
Question 5
Un volume Docker est :
Question 6
Indiquez la ou les affirmations vraies :
Question 7
Un Compose file ou fichier Compose permet :
Question 8
Indiquez la ou les affirmations vraies :
[Link] 121/181
30/01/2024 23:20 Exporter tout le contenu
Question 9
Indiquez la ou les affirmations vraies :
1. Docker est très pratique pour distribuer un logiciel mais tous les conteneurs doivent
obligatoirement être exposés à Internet.
2. Docker utilise un cloud pour distribuer facilement des logiciels dans de nombreuses
versions.
3. Docker est une catastrophe en terme de sécurité car les conteneurs sont peu isolés.
Question 10
Docker Swarm est :
Kubernetes
Module 3
Kubernetes
Administrer des applications multiconteneurs complexes
Historique et popularité
Kubernetes est un orchestrateur développé originellement par Google et basé sur une
dizaine d’années d’expérience de déploiement d’application énormes.
La première version est sortie en 2014 et K8S est devenu depuis l’un des projets open
source les plus populaires du monde.
Il s’agit d’une solution robuste, structurante et open source qui se construit autour des
objectifs de:
Rapidité
Scaling des logiciels et des équipes de développement
Abstraction et uniformisation des infrastructures
[Link] 123/181
30/01/2024 23:20 Exporter tout le contenu
Architecture de Kubernetes
Faiblesses de Kubernetes
Une difficulté à manier tout ce qui est stateful, comme des bases de données
[Link] 124/181
30/01/2024 23:20 Exporter tout le contenu
L’écosystème Kubernetes
Kubernetes n’est qu’un ensemble de standards. Il existe beaucoup de variétés (flavours)
de Kubernetes, implémentant concrètement les solutions techniques derrière tout ce que
Kubernetes ne fait que définir : solutions réseau, stockage (distribué ou non),
loadbalancing, service de reverse proxy (Ingress), autoscaling de cluster (ajout de
nouvelles VM au cluster automatiquement), monitoring…
Il est très possible de monter un cluster Kubernetes en dehors de ces fournisseurs, mais
cela demande de faire des choix (ou bien une solution opinionated ouverte comme
Rancher) et une relative maîtrise d’un nombre varié de sujets (bases de données,
solutions de loadbalancing, redondance du stockage…).
C’est là la relative hypocrisie de Kubernetes : tout est ouvert et standardisé, mais devant la
(relative) complexité et connaissance nécessaire pour mettre en place sa propre solution
(de stockage distribué par exemple), nous retombons rapidement dans la facilité et les
griffes du vendor lock-in (enfermement propriétaire).
[Link] 125/181
30/01/2024 23:20 Exporter tout le contenu
Un écosystème Kubernetes assez standard à la sauce Amazon axé sur l’intégration avec le
cloud Amazon (la gestion de l’accès, des loadbalancers ou du scaling notamment, le
stockage avec Amazon EBS, etc.)
Rancher
Un écosystème Kubernetes très complet, assez opinionated et entièrement open-source,
non lié à un fournisseur de cloud. Inclut l’installation de stack de monitoring
(Prometheus), de logging, de réseau mesh (Istio) via une interface web agréable. Rancher
maintient aussi de nombreuses solutions open source, comme par exemple Longhorn
pour le stockage distribué.
k3s
Un écosystème Kubernetes fait par l’entreprise Rancher et axé sur la légèreté. Il remplace
etcd par une base de données Postgres, utilise Traefik pour l’ingress et Klipper pour le
loadbalancing.
Openshift
Une version de Kubernetes configurée et optimisée par Red Hat pour être utilisée dans
son écosystème. Tout est intégré donc plus guidé, avec l’inconvénient d’être un peu
captif·ve de l’écosystème et des services vendus par Red Hat.
Concurrents
Apache Mesos
Mesos est une solution plus générale que Kubernetes pour exécuter des applications
distribuées. En combinant Mesos avec son “application framework” Marathon on obtient
une solution équivalente sur de nombreux points à Kubernetes.
Elle est cependant moins standard : - Moins de ressources disponibles pour apprendre,
intégrer avec d’autre solution etc. - Peu vendu en tant que service par les principaux cloud
provider. - Plus chère à mettre en oeuvre.
Parenthèse : Le YAML
Kubernetes décrit ses ressources en YAML. A quoi ça ressemble, YAML ?
- marché:
lieu: Marché de la Place
jour: jeudi
horaire:
unité: "heure"
min: 12
max: 20
[Link] 126/181
30/01/2024 23:20 Exporter tout le contenu
fruits:
- nom: pomme
couleur: "verte"
pesticide: avec
- nom: poires
couleur: jaune
pesticide: sans
légumes:
- courgettes
- salade
- potiron
Syntaxe
Alignement ! (2 espaces !!)
ALIGNEMENT !! (comme en python)
ALIGNEMENT !!! (le défaut du YAML, pas de correcteur syntaxique automatique,
c’est bête mais vous y perdrez forcément du temps !)
des listes (tirets)
des paires clé: valeur
Un peu comme du JSON, avec cette grosse différence que le JSON se fiche de
l’alignement et met des accolades et des points-virgules
les extensions Kubernetes et YAML dans VSCode vous aident à repérer des
erreurs
Noeuds Kubernetes
Les nœuds d’un cluster sont les machines (serveurs physiques, machines virtuelles, etc.)
qui exécutent vos applications et vos workflows. Le master node Kubernetes contrôle
chaque noeud; vous interagirez rarement directement avec les nœuds.
[Link] 127/181
30/01/2024 23:20 Exporter tout le contenu
Pour utiliser Kubernetes, vous utilisez les objets de l’API Kubernetes pour décrire
l’état souhaité de votre cluster: quelles applications ou autres processus que vous
souhaitez exécuter, quelles images de conteneur elles utilisent, le nombre de réplicas,
les ressources réseau et disque que vous mettez à disposition, et plus encore.
Vous définissez l’état souhaité en créant des objets à l’aide de l’API Kubernetes,
généralement via l’interface en ligne de commande, kubectl . Vous pouvez
également utiliser l’API Kubernetes directement pour interagir avec le cluster et
définir ou modifier l’état souhaité.
Une fois que vous avez défini l’état souhaité, le plan de contrôle Kubernetes (control
plane) permet de faire en sorte que l’état actuel du cluster corresponde à l’état
souhaité. Pour ce faire, Kubernetes effectue automatiquement diverses tâches, telles
que le démarrage ou le redémarrage de conteneurs, la mise à jour du nombre de
replicas d’une application donnée, etc.
kube-apiserver
kube-controller-manager
kube-scheduler
Chaque nœud non maître de votre cluster exécute deux processus : kubelet ,
qui communique avec le Kubernetes master. kube-proxy , un proxy réseau
reflétant les services réseau Kubernetes sur chaque nœud.
Les différentes parties du control plane Kubernetes, telles que les processus Kubernetes
master et kubelet, déterminent la manière dont Kubernetes communique avec votre
cluster.
[Link] 128/181
30/01/2024 23:20 Exporter tout le contenu
Par exemple, lorsque vous utilisez l’API Kubernetes pour créer un objet Deployment ,
vous fournissez un nouvel état souhaité pour le système. Le control plane
Kubernetes enregistre la création de cet objet et exécute vos instructions en lançant les
applications requises et en les planifiant vers des nœuds de cluster, afin que l’état actuel
du cluster corresponde à l’état souhaité.
Le client kubectl
Permet depuis sa machine de travail de contrôler le cluster avec une ligne de commande
qui ressemble un peu à celle de Docker (cf. TP1 et TP2):
Cet utilitaire s’installe avec un gestionnaire de paquet classique mais est souvent fourni
directement par une distribution de développement de kubernetes.
Ces informations sont fournies sous forme d’un fichier YAML appelé kubeconfig
Comme nous le verrons en TP ces informations sont généralement fournies
directement par le fournisseur d’un cluster k8s (provider ou k8s de dev)
Le même fichier kubeconfig peut stocker plusieurs configurations dans un fichier YAML
:
Exemple :
apiVersion: v1
clusters:
- cluster:
certificate-authority: /home/jacky/.minikube/[Link]
server: [Link]
name: minikube
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR
server: [Link]
name: do-lon1-k8s-tp-cluster
contexts:
- context:
cluster: minikube
[Link] 129/181
30/01/2024 23:20 Exporter tout le contenu
user: minikube
name: minikube
- context:
cluster: do-lon1-k8s-tp-cluster
user: do-lon1-k8s-tp-cluster-admin
name: do-lon1-k8s-tp-cluster
current-context: do-lon1-k8s-tp-cluster
kind: Config
preferences: {}
users:
- name: do-lon1-k8s-tp-cluster-admin
user:
token: 8b2d33e45b980c8642105ec827f41ad343e8185f6b4526a481e312822d634aa
- name: minikube
user:
client-certificate: /home/jacky/.minikube/profiles/minikube/[Link]
client-key: /home/jacky/.minikube/profiles/minikube/[Link]
Installation de développement
Pour installer un cluster de développement :
solution officielle : Minikube, tourne dans Docker par défaut (ou dans des VMs)
alternative qui possède de nombreux addons : microk8s
avec Docker Desktop depuis peu (dans une VM aussi)
un cluster léger avec k3s , de Rancher
[Link] 130/181
30/01/2024 23:20 Exporter tout le contenu
On peut également installer Kubernetes de façon encore plus manuelle soit pour déployer
une configuration vraiment spécifique ou simplement pour mieux comprendre ses
rouages et composants.
Ce type d’installation est décrite par exemple ici : Kubernetes the hard way.
Google Cloud Plateform avec Google Kubernetes Engine (GKE) : très populaire car
très flexible et l’implémentation de référence de Kubernetes.
AWS avec EKS : Kubernetes assez standard mais à la sauce Amazon pour la gestion
de l’accès, des loadbalancers ou du scaling.
DigitalOcean ou Scaleway : un peu moins de fonctions mais plus simple à
appréhender
Découverte de Kubernetes
Nous allons explorer kubectl au fur et à mesure des TPs. Cependant à noter que :
[Link] 131/181
30/01/2024 23:20 Exporter tout le contenu
La méthode d’installation importe peu. Pour installer kubectl sur Ubuntu nous ferons
simplement: sudo snap install kubectl --classic .
Installer Minikube
Minikube est la version de développement de Kubernetes (en local) la plus répendue. Elle
est maintenue par la cloud native foundation et très proche de kubernetes upstream. Elle
permet de simuler un ou plusieurs noeuds de cluster sous forme de conteneurs docker ou
de machines virtuelles.
Nous utiliserons classiquement docker comme runtime pour minikube (les noeuds k8s
seront des conteneurs simulant des serveurs). Ceci est, bien sur, une configuration de
développement. Elle se comporte cependant de façon très proche d’un véritable cluster.
Si Docker n’est pas installé, installer Docker avec la commande en une seule ligne :
curl -fsSL [Link] | sh , puis ajoutez-vous au groupe Docker
avec sudo usermod -a -G docker <votrenom> , et faites sudo reboot pour que
cela prenne effet.
Pour lancer le cluster faites simplement: minikube start (il est également possible
de préciser le nombre de coeurs de calcul, la mémoire et et d’autre paramètre pour
adapter le cluster à nos besoins.)
Bash completion
Vous pouvez désormais appuyer sur <Tab> pour compléter vos commandes
kubectl , c’est très utile !
Notre cluster k8s est plein d’objets divers, organisés entre eux de façon dynamique pour
décrire des applications, tâches de calcul, services et droits d’accès. La première étape
consiste à explorer un peu le cluster :
Listez les nodes pour récupérer le nom de l’unique node ( kubectl get nodes ) puis
affichez ses caractéristiques avec kubectl describe node/minikube .
La commande get est générique et peut être utilisée pour récupérer la liste de tous les
types de ressources.
De même, la commande describe peut s’appliquer à tout objet k8s. On doit cependant
préfixer le nom de l’objet par son type (ex : node/minikube ou nodes minikube ) car
k8s ne peut pas deviner ce que l’on cherche quand plusieurs ressources ont le même
nom.
Pour afficher tous les types de ressources à la fois que l’on utilise : kubectl get
all
Il semble qu’il n’y a qu’une ressource dans notre cluster. Il s’agit du service d’API
Kubernetes, pour qu’on puisse communiquer avec le cluster.
En réalité il y en a généralement d’autres cachés dans les autres namespaces . En effet les
éléments internes de Kubernetes tournent eux-mêmes sous forme de services et de
daemons Kubernetes. Les namespaces sont des groupes qui servent à isoler les
ressources de façon logique et en termes de droits (avec le Role-Based Access Control
(RBAC) de Kubernetes).
[Link] 133/181
30/01/2024 23:20 Exporter tout le contenu
A ce stade le déploiement n’est pas encore accessible de l’extérieur du cluster pour cela
nous devons l’exposer en tant que service :
affichons la liste des services pour voir le résultat: kubectl get services
Un service permet d’exposer un déploiement soit par port soit grâce à un loadbalancer.
Pour exposer cette application sur le port de notre choix, nous devrions avoir recours à un
LoadBalancer.
Nous ne verrons pas ça ici (il faudrait utiliser l’addon MetalLB de Minikube).
Mais nous pouvons quand même lancer une commande dans notre environnement de
dev : kubectl port-forward svc/microbot-service 8080:8080 --address [Link]
Minikube intègre aussi une façon d’accéder à notre service : c’est la commande minikube
service microbot-service
[Link] 134/181
30/01/2024 23:20 Exporter tout le contenu
Essayez d’afficher les serviceaccounts (users) et les namespaces avec une commande
courte.
Installer Lens
Lens est une interface graphique sympatique pour Kubernetes.
Sur DigitalOcean, il vous est proposé dans l’étape 3 ou sur la page de votre cluster
Kubernetes de télécharger le fichier kubeconfig . (download the cluster
configuration file, ou bien Download Config File).
De même, sur Scaleway, sur la page décrivant votre cluster, un gros bouton en bas de
la page vous incite à télécharger ce même fichier kubeconfig (Download
Kubeconfig).
clusters
contexts
users
[Link] 135/181
30/01/2024 23:20 Exporter tout le contenu
Déployer l’application
Lancez kubectl cluster-info , l’API du cluster est accessible depuis un nom de
domaine généré par le provider.
Déployez l’application microbot comme dans la partie précédente avec minikube
Pour visitez l’application vous devez trouver l’IP publique d’un des nœuds du cluster
en listant les objets de type Service , ou sur la page du fournisseur de cloud.
Haute disponibilité
Faire en sorte qu’un service ait un “uptime” élevé.
On veut que le service soit tout le temps accessible même lorsque certaines ressources
manquent :
Plusieurs serveurs
Plusieurs versions des données
Plusieurs accès réseau
Il faut que les ressources disponibles prennent automatiquement le relais des ressources
indisponibles. Pour cela on utilise généralement:
Mais aussi :
Nous allons voir que Kubernetes intègre automatiquement les principes de load balancing
et de healthcheck dans l’orchestration de conteneurs
[Link] 136/181
30/01/2024 23:20 Exporter tout le contenu
Cas d’usage :
Éviter la surcharge : les requêtes sont réparties sur différents backends pour éviter de
les saturer.
L’objectif est de permettre la haute disponibilité : on veut que notre service soit toujours
disponible, même en période de panne/maintenance.
Healthchecks
Fournir à l’application une façon d’indiquer qu’elle est disponible, c’est-à-dire :
par exemple avec des fichiers de configuration fournie via des volumes
ou via des variables d’environnement
[Link] 137/181
30/01/2024 23:20 Exporter tout le contenu
Un exemple historique de découverte de service est le DNS : on fait une requête vers un
serveur spécial pour retrouver une adresse IP (on découvre le serveur dont on a besoin).
Cependant le DNS n’a pas été pensé pour ça :
Recreate : arrêter les pods avec l’ancienne version en même temps et créer les
nouveaux simultanément
RollingUpdate : mise à jour continue, arrêt des anciens pods les uns après les
autres et création des nouveaux au fur et à mesure (paramétrable)
Mais il existe un panel de stratégies plus large pour updater ses apps :
blue/green : publier une nouvelle version à côté de l’ancienne puis changer de trafic
canary : diffuser une nouvelle version à un sous-ensemble d’utilisateurs, puis
procéder à un déploiement complet
A/B testing: diffusion d’une nouvelle version à un sous-ensemble d’utilisateurs de
manière précise (en-têtes HTTP, cookie, région, etc.).
pas possible par défaut avec Kubernetes, implique une infrastructure plus
avancée avec reverse proxy (Istio, Traefik, nginx/haproxy personnalisé, etc.).
Source : [Link]
[Link] 138/181
30/01/2024 23:20 Exporter tout le contenu
en lançant une commande kubectl run <conteneur> ... , kubectl expose ...
en décrivant un objet dans un fichier YAML ou JSON et en le passant au client
kubectl apply -f [Link]
Vous pouvez également écrire des programmes qui utilisent directement l’API Kubernetes
pour interagir avec le cluster et définir ou modifier l’état souhaité. Kubernetes est
complètement automatisable !
La commande apply
Kubernetes encourage le principe de l’infrastructure-as-code : il est recommandé d’utiliser
une description YAML et versionnée des objets et configurations Kubernetes plutôt que la
CLI.
Lorsqu’on vient d’appliquer une description on peut l’afficher dans le terminal avec
kubectl apply -f [Link] view-last-applied
Exemples
Création d’un service simple :
[Link] 139/181
30/01/2024 23:20 Exporter tout le contenu
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard
type: NodePort
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
Remarques de syntaxe :
Toutes les descriptions doivent commencer par spécifier la version d’API (minimale)
selon laquelle les objets sont censés être créés
Il faut également préciser le type d’objet avec kind
Le nom dans metadata:\n name: value est également obligatoire.
On rajoute généralement une description longue démarrant par spec:
[Link] 140/181
30/01/2024 23:20 Exporter tout le contenu
On peut sauter des lignes dans le YAML et rendre plus lisible les descriptions
On sépare les différents objets par ---
Objets de base
Les namespaces
Tous les objets Kubernetes sont rangés dans différents espaces de travail isolés appelés
namespaces .
ne voir que ce qui concerne une tâche particulière (ne réfléchir que sur une seule
chose lorsqu’on opère sur un cluster)
créer des limites de ressources (CPU, RAM, etc.) pour le namespace
définir des rôles et permissions sur le namespace qui s’appliquent à toutes les
ressources à l’intérieur.
Lorsqu’on lit ou créé des objets sans préciser le namespace, ces objets sont liés au
namespace default .
Kubernetes gère lui-même ses composants internes sous forme de pods et services.
Si vous ne trouvez pas un objet, essayez de lancer la commande kubectl avec l’option
-A ou --all-namespaces
Les Pods
Un Pod est l’unité d’exécution de base d’une application Kubernetes que vous créez ou
déployez. Un Pod représente des process en cours d’exécution dans votre Cluster.
Un Pod représente une unité de déploiement : un petit nombre de conteneurs qui sont
étroitement liés et qui partagent :
[Link] 141/181
30/01/2024 23:20 Exporter tout le contenu
Chaque Pod est destiné à exécuter une instance unique d’un workload donné. Si vous
désirez mettre à l’échelle votre workload, vous devez multiplier le nombre de Pods.
Pour plus de détail sur la philosophie des pods, vous pouvez consulter ce bon article.
Enfin, pour debugger la sortie réseau d’un programme on peut rapidement forwarder un
port depuis un pods vers l’extérieur du cluster :
Un manifeste de Pod
[Link]
apiVersion: v1
kind: Pod
metadata:
name: nom_pod
spec:
containers:
- image: tecpi/pod_image:0.1
name: nom_conteneur
ports:
- containerPort: 8080
name: http
protocol: TCP
Les ReplicaSet
Un ReplicaSet ou rs est une ressource qui permet de spécifier finement le nombre de
réplication d’un pod à un moment donné.
[Link] 142/181
30/01/2024 23:20 Exporter tout le contenu
Les Deployments
Plutôt que d’utiliser les replicasets il est recommander d’utiliser un objet de plus haut
niveau : les deployments.
De la même façon que les ReplicaSets gèrent les pods, les Deployments gèrent les
ReplicaSet.
Un déploiement sert surtout à gérer le déploiement d’une nouvelle version d’un pod.
Un deployment est un peu l’équivalent d’un service docker : il demande la création d’un
ensemble de Pods désignés par une étiquette label .
Exemple :
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
strategy:
type: Recreate
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
[Link] 143/181
30/01/2024 23:20 Exporter tout le contenu
Les Services
Dans Kubernetes, un service est un objet qui :
L’ensemble des pods ciblés par un service est déterminé par un selector .
Par exemple, considérons un backend de traitement d’image (stateless, c’est-à-dire ici sans
base de données) qui s’exécute avec 3 replicas. Ces replicas sont interchangeables et les
frontends ne se soucient pas du backend qu’ils utilisent. Bien que les pods réels qui
composent l’ensemble backend puissent changer, les clients frontends ne devraient pas
avoir besoin de le savoir, pas plus qu’ils ne doivent suivre eux-mêmes l’état de l’ensemble
des backends.
ClusterIP : expose le service sur une IP interne au cluster appelée ClusterIP. Les
autres pods peuvent alors accéder au service mais pas l’extérieur.
NodePort : expose le service depuis l’IP publique de chacun des noeuds du cluster
en ouvrant port directement sur le nœud, entre 30000 et 32767. Cela permet
d’accéder aux pods internes répliqués. Comme l’IP est stable on peut faire pointer un
DNS ou Loadbalancer classique dessus.
Il faut :
[Link] 144/181
30/01/2024 23:20 Exporter tout le contenu
le créer à la main ou suivre le reste du tutoriel qui passe par l’outil Kustomize
(attention, Kustomize ajoute un suffixe aux ressources qu’il créé)
On peut ensuite observer les différents objets créés, et optimiser le process avec un fichier
[Link] plus complet.
Entrez dans un des pods, et de l’intérieur, lisez le secret qui lui a été rendu accessible.
[Link] :
apiVersion: v1
kind: Service
metadata:
name: db
labels:
app: words-db
spec:
ports:
- port: 5432
targetPort: 5432
name: db
selector:
app: words-db
clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: db
labels:
app: words-db
spec:
selector:
matchLabels:
app: words-db
template:
metadata:
labels:
app: words-db
spec:
containers:
- name: db
image: dockersamples/k8s-wordsmith-db
ports:
- containerPort: 5432
name: db
---
apiVersion: v1
kind: Service
metadata:
name: words
[Link] 145/181
30/01/2024 23:20 Exporter tout le contenu
labels:
app: words-api
spec:
ports:
- port: 8080
targetPort: 8080
name: api
selector:
app: words-api
clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: words
labels:
app: words-api
spec:
selector:
matchLabels:
app: words-api
replicas: 5
template:
metadata:
labels:
app: words-api
spec:
containers:
- name: words
image: dockersamples/k8s-wordsmith-api
ports:
- containerPort: 8080
name: api
---
apiVersion: v1
kind: Service
metadata:
name: web
labels:
app: words-web
spec:
ports:
- port: 8081
targetPort: 80
name: web
selector:
app: words-web
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: words-web
spec:
[Link] 146/181
30/01/2024 23:20 Exporter tout le contenu
selector:
matchLabels:
app: words-web
template:
metadata:
labels:
app: words-web
spec:
containers:
- name: web
image: dockersamples/k8s-wordsmith-web
ports:
- containerPort: 80
name: words-web
ClusterIP : expose le service sur une IP interne au cluster appelée ClusterIP. Les
autres pods peuvent alors accéder au service mais pas l’extérieur.
NodePort : expose le service depuis l’IP publique de chacun des noeuds du cluster
en ouvrant port directement sur le nœud, entre 30000 et 32767. Cela permet
d’accéder aux pods internes répliqués. Comme l’IP est stable on peut faire pointer un
DNS ou Loadbalancer classique dessus.
[Link] 147/181
30/01/2024 23:20 Exporter tout le contenu
[Link] 148/181
30/01/2024 23:20 Exporter tout le contenu
ces implémentations sont souvent concrètement des DaemonSets : des pods qui
tournent dans chacun des nodes de Kubernetes
Calico, Flannel, Weave ou Cilium sont très employées et souvent proposées en option
par les fournisseurs de cloud
Cilium a la particularité d’utiliser la technologie eBPF de Linux qui permet une
sécurité et une rapidité accrue
Comparaisons :
[Link]
kubernetes/
[Link]
flannel-calico-canal-and-weave/
Par défaut, les pods ne sont pas isolés au niveau réseau : ils acceptent le trafic de
n’importe quelle source.
Les pods deviennent isolés en ayant une NetworkPolicy qui les sélectionne. Une fois
qu’une NetworkPolicy (dans un certain namespace) inclut un pod particulier, ce pod
rejettera toutes les connexions qui ne sont pas autorisées par cette NetworkPolicy.
Le loadbalancing
Le loadbalancing permet de balancer le trafic à travers plusieurs nodes Kubernetes.
[Link] 149/181
30/01/2024 23:20 Exporter tout le contenu
Un Ingress est un objet pour gérer le reverse proxy dans Kubernetes : il a besoin d’un
ingress controller installé sur le cluster, qui agit donc au niveau du protocole HTTP et
écoute sur un port ( 80 ou 443 généralement), pour pouvoir rediriger vers différents
services (qui à leur tour redirigent vers différents ports sur les pods) selon l’URL.
Un ingress basé sur Nginx plus ou moins officiel à Kubernetes et très utilisé
Traefik est optimisé pour k8s
il en existe d’autres : celui de l’entreprise Nginx, Istio, Contour, HAProxy….
Comparaison : [Link]
kubernetes-9b397483b46b
Il faut y penser comme des super-ingresses : des proxy qui font beaucoup plus que
du reverse proxy
Vidéos
Des vidéos assez complètes sur le réseau, faites par Calico :
Nous voudrions déployer notre stack monster_app . Nous allons commencer par créer
un pod avec seulement notre conteneur monstericon .
[Link]
apiVersion: apps/v1
kind: Deployment
metadata:
name: monstericon
[Link] 151/181
30/01/2024 23:20 Exporter tout le contenu
labels:
<labels>
spec:
template:
spec:
Remplissons la section spec de notre pod monstericon à partir d’un modèle de pod
lançant un conteneur Nginx :
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
metadata:
labels:
app: monsterstack
partie: monstericon
A ce stade nous avons décrit les pods de notre déploiement avec leurs labels (un label
commun à tous les objets de l’app, un label plus spécifique à la sous-partie de l’app).
[Link] 152/181
30/01/2024 23:20 Exporter tout le contenu
selector:
matchLabels:
app: monsterstack
partie: monstericon
strategy:
type: Recreate
Cette section indique les labels à utiliser pour repérer les pods de ce déploiement parmi
les autres.
Puis est précisée la stratégie de mise à jour (rollout) des pods pour le déploiement :
Recreate désigne la stratégie la plus brutale de suppression complète des pods puis de
redéploiement.
apiVersion: apps/v1
kind: Deployment
metadata:
name: monstericon
labels:
app: monsterstack
spec:
template:
spec:
containers:
- name: monstericon
image: tecpi/monster_icon:0.1
ports:
- containerPort: 9090
metadata:
labels:
app: monsterstack
partie: monstericon
selector:
matchLabels:
app: monsterstack
partie: monstericon
strategy:
type: Recreate
replicas: 3
Listez également les pods en lançant kubectl get pods --watch pour vérifier que
les conteneurs tournent.
[Link] 153/181
30/01/2024 23:20 Exporter tout le contenu
readinessProbe:
failureThreshold: 5 # Reessayer 5 fois
httpGet:
path: /
port: 9090
scheme: HTTP
initialDelaySeconds: 30 # Attendre 30s avant de tester
periodSeconds: 10 # Attendre 10s entre chaque essai
timeoutSeconds: 5 # Attendre 5s la reponse
Ainsi, k8s sera capable de savoir si le conteneur fonctionne bien en appelant la route / .
C’est une bonne pratique pour que Kubernetes sache quand redémarrer un pod.
resources:
requests:
cpu: "100m"
memory: "50Mi"
Nos pods auront alors la garantie de disposer d’un dixième de CPU et de 50 mégaoctets
de RAM.
[Link] final :
apiVersion: apps/v1
kind: Deployment
metadata:
name: monstericon
labels:
app: monsterstack
spec:
template:
spec:
containers:
- name: monstericon
image: tecpi/monster_icon:0.1
ports:
[Link] 154/181
30/01/2024 23:20 Exporter tout le contenu
- containerPort: 9090
readinessProbe:
failureThreshold: 5 # Reessayer 5 fois
httpGet:
path: /
port: 9090
scheme: HTTP
initialDelaySeconds: 30 # Attendre 30s avant de tester
periodSeconds: 10 # Attendre 10s entre chaque essai
timeoutSeconds: 5 # Attendre 5s la reponse
resources:
requests:
cpu: "100m"
memory: "50Mi"
metadata:
labels:
app: monsterstack
partie: monstericon
selector:
matchLabels:
app: monsterstack
partie: monstericon
strategy:
type: Recreate
replicas: 5
[Link] :
apiVersion: apps/v1
kind: Deployment
metadata:
name: dnmonster
labels:
app: monsterstack
spec:
selector:
matchLabels:
app: monsterstack
partie: dnmonster
strategy:
type: Recreate
replicas: 5
template:
metadata:
labels:
app: monsterstack
partie: dnmonster
spec:
[Link] 155/181
30/01/2024 23:20 Exporter tout le contenu
containers:
- image: amouat/dnmonster:1.0
name: dnmonster
ports:
- containerPort: 8080
[Link] :
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
labels:
app: monsterstack
spec:
selector:
matchLabels:
app: monsterstack
partie: redis
strategy:
type: Recreate
replicas: 1
template:
metadata:
labels:
app: monsterstack
partie: redis
spec:
containers:
- image: redis:latest
name: redis
ports:
- containerPort: 6379
apiVersion: v1
kind: Service
metadata:
name: <nom_service>
labels:
app: monsterstack
spec:
ports:
- port: <port>
selector:
[Link] 156/181
30/01/2024 23:20 Exporter tout le contenu
app: <app_selector>
partie: <tier_selector>
type: <type>
---
Ajoutez le code suivant au début de chaque fichier déploiement. Complétez pour chaque
partie de notre application : - le nom du service et le nom de la partie par le nom de
notre programme ( monstericon , dnmonster et redis ) - le port par le port du service
- les selectors app et partie par ceux du ReplicaSet correspondant.
Le type sera : ClusterIP pour dnmonster et redis , car ce sont des services qui n’ont
à être accédés qu’en interne, et LoadBalancer pour monstericon .
[Link]
[Link]
[Link]
Créez également un fichier [Link] avec à l’intérieur:
resources:
- [Link]
- [Link]
- [Link]
[Link] 157/181
30/01/2024 23:20 Exporter tout le contenu
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: monster-ingress
annotations:
[Link]/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /monstericon
backend:
serviceName: monstericon
servicePort: 9090
Solution
Le dépôt Git des solutions est accessible ici : [Link]
Formation/tp2_k8s_monsterstack_correction
Rappels Docker
Les Dockerfiles
Cours
TP
PersistentVolumeClaims et PersistentVolumes
Quand un conteneur a besoin d’un volume, il crée une PersistentVolumeClaim : une
demande de volume (persistant). Si un des objets StorageClass est en capacité de le
fournir, alors un PersistentVolume est créé et lié à ce conteneur : il devient disponible en
tant que volume monté dans le conteneur.
StatefulSets
On utilise les Statefulsets pour répliquer un ensemble de pods dont l’état est
important : par exemple, des pods dont le rôle est d’être une base de données, manipulant
des données sur un disque.
Les StatefulSets utilisent un nom en commun suivi de numéros qui se suivent. Par
exemple, un StatefulSet nommé web comporte des pods nommés web-0 , web-1 et
web-2 . Par défaut, les pods StatefulSet sont déployés dans l’ordre et arrêtés dans l’ordre
inverse ( web-2 , web-1 puis web-0 ).
DaemonSets
[Link] 159/181
30/01/2024 23:20 Exporter tout le contenu
Une autre raison de répliquer un ensemble de Pods est de programmer un seul Pod sur
chaque nœud du cluster. En général, la motivation pour répliquer un Pod sur chaque
nœud est de faire atterrir une sorte d’agent ou de démon sur chaque nœud, et l’objet
Kubernetes pour y parvenir est le DaemonSet. Par exemple pour des besoins de
monitoring, ou pour configurer le réseau sur chacun des nœuds.
lorsque l’ordre de création des replicas et le nom des pods est important
lorsqu’on fait des opérations stateful (écrire dans une base de données)
Jobs
Les jobs sont utiles pour les choses que vous ne voulez faire qu’une seule fois, comme les
migrations de bases de données ou les travaux par lots. Si vous exécutez une migration en
tant que Pod normal, votre tâche de migration de base de données se déroulera en
boucle, en repeuplant continuellement la base de données.
CronJobs
Comme des jobs, mais se lance à un intervalle régulier, comme avec cron .
Les ConfigMaps
D’après les recommandations de développement 12factor, la configuration de nos
programmes doit venir de l’environnement. L’environnement est ici Kubernetes.
Les objets ConfigMaps permettent d’injecter dans des pods des fichiers de configuration
en tant que volumes.
les Secrets
Les Secrets se manipulent comme des objets ConfigMaps, mais sont faits pour stocker
des mots de passe, des clés privées, des certificats, des tokens, ou tout autre élément de
[Link] 160/181
30/01/2024 23:20 Exporter tout le contenu
config dont la confidentialité doit être préservée. Un secret se créé avec l’API Kubernetes,
puis c’est au pod de demander à y avoir accès.
le secret est un fichier que l’on monte en tant que volume dans un conteneur (pas
nécessairement disponible à l’ensemble du pod). Il est possible de ne jamais écrire ce
secret sur le disque (volume tmpfs ).
le secret est une variable d’environnement du conteneur.
cas spécifique aux registres : le secret est récupéré par kubelet quand il pull une
image.
Pour définir qui et quelle app a accès à quel secret, on utilise les fonctionnalités dites
“RBAC” de Kubernetes.
A côté des rôles crées pour les utilisateur·ices et processus du cluster, il existe des modèles
de rôles prédéfinis qui sont affichables avec :
La commande kubectl auth can-i permet de déterminer selon le profil utilisé (défini
dans votre kubeconfig ) les permissions actuelles de l’user sur les objets Kubernetes.
[Link] 161/181
30/01/2024 23:20 Exporter tout le contenu
Kubernetes. Combinés à des Operators (du code d’API en Go), ils permettent d’étendre
Kubernetes pour gérer de nouveaux objets qui eux-même interagissent avec des objets
Kubernetes.
Exemples :
la chart officielle de la suite Elastic (ELK) définit des objets de type elasticsearch
KubeVirt permet de rajouter des objets de type VM pour les piloter depuis
Kubernetes
Azure propose des objets correspondant à ses ressources du cloud Azure, pour
pouvoir créer et paramétrer des ressources Azure directement via la logique de
Kubernetes
Exemple:
k8s-mysql/
├── [Link]
├── [Link]
└── [Link]
[Link]
[Link] 162/181
30/01/2024 23:20 Exporter tout le contenu
secretGenerator:
- name: mysql-pass
literals:
- password=YOUR_PASSWORD
resources:
- [Link]
- [Link]
Helm
Quand on a une seule application cela reste gérable avec des kustomizations ou sans,
mais dès qu’on a plusieurs environnements, applications et services, on se retrouve vite
submergé·es de fichiers de centaines, voire de milliers, de lignes qui sont, de plus, assez
semblables. C’est donc “trop” déclaratif, et il faut se concentrer sur les quelques propriétés
que l’on souhaite créer ou modifier,
Pour pallier ce problème, il existe l’utilitaire Helm, qui produit les fichiers de déploiement
que l’on souhaite.
Helm est le package manager recommandé par Kubernetes, il utilise les fonctionnalités de
templating du langage Go.
la possibilité de mettre les Charts dans un répertoire distant (Git, disque local ou
partagé…), et donc de distribuer ces Charts publiquement.
un système facilitant les Updates et Rollbacks de vos applications.
Il existe des sortes de stores d’applications Kubernetes packagées avec Helm, le plus gros
d’entre eux est Kubeapps Hub, maintenu par l’entreprise Bitnami qui fournit de
nombreuses Charts assez robustes.
Si vous connaissez Ansible, un chart Helm est un peu l’équivalent d’un rôle Ansible dans
l’écosystème Kubernetes.
Concepts
Les quelques concepts centraux de Helm :
[Link] 163/181
30/01/2024 23:20 Exporter tout le contenu
Pour fonctionner sur le cluster, Helm a besoin d’installer un gestionnaire appelé Tiller :
c’est le serveur qui communique avec le client Helm et l’API de Kubernetes pour gérer vos
déploiements.
On constate que Helm rassemble des fichiers de descriptions d’objets k8s avec des
variables (moteur de templates de Go) à l’intérieur, ce qui permet de factoriser le code et
de gérer puissamment la différence entre les versions.
[Link] 164/181
30/01/2024 23:20 Exporter tout le contenu
Installer Helm
Pour installer Helm sur Ubuntu, utilisez : snap install helm --classic
Suivez le Quickstart : [Link]
Notre Wordpress est prêt. Connectez-vous-y avec les identifiants affichés (il faut
passer les commandes indiquées pour récupérer le mot de passe stocké dans un
secret k8sen).
Explorez les différents objets k8s créés par Helm avec Lens.
TP 5 - Cloud Azure
Nous allons déployer une application dans Azure à l’aide de charts Helm :
[Link]
# Login
az login --allow-no-subscriptions
[Link] 165/181
30/01/2024 23:20 Exporter tout le contenu
# Créer le groupe de ressources
az group create --name aks-resource-group --location westeurope
# Créer le registry
az acr create --resource-group aks-resource-group --name pommedeterrepoire
az acr login --name pommedeterrepoirekiwi
[Link] 166/181
30/01/2024 23:20 Exporter tout le contenu
# Ajout de la chart
helm repo add bitnami [Link]
# Installer la chart
helm install wordpress bitnami/wordpress \
--set serviceType=LoadBalancer \
--set [Link]="[Link]" \
--set [Link]={read-registry-account} \
--set [Link]=bitnami/wordpress \
--set [Link]=latest
Des messages s’affichent suite à l’application de la chart Helm, suivez les instructions pour
accéder au Wordpress.
Documentation
[Link]
[Link]
azurerm/tree/master/examples/kubernetes
[Link]
cluster/azurerm/latest
[Link]
controller
[Link] 167/181
30/01/2024 23:20 Exporter tout le contenu
[Link] 168/181
30/01/2024 23:20 Exporter tout le contenu
Minikube
[Link]
Azure AKS
[Link]
DNS
Pour les DNS, 3 solutions :
TP opt. - Le RBAC
Les rôles et le RBAC
1. Configurer Minikube pour activer RBAC.
Ressources
[Link]
4deed658ea7b
[Link]
Conclusion
Points forts de Kubernetes
Open source et très actif.
Une communauté très visible et présente dans l’évolution de l’informatique.
Un standard collectif qui permet une certaine interopérabilité dans le cloud.
Les pods tendent à se rapprocher plus d’une VM du point de vue de l’application.
Hébergeable de façon quasi-identique dans le cloud, on-premise ou en mixte.
Kubernetes a un flat network ce qui permet de faire des choses puissante facilement
comme le multi-datacenter.
K8s est pensé pour la scalabilité et le calcul distribué.
Faiblesses de Kubernetes
Une difficulté à manier tout ce qui est stateful, comme des bases de données
[Link] 170/181
30/01/2024 23:20 Exporter tout le contenu
Pour approfondir
Monitoring et logging
Avec Prometheus et la suite Elastic.
Déploiement continu
Exemple de workflow de déploiement continu (CD)
par exemple avec Gitlab (possiblement auto-hébergé dans K8s)
se connecter à un bastion
git pull
puis kubectl apply
Prometheus est un serveur de métriques c’est à dire qu’il enregistre des informations
précises (de petite taille) sur différents aspects d’un système informatique et ce de façon
périodique en effectuant généralement des requêtes vers les composants du système
(metrics scraping).
[Link] 171/181
30/01/2024 23:20 Exporter tout le contenu
helm install \
--namespace=monitoring \
--version=13.2.1 \
--set=[Link]=NodePort \
prometheus \
prometheus-community/prometheus
Une fois le chart installé vous pouvez visualisez les informations dans Lens, dans la
premiere section du menu de gauche Cluster .
Nous allons d’abord construire l’image docker de l’application à partir des sources. Cette
image doit être stockée dans le registry de minikube pour pouvoir être ensuite déployée
dans le cluster. En mode développement Minikube s’interface de façon très fluide avec la
[Link] 172/181
30/01/2024 23:20 Exporter tout le contenu
Changez le contexte de docker cli pour pointer vers minikube avec eval et la
commande précédente.
réponse:
réponse:
réponse:
réponse:
Faites un forwarding de port Minikube pour accéder au service goprom dans votre
navigateur.
réponse:
réponse:
réponse:
[Link] 173/181
30/01/2024 23:20 Exporter tout le contenu
Maintenant Grafana est installé vous pouvez y acccéder en forwardant le port du service
grace à Minikube:
Il faut ensuite connecter Grafana à Prometheus, pour ce faire ajoutez une DataSource :
Name: prometheus
Type: Prometheus
Url: [Link]
Access: Server
Créer une dashboard avec un Graphe. Utilisez la requête prometheus (champ query
suivante):
[Link] 174/181
30/01/2024 23:20 Exporter tout le contenu
sum(rate(http_requests_total{app="goprom"}[5m])) by (version)
Lisez l’article.
Vous pouvez testez les différentes stratégies de déploiement en lisant leur
[Link] .
Dans un second terminal (pendant que les requêtes tournent) appliquer le fichier
[Link] correspondant.
[Link] 175/181
30/01/2024 23:20 Exporter tout le contenu
Contenu intégral
Contenu intégral
Tutoriels utiles
Vous trouverez ici quelques tutoriels qui peuvent être utiles dans le cadre des formations.
[Link] 176/181
30/01/2024 23:20 Exporter tout le contenu
Bibliographie
Linux
Shotts 2012 - The Linux Command Line - A complete introduction
Yao 2014 - Linux command line - A beginner’s guide
Ressources
OpenClassrooms - Reprenez le contrôle à l’aide de Linux !
[Link]
Ansible
Jeff Geerling - Ansible for DevOps - Leanpub
[Link] 177/181
30/01/2024 23:20 Exporter tout le contenu
Cheatsheet
[Link]
guide
Docker
McKendrick, Gallagher 2017 Mastering Docker - Second Edition
Cheatsheet
[Link]
Ressources
Doc officielle : [Link]
Référence officielle : [Link]
Awesome Docker, liste de ressources sur Docker :
[Link]
Portainer, GUI pour Docker : [Link]
Lazy Docker, terminal pour Docker : [Link]
Convoy, driver pour volumes Docker : [Link]
Accéder à ses containers dans Minecraft : [Link]
Doc officielle sur la sécurité dans Docker : [Link]
Documentation sur le système de filesystem overlay de Docker :
[Link]
Tutoriels officiels sur la sécurité dans Docker :
[Link]
Vidéo sur les bonnes pratiques dans Docker : [Link]
Vidéo “Containers, VMs… Comment ces technologies fonctionnent et comment les
différencier ?” (Quentin Adam) [Link]
Diapositives sur Docker, Swarm, Kubernetes : [Link]
Kubernetes
Kubernetes Up and Running, O’Reilly 2019
Ressources
[Link] 178/181
30/01/2024 23:20 Exporter tout le contenu
Awesome Kubernetes
Réseau
Documentation officielle : [Link]
networking/service/
An introduction to service meshes - DigitalOcean
Kubernetes NodePort vs LoadBalancer vs Ingress? When should I use what?
Determine best networking option - Project Calico
Doc officielle sur les solutions de networking
Comparatif de solutions réseaux (fr) : [Link]
[Link]/fr/blog/2018/07/05/comparatif-solutions-reseaux-kubernetes/#Flannel
Comparatif de solutions réseaux (en) :[Link]
comparing-kubernetes-cni-providers-flannel-calico-canal-and-weave/
Stockage
Rook et Ceph (fr)
Longhorn
Sécurité de Kubernetes
[xmco-actusecu-51-dossier_kubernetes (fr)]([Link] -
Système/FR - xmco-actusecu-51-dossier_kubernetes.pdf)
[hacking_and_hardening_kubernetes_by_example_v2 (en)]([Link]
[Link]/Exploitation - Système/EN -
hacking_and_hardening_kubernetes_by_example_v2.pdf)
[ht-w02_hacking_and_hardening_kubernetes (en)]([Link]
[Link]/Exploitation - Système/EN - ht-w02_hacking_and_hardening_kubernetes.pdf)
Autres
Bitnami Helm : [Link]
BKPR : [Link]
Vitess : A database clustering system for horizontal scaling of MySQL : [Link]
Rancher
Charts Helm : [Link]
[Link] 179/181
30/01/2024 23:20 Exporter tout le contenu
Azure AKS
Documentation
[Link]
[Link]
[Link]
[Link]
[Link]
cli
Terraform est un outil permettant de décrire des ressources cloud dans un fichier pour utiliser le
concept d’infrastructure-as-code avec tous les objets des fournisseurs de Cloud.
[Link]
[Link]
azurerm/tree/master/examples/kubernetes
[Link]
[Link]
Autres
Les CRD : utiliser des objets Kubernetes pour définir des ressources Azure :
[Link]
Demo : [Link]
Cheatsheets
[Link]
Short names in k8s : [Link]
c8eff9fb7202
DevOps
Krief - Learning DevOps - The complete guide (Azure Devops, Jenkins, Kubernetes,
Terraform, Ansible, sécurité) - 2019
The DevOps Handbook
[Link] 181/181