Gateway applicativo per contenitori - Configurare il gateway di inferenza

Questo articolo illustra come esporre un server di modelli vLLM ospitato autonomamente tramite il gateway di inferenza di Application Gateway for Containers utilizzando l'estensione di inferenza dell'API Gateway di Kubernetes. La configurazione usa le risorse dell'API gateway, un InferencePoole l'estensione EPP (Endpoint Picker) per instradare le richieste di inferenza ai pod del server modello.

In questa guida, distribuirai:

  • Un server modello vLLM basato su GPU che gestisce un'API compatibile con OpenAI
  • Risorse dell'estensione di inferenza di Gateway API
  • Un gateway
  • Una distribuzione EPP, un servizio e InferencePool
  • Un HTTPRoute che invia il traffico /v1 a InferencePool

Come si integrano i componenti

Gateway applicazione per contenitori riceve le richieste in corrispondenza del listener Gateway e le confronta con un elemento HTTPRoute. Quando il backendRef della route è un InferencePool, il controller ALB configura il percorso dei dati per consultare l'Endpoint Picker (EPP) per ogni richiesta. EPP monitora i pod che corrispondono al selettore InferencePool, legge le metriche di vLLM (profondità della coda, utilizzo della cache KV, modelli serviti) e indica al piano dati a quale pod specifico inviare la richiesta.

Importante

Il gateway di inferenza per Application Gateway for Containers è attualmente in anteprima.
Vedi le Condizioni supplementari d'uso per le anteprime di Microsoft Azure per conoscere le condizioni legali applicabili alle funzionalità di Azure che sono in beta, in anteprima o non ancora rilasciate nella disponibilità generale.

Prerequisiti

Prima di iniziare, completare le attività seguenti:

  1. Distribuisci Application Gateway per i contenitori e il controller ALB. Per altre informazioni, vedere Avvio rapido: Distribuire il controller ALB del gateway applicativo per contenitori.
  2. Abilitare la funzionalità gateway di inferenza nel controller ALB. Per le nuove installazioni o gli aggiornamenti del controller ALB, includere --set albController.aiGateway=true nel comando Helm. Quando abiliti questa impostazione, ALB Controller installa anche la versione 1.3.1 dei CRD di Gateway API Inference Extension.

Note

Inference gateway attualmente non è supportato tramite l'add-on AKS di Application Gateway for Containers. Per configurare questa funzionalità, è necessario distribuire il controller ALB del gateway applicazione per contenitore per grafico Helm.

  1. Preparare un cluster AKS con un pool di nodi GPU con almeno una GPU schedulabile e il plug-in del dispositivo NVIDIA installato. Per istruzioni, vedere Usare GPU per carichi di lavoro a elevato utilizzo di calcolo nel servizio Azure Kubernetes.
  2. Installare gli strumenti seguenti nella workstation o usare Azure Cloud Shell, se disponibili:
    • interfaccia della riga di comando di Azure
    • kubectl
    • helm
  3. Creare o ottenere un token di accesso Hugging Face che consenta di scaricare il modello usato dal deployment vLLM.

Impostare le variabili di ambiente

Impostare le variabili usate dai comandi in questo articolo.

NAMESPACE='inference'
INFERENCE_POOL_NAME='vllm-qwen2-5-0-5b'
MODEL_NAME='Qwen/Qwen2.5-0.5B-Instruct'
GATEWAY_NAME='ai-gateway'
HF_TOKEN='<your Hugging Face access token>'

Se utilizzi la strategia di distribuzione gestita di ALB, imposta lo spazio dei nomi e il nome della risorsa ApplicationLoadBalancer.

ALB_NAMESPACE='alb-test-infra'
ALB_NAME='alb-test'

Creare uno spazio dei nomi

Crea un namespace per le risorse del server del modello, Gateway, HTTPRoute, InferencePool ed EPP.

kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f -

Verificare le CRD dell'estensione di inferenza di Gateway API

Verifica che ALB Controller abbia installato le CRD di Gateway API Inference Extension.

kubectl get crds | grep inference.networking

Risultato previsto (nomi CRD; marche temporali di creazione diverse):

