WIKI
SUPPORT-IA Support N2/N3 · plateformes IA Azure

11 · Attentes du poste et compléments

17 min de lecture Mis à jour le 23 octobre 2026
Sur cette page

Version : 1.0 · Date : 2026-10-23

En une phrase : ce chapitre relie les attentes exprimées pour un poste de Run N2/N3 sur des applications IA (chatbots, agents, systèmes multi-agents) aux chapitres du cours, et comble les sujets qui n'y étaient pas encore : External Secrets Operator, Argo CD en synchronisation manuelle, Helm, le Run limité à un namespace, Langfuse côté reporting, Document Intelligence Studio et Grafana « as code ».


1. Le poste en clair#

Élément Ce que cela implique pour toi
Support N2/N3 de chatbots, agents et systèmes multi-agents Les métiers signalent « ça ne marche pas » ou « la réponse est fausse » : il faut une investigation structurée jusqu'à la cause
Accès aux logs, aux traces Langfuse, aux dashboards Grafana, aux ressources Kubernetes et au code si besoin Savoir lire chaque outil, et surtout relier les informations entre eux
Amélioration continue : scripts, dashboards, workbooks, exports Chaque incident résolu peut devenir une vue, une requête ou un script ; expliquer le problème que ça résout
Une équipe plateforme gère les clusters AKS ; le Run intervient dans des namespaces alloués Tu n'administres pas le cluster : tu diagnostiques dans ton périmètre et tu escalades avec des faits
Équipe Run en construction, travail avec les squads Build Documenter, standardiser, poser des runbooks

Priorités de préparation :

  • P1 : diagnostic Web Apps et AKS, lecture des logs, traces Langfuse, accès aux secrets, principes du RAG (savoir distinguer panne technique et mauvaise réponse IA).
  • P2 : Grafana et Prometheus, Document Intelligence, Azure AI Search, Argo CD.
  • Moins prioritaire : les mathématiques des LLM, l'administration complète des clusters, les slots de Web App, le détail des PV/PVC (connaître leur définition suffit).

2. Où chaque attente est traitée#

# Prio Travail attendu Preuve à pouvoir montrer Dans le cours
01 P1 Web Apps et réseau Schéma entrée privée (Private Endpoint) et sortie (VNet Integration), DNS, deux subnets distincts 06, 01 § réseau
02 P1 Docker, ACR et pipeline Image versionnée, droits push et pull, test de démarrage, retour arrière 05, § 6 ci-dessous
03 P1 Logs et supervision Azure Erreur reproduite, vue Log stream, vue persistée, 3 requêtes KQL 07, § 6.3
04 P1 Langfuse Trace à plusieurs étapes, feedback, filtre sur une interaction, export 07, § 7
05 P1 Run Kubernetes Panne analysée avec get, describe, logs, événements 04, § 5
06 P1 Quotas et ressources Requests, limits et quota expliqués, refus de création compris § 5
07 P1 Identités et secrets Schéma de fédération, lecture des manifests du mécanisme utilisé 04, § 3 (External Secrets)
08 P1 RAG de bout en bout Deux pipelines dessinées, causes de mauvaise réponse 03
09 P2 Document Intelligence PDF avec tableau analysé dans le Studio, JSON expliqué § 8
10 P2 Azure AI Search Schéma d'index, métadonnées, recherche et filtre 03, § 9
11 P2 Grafana et Prometheus Dashboard 3 panneaux, une variable, export / import JSON 07, § 10
12 P2 Helm et Argo CD Values reconnues, diff observé, synchronisation manuelle, santé vérifiée § 4 et § 4.3
13 P2 Modèles, tokens et cache Fiche des familles, compteurs, cache expliqué 02
14 P1 Simulation d'entretien Présentation courte et deux incidents traités en 5 minutes chacun 09, 08

3. Secrets : External Secrets Operator ou Secrets Store CSI Driver#

