Déployer une API Python sur Google App Engine Standard, avec FastAPI.

Publié le
Auteurs et autrices

Cet article a été initialement publié en 2021 sur le site de mon entreprise Aynils. Je l'ai déplacé car ça fait plus de sens de m'exprimer en mon nom propre ici. J'évite mainenant d'utiliser les services de Google mais cet article reste pertinent pour celleux qui n'ont pas le choix, dans le cadre d'un projet.

Table des matières

Google App Engine Standard (GAE) était mon service préféré (avant ma réflexion sur le monopole malsain des GAFAM) pour le déploiement de mes services Python et Node.js. En plus de la générosité de son offre gratuite, j'aime GAE pour ces avantages:

  • Scaling automatique ;
  • Portail d'administration clair ;
  • Déploiement simple, en une seule commande ;
  • Écosystème Google Cloud Portal permettant d'accéder simplement à toute une série de services complémentaires: Pub/Sub, Cron tasks, DB managée, AI APIs, etc.

À côté de ces avantages, le point négatif des services de Google est souvent la précision de la documentation. Quand j'utilise un nouveau service, je dois souvent passer beaucoup de temps à chercher des réponses à mes questions et quand j'en trouve, elles ne sont pas toujours à jour.

J'ai donc décidé de contribuer à améliorer la situation en publiant ce guide pour déployer une API Python sur Google App Engine Standard.

Prérequis

  • Un accès owner à un compte Google Cloud Portal (GCP);
  • Python 3.8 installé sur ta machine;
  • Un dépôt GitHub pour ton projet.

Conventions

Les instructions sont testées depuis Linux (Ubuntu 20.04.1 LTS) et devraient fonctionner également sous Mac OS. Si tu utilises Windows, désolé mais il faudra un peu adapter.

Quand une ligne de code commence par $, cela signifie qu'elle doit être entrée dans ton terminal. Le $ ne doit jamais être entré avec la commande qui suit.

L'API

Tout d’abord, commençons par développer une API simple, pour les besoins de cet exercice. Si tu as déjà une application prête à être déployée, tu peux directement aller à l'étape suivante: Configuration

Création de la base du projet

Pour partir d'un environnement Python propre, crée d'abord un nouveau dossier et accédes-y.

$ mkdir ma-super-api && cd ma-super-api

Crée un environnement virtuel.

$ python3.8 -m venv venv

Maintenant, tu as besoin d'un fichier requirements.txt pour spécifier les packages à importer.

$ touch requirements.txt

Et le fichier qui contiendra le code de notre API.

$ touch main.py

Le code

Pour ce guide, j'ai choisi de créer une API simple, en utilisant le package FastAPI. Qui permet de développer rapidement des API Python asynchrones.

L'environement

Depuis /ma-super-api/ :

Accède à l'environnement virtuel:

$ source venv/bin/activate

Si l'action à fonctionné, tu verras (venv) indiqué devant ton nom d'utilisateur, dans le terminal. Toutes les actions effectuées à partir de maintenant le seront depuis le contexte de cet environnement virtuel.

Documente les packages à installer dans le fichier requirements.txt

fastapi
uvicorn
gunicorn
uvloop
httptools
websockets

Puis installe les packages documentés

$ pip install -r requirements.txt

Le code

Ouvre le fichier main.py dans ton éditeur favori et colles-y le code suivant:

import os
import uvicorn
from fastapi import FastAPI

app = FastAPI()

@app.get("/salut")
async def getCity():
    return {
        "message": "Hey, salut!"
    }

if __name__ == "__main__" and os.environ.get("ENVIRONMENT") != "PRODUCTION":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Tu peux maintenant tester le résultat localement

$ python main.py

Le message suivant devrait être affiché dans ton terminal:

INFO:     Started server process [20686]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

Et si tu ouvres ton navigateur et navigues à l'adresse http://0.0.0.0:8000/salut, tu y verras le résultat suivant:

{"message":"Hey, salut!"}

Si ça marche, tu peux arrêter le serveur en appuyant sur CTRL + C puis sortir de l’environnement virtuel $ deactivate

Configuration

Git

Il te faut un dépôt git local, synchronisé avec le dépôt GitHub de ce projet.

$ git init

$ git remote add origin <URL_DE_TON_DEPOT_GITHUB>

Et un gitignore pour ne pas synchroniser ton environnement virtuel avec le dépôt.

$ echo "venv" > .gitignore

Google App Engine

Création de l'app

Ouvre le portal de Google App Engine et clique sur Créer une application. Choisis les options suivantes:

  • Localisation: choisis le serveur le plus près des services qui utiliseront l'API
  • Langage: Python
  • Environnement: Standard