inferenceobjectives.inference.networking.x-k8s.io   2026-05-06T22:07:44Z
inferencepools.inference.networking.k8s.io          2026-05-06T22:07:45Z

Distribuire un server modello vLLM

Creare un segreto Kubernetes per il token di accesso di Hugging Face.

kubectl create secret generic hf-token \
  --namespace $NAMESPACE \
  --from-literal=token=$HF_TOKEN \
  --dry-run=client -o yaml | kubectl apply -f -

Distribuire un server modello vLLM. L'esempio usa Qwen/Qwen2.5-0.5B-Instruct, ma la configurazione di Application Gateway for Containers e dell'estensione di inferenza di Gateway API è indipendente dal modello. È possibile sostituire qualsiasi modello compatibile con vLLM che si adatti allo SKU della GPU.

Il pod vLLM richiede un nvidia.com/gpu e tollera una contaminazione sku=gpu:NoSchedule, quindi viene eseguito su un nodo GPU. Rimuovere la tolleranza se il pool di nodi non è contaminato, oppure applicare la contaminazione con kubectl taint nodes -l agentpool=<gpu-pool> sku=gpu:NoSchedule. Le etichette dei pod (app: ${INFERENCE_POOL_NAME}) sono quelle che InferencePool usa in seguito per la selezione, quindi non modificarle senza aggiornare anche il valore inferencePool.modelServers.matchLabels.app del chart.

kubectl apply -n $NAMESPACE -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${INFERENCE_POOL_NAME}
  labels:
    app: ${INFERENCE_POOL_NAME}
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ${INFERENCE_POOL_NAME}
  template:
    metadata:
      labels:
        app: ${INFERENCE_POOL_NAME}
        inference.networking.k8s.io/engine-type: vllm
    spec:
      containers:
      - name: vllm
        image: vllm/vllm-openai:latest
        imagePullPolicy: Always
        command: ["python3", "-m", "vllm.entrypoints.openai.api_server"]
        args:
        - "--model"
        - "${MODEL_NAME}"
        - "--port"
        - "8000"
        - "--max-model-len"
        - "2048"
        - "--gpu-memory-utilization"
        - "0.8"
        env:
        - name: HUGGING_FACE_HUB_TOKEN
          valueFrom:
            secretKeyRef:
              name: hf-token
              key: token
        ports:
        - containerPort: 8000
          name: http
          protocol: TCP
        readinessProbe:
          httpGet:
            path: /health
            port: http
          periodSeconds: 5
          failureThreshold: 12
        startupProbe:
          httpGet:
            path: /health
            port: http
          periodSeconds: 10
          failureThreshold: 60
        resources:
          limits:
            nvidia.com/gpu: "1"
          requests:
            nvidia.com/gpu: "1"
        volumeMounts:
        - mountPath: /dev/shm
          name: shm
      tolerations:
      - key: "sku"
        operator: "Equal"
        value: "gpu"
        effect: "NoSchedule"
      - key: "nvidia.com/gpu"
        operator: "Exists"
        effect: "NoSchedule"
      volumes:
      - name: shm
        emptyDir:
          medium: Memory
EOF

Attendere che il server del modello sia pronto. Il download e l'avvio del modello possono richiedere alcuni minuti.

kubectl rollout status deployment/${INFERENCE_POOL_NAME} -n $NAMESPACE --timeout=900s

Output previsto:

deployment "vllm-qwen2-5-0-5b" successfully rolled out

Creare il gateway

Creare un gateway Gateway applicazione per contenitori. Selezionare la scheda relativa alla strategia di distribuzione.

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: ${GATEWAY_NAME}
  namespace: ${NAMESPACE}
  annotations:
    alb.networking.azure.io/alb-namespace: ${ALB_NAMESPACE}
    alb.networking.azure.io/alb-name: ${ALB_NAME}
spec:
  gatewayClassName: azure-alb-external
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: Same
EOF

Attendere che il gateway venga programmato.

kubectl wait \
  --for=condition=Programmed \
  gateway/${GATEWAY_NAME} \
  -n $NAMESPACE \
  --timeout=300s

Quando è pronto, viene visualizzato il messaggio seguente:

gateway.gateway.networking.k8s.io/ai-gateway condition met

