diff --git a/chapters/application.qmd b/chapters/application.qmd index 332b1a0..7c19bcf 100644 --- a/chapters/application.qmd +++ b/chapters/application.qmd @@ -952,7 +952,7 @@ git checkout appli15 ::: -{{< include "./applications/_appli17.qmd" >}} +{{< include "./applications/_appli16.qmd" >}} ## Étape 2: déployer l'API de manière manuelle @@ -961,7 +961,7 @@ git checkout appli15 ## Si vous prenez ce projet fil rouge en cours de route ```{.bash filename="terminal"} -git checkout appli18 +git checkout appli16 ``` ![](/checkpoint.jpg){width=80% fig-align="center"} @@ -978,7 +978,7 @@ et d'avoir un serveur, en arrière plan, qui effectuera les opérations pour ré requête. Pour se faire, on va utiliser les possibilités offertes par `Kubernetes`, sur lequel est basé le [SSP Cloud](https://datalab.sspcloud.fr). -{{< include "./applications/_appli18a.qmd" >}} +{{< include "./applications/_appli17.qmd" >}} Nous avons préparé la mise à disposition de notre API mais à l'heure @@ -987,7 +987,20 @@ de lancer manuellement une image `Docker` pour pouvoir y accéder. Ce type de travail est la spécialité de `Kubernetes` que nous allons utiliser pour gérer la mise à disposition de notre API. -{{< include "./applications/_appli18b.qmd" >}} +{{< include "./applications/_appli18.qmd" >}} + +::: {.callout-note title="Gérer le CORS"} +Notre API est accessible sans problème depuis `Python` ou notre navigateur. + +En revanche, si on désire utiliser `JavaScript` pour créer une application +interactive il est indispensable de mettre +les lignes un peu obscure sur le CORS dans le fichier `ingress.yaml`. + +Comme c'est un point technique qui ne concerne pas les compétences +liées à ce cours, nous donnons directement les mises à jour nécessaires +du projet. +::: + On peut remarquer quelques voies d'amélioration de notre approche qui seront ultérieurement traitées: @@ -1071,19 +1084,6 @@ Il y a donc un élément qui fait la liaison entre ces deux pipelines et qui nou -::: {.callout-note title="Gérer le CORS"} -Notre API est accessible sans problème depuis `Python` ou notre navigateur -mais si on désire utiliser `JavaScript` pour créer une application -interactive, on va essuyer un refus à cause du [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). - -Permettre à n'importe quel client de se connecter à -notre API permettra de faire un site web exploitant notre API. -Comme c'est un point technique qui ne concerne pas les compétences -liées à ce cours, nous donnons directement les mises à jour nécessaires -du projet: -::: - -{{< include "./applications/_cors.qmd" >}} ## Etape 4: construire un site web diff --git a/chapters/applications/_appli17.qmd b/chapters/applications/_appli17.qmd index d6ae7ad..524d5ca 100644 --- a/chapters/applications/_appli17.qmd +++ b/chapters/applications/_appli17.qmd @@ -1,74 +1,31 @@ ::: {.callout-tip} +## Application 17: Dockeriser l'API (intégration continue) -## Application 16: Mise à disposition sous forme d'API locale +- Pour rendre la structure du projet plus lisible, déplacer `api.py` -> `api/main.py` -- Installer `fastAPI` et `uvicorn` puis les ajouter au `requirements.txt` -- Renommer le fichier `main.py` en `train.py`. Dans ce script, ajouter une -sauvegarde du modèle après l'avoir entraîné, sous le -format [`joblib`](https://scikit-learn.org/stable/model_persistence.html#python-specific-serialization). -- Faire tourner - -```{.bash filename="terminal"} -python train.py -``` - -pour enregistrer en local votre modèle de production. - -- Modifier les appels à `main.py` dans votre `Dockerfile` et vos actions `Github` -sous peine d'essuyer des échecs lors de vos actions `Github` après le prochain _push_. - -- Ajouter `model.joblib` au `.gitignore` car `Git` n'est pas fait pour -ce type de fichiers. - -Nous allons maintenant passer au développement de l'API. -Comme découvrir `FastAPI` n'est pas l'objet de cet enseignement, nous -donnons directement le modèle pour créer l'API. Si vous -désirez tester de vous-mêmes, vous pouvez créer votre -fichier sans vous référer à l'exemple - -- Créer le fichier `api.py` permettant d'initialiser l'API: +- Créer un script `api/run.sh` à la racine du projet qui lance le script `train.py` puis déploie localement l'API
- -Fichier `api.py` - +Fichier `run.sh` -```{.python include="./applications/code/appli17_api_main.py" filename="src/models/train_evaluation.py"} -``` -
- -- Déployer en local l'API avec la commande +```{.bash filename="api/run.sh" no-prefix=true} +#/bin/bash -```{.bash filename="terminal"} -uvicorn api:app --reload --host "0.0.0.0" --port 5000 -``` - -- A partir du `README` du service, se rendre sur l'URL de déploiement, -ajouter `/docs/` à celui-ci et observer la documentation de l'API -- Se servir de la documentation pour tester les requêtes `/predict` -- Récupérer l'URL d'une des requêtes proposées. La tester dans le navigateur -et depuis `Python` avec `requests` : - -```{.python} -import request -requests.get(url).json() +python3 train.py +uvicorn api.main:app --reload --host "0.0.0.0" --port 5000 ``` + -- Une fois que vous avez testé, vous pouvez tuer l'application en faisant CTRL+C. Retester -votre bout de code `Python` et comprendre l'origine du problème. +- Donner au script `api/run.sh` des permissions d'exécution : `chmod +x api/run.sh` -::: +- Ajouter `COPY api ./api` pour avoir les fichiers nécessaires au lancement dans l'API dans l'image -::: {.callout-caution collapse="true"} -## Checkpoint +- Changer l'instruction `CMD` du `Dockerfile` pour exécuter le script `api/run.sh` au lancement du conteneur (`CMD ["bash", "-c", "./api/run.sh"]`) -```{.bash filename="terminal"} -git stash #<1> -git checkout appli17 -``` -1. Pour annuler les modifications depuis le dernier _commit_ +- Mettre à jour votre `requirements.txt` pour tenir compte des nouveaux _packages_ utilisés +- *Commit* et *push* les changements -![](/checkpoint.jpg){width=80% fig-align="center"} +- Une fois le CI terminé, récupérer la nouvelle image dans votre environnement de test de `Docker` et vérifier que l'API se déploie correctement ::: \ No newline at end of file diff --git a/chapters/applications/_appli18a.qmd b/chapters/applications/_appli18a.qmd deleted file mode 100644 index f079bf7..0000000 --- a/chapters/applications/_appli18a.qmd +++ /dev/null @@ -1,27 +0,0 @@ -::: {.callout-tip} -## Application 18a: Dockeriser l'API (intégration continue) - -- Pour rendre la structure du projet plus lisible, déplacer `api.py` -> `api/main.py` - -- Créer un script `api/run.sh` à la racine du projet qui lance le script `train.py` puis déploie localement l'API - -
-Fichier `run.sh` - -```{.bash filename="api/run.sh" no-prefix=true} -#/bin/bash - -python3 train.py -uvicorn api.main:app --reload --host "0.0.0.0" --port 5000 -``` -
- -- Donner au script `api/run.sh` des permissions d'exécution : `chmod +x api/run.sh` - -- Changer l'instruction `CMD` du `Dockerfile` pour exécuter le script `api/run.sh` au lancement du conteneur (`CMD ["bash", "-c", "./api/run.sh"]`) - -- *Commit* et *push* les changements - -- Une fois le CI terminé, récupérer la nouvelle image dans votre environnement de test de `Docker` et vérifier que l'API se déploie correctement - -::: \ No newline at end of file diff --git a/chapters/applications/_appli18b.qmd b/chapters/applications/_appli18b.qmd deleted file mode 100644 index c9300e7..0000000 --- a/chapters/applications/_appli18b.qmd +++ /dev/null @@ -1,113 +0,0 @@ -::: {.callout-tip} -## Application 18b: Mettre à disposition l'API (déploiement manuel) - -Cette partie nécessite d'avoir à disposition une infrastructure _cloud_. - -- Créer un dossier `deployment` à la racine du projet qui va contenir les fichiers de configuration nécessaires pour déployer sur un cluster `Kubernetes` - -- En vous inspirant de la [documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment), y ajouter un premier fichier `deployment.yaml` qui va spécifier la configuration du *Pod* à lancer sur le cluster - -
-Fichier `deployment/deployment.yaml` - -```{.yaml filename="deployment/deployment.yaml"} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: titanic-deployment - labels: - app: titanic -spec: - replicas: 1 - selector: - matchLabels: - app: titanic - template: - metadata: - labels: - app: titanic - spec: - containers: - - name: titanic - image: linogaliana/application-correction:latest - ports: - - containerPort: 5000 -``` -
- -- En vous inspirant de la [documentation](https://kubernetes.io/fr/docs/concepts/services-networking/service/#d%C3%A9finition-d-un-service), y ajouter un second fichier `service.yaml` qui va créer une ressource `Service` permettant de donner une identité fixe au `Pod` précédemment créé au sein du cluster - -
-Fichier `deployment/service.yaml` - -```{.yaml filename="deployment/service.yaml"} -apiVersion: v1 -kind: Service -metadata: - name: titanic-service -spec: - selector: - app: titanic - ports: - - protocol: TCP - port: 80 - targetPort: 5000 -``` -
- -- En vous inspirant de la [documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#the-ingress-resource), y ajouter un troisième fichier `ingress.yaml` qui va créer une ressource `Ingress` permettant d'exposer le service via une URL en dehors du cluster - -
-Fichier `deployment/ingress.yaml` - -```{python} -#| eval: false -#| filename: "deployment/ingress.yaml" -#| source-line-numbers: "10-13" -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: titanic-ingress - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / -spec: - ingressClassName: nginx - tls: - - hosts: - - # METTRE URL ICI #<1> - rules: - - host: # METTRE URL ICI #<2> - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: titanic-service - port: - number: 80 -``` -1. Mettez l'URL auquel vous voulez exposer votre service. Sur le modèle de `titanic.kub.sspcloud.fr` (mais ne tentez pas celui-là, il est déjà pris 😃) -2. Mettre ici aussi -
- -- Appliquer ces fichiers de configuration sur le cluster : `kubectl apply -f deployment/` - -- Si tout a correctement fonctionné, vous devriez pouvoir accéder depuis votre navigateur à l'API à l'URL spécifiée dans le fichier `deployment/ingress.yaml`. Par exemple `https://toto.kub.sspcloud.fr/` si vous avez mis celui-ci plus tôt (et `https://toto.kub.sspcloud.fr/docs` pour la documentation). - -::: - -::: {.callout-caution collapse="true"} -## Checkpoint - -```{.bash filename="terminal"} -git stash #<1> -git checkout appli18 -``` -1. Pour annuler les modifications depuis le dernier _commit_ - - -![](/checkpoint.jpg){width=80% fig-align="center"} - -::: - diff --git a/chapters/applications/_appli19b.qmd b/chapters/applications/_appli19b.qmd index 0bd8775..af8d9ec 100644 --- a/chapters/applications/_appli19b.qmd +++ b/chapters/applications/_appli19b.qmd @@ -21,6 +21,7 @@ on: - main - dev tags: + - 'v*.*.*' jobs: docker: