Skip to content

Phase 6 — Applications Python

Déploiement des 3 applications Python sur le cluster k3s via GitOps (ArgoCD).


Vue d'ensemble

Application Stack Déploiement
FastAPI API REST, Prometheus client ArgoCD → k3s
Streamlit Dashboard data ArgoCD → k3s
Flask Application web simple ArgoCD → k3s

Bootstrap Ansible — namespaces et ArgoCD Applications

# playbooks/20-apps-bootstrap.yml
- hosts: k3s_master
  tasks:
    - name: Créer les namespaces
      ansible.builtin.shell:
        cmd: |
          kubectl create namespace {{ item }} --dry-run=client -o yaml | kubectl apply -f -
      loop:
        - fastapi
        - streamlit
        - flask

    - name: Déployer les Applications ArgoCD
      ansible.builtin.shell:
        cmd: |
          cat <<EOF | kubectl apply -f -
          apiVersion: argoproj.io/v1alpha1
          kind: Application
          metadata:
            name: {{ item.name }}
            namespace: argocd
          spec:
            project: default
            source:
              repoURL: https://gitlab.com/Mounicou/homelab-proxmox
              targetRevision: HEAD
              path: manifests/apps/{{ item.name }}
            destination:
              server: https://kubernetes.default.svc
              namespace: {{ item.name }}
            syncPolicy:
              automated:
                prune: true
                selfHeal: true
          EOF
      loop:
        - { name: fastapi }
        - { name: streamlit }
        - { name: flask }

Structure d'un projet applicatif

Chaque application suit la même structure de dépôt GitLab :

app-name/
├── .gitlab-ci.yml
├── Dockerfile
├── requirements.txt
├── app/
│   └── main.py
├── tests/
│   └── test_main.py
└── manifests/
    ├── deployment.yaml
    ├── service.yaml
    └── ingress.yaml

Dockerfile générique

FROM python:3.13-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app/ .

EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Manifest Kubernetes (exemple FastAPI)

# manifests/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi
  namespace: fastapi
spec:
  replicas: 2
  selector:
    matchLabels:
      app: fastapi
  template:
    metadata:
      labels:
        app: fastapi
    spec:
      containers:
        - name: app
          image: harbor.mounik.ovh/fastapi/app:latest
          ports:
            - containerPort: 8000
          env:
            - name: OIDC_ISSUER
              value: "https://keycloak.mounik.ovh/realms/homelab"
# manifests/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: fastapi
  namespace: fastapi
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: 8000
  selector:
    app: fastapi
# manifests/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: fastapi
  namespace: fastapi
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
spec:
  ingressClassName: traefik
  rules:
    - host: app-fastapi.mounik.ovh
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: fastapi
                port:
                  number: 80

Pipeline CI/CD (applicatif)

# .gitlab-ci.yml de chaque application
stages:
  - test
  - sast
  - build
  - scan
  - push
  - dast
  - deploy

variables:
  DOCKER_IMAGE: harbor.mounik.ovh/{{ CI_PROJECT_NAME }}/app
  DD_URL: https://defectdojo.mounik.ovh

Chaque pipeline suit le même schéma décrit dans la Phase 7 — DevSecOps.

Déploiement

  1. Le développeur pousse du code sur GitLab.com
  2. Le pipeline CI/CD build, scan et push l'image sur Harbor
  3. Le pipeline met à jour le manifest Kubernetes (tag image)
  4. ArgoCD détecte le changement et synchronise le cluster
  5. L'application est déployée sur k3s

Livrable : 3 applications déployées et accessibles via app-*.mounik.ovh.


Pour aller plus loin