Distribuisci InferencePool e il selettore di endpoint

Distribuisci EPP e InferencePool insieme utilizzando il inferencepool chart Helm pubblicato dal progetto Kubernetes Gateway API Inference Extension. Il chart crea un EPP Deployment, una Service sulla porta 9002, ServiceAccount, Role e RoleBinding che consentono all’EPP di monitorare i pod, e la risorsa InferencePool stessa (con il nome della release Helm).

IGW_CHART_VERSION='v1.3.1'
EPP_IMAGE_TAG='v1.3.1'

Installare il grafico.

Note

Il chart aggiunge -epp al nome della release Helm quando assegna il nome a EPP Deployment e Service (${INFERENCE_POOL_NAME}-epp). I passaggi successivi fanno riferimento a quel nome durante il controllo dello stato dell'implementazione, la visualizzazione dei log in tempo reale e l'ispezione delle sezioni degli endpoint.

helm upgrade --install "${INFERENCE_POOL_NAME}" \
  --namespace "${NAMESPACE}" \
  --set "inferencePool.modelServers.matchLabels.app=${INFERENCE_POOL_NAME}" \
  --set "inferenceExtension.image.tag=${EPP_IMAGE_TAG}" \
  --set "provider.name=none" \
  --version "${IGW_CHART_VERSION}" \
  oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool

Avvertimento

Il chart Helm inferencepool gestito dal progetto Kubernetes Gateway API Inference Extension genera una risorsa InferencePool con il nome della release Helm. Se un InferencePool con lo stesso nome esiste già nello spazio dei nomi ed è stato creato al di fuori di Helm, helm upgrade --install si rifiuta di adottarlo e il comando ha esito negativo con un errore invalid ownership metadata. Se il pool esistente è di proprietà di una release Helm diversa, l'installazione sovrascrive la specifica di quel InferencePool, compresa la reimpostazione dell'immagine EPP, del selettore e di endpointPickerRef sui valori predefiniti del chart v1.3.1. Prima di eseguire il comando, eliminare il pool esistente (kubectl delete inferencepool <name> -n $NAMESPACE) o selezionare un altro INFERENCE_POOL_NAME per questa guida.

Attendere che la distribuzione EPP diventi disponibile.

kubectl rollout status deployment/${INFERENCE_POOL_NAME}-epp -n $NAMESPACE --timeout=180s

Quando è pronto, viene visualizzato il messaggio seguente:

deployment "vllm-qwen2-5-0-5b-epp" successfully rolled out

Verificare InferencePool

Il chart Helm ha creato una risorsa InferencePool denominata ${INFERENCE_POOL_NAME} che seleziona i pod etichettati app=${INFERENCE_POOL_NAME} e fa riferimento al servizio EPP installato dal chart. Verificare che esista.

kubectl get inferencepool ${INFERENCE_POOL_NAME} -n $NAMESPACE -o yaml

Cercare Accepted=True e ResolvedRefs=True nello stato InferencePool.

Crea l'HTTPRoute

Crea un HTTPRoute che usa InferencePool come backend per Gateway API.

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: ${INFERENCE_POOL_NAME}
  namespace: ${NAMESPACE}
spec:
  parentRefs:
  - name: ${GATEWAY_NAME}
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /v1
    backendRefs:
    - group: inference.networking.k8s.io
      kind: InferencePool
      name: ${INFERENCE_POOL_NAME}
EOF

Verificare lo stato della route

Verificare che l'HTTPRoute sia stato accettato e che i riferimenti siano stati risolti.

kubectl get httproute ${INFERENCE_POOL_NAME} -n $NAMESPACE -o yaml

Cercare condizioni simili all'output seguente.

  status:
    parents:
    - conditions:
      - lastTransitionTime: "2026-05-07T03:54:14Z"
        message: ""
        observedGeneration: 3
        reason: ResolvedRefs
        status: "True"
        type: ResolvedRefs
      - lastTransitionTime: "2026-05-07T03:54:14Z"
        message: Route is Accepted
        observedGeneration: 3
        reason: Accepted
        status: "True"
        type: Accepted
      - lastTransitionTime: "2026-05-07T03:54:14Z"
        message: Application Gateway for Containers resource has been successfully
          updated.
        observedGeneration: 3
        reason: Programmed
        status: "True"
        type: Programmed
      controllerName: alb.networking.azure.io/alb-controller
      parentRef:
        group: gateway.networking.k8s.io
        kind: Gateway
        name: ai-gateway

