# Le guide ultime de Kubernetes à ViaRézo L'objectif est de déployer un site complexe par petits groupes de 2 ou 3 et d'en apprendre un maximum sur comment on fait du Kubernetes à ViaRézo. ## 0. Installer le nécessaire Il va falloir mettre en place quelque utilitaires de base pour pouvoir réaliser cette formation: - [`docker`](https://docs.docker.com/get-docker/) - [`kubectl`](https://kubernetes.io/docs/tasks/tools/#kubectl) - [`helm`](https://helm.sh/docs/intro/install/) Pour configurer l'accès au cluster de test de ViaRézo, il faut que tu ailles récupérer un fichier sur le cluster de test de ViaRézo: ```bash ssh 138.195.139.40 "sudo cp ~root/.kube/config ." scp 138.195.139.40:config ~/.kube/config ``` Vérifie que tous marche bien avec. ```bash kubectl get nodes ``` Un petit conseil pour les utilisateurs de OhMyZsh: n'hésitez pas à activer les plugins associées à ces applications. ```bash omz plugin enable docker omz plugin enable kubectl omz plugin enable helm ``` Ça permet de faire de l'auto-complétion et pour les plus aventureux il y a des alias sympa. Un petit conseil pour ceux qui n'utilisent pas OhMyZsh: **installer ohmyzsh**. ### Vérifie que tout marche bien avant de continuer - [ ] Je peux lancer un `kubectl get nodes` - [ ] Je peux lancer un `helm version` - [ ] Je peux lancer un conteneur `docker run hello-world` ## 1. Créer un namespace pour le groupe Un namespace, c'est une façon d'isoler des resources entre elles. On va donc créer un namespace pour le groupe, c'est dans ce namespace que vous allez travailler. Pour un seul des membres du groupe uniquement: ```bash kubectl create namespace <le nom de mon équipe géniale> ``` On définit ensuite ce namespace comme namespace par défaut (Pour tous les membres du groupe): ```bash kubectl config set-context --current --namespace <le nom de mon équipe géniale> ``` Cela veut dire que si vous ne spécifiez pas explicitement de namespace lorsque vous créez des ressources, elles seront créées dans ce namespace. ## 2. Il est temps de construire l'application elle-même Et cette application c'est VRoum. Pour cette première partie, l'objectif est de construire les images qui vont faire tourner notre site, il y a deux images à vous répartir (ou à faire ensemble séquentiellement). Pour un petit pense-bête sur Docker, n'hésite pas à lire [cette petite fiche](./Docker.md) ### Le Front #### Créer l'image Le code source du front est dans le dossier front. Ton objectif est de créer un Dockerfile et de faire tourner le front de VRoum en local. Le front est fait en React: vous deverez donc faire un **multi-stage** build: - Stage 0: build l'application React (Attention le .env doit être rempli pour cette étape) - Stage 1: Servir le site avec une image Nginx. #### Tester l'image Test ton image Docker: ```bash docker run -p 8080:80 vroum-front ``` Vérifie ensuite dans ton navigateur que tu peux bien voir le front de Vroum #### Challenge supplémentaire (Facultatif) Il est souvent considéré comme une mauvaise pratique d'avoir des conteneurs qui tournent avec l'utilisateur **root** en production. Vérifie que ce n'est pas le cas ou alors fait les changements nécéssaires. ### Le Back #### Créer l'image Le code source du back est dans le dossier back. Ton objectif est de créer un Dockerfile et de construire une image avec pour enfin le faire tourner en local. Le back est fait en Django: je te souhaite bon courage. #### Tester l'image Pour tester que le back fonctionne bien il va falloir d'abord mettre en place une base de donnée mysql, pour que le back s'y connecte. ``` docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=password -d mysql ``` Puis faire tourner le back: ``` docker run -p 8000:8000 --env-file .env vroum-back ``` Attention à bien remplir le .env avec les bonnes valeur pour se connecter à la BDD. Faire des curl pour tester que tout marche à peu près bien. #### Challenge supplémentaire (Facultatif et plus dur que pour le front) Il est souvent considéré comme une mauvaise pratique d'avoir des conteneurs qui tournent avec l'utilisateur **root** en production. Vérifie que ce n'est pas le cas ou alors fait les changements nécéssaires. #### Challenge supplémentaire (Facultatif et un peu dur ne pas hésiter à passer) On préfère souvent utiliser une image alpine à une image debian en production, car celle-ci sont beaucoup plus légère. Néanmoins la gestion des dépendences, est souvent plus difficile. Utilise une image alpine (python:3.8-alpine) comme base pour ton image. Ne cherchez pas de solution j'ai eu la flemme d'en faire une. ## Déployer l'application sur kubernetes Kubernetes c'est un orchestrateur de conteneur. Ca permet de gérer pleins de conteneurs et de faire des trucs inteligents avec comme créer des réplicat et de recréer dynamiquement les conteneurs qui crashent. Kubernetes fonctionne sur un mode de déclaration des ressources. On écrit ce qu'on veux dans des fichiers yaml et il suffit de lancer la commande ``` kubectl apply -f <myfile.yaml> ``` Pour deployer sur le cluster l'objet décrit. Une fois l'objet déployé on peux obtenir la liste de ces objets avec la commande: ``` kubectl get <objet> ``` On peux aussi obtenir des détails sur l'objet: ``` kubectl describe <objet> <nom de l'objet> ``` ### Pousser les images sur le registry La première étape du déploiement sur kubernetes va être de pousser les images sur le registry afin que le cluster kube puisse les récupérer. Le registry c'est un serveur qui stocke les images docker. Pour cela il faut d'abord renomer nos images docker afin d'indiquer a docker ou les pousser. La forme du tag du docker doit être : ``` registry/project/nom_de_l'image:version ``` Dans notre cas on souhaite pousser sur le registry de viarezo (registry.viarezo.fr) dans le projet "formation-kube". Il suffit ensuite de pousser l'image avec ``` docker push ``` Note: Dans notre cas le projet formation-kube est en public est donc accessible à tous. Si ça n'est pas le cas il peut etre nécessaire de faire un ```bash docker login ``` pour s'identifier auprès du registry. ### Déploiement ### L'unité de base de kubernetes c'est le pod. Un pod correspond à une ou plusieurs conteneurs gérés comme un tout. Il est possible de créer un pod directement mais en pratique personne le fait. Habituellement on créer les pods au travers de déploiement. Le déploiement est un objet qui permet de créer un pod et gère ses réplications. Il s'assure qu'il y ait toujours le bon nombre de réplicat disponible sur le cluster en récréant/supprimant des pods si besoin. Le déploiement de base se décrit grace au template suivant (N'hésitez pas a installer l'extension kubernetes de vscode qui écrit les templates toute seule): ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp image: <Image> resources: limits: memory: "128Mi" cpu: "500m" ports: - containerPort: <Port> ``` Ecrivez donc un déploiement pour le back et un pour le front. Vérifiez ensuite que vos pods sont bien marqués en ready. ``` kubectl port-forward <nom_du_pod> <port_du_pod>:<port_où_exposer> ``` ### Service Un service est une entitée qui permet aux pods de communiquer entre eux au sein du cluster. Il s'occupe aussi du load balancing entre les réplicats des pods. Le template d'un service est le suivant : ``` yaml apiVersion: v1 kind: Service metadata: name: myapp spec: selector: app: myapp ports: - port: <Port> targetPort: <Target Port> ``` ### Exposer un service vers l'exterieur Avec notre service nous avons exposés notre app au sein du cluster. Maintenant nous allons l'exposer vers le moooooooonde. Pour cela nous alons mettre en place des ingress. Un ingress est un proxy qui en fonction du nom de domaine de la requête redirige vers le service adapté. Ici, à Viarezo, nous utilisons des IngressRoutes gérés par traefik. Traefik est un logiciel qui s'occupe de gérer toutes les routes décrites dans des ingress et ingressroutes (c'est sensiblement la même chose). Pour les noms de domaine, il faut créer une entrée A sur le DNS qui redirige vers traefik. Cette partie a déja été fait pour vous, prenez juste un nom de domaine en ``.kube.test.viarezo.fr`` ```yaml apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: <nom> spec: entryPoints: - websecure routes: - kind: Rule match: Host(`<nom de domaine>`) priority: 30 services: - kind: Service name: <nom du service> port: <port> tls: secretName: <secrte du certificat> ``` Afin d'avoir du https il faut créer un certificat: ```yaml apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: <nom du certificat> spec: secretName: <nom du secret du certificat> dnsNames: - <nom de domaine> issuerRef: name: letsencrypt kind: ClusterIssuer ``` Ce certificat va être autaumatiquement être signé par Letsencrypt grace à certmanager un utilitaire installé sur les clusters. A l'issue de cette étape vous devriez pouvoir acccéder à votre application en HTTPS sur votre nom de domaine !! Si c'est le cas bravo ! Sinon vous pouvez vérifier que votre ingress apparaaisse bien sur ``https://traefik.test.viarezo.fr`` A ce point de la formation vous devez avoir les fichiers suivants. ``` deploiement_front.yaml deploiement_back.yaml service_front.yaml service_back.yaml ingress_front.yaml ingress_back.yaml ``` Afin d'éviter de flood la cluster pensez à supprimer vots ressources afin de passer à la suite. Vous pouvez le faire avec la commande suivante. ## Helm le apt de kubernetes C'est bien sympatique tout ça mais c'est loooong. Heureusement helm est la. Helm permet de templatiser les fichiers kubernetes. Une application Helm s'appelle une chart. Une chart s'organise comme suis: ``` VROUM │ Chart.yaml │ values.yaml │ └───templates │ deploiment_front.yaml │ deploiment_backt.yaml | service_front.yaml | service_back.yaml | ingress_front.yaml | ingress_back.yaml ``` Le fichier Chart.yml décrit l'application. Il permet aussi d'inclure d'autre charts en dépendance de la notre. Il s'écrit sous la forme : ``` apiVersion: v2 name: <nom> description: <description> type: application version: 0.1.1 appVersion: "<version>" ``` Le values.yaml permet de passer en argument des paramètres aux templates. On va remplacer dans les fichiers créés précedement les valeurs par de la templatisation de la forme: ``` {{.Values.front.deploiement.name}} ``` Cette chaine de caractère va être remplacé par la valeur donnée dans le value.yaml : ```yaml front: deployment: name: coucou ```