Deux mécanismes répandus font arriver un secret de Key Vault dans un pod. Ils n'ont pas les mêmes objets ni les mêmes pannes : la première question à se poser est donc « lequel est utilisé ici ? » (kubectl get secretstore,externalsecret,secretproviderclass -n <namespace>).

External Secrets Operator (ESO) Secrets Store CSI Driver (+ provider Key Vault)
Objets SecretStore (ou ClusterSecretStore) : comment joindre le coffre ; ExternalSecret : quels secrets copier SecretProviderClass : quel coffre et quels secrets monter
Qui lit le coffre Le contrôleur ESO, avec le ServiceAccount référencé par le SecretStore Le provider CSI au montage du volume du pod
Résultat Un Secret Kubernetes créé et rafraîchi (refreshInterval) Des fichiers dans le pod, et éventuellement un Secret synchronisé
Où voir l'erreur kubectl describe externalsecret / secretstore (conditions, événements) Événement FailedMount sur le pod (pod bloqué en ContainerCreating)
Le pod démarre si le coffre est injoignable ? Oui, avec l'ancienne valeur du Secret s'il existe déjà Non, le montage échoue

3.1 Les manifests ESO à savoir lire#

apiVersion: v1
kind: ServiceAccount
metadata:
  name: workload-identity-sa
  annotations:
    azure.workload.identity/client-id: <client id de l'identité managée>
    azure.workload.identity/tenant-id: <tenant id>
---
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
  name: azure-store
spec:
  provider:
    azurekv:
      authType: WorkloadIdentity
      vaultUrl: "https://<coffre>.vault.azure.net"
      serviceAccountRef:
        name: workload-identity-sa          # le ServiceAccount fédéré (subject system:serviceaccount:<ns>:workload-identity-sa)
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: chatbot-secrets
spec:
  refreshInterval: 1h0m0s                  # fréquence de relecture du coffre ; 0 = créé une fois, jamais mis à jour
  secretStoreRef: { kind: SecretStore, name: azure-store }
  target: { name: chatbot-secrets, creationPolicy: Owner }
  data:
  - secretKey: langfuse-secret-key         # clé dans le Secret Kubernetes
    remoteRef: { key: secret/langfuse-secret-key }   # nom du secret dans Key Vault