Inviare il traffico di inferenza

Ottenere l'indirizzo del gateway.

GATEWAY_ADDRESS=$(kubectl get gateway/${GATEWAY_NAME} \
  -n $NAMESPACE \
  -o jsonpath='{.status.addresses[0].value}')

Invia una richiesta di completamento chat tramite Application Gateway for Containers.

curl -i http://${GATEWAY_ADDRESS}/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d "{
    \"model\": \"${MODEL_NAME}\",
    \"messages\": [{\"role\": \"user\", \"content\": \"What is 2+2? Answer in one word.\"}],
    \"max_tokens\": 10
  }"

Risposta prevista (ID, timestamp e conteggi dei token saranno diversi):

HTTP/1.1 200 OK
content-type: application/json

{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "model": "Qwen/Qwen2.5-0.5B-Instruct",
  "choices": [{
    "index": 0,
    "message": {"role": "assistant", "content": "Four."},
    "finish_reason": "stop"
  }],
  "usage": {"prompt_tokens": 18, "completion_tokens": 2, "total_tokens": 20}
}

È anche possibile testare i completamenti del testo.

curl -i http://${GATEWAY_ADDRESS}/v1/completions \
  -H 'Content-Type: application/json' \
  -d "{
    \"model\": \"${MODEL_NAME}\",
    \"prompt\": \"San Francisco is\",
    \"max_tokens\": 50
  }"

Facoltativo: creare un oggetto InferenceObjective

Crea un InferenceObjective quando vuoi che i client segnalino la priorità di servizio all'EPP. L'EPP utilizza l'obiettivo; HTTPRoute non vi fa riferimento direttamente. I valori priority più elevati vengono serviti prima di quelli inferiori quando l'EPP deve ridurre il carico.

Avvertimento

La risorsa InferenceObjective è attualmente nel gruppo API inference.networking.x-k8s.io/v1alpha2, mentre InferencePool è passata a v1; i due gruppi coesistono mentre l'API InferenceObjective si sta stabilizzando. Aspettarsi modifiche all'API nella risorsa.

kubectl apply -n $NAMESPACE -f - <<EOF
apiVersion: inference.networking.x-k8s.io/v1alpha2
kind: InferenceObjective
metadata:
  name: critical-inference
spec:
  poolRef:
    group: inference.networking.k8s.io
    kind: InferencePool
    name: ${INFERENCE_POOL_NAME}
  priority: 10
EOF

Inviare una richiesta che usa l'obiettivo.

curl -i http://${GATEWAY_ADDRESS}/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -H 'x-gateway-inference-objective: critical-inference' \
  -d "{
    \"model\": \"${MODEL_NAME}\",
    \"messages\": [{\"role\": \"user\", \"content\": \"Summarize what an inference gateway does.\"}],
    \"max_tokens\": 80
  }"

Osserva il comportamento del selettore di endpoint

Esaminare i log EPP per confermare che le richieste passano attraverso la selezione dell'endpoint.

kubectl logs deployment/${INFERENCE_POOL_NAME}-epp -n $NAMESPACE --tail=100

Esaminare le metriche vLLM dal pod del server modello.

POD=$(kubectl get pods -n $NAMESPACE -l app=${INFERENCE_POOL_NAME} -o jsonpath='{.items[0].metadata.name}')

kubectl exec -n $NAMESPACE $POD -- curl -s http://localhost:8000/metrics \
  | grep -E "^vllm:(num_requests_waiting|num_requests_running|kv_cache_usage_perc)"

Troubleshoot