A l'étape Déployer avec le SDK Google Cloud, clique sur Je le ferai plus tard

Activation de Cloud build API

Ouvre le portail Cloud Build et clique sur Activer

Configuration de l'API

La configuration de l'instance Google App Engine sur laquelle ton API sera déployée se trouve dans le fichier app.yaml, déployé avec ton application. Crée ce fichier:

$ touch app.yaml

Ensuite, ajoutes-y le contenu suivant:

runtime: python38

entrypoint: gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker

instance_class: F2

env_variables:
  ENVIRONMENT: "PRODUCTION

handlers:
- url: /.*
  secure: always
  redirect_http_response_code: 301
  script: auto

La documentation concernant ce fichier est disponible ici

Compte de service

Pour créer l'instance Google App Engine et y déployer l'API, tu as besoin d'un compte de service. Pour le créer, ça se passe dans la section IAM de ton compte Google Cloud Portal, onglet "Comptes de service".

Clique sur Créer un compte de service dans la barre supérieure et remplisse les différents champs de l'étape 1 Détails du compte de service avec les données suivantes:

  • Nom du compte de service: github-action
  • ID du compte de service: laisser la valeur par défaut
  • Description du compte de service: Compte utilisé par GitHub actions pour gérer les instances

A l'étape 2 Autoriser ce compte de service à accéder au projet, ajoute les rôles suivants:

  • Déployeur App Engine
  • Administrateur de services App Engine
  • Éditeur Cloud Build
  • Utilisateur du compte de service
  • Créateur des objets de l'espace de stockage
  • Lecteur des objets de l'espace de stockage

N'entre rien à l'étape 3 Autoriser les utilisateurs à accéder à ce compte de service et clique sur OK pour valider.

Ensuite, ouvre le menu en cliquant sur les trois points dans la colonne tout à droite de la ligne correspondant au compte de service nouvellement créé et choisis l'option créer une clé.

Choisir json et enregistrer le fichier localement. ⚠️Cette clé permet d'accéder à ton compte et doit donc être stockée en sécurité.

Pour utiliser la clé pour le déploiement, tu as besoin de sa représentation en base 64. Pour ce faire, ouvre ton terminal dans le dossier ou se trouve la clé que tu viens de télécharger et utilise la commande suivante:

$ base64 <NOM_DU_FICHIER_DE_CLE>

Copier le résultat et le conserver pour l'étape suivante.

GitHub

Secret

Dans ton compte GitHub, aller navigue vers le dépôt de ce projet puis ouvre la page Settings puis l'onglet Secrets.

Crée un nouveau secret en cliquant sur New repository secret avec les données suivantes:

  • Name: GAE_DEPLOY_KEY
  • Value: copie ici la représentation base64 de ta clé que tu viens de créer à l'étape précédente
Action

La configuration se trouve dans un fichier .yaml à créer dans le projet.

$ mkdir -p .github/workflows/

$ touch .github/workflows/gae.yaml

Ouvre le fichier et y ajoutes-y la configuration suivante:

name: Deploy to Google App Engine

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@master

      - name: Deploy to production
        if: github.ref == 'refs/heads/main'
        uses: google-github-actions/deploy-appengine@main
        with:
          credentials: ${{ secrets.GAE_DEPLOY_KEY }}
          deliverables: app.yaml

Déploiement

Ça y est, c'est le moment de déployer ton API! 🥳

Premièrement, commit tes changements localement

$ git add .

$ git commit -m "initial commit"

Et puis, pousse les changements vers le dépôt distant GitHub.

$ git branch -M main ❗Cette étape sert à renommer la branche master crée par défaut localement vers main qui est le nouveau nom de la branche principale sur GitHub

$ git push -u origin main

Maintenant, tout est prêt. Il ne te reste plus qu'à tester. Pour cela, il faut un changement pour pouvoir pousser à nouveau vers GitHub et déclencher l'action qui à été créée à l'étape précédente.

$ touch README.MD

$ git add .

$ git commit -m "add README"

$ git push

Test

Pour vérifier le statut du déploiement, ça se passe sur GitHub, sur la page du dépôt du projet, dans l'onglet Actions.

Si c'est vert, c'est bon. Si c'est rouge, c'est pas bon. (merci Captain Obvious!).

Pour accéder à l'API, il te reste à trouver son url. Elle se trouve sur le portail Google App Engine, en haut à droite. Elle ressemble à <NOM_DE_TON_PROJET>.uc.r.appspot.com

Ouvre ton navigateur et navigues vers <URL_DE_TON_APP_ENGINE>/salut et tu devrais voir le résultat:

{ 'message': 'Hey, salut!' }

Et voilà! ✨