La chaîne de confiance est la même que pour Workload Identity (chapitre 04) : identité managée avec le rôle Key Vault Secrets User, federated credential (issuer OIDC du cluster, subject du ServiceAccount, audience api://AzureADTokenExchange), ServiceAccount annoté. La différence : c'est le contrôleur ESO qui s'authentifie, pas le code de l'appli.

3.2 Diagnostic ESO#

kubectl get externalsecret -n <ns>                       # colonne STATUS / READY
kubectl describe externalsecret chatbot-secrets -n <ns>  # condition Ready, raison, message, événements
kubectl describe secretstore azure-store -n <ns>         # le store est-il valide ?
kubectl get secret chatbot-secrets -n <ns>               # existe-t-il ? (ne jamais afficher la valeur dans un ticket)
kubectl annotate es chatbot-secrets force-sync=$(date +%s) --overwrite   # forcer une relecture (action : à faire selon la procédure)
Symptôme Cause probable Vérification
Ready=False sur l'ExternalSecret, message d'authentification Federated credential absente ou subject faux ; annotation client-id erronée Subject = system:serviceaccount:<ns>:<sa> ; client ID de l'identité
Message d'autorisation (403) Rôle Key Vault Secrets User manquant sur le coffre az role assignment list --assignee <client-id> --scope <id du coffre>
Message « secret introuvable » remoteRef.key faux ou secret supprimé / désactivé Nom exact dans le coffre
Timeout réseau Coffre privé non résolu en IP privée depuis le cluster nslookup <coffre>.vault.azure.net depuis un pod du namespace
Le secret a changé dans le coffre mais l'appli garde l'ancien refreshInterval long, et l'appli lit la variable d'environnement au démarrage seulement Date de status.refreshTime ; redémarrage du pod nécessaire si le secret est injecté en variable

Distinguer les trois refus : authentification (qui es-tu ? : identité, fédération), autorisation (as-tu le droit ? : rôle), réseau (peux-tu joindre ? : DNS, private endpoint). C'est la phrase à dire en entretien.


4. Argo CD en synchronisation manuelle, avec Helm#

4.1 Refresh, diff, sync : trois actions différentes#

Action Ce qu'elle fait Ce qu'elle ne fait pas
Refresh Relit Git et recalcule l'écart avec le cluster → Synced ou OutOfSync Ne déploie rien
Diff Montre ligne par ligne ce qui changerait Ne déploie rien
Sync Applique l'état de Git dans le cluster Ne garantit pas que l'appli fonctionne (voir Health)

Dans un contexte où la sync est manuelle, un commit produit OutOfSync et attend une sync : « Git est à jour mais rien ne change » est alors un comportement normal, pas une panne. Après la sync, vérifier Healthy puis faire un test applicatif.

argocd app get <app>            # source (repo, révision, chemin ou chart), destination, Sync et Health status
argocd app diff <app>           # l'écart entre Git et le cluster
argocd app history <app>        # les révisions déjà déployées
argocd app sync <app>           # action : appliquer Git (selon la procédure de l'équipe)

Le retour arrière durable passe par Git (revert du commit puis sync). Un rollback dans l'interface d'Argo CD revient à une révision précédente, mais si Git n'est pas corrigé, la prochaine sync remettra la version fautive.

L'accès au dépôt (Azure DevOps) peut se faire par PAT, par SSH ou par Workload Identity selon l'environnement : si l'application affiche une erreur de comparaison (ComparisonError), regarder d'abord les identifiants du dépôt (PAT expiré, droits retirés).

4.2 Helm, ce qu'il faut savoir lire#

Une chart = des templates de ressources Kubernetes + un fichier de values (configuration par environnement). Exemple typique : la chart publique de Langfuse, avec des values propres à l'entreprise conservées dans Azure DevOps.

helm show values <repo>/<chart>                     # les valeurs par défaut de la chart
helm template <nom> <repo>/<chart> -f values-prd.yaml > rendu.yaml   # voir les manifests produits, sans rien installer

Important

Quand Argo CD déploie une chart, il la rend lui-même (équivalent de helm template) et gère le cycle de vie : helm list dans le namespace peut être vide. Les values effectivement appliquées se lisent dans l'Application Argo CD (onglet Parameters / App details, ou argocd app get <app> -o yaml), pas avec helm get values.

4.3 Exercice#

Modifier une value dans Git (par exemple le nombre de réplicas), faire un refresh, constater OutOfSync, lire le diff, faire la sync, vérifier Healthy, puis retrouver le commit et les événements Kubernetes du changement.


5. Le Run dans un namespace#

5.1 Ce qu'on peut faire, ce qu'on escalade#

kubectl config current-context                     # toujours vérifier le cluster avant tout
kubectl auth can-i get pods -n <ns>                # mes droits réels (RBAC via groupes Entra ID)
kubectl auth can-i create pods/exec -n <ns>
kubectl get resourcequota,limitrange -n <ns>
kubectl describe resourcequota <quota> -n <ns>     # utilisé / autorisé, par ressource
Objet Définition à savoir donner
requests Ce que le conteneur réserve : sert au placement du pod sur un nœud
limits Le plafond : au-delà de la mémoire limite → OOMKilled ; au-delà du CPU limite → ralentissement (throttling)
ResourceQuota Plafond du namespace (CPU, mémoire, nombre d'objets). Une création qui le dépasse est refusée : le pod n'apparaît même pas
LimitRange Valeurs par défaut et bornes par conteneur dans le namespace
StatefulSet Pods avec identité et stockage stables (app-0, app-1) ; il ne gère pas à lui seul la réplication d'une base
PV / PVC Volume persistant / demande de volume par un pod
HPA Ajuste le nombre de réplicas selon une métrique (CPU, mémoire…)
KEDA Scaling piloté par des événements ou des sources externes (file de messages, requêtes…)

Quota dépassé : le Deployment existe mais aucun nouveau pod n'apparaît. Le message est sur le ReplicaSet :

kubectl describe rs -n <ns> -l app=<app>     # événement FailedCreate : ... exceeded quota ...
kubectl get events -n <ns> --sort-by=.lastTimestamp

5.2 Escalader à l'équipe plateforme (modèle de ticket)#

Impact : chatbot X indisponible pour les utilisateurs de Y depuis 14 h 05. Périmètre : namespace chatbot-prd, cluster aks-…. Constat : nouveau pod non créé, FailedCreate: exceeded quota: requests.memory=4Gi, used=3.8Gi, requested=512Mi. Déjà vérifié : pas de fuite (mémoire stable sur 7 jours dans Grafana), demande cohérente avec la montée en charge prévue. Besoin chiffré : passer requests.memory du quota de 4 Gi à 6 Gi, ou valider une réduction des requests à 384 Mi.


6. Web App : chaîne de déploiement et logs#

6.1 « La pipeline est verte mais l'appli ne démarre pas »#

La pipeline a seulement prouvé que l'image est construite et poussée. Vérifier dans l'ordre :

  1. L'image : le tag configuré sur la Web App existe-t-il dans l'ACR ? (az acr repository show-tags)
  2. Le pull : l'identité de la Web App a-t-elle AcrPull, et l'ACR privé est-il joignable (VNet Integration, DNS) ? Logs de plateforme (AppServicePlatformLogs) : échec de pull.
  3. Le port : l'appli écoute-t-elle sur le port attendu (WEBSITES_PORT) ? Message container didn't respond to HTTP pings.
  4. La configuration : variables et références Key Vault résolues ? Logs de console (AppServiceConsoleLogs).
  5. Les dépendances : au démarrage, l'appli joint-elle la base, le coffre, le modèle (DNS privé) ?

Retour arrière : redéployer le dernier tag connu comme sain (relancer la pipeline sur ce tag ou remettre ce tag dans la configuration du conteneur), d'où l'importance de tags immuables (Build.BuildId, SHA du commit) et jamais latest.

6.2 Deux identités, deux droits#

Qui Pour quoi Droit
La pipeline (service connection) Pousser l'image, modifier la Web App Push sur l'ACR (selon le mode RBAC du registre), contributeur sur la Web App
La Web App (identité managée) Tirer l'image AcrPull

Les variable groups centralisent les paramètres (noms, environnements) ; la service connection porte l'identité et son périmètre. Un agent de pipeline (hébergé par Microsoft ou auto-hébergé, par exemple sur VMSS) doit pouvoir joindre les endpoints privés utilisés pendant le déploiement.

6.3 Métriques, logs, traces : trois mécanismes#

  • Avoir des métriques d'une Web App ne prouve pas que ses logs arrivent dans Log Analytics : les métriques de plateforme sont collectées automatiquement, les logs demandent un diagnostic setting.
  • La connection string Application Insights dit où envoyer la télémétrie ; elle n'instrumente pas l'appli à elle seule (il faut un SDK, OpenTelemetry ou l'auto-instrumentation compatible avec la pile).
  • Log stream sert pendant une reproduction en direct ; ce n'est pas un stockage.

Trois requêtes à savoir écrire (adapter le nom des colonnes au schéma de la ressource) :

// 1. Erreurs de console sur une période
AppServiceConsoleLogs
| where TimeGenerated > ago(1h) and _ResourceId has "<nom-webapp>"
| where ResultDescription has_any ("error", "exception")
| project TimeGenerated, ResultDescription
| order by TimeGenerated desc

// 2. Erreurs regroupées par type (Application Insights)
exceptions
| where timestamp > ago(24h)
| summarize nb = count() by type, outerMessage
| order by nb desc

// 3. Chronologie complète d'une requête
union requests, dependencies, exceptions, traces
| where operation_Id == "<operation_Id>"
| project timestamp, itemType, name, target, duration, success, message
| order by timestamp asc

7. Langfuse côté exploitation et reporting#

7.1 Organisation et lecture#

Une instance Langfuse (souvent auto-hébergée dans Kubernetes et gérée centralement) contient des organisations (par exemple développement et production) et des projets (un par application). Avant toute analyse : bonne organisation, bon projet, bon environnement, bonne période.

Une trace = une interaction ; elle contient des observations : appels de modèle (générations), appels d'outils, recherche documentaire, chunks retournés. Pour un agent, plusieurs appels de modèle et d'outils se succèdent dans la même trace : une boucle d'outils se voit à la répétition des observations, et à la hausse des tokens et du coût.

Une vue vide ne prouve pas l'absence de trafic : l'information visible dépend de ce que l'application a instrumenté (si seul le message final est envoyé, on ne voit ni les chunks, ni les appels d'outils, ni les tokens par étape).

7.2 Feedbacks utilisateur#

Le pouce levé ou baissé (et un commentaire) est enregistré comme un score rattaché à la trace :

from langfuse import get_client

langfuse = get_client()
langfuse.create_score(
    trace_id="<id de la trace>",
    name="user-feedback",
    value=1,                      # 1 = pouce levé, 0 = pouce baissé
    comment="Réponse exacte et sourcée",
)

Un feedback négatif ne réentraîne pas le modèle : c'est une donnée d'observation et de reporting, utile pour retrouver les interactions à analyser (filtrer les traces avec un score à 0).

7.3 Export et reporting#

Langfuse propose un export depuis l'interface (extraction ponctuelle filtrée), un export planifié vers un stockage, une API publique et une Metrics API (coût, usage, latence, volume, scores agrégés). Un usage courant : export → stockage → Power BI pour suivre l'usage et les feedbacks, avec des identifiants d'utilisateurs plutôt que leurs noms.

Le coût affiché par Langfuse est un calcul à partir des tokens et d'une table de prix configurée dans l'outil : il peut différer du coût Azure réellement facturé (déploiement, mode de facturation, remises, PTU). Toujours confronter à Cost Management.

7.4 Cas : « les traces existent mais le reporting semble faux »#

Vérification Pourquoi
Projet, organisation, environnement Mélange dev / prod ou mauvaise appli
Fuseau horaire et période Un export en UTC comparé à un rapport en heure de Paris
Filtres et pagination de l'export / de l'API Export tronqué
Rattachement des scores Feedback attaché à la mauvaise trace (identifiant de trace non propagé)
Homogénéité de l'instrumentation Une version de l'appli n'envoie pas les tokens ou les scores
Table de prix des modèles Nom de modèle ou de déploiement non reconnu → coût vide ou faux

8. Document Intelligence Studio : lire un résultat Layout#

Exercice : dans Document Intelligence Studio, choisir Layout, charger un PDF contenant du texte et un tableau, puis comparer le rendu visuel et le JSON :

Partie du JSON (analyzeResult) Contenu
content Tout le texte extrait (en Markdown si demandé)
pages Une entrée par page : mots, lignes, dimensions
paragraphs Les paragraphes, avec leur rôle éventuel (titre, en-tête…)
tables → cells Chaque cellule avec rowIndex, columnIndex et son contenu
sections, figures Structure du document, images détectées

À garder : un exemple de mauvaise extraction (tableau fusionné, colonnes mélangées, texte d'image non lu) et son effet en aval : chunk incohérent → mauvais passage récupéré → réponse fausse alors que tout répond en HTTP 200. La description d'une image par un modèle (« verbalisation ») est une étape supplémentaire possible, pas une fonction du modèle Layout.


9. Azure AI Search : trois précisions qui reviennent#

  • Le champ clé identifie chaque document de recherche : sa valeur est fournie par l'ingestion (par exemple <doc-id>_<n° de chunk>). Ne pas supposer que le service l'invente.
  • Des métadonnées (projet, catégorie, groupe autorisé) permettent de filtrer ; leur seule présence ne sécurise rien : l'application doit appliquer le filtre à chaque requête.
  • Le semantic ranker ne s'applique pas automatiquement : il faut une configuration sémantique et queryType=semantic. Son gain se mesure sur un jeu de questions représentatif, pas sur un chiffre annoncé.

Document manquant dans les réponses : vérifier l'ingestion (job réussi ?), le bon index, les champs chargés (contenu, vecteur, métadonnées) et le filtre de droits appliqué à la requête.


10. Grafana « as code »#

  • Un dashboard contient des panneaux ; chaque panneau a sa requête et peut utiliser sa propre data source (Azure Monitor métriques, Log Analytics en KQL, Prometheus en PromQL).
  • Une variable ($namespace, $app) rend le dashboard réutilisable pour plusieurs applications.
  • L'export JSON (partage → export) conserve la structure et les requêtes ; on peut le réimporter ailleurs ou le déployer par une pipeline.
Langage Données Exemple
KQL Logs et tables Azure (Log Analytics, App Insights) requests | summarize count() by bin(timestamp, 5m), resultCode
PromQL Séries temporelles Prometheus (Azure Monitor workspace) sum(rate(container_cpu_usage_seconds_total{namespace="$namespace"}[5m])) by (pod)

Une seule visualisation vide alors que les autres marchent : regarder d'abord sa requête, sa data source, sa variable et la période ; ensuite seulement les droits de l'identité de Grafana et le réseau (voir chapitre 07). L'accès à l'interface Grafana (rôles Grafana Viewer / Editor / Admin) est distinct de l'accès de Grafana aux données (rôles Azure de son identité managée : Monitoring Reader, Monitoring Data Reader sur l'Azure Monitor workspace).


11. La démarche à raconter#

  1. Qualifier : application, environnement, utilisateurs touchés, début, fréquence, message exact, impact métier.
  2. Reproduire avec une requête et un identifiant de corrélation.
  3. Vérifier les changements récents et la santé de l'hébergement.
  4. Suivre le parcours dans les logs et les traces pour isoler l'étape fautive.
  5. Corriger dans son périmètre ou escalader au bon propriétaire, avec des faits.
  6. Valider par un test métier, puis documenter la cause et l'action préventive.

Ne pas redémarrer ni resynchroniser par réflexe : d'abord recueillir les éléments (logs --previous, événements, trace), sinon la preuve disparaît.


12. Questions à poser en entretien#

  • Quel mécanisme amène les secrets dans les pods : External Secrets Operator, CSI Driver, autre ? Quelles versions ?
  • Comment sont corrélées une trace Langfuse et une requête Application Insights (identifiant commun) ?
  • Quels namespaces, quotas, droits et outils d'accès pour le Run ? Quelle procédure d'escalade vers l'équipe plateforme ?
  • Quels objectifs de disponibilité et de délai de prise en charge (SLO, SLA) ? Comment sont priorisés les incidents ?
  • Quelles versions de Langfuse et d'Argo CD ? La sync est-elle manuelle partout ?
  • Quels sont les incidents les plus fréquents aujourd'hui, et qu'est-ce qui manque le plus à l'équipe Run ?

Références#

Relevé du 23/10/2026.

Sur cette page
Échap

Tape au moins 2 lettres. Plusieurs mots : tous doivent apparaître.