Pourquoi CI/CD pour FastAPI avec GitHub Actions ?
Contexte réel : Un développeur de logiciels a besoin de CI/CD pour automatiser les tests et la délivrance des applications. Cela permet d'identifier rapidement les erreurs potentielles, de garantir une qualité continue du code et de rendre le déploiement régulier et fiable.
Un cas d'usage concret : Imaginez un développeur travaillant sur une application FastAPI qui gère une base de données. Chaque fois qu'un nouveau commit est poussé sur la branche principale, il voudrait que son code soit automatisément testé et déployé sur un environnement de production sécurisé.
Prerequis
Connaissances nécessaires :
- Connaissance de FastAPI
- Compétences en Python
- Familiarité avec les systèmes de contrôle de version comme Git
- Compréhension des pipelines de CI/CD
Outils à installer :
- Git
- Python (v3.8+)
- GitHub
- GitHub Actions
Concepts fondamentaux
Pipeline CI/CD
Un pipeline CI/CD comprend les étapes suivantes :
- Build : Compile le code source.
- Test : Exécute les tests pour s'assurer que le code fonctionne correctement.
- Deploy : Déploie l'application sur un environnement de production.
GitHub Actions
GitHub Actions est une plateforme de CI/CD intégrée à GitHub qui permet d'automatiser des workflows.
Workflow Definition
Un workflow est défini dans un fichier YAML placé dans le répertoire .github/workflows du dépôt.
## .github/workflows/fastapi-ci-cd.yml
name: FastAPI CI/CD
on:
push:
branches:
- main
Job Build et Test
Un job est une série d'étapes qui s'exécutent en parallèle ou en séquence.
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: pytest
Job Deploy
Le déploiement peut être réalisé sur divers environnements, comme AWS ou Heroku.
deploy:
runs-on: ubuntu-latest
needs: build-and-test
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Deploy to Heroku
uses: akhileshns/heroku-deploy@v3.12.12
with:
heroku_api_key: $secrets.HEROKU_API_KEY
heroku_app_name: "your-heroku-app-name"
heroku_email: "your-email@example.com"
Mise en pratique : projet fil rouge
Projet : Un gestionnaire de tâches simple avec FastAPI.
Créer le répertoire du projet
mkdir fastapi-todo && cd fastapi-todo git initInitialiser un environnement virtuel
python -m venv venv source venv/bin/activate # Linux/MacOS .\venv\Scripts\activate # WindowsInstaller FastAPI et Uvicorn
pip install fastapi uvicornCréer le fichier
main.pyfrom fastapi import FastAPI, HTTPException from pydantic import BaseModel app = FastAPI() class Task(BaseModel): id: int title: str completed: bool = False tasks = {} @app.post("/tasks/") async def create_task(task: Task): if task.id in tasks: raise HTTPException(status_code=400, detail="Task ID already exists") tasks[task.id] = task.dict() return tasks[task.id] @app.get("/tasks/{task_id}") async def get_task(task_id: int): if task_id not in tasks: raise HTTPException(status_code=404, detail="Task not found") return tasks[task_id] @app.put("/tasks/{task_id}") async def update_task(task_id: int, task: Task): if task_id not in tasks: raise HTTPException(status_code=404, detail="Task not found") tasks[task_id] = task.dict() return tasks[task_id] @app.delete("/tasks/{task_id}") async def delete_task(task_id: int): if task_id not in tasks: raise HTTPException(status_code=404, detail="Task not found") del tasks[task_id] return {"message": "Task deleted"}Créer le fichier
requirements.txtfastapi uvicorn python-multipart pydanticAjouter un fichier
README.md# FastAPI Todo Manager Un gestionnaire de tâches simple avec FastAPI.Initialiser le dépôt Git et ajouter les fichiers
git add . git commit -m "Initial commit"Ajouter un fichier
.gitignorevenv/ __pycache__/ .venv *.pyc *~ .DS_StoreCréer le workflow GitHub Actions
# .github/workflows/fastapi-ci-cd.yml name: FastAPI CI/CD on: push: branches: - main jobs: build-and-test: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.8' - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Run tests run: pytest deploy: runs-on: ubuntu-latest needs: build-and-test steps: - name: Checkout code uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.8' - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Deploy to Heroku uses: akhileshns/heroku-deploy@v3.12.12 with: heroku_api_key: $secrets.HEROKU_API_KEY heroku_app_name: "your-heroku-app-name" heroku_email: "your-email@example.com"Ajouter le secret
HEROKU_API_KEYà GitHub- Allez dans les paramètres du dépôt sur GitHub.
- Sélectionnez "Secrets" > "New repository secret".
- Ajoutez un nom comme
HEROKU_API_KEYet sa valeur (votre clé API Heroku).
Tester le workflow
- Faites un commit avec une modification dans votre code.
- Pousser les modifications sur la branche main.
Le pipeline GitHub Actions devrait s'exécuter automatiquement, tester votre application et déployer sur Heroku si tout fonctionne bien.
Erreurs fréquentes et debugging
1. ModuleNotFoundError
Message d'erreur :
ModuleNotFoundError: No module named 'uvicorn'
Code incorrect :
## main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello World"}
Code correct :
## main.py
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello World"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
2. pytest: command not found
Message d'erreur :
pytest: command not found
Code incorrect :
## .github/workflows/fastapi-ci-cd.yml
name: FastAPI CI/CD
on:
push:
branches:
- main
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: pytest
Code correct :
## .github/workflows/fastapi-ci-cd.yml
name: FastAPI CI/CD
on:
push:
branches:
- main
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: pytest --version
3. Permission denied
Message d'erreur :
Permission denied
Code incorrect :
## Deploy to Heroku
uses: akhileshns/heroku-deploy@v3.12.12
with:
heroku_api_key: $secrets.HEROKU_API_KEY
heroku_app_name: "your-heroku-app-name"
heroku_email: "your-email@example.com"
Code correct :
## Deploy to Heroku
uses: akhileshns/heroku-deploy@v3.12.12
with:
heroku_api_key: $secrets.HEROKU_API_KEY
heroku_app_name: "your-heroku-app-name"
heroku_email: "your-email@example.com"
Pour aller plus loin
1. Utilisation de Docker pour le déploiement
Vous pouvez utiliser Docker pour encapsuler votre application FastAPI et la déployer facilement.
2. Configuration des variables d'environnement
Utilisez des variables d'environnement pour gérer les configurations sensibles comme les clés API, les mots de passe, etc.
3. Intégration avec AWS Elastic Beanstalk
Déployez votre application sur AWS Elastic Beanstalk en utilisant GitHub Actions et le plugin aws-actions-deploy-to-elastic-beanstalk.
Défi pratique :
Créez un script Python qui utilise FastAPI pour créer une API de blog simple, y compris des routes pour créer, lire, mettre à jour et supprimer les articles. Assurez-vous que votre application fonctionne localement et que le pipeline GitHub Actions est configuré pour déployer l'application sur Heroku.