Se il traffico non raggiunge il server modello, usare i controlli seguenti:

  • Verificare che il controller ALB sia in esecuzione con la funzionalità gateway di intelligenza artificiale abilitata.
  • Verificare che lo Gateway stato includa Accepted=True e Programmed=True.
  • Verificare che lo HTTPRoute stato includa Accepted=True, ResolvedRefs=Truee Programmed=True.
  • Verificare che lo InferencePool stato includa Accepted=True e ResolvedRefs=True.
  • Verificare che il InferencePool selettore corrisponda alle etichette nei pod vLLM.
  • Verificare che il servizio EPP e la distribuzione siano in esecuzione nello stesso spazio dei nomi di InferencePool.
  • Verificare che i pod del server dei modelli siano pronti ed espongano la porta 8000.
  • Esaminare i log EPP per individuare errori di selezione degli endpoint o errori di ricerca del modello.

Errori comuni

Sintomo Causa possibile Correzione
Pod vLLM bloccato in Pending Nessuna GPU allocabile, i taint non corrispondono alle tolleranze del pod oppure la risorsa nvidia.com/gpu non è pubblicizzata dal plugin del dispositivo. Usa kubectl describe pod per vedere il messaggio dell'Utilità di pianificazione. Verificare che il pool di nodi GPU esista, che il DaemonSet del plug-in del dispositivo NVIDIA sia Ready e che la tolleranza corrisponda alla contaminazione.
Pod vLLM in CrashLoopBackOff con 401 Unauthorized nei log Il token di Hugging Face non è valido, è scaduto o non dispone dell'accesso al modello. Ricreare il hf-token segreto con un token che abbia accesso in lettura al repository dei modelli, quindi eseguire kubectl rollout restart deployment/${INFERENCE_POOL_NAME}.
HTTPRoute lo stato mostra ResolvedRefs=False con reason: BackendNotFound e message: InferencePool <namespace>/<name> not found Il nome di HTTPRoutebackendRef non corrisponde a un InferencePool esistente, oppureInferencePool esiste ma non dispone di endpoint pronti (ad esempio, il pod vLLM è Pending perché non è stato possibile pianificare o scalare un nodo GPU). Il controller ALB segnala un pool con zero endpoint disponibili come BackendNotFound. Esegui kubectl get inferencepool -n $NAMESPACE per confermare che il nome corrisponda al backendRef del percorso. Esegui quindi kubectl get pods -n $NAMESPACE -l app=${INFERENCE_POOL_NAME} e kubectl describe pod <pod> -n $NAMESPACE. Se il pod è Pending con eventi FailedScheduling come Insufficient nvidia.com/gpu o untolerated taint(s), aumentare le dimensioni del pool di nodi GPU, correggere la tolleranza o selezionare uno SKU con capacità GPU disponibile.
curl restituisce 503 dal gateway EPP non è in grado di raggiungere il pool (nessun endpoint pronto) oppure il nome del servizio EPP in endpointPickerRef non viene risolto correttamente. Controllare kubectl get endpointslices -n $NAMESPACE -l kubernetes.io/service-name=${INFERENCE_POOL_NAME}-epp e confermare che InferencePool.spec.endpointPickerRef.name corrisponda al nome del servizio installato dal chart.
curl restituisce 404 Il percorso non corrisponde a HTTPRoute. Verificare che il percorso della richiesta inizi con /v1 e che la route parentRefs faccia riferimento allo stesso gateway nello stesso spazio dei nomi.
Le richieste rimangono bloccate per >60 secondi, quindi si verifica un errore VLLM sta ancora caricando il modello in memoria GPU. Attendere che la probe di idoneità abbia esito positivo; seguire i log di vLLM finché non viene visualizzato Application startup complete.

Pulire le risorse

Elimina le risorse create in questo articolo.

kubectl delete inferenceobjective critical-inference -n $NAMESPACE --ignore-not-found
kubectl delete httproute ${INFERENCE_POOL_NAME} -n $NAMESPACE --ignore-not-found
helm uninstall ${INFERENCE_POOL_NAME} -n $NAMESPACE 2>/dev/null || true
kubectl delete gateway ${GATEWAY_NAME} -n $NAMESPACE --ignore-not-found
kubectl delete deployment ${INFERENCE_POOL_NAME} -n $NAMESPACE --ignore-not-found
kubectl delete secret hf-token -n $NAMESPACE --ignore-not-found
kubectl delete namespace $NAMESPACE --ignore-not-found

Passaggi successivi