Portare un modello in produzione, in Azure Machine Learning, significa scegliere fra due modi molto diversi di consumarlo e poi accettare che quel modello verrà sostituito, più di una volta, mentre il servizio è vivo. Chi lavora in MLOps viene valutato soprattutto sulla seconda parte: spostare il traffico da una versione all altra senza fermare nulla, e tornare indietro in un comando quando la nuova versione si comporta male.
Endpoint e deployment non sono la stessa cosa
Un endpoint è un URL stabile e durevole con un meccanismo di autenticazione e di autorizzazione. Un deployment è l insieme di risorse e di compute che ospita davvero il modello e fa l inferenza. Un endpoint online o batch può contenere più deployment e possiede un routing che decide a quale indirizzare le richieste: è questa separazione a rendere possibile il rilascio progressivo.
Le forme disponibili sono tre. Le standard deployment servono a consumare modelli di base del catalogo senza personalizzare lo stack di inferenza: niente deployment multipli, niente routing né mirroring, autenticazione a chiave e nessun consumo di quota di compute della sottoscrizione. Gli online endpoint sono la scelta per l inferenza sincrona a bassa latenza su modelli propri: supportano più deployment, traffic split, mirroring, autenticazione a chiave e con Microsoft Entra ID (in anteprima), e allocano risorse al momento del deploy, quindi si pagano anche mentre non arrivano richieste. I batch endpoint servono all inferenza asincrona su grandi volumi: la invoke non restituisce la previsione ma genera un job, il routing si limita a passare al deployment predefinito, il cluster può scendere a zero nodi e il costo matura solo quando il job gira. Anche l autoscale differisce: sull uso delle risorse per gli online, sul numero di job per i batch.
Distribuire: no-code, scoring script e impostazioni del batch
Su un online endpoint un modello MLflow si distribuisce senza scoring script né environment. Per un modello custom serve uno score.py con init(), eseguita all avvio del container, e run(), invocata a ogni richiesta; il modello si dichiara nel deployment come path locale o come riferimento a un modello registrato e versionato, e dopo la creazione la variabile AZUREML_MODEL_DIR punta alla sua posizione nel container.
$schema: https://azuremlschemas.azureedge.net/latest/managedOnlineDeployment.schema.json
name: green
endpoint_name: credit-scoring
model: azureml:credit-default:8
instance_type: Standard_DS3_v2
instance_count: 2
Il batch ha una firma diversa: init() viene eseguita una volta per processo e run(mini_batch) riceve una lista di file. Le impostazioni che l esame chiede di riconoscere sono mini_batch_size (quanti file arrivano a ogni chiamata), max_concurrency_per_instance, retry_settings con max_retries e timeout, error_threshold (il numero di file falliti tollerati, con -1 che significa nessun limite), output_action con i due valori append_row e summary_only, output_file_name e logging_level.
az ml batch-endpoint invoke --name credit-batch \
--input azureml://datastores/mystore/paths/richieste/ --input-type uri_folder \
--query name -o tsv
Il comando restituisce il nome del job, che si segue con az ml job stream o az ml job show.
Rilascio progressivo e rollback
Lo schema blue/green vive dentro un solo endpoint. Il deployment nuovo si crea con zero traffico, così non riceve richieste reali; lo si prova indirizzando esplicitamente la invoke con --deployment-name green. Il passo successivo è il mirroring: una copia di una percentuale del traffico live viene inviata anche al deployment nuovo, ma la risposta restituita al client resta quella del deployment attivo. Da ricordare i limiti: si può mirrorare verso un solo deployment, il massimo è il 50 percento, non è supportato sugli endpoint online Kubernetes, un deployment riceve traffico live oppure mirrorato ma non entrambi, e se la invoke specifica il deployment il mirroring non avviene.
az ml online-endpoint update --name credit-scoring --mirror-traffic "green=10"
az ml online-endpoint update --name credit-scoring --traffic "blue=90 green=10"
az ml online-endpoint update --name credit-scoring --traffic "blue=0 green=100"
Il rollback è la stessa operazione al contrario: si riporta il traffico su blue con un solo aggiornamento, senza ricostruire nulla, e solo dopo si elimina il deployment fallito. È il motivo per cui il vecchio deployment va tenuto in piedi per qualche tempo dopo il cutover, e per cui la percentuale di mirroring va riportata a zero quando il test è finito.
Testare e diagnosticare
Prima del cloud conviene il locale: aggiungendo --local il deployment gira in Docker sulla macchina di sviluppo, con creazione, aggiornamento, invoke e log. In cloud i log si leggono con az ml online-deployment get-logs, che di default mostra il server di inferenza — cioè l output di print e logging dello scoring script — mentre con l opzione di container si legge lo storage initializer, utile quando modello o codice non sono stati scaricati.
Gli errori di deployment hanno nomi ricorrenti: ImageBuildFailure quando la build dell immagine fallisce (il log sta nello storage predefinito del workspace), OutOfQuota quando manca quota di CPU, cluster, disco, memoria o endpoint, ResourceNotReady quando il container va in crash all avvio, tipicamente per un errore in score.py o per probe troppo strette, ResourceNotFound quando un percorso o un registry privato non sono raggiungibili. Lato consumo contano invece gli stati HTTP: 401 per credenziali o token, 404 quando nessun deployment ha peso positivo, 408 per timeout, 424 quando è il container del modello a restituire un errore, 429 per troppe richieste, 502 per un eccezione nel metodo run().
Da ricordare per l esame
- Endpoint è l URL con autenticazione, deployment è ciò che esegue il modello: solo online e batch supportano più deployment sullo stesso endpoint.
- Online significa risposta sincrona e risorse sempre allocate; batch significa job asincrono, cluster che scala a zero e costo solo durante l esecuzione.
- Nel batch,
run()riceve un mini batch di file;output_actionaccettaappend_rowosummary_onlyederror_thresholda-1tollera qualunque numero di fallimenti. - Il mirroring va a un solo deployment, al massimo al 50 percento, non su Kubernetes, e non restituisce mai la risposta al client.
- Il rollback è un aggiornamento del traffico verso il deployment precedente, non un nuovo rilascio;
ResourceNotReadypunta quasi sempre ascore.py, da provare in locale con--local.