Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
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
HTTPRouteche invia il traffico/v1aInferencePool
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:
- 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.
- Abilitare la funzionalità gateway di inferenza nel controller ALB. Per le nuove installazioni o gli aggiornamenti del controller ALB, includere
--set albController.aiGateway=truenel 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.
- 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.
- Installare gli strumenti seguenti nella workstation o usare Azure Cloud Shell, se disponibili:
- interfaccia della riga di comando di Azure
kubectlhelm
- 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
Gatewaystato includaAccepted=TrueeProgrammed=True. - Verificare che lo
HTTPRoutestato includaAccepted=True,ResolvedRefs=TrueeProgrammed=True. - Verificare che lo
InferencePoolstato includaAccepted=TrueeResolvedRefs=True. - Verificare che il
InferencePoolselettore 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