Skip to content
Snippets Groups Projects
Commit 3c45f0e0 authored by Florentin Labelle's avatar Florentin Labelle
Browse files

Add solutions and rewrite a bit of everything

parent 561ce7c4
Branches
No related tags found
No related merge requests found
Showing
with 406 additions and 54 deletions
......@@ -108,7 +108,6 @@ Pour tester le back, tu peux ausi utiliser le front en lançant les deux contene
#### 2.2.3 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.
Ne cherchez pas de solution j'ai eu la flemme d'en faire une.
#### 2.2.4 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.
......@@ -137,9 +136,9 @@ kubectl describe <objet> <nom de l'objet>
Dans un premier temps, pour créer la BDD, on va faire tourner un simple pod _mysql_. Cette solution est loin d'être optimal mais va nous permettre de se familiariser avec **kubectl**.
Pour créer un pod c'est pas très compliqué:
Pour créer un pod _mysql_ c'est pas très compliqué, mais il y a pas mal de variables d'environnement à remplir:
```bash
kubectl run mysql --image=mysql --port 3306 --env "MYSQL_USER=username" --env "MYSQL_PASSWORD=password" --env "MYSQL_DATABASE=vroum" --env "MYSQL_RANDOM_ROOT_PASSWORD=yes"
kubectl run mysql --image=mysql --port 3306 --env "MYSQL_USER=vroum" --env "MYSQL_PASSWORD=password" --env "MYSQL_DATABASE=vroum" --env "MYSQL_RANDOM_ROOT_PASSWORD=yes"
```
Vérifie que ton pod tourne comme il faut avec:
......@@ -155,7 +154,7 @@ kubectl exec -it mysql -- bash
Vérifie que tu peux te connecter à la base de donnée:
```bash
mysql --protocol=tcp -u username --database vroum -p
mysql -u username --database vroum -p
```
Regarde les logs de ton pod pour voir comment il se porte:
......@@ -167,8 +166,7 @@ Récupère un peu plus d'information pour ton pod
```bash
kubectl get pod mysql -o wide
```
Attention, note bien l'addresse ip du pod dans un coin de ta tête, tu en aura besoin plus tard.
Tu peux notamment voir l'addresse du pod au sein du cluster, tu en auras besoin pour configure ton back.
### 3.2 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 :
......@@ -202,8 +200,8 @@ Maintenant les choses sérieuses commencent, on commence à faire du Kubernetes
### 3.3 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 ploiement. Le 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.
L'unité de base de kubernetes c'est le **pod**. Un **pod** correspond à un ou plusieurs conteneurs gérés ensemble.
Il est possible de créer un pod directement (comme on l'a vu précédemment) mais en pratique c'est rarement fait. Habituellement on créé les pods au travers de **deployment**. Le **deployment** est une resource qui permet de créer un ou plusieurs **pods** et de gérer leur cycle de vie. 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):
......@@ -246,8 +244,8 @@ patek: annulé
```
Attention pour le back, il est nécéssaire de passer au conteneur des [variables d'environnement](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) !
Tu peux retrouver les client ID et client secret sur l'auth, tandis que les variables de la base de données sont à récupérer à l'étape n-2.
Pour l'instant ne vous embêtez pas avec les secrets.
Tu peux retrouver les client ID et client secret sur l'auth (J'ai créé un client dédié `VRoum Formation Kubernetes`), tandis que les variables de la base de données sont à récupérer à l'étape n-2.
Tu peux alors tester que ton front marche bien avec
......@@ -272,16 +270,17 @@ spec:
targetPort: <Target Port>
```
Le **selector** est particulièrement important, les labels qui sont dedans doivent correspondre aux labels des pods qui correspondent au service, donc les mêmes que vous avez mis dans votre déploiement.
Le **selector** est particulièrement important, il permet de _séléctionner_ les pods qui appartiennent à ce service. Les labels qui sont dedans doivent donc correspondre aux labels que vous avez mis dans votre déploiement.
Le **targetPort** correspond au port que vous avez choisi d'exposer dans votre déploiement, et le **port** correspond au port sur lequel vous aimeriez bien joindre ce service (souvent le port 80).
Le **targetPort** correspond au port que vous avez choisi d'exposer dans votre déploiement (le champs _containerPort_), et le **port** correspond au port sur lequel vous aimeriez bien joindre ce service (pour les service http c'est donc souvent 80).
### 3.5 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).
Avec notre service nous avons exposés notre app au sein du cluster. Maintenant nous allons l'exposer vers le moooooooonde. Pour cela nous allons 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, à Viazo, 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 desIngressRoutes.
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``
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é faite pour vous, prenez juste un nom de domaine en ``.kube.test.viarezo.fr``
```yaml
# ingressroute_front/back.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
......@@ -291,16 +290,17 @@ spec:
- websecure
routes:
- kind: Rule
match: Host(`<nom de domaine>`)
match: Host(`<nom de domaine>`) && PathPrefix(`/path`)
services:
- kind: Service
name: <nom du service>
port: <port>
tls:
secretName: <secrte du certificat>
secretName: <secret du certificat>
```
Afin d'avoir du https il faut créer un certificat:
Afin d'avoir du https signé par letsencrypt, il faut aussi créer un **certificate**:
```yaml
# certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
......@@ -313,10 +313,25 @@ spec:
name: letsencrypt
kind: ClusterIssuer
```
Ce certificat va être automatiquement ê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 apparaisse bien sur https://traefik.test.viarezo.fr
Ce **certificate** va être automatiquement être signé par Letsencrypt grace à certmanager un utilitaire installé sur les clusters.
``Attention, pensez à mettre le même nom de domaine pour le back et le front et à filter sur le PathPrefix pour le back (/api), pour éviter les problèmes de CORS, et à rebuild l'image du front si nécessaire pour bien mettre les bonnes REACT_APP_CLIENT_URL et REACT_APP_API_URL``
``Pour l'auth, il faut que tu ajoutes **mondomaine/api/auth/callback** dans les URIs de redirection du client Auth **VRoum Formation Kubernetes``
Si ça ne fonctionne pas, on n'oublie pas les outils classique de débug sur kubernetes:
```bash
kubectl get certificate
kubectl get ingressroute
kubectl describe certificate
kubectl describe ingressroute
```
Et ne pas hésiter à aller check les erreurs dans la console du navigateur.
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 !**.
A ce point de la formation vous devez avoir les fichiers suivants.
```
......@@ -324,17 +339,18 @@ deploiement_front.yaml
deploiement_back.yaml
service_front.yaml
service_back.yaml
ingress_front.yaml
ingress_back.yaml
ingressroute_front.yaml
ingressroute_back.yaml
certificate.yaml
```
Afin d'éviter de flood la cluster pensez à supprimer vots ressources afin de passer à la suite.
Afin d'éviter de rentrer en conflit avec la suite, pensez à supprimer vos ressources avant de passer à la suite.
Vous pouvez le faire avec la commande suivante.
```bash
kubeclt delete -f le_dossier_qui_contient_tous_mes_fichiers
```
## 3.6 Helm le ansible de kubernetes
### 3.6 Helm le ansible 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 suit:
......@@ -344,12 +360,13 @@ VROUM
│ values.yaml
└───templates
│ deploiment_front.yaml
│ deploiment_backt.yaml
│ deployment_front.yaml
│ deployment_backt.yaml
| service_front.yaml
| service_back.yaml
| ingress_front.yaml
| ingress_back.yaml
| certificate.yaml
```
Le fichier Chart.yml décrit l'application. Il s'écrit sous la forme :
......@@ -362,39 +379,65 @@ version: 0.0.0
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:
Le values.yaml permet de passer en argument des variables aux templates.
Les variables dans le template s'écrivent avec des double crochets:
Pour accéder aux variables du `values.yaml`:
```
{{ .Values.<yaml path> }}
```
Ainsi
```
{{ .Values.front.deployment.name }}
```
Cette chaine de caractère va être remplacé par la valeur donnée dans le values.yaml :
devient
```
coucou
```
avec les values suivantes
```yaml
front:
deployment:
name: coucou
```
Pour verifier et tester votre charte helm vous pouvez utiliser :
On peut utiliser les valeurs du Chart.yaml avec:
```
{{ .Chart.<yaml path> }}
```
Pour verifier les manifestes générés par helm ,vous pouvez utiliser :
```
helm template <nom_de_la_chart>
```
Pour vérifier les fichiers générés par helm depuis le template.
Vous pouvez ensuite lancer un
```
helm install <nom_de_la_chart> <nom_de_l'installation>
```bash
helm install <nom de l'installation> <chemin vers la charte>
```
pour installer votre application.
Normalement à ce moment votre vroum est disponible sur son nom de domaine.
Vous pouvez ensuite désinstaller votre chart avec
Si vous avez besoin de modifier votre charte puis de réappliquer des changements, il faudra utiliser la commande `upgrade`:
```bash
helm upgrade <nom de l'installation> <chemin vers la charte>
```
Normalement à ce moment votre vroum est disponible sur son nom de domaine.
Vous pouvez ensuite désinstaller votre charte avec
```bash
helm uninstall <nom_de_l'installation>
```
avant de passer à la suite.
Vous l'aurez remarqué, Helm permet de définir une chart, de l'installer, de la désinstaller et de la mettre à jours. Dans ce sens, Helm s'apparente à un gestionnaire de paquets pour kubernetes.
## 4. Helm le apt de kubernetes
### 4.1 Helm install mysql
Helm est aussi très pratique pour installer des trucs fait par des autres gens.
Helm est aussi très pratique pour installer des trucs mis à disposition par d'autres utilisateurs.
On va notamment utiliser Helm pour faire un déploiement un peu plus propre de notre base de donnée mysql.
D'abord supprimons notre pod mysql
......@@ -418,7 +461,7 @@ auth:
Installe mysql avec
```bash
helm install mysql bitnami/mysql
helm install mysql bitnami/mysql -f values.yaml
```
Récupère le nom du service mysql
......@@ -432,7 +475,7 @@ Modifie les variables d'environnement pour ton déploiement back pour qu'il se c
Au lieu d'installer MySQL à la main puis d'installer ta charte **VRoum** tu peux faire d'une pierre deux coups en déclarant MySQL comme dépendance de **VRoum** pour cela:
Pense d'abord à désinstaller MySQL
Pense d'abord à désinstaller MySQL:
```bash
helm uninstall mysql
```
......@@ -456,30 +499,47 @@ Et ajoute dans ton values.yaml
mysql:
auth:
rootPassword: verystrongpassword
username: username
username: vroum
database: vroum
password: password
```
``N'hésite pas à modifier tes templates pour ne pas avoir de valeurs en double dans ton values.yaml``
Désormais, lorsque tu déploiera **VRoum** comme à l'étape précédente, ton application sera déployé avec ta base de donnée MySQL.
MySQL peut prendre pas mal de temps à se lancer et ton back, va probablement redémarrer plusieurs fois avant de démarrer correctement, il risque même de `CrashLoopBackoff` et donc de ne pas tenter de redémarrer pendant 5mins.
Si tu n'as pas envie d'attendre, tu peux le relancer à la main:
```bash
kubectl rollout restart deployment vroum-back
```
Pour le tester,
```bash
helm dependency build vroum
helm install vroum vroum/
```
Pour la prochaine étape, tu peux supprimer le `Chart.lock` et le dossier `Chart/` qui a été généré par le `helm dependency build`.
Tu disposes désormais d'une application que tu peux installer et désinstaller facilement, en https, avec une bdd, etc... C'est plutôt cool non ? Mais bon il faut encore déployer l'appli à la main et c'est un peu contraignant.
## 5. ArgoCD
VOus qui arrivez ici, BRAVO!
Vous qui arrivez ici, BRAVO!
Il ne vous reste plus qu'a automatiser ce déploiement. Pour cela on utilise un utilitaire du nom de argocd. Argocd synchronise automatiquement le cluster avec les ressources décrites sur le gitlab.
Il ne vous reste plus qu'a automatiser ce déploiement. Pour cela on utilise un utilitaire du nom de ArgoCD. ArgoCD synchronise automatiquement le cluster avec les ressources décrites sur le gitlab.
Dans le cadre d'une mise en production tout se passerais sur le dépot [argocd](https://gitlab.viarezo.fr/ViaRezo/kubernetes/argocd) du gitlab. Cependant pour l'occasion vous allez reconfigurer un nouveau dépot de 0.
Dans le cadre d'une mise en production tout se passerais sur le dépot [argocd](https://gitlab.viarezo.fr/ViaRezo/kubernetes/argocd) du Gitlab. Cependant pour l'occasion vous allez reconfigurer un nouveau dépot de 0.
Vous pouvez donc créer un nouveau dépot sur le gitlab et push votre chart dessus. (Ou alors faire un fork du projet et ajouter votre camarade dessus)
``Oui vous avez bien entendu on vous demande de push des secrets sur le gitlab, c'est pas fou mais ça ira le temps de cette formation``
Tous se passe sur le site [argocd.viarezo.fr](https://argocd.viarezo.fr). ``Attention ce site gère aussi la prod``
ArgoCD fontionne avec des resources appelées **Applications** chauque applications gère une chart.
ArgoCD fontionne avec des resources appelées **Applications**, chaque Applications gère une charte helm et la déploie sur le cluster.
Vous pouvez créer des applications depuis l'interface.
D'abord ajouter un nouveau repository sur ArgoCD:
......
REACT_APP_API_URL=http://localhost:8000
REACT_APP_API_URL=http://localhost:8000/api
REACT_APP_LOGIN_ROUTE=/auth/login
REACT_APP_LOGOUT_ROUTE=/auth/logout
REACT_APP_CLIENT_URL=http://localhost:8080
\ No newline at end of file
REACT_APP_API_URL=http://localhost:8000
REACT_APP_API_URL=http://localhost:8000/api
REACT_APP_LOGIN_ROUTE=/auth/login
REACT_APP_LOGOUT_ROUTE=/auth/logout
REACT_APP_CLIENT_URL=http://localhost:8080
\ No newline at end of file
FROM python:3.8-alpine3.15
RUN adduser -D vroum
USER vroum
WORKDIR /home/vroum
# Required apk packages for building of mysqlclient and cffi python packages
RUN apk update \
&& apk add --virtual build-deps gcc musl-dev mariadb-dev libffi-dev
&& apk add gcc musl-dev mariadb-dev libffi-dev
USER vroum
COPY requirements.txt /home/vroum
RUN pip install -r requirements.txt
# Remove apk packages that were only necessary at build time
RUN apk del build-deps
COPY --chown=vroum:vroum back/ /home/vroum/back/
COPY --chown=vroum:vroum car/ /home/vroum/car/
......
apiVersion: apps/v1
kind: Deployment
metadata:
name: vroum-back
spec:
selector:
matchLabels:
app: vroum
tier: backend
template:
metadata:
labels:
app: vroum
tier: backend
spec:
containers:
- name: main
image: registry.viarezo.fr/formation-kube/back:florentin
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 8000
env:
- name: "BACK_ROOT"
value: https://vroum.kube.test.viarezo.fr/api
- name: "FRONT_ROOT"
value: https://vroum.kube.test.viarezo.fr
- name: "CLIENT_ID"
value: client_id
- name: "CLIENT_SECRET"
value: client_secret
- name: "PRODUCTION"
value: "TRUE"
- name: "ALLOWED_HOSTS"
value: "vroum.kube.test.viarezo.fr"
- name: "DATABASE_NAME"
value: "vroum"
- name: "DATABASE_USER"
value: "vroum"
- name: "DATABASE_PASSWORD"
value: "password"
- name: "DATABASE_HOST"
value: 10.244.1.19
- name: "SALT"
value: "verylongstring"
apiVersion: apps/v1
kind: Deployment
metadata:
name: vroum-front
spec:
selector:
matchLabels:
app: vroum
tier: frontend
template:
metadata:
labels:
app: vroum
tier: frontend
spec:
containers:
- name: main
image: registry.viarezo.fr/formation-kube/front:florentin
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 8080
apiVersion: v1
kind: Service
metadata:
name: vroum-back
spec:
selector:
app: vroum
tier: backend
ports:
- port: 80
targetPort: 8000
apiVersion: v1
kind: Service
metadata:
name: vroum-front
spec:
selector:
app: vroum
tier: frontend
ports:
- port: 80
targetPort: 8080
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: vroum
spec:
secretName: vroum
dnsNames:
- vroum.kube.test.viarezo.fr
issuerRef:
name: letsencrypt
kind: ClusterIssuer
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: vroum-back
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`vroum.kube.test.viarezo.fr`) && PathPrefix(`/api`)
services:
- kind: Service
name: vroum-back
port: 80
tls:
secretName: vroum-back
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: vroum-front
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`vroum.kube.test.viarezo.fr`)
services:
- kind: Service
name: vroum-front
port: 80
tls:
secretName: vroum-front
apiVersion: v2
name: vroum
description: lets-deploy-vroum
type: application
version: 0.0.0
appVersion: "je sais pas trop"
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ .Chart.Name }}
spec:
secretName: {{ .Chart.Name }}-tls
dnsNames:
- {{ .Values.domain }}
issuerRef:
name: letsencrypt
kind: ClusterIssuer
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name }}-back
spec:
selector:
matchLabels:
app: {{ .Chart.Name }}
tier: backend
template:
metadata:
labels:
app: {{ .Chart.Name }}
tier: backend
spec:
containers:
- name: main
image: {{ .Values.back.repository }}:{{ .Values.back.tag }}
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: {{ .Values.back.port }}
env:
- name: "BACK_ROOT"
value: https://{{ .Values.domain }}/api
- name: "FRONT_ROOT"
value: https://{{ .Values.domain }}
- name: "CLIENT_ID"
value: client_id
- name: "CLIENT_SECRET"
value: client_secret
- name: "PRODUCTION"
value: "TRUE"
- name: "ALLOWED_HOSTS"
value: {{ .Values.domain }}
- name: "DATABASE_NAME"
value: {{ .Values.mysql.name }}
- name: "DATABASE_USER"
value: {{ .Values.mysql.user }}
- name: "DATABASE_PASSWORD"
value: {{ .Values.mysql.password }}
- name: "DATABASE_HOST"
value: {{ .Values.mysql.host }}
- name: "SALT"
value: "verylongstring"
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name }}-front
spec:
selector:
matchLabels:
app: {{ .Chart.Name }}
tier: frontend
template:
metadata:
labels:
app: {{ .Chart.Name }}
tier: frontend
spec:
containers:
- name: main
image: {{ .Values.front.repository }}:{{ .Values.front.tag}}
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: {{ .Values.front.port }}
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: {{ .Chart.Name }}-back
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`{{ .Values.domain }}`) && PathPrefix(`/api`)
services:
- kind: Service
name: {{ .Chart.Name }}-back
port: 80
tls:
secretName: {{ .Chart.Name }}-tls
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: {{ .Chart.Name }}-front
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`{{ .Values.domain }}`)
services:
- kind: Service
name: {{ .Chart.Name }}-front
port: 80
tls:
secretName: {{ .Chart.Name }}-tls
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}-back
spec:
selector:
app: {{ .Chart.Name }}
tier: backend
ports:
- port: 80
targetPort: {{ .Values.back.port }}
apiVersion: v1
kind: Service
metadata:
name: {{ .Chart.Name }}-front
spec:
selector:
app: {{ .Chart.Name }}
tier: frontend
ports:
- port: 80
targetPort: {{ .Values.front.port }}
domain: vroum.kube.test.viarezo.fr
front:
repository: registry.viarezo.fr/formation-kube/front
tag: florentin
port: 8080
back:
repository: registry.viarezo.fr/formation-kube/back
tag: florentin
port: 8000
mysql:
user: vroum
password: password
host: 10.244.1.34
database: vroum
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment