# Model Deployment Strategies on Azure

**Område:** MLOps & GenAIOps
**Dato:** 2026-02-04
**Målgruppe:** Arkitekter som planlegger ML-modellutplassering i produksjon
**Konfidensgrad:** ⚡️⚡️⚡️ Høy (basert på Microsoft Learn + offisielle code samples)

## Introduksjon

Model deployment strategies handler om hvordan man trygt og effektivt ruller ut nye ML-modeller eller modellversjoner til produksjon uten å forårsake nedetid eller forringet brukeropplevelse. Azure Machine Learning tilbyr flere deployment patterns som støtter **progressive exposure**, **traffic routing**, og **rollback-mekanismer**.

Korrekt valg av deployment strategy reduserer risiko, muliggjør raskere iterasjoner, og sikrer at feil oppdages tidlig før full produksjonsrullering. Dette er spesielt kritisk for GenAI-løsninger hvor modelloppførsel kan variere betydelig mellom versjoner.

**Hovedutfordringer:**
- Unngå service disruption ved modellbytte
- Validere ny modell mot reell produksjonstrafikk
- Kunne rulle tilbake raskt ved feil
- Sammenligne modellytelse mellom versjoner (A/B testing)
- Håndtere stateful components (databaser, schemas) ved rollback

## Kjernekomponenter

### 1. Azure Machine Learning Online Endpoints

**Online endpoints** er det primære konseptet for real-time inferencing i Azure ML. Et endpoint fungerer som et API som klienter kan konsumere, mens underliggende **deployments** representerer den faktiske implementasjonen.

**Nøkkelkonsept:**
- **Endpoint** = API-kontrakten (URL, autentisering)
- **Deployment** = Konkret modellversjon + infrastruktur + scoring script
- Ett endpoint kan ha **flere deployments** samtidig
- Traffic routing styres på endpoint-nivå

**To typer online endpoints:**
1. **Managed Online Endpoints** – Azure administrerer infrastruktur (anbefalt)
2. **Kubernetes Online Endpoints** – Du administrerer AKS-cluster

**Eksempel (Python SDK):**
```python
from azure.ai.ml.entities import ManagedOnlineEndpoint, ManagedOnlineDeployment

# Opprett endpoint
endpoint = ManagedOnlineEndpoint(
    name="heart-classifier-endpoint",
    auth_mode="key",
    description="Production endpoint for heart disease classifier"
)
ml_client.online_endpoints.begin_create_or_update(endpoint).result()

# Deployment (med modell, environment, scoring script)
blue_deployment = ManagedOnlineDeployment(
    name="blue",
    endpoint_name="heart-classifier-endpoint",
    model=model,
    environment=env,
    code_configuration=CodeConfiguration(code="./src", scoring_script="score.py"),
    instance_type="Standard_DS3_v2",
    instance_count=2
)
ml_client.online_deployments.begin_create_or_update(blue_deployment).result()

# Allokér all trafikk til blue
endpoint.traffic = {"blue": 100}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()
```

**Referanse:** [Managed online endpoints](https://learn.microsoft.com/en-us/azure/machine-learning/concept-endpoints-online?view=azureml-api-2)

---

### 2. Blue-Green Deployment

**Blue-green deployment** er en strategi der to identiske miljøer (blue = nåværende, green = ny) kjører parallelt. Trafikken byttes gradvis fra blue til green, og man kan raskt rulle tilbake ved feil.

**Workflow:**
1. **Blue (v1)** kjører i produksjon med 100% trafikk
2. Deploy **Green (v2)** til samme endpoint med 0% trafikk
3. Test Green isolert (via deployment-name parameter)
4. Allokér små andeler trafikk til Green (10%, 25%, 50%)
5. Monitorér health metrics, error rates, latency
6. Gradvis øk til 100% Green
7. Fjern Blue deployment når Green er stabil

**Eksempel (Azure CLI):**
```bash
# Deploy green deployment (0% traffic)
az ml online-deployment create --name green \
  --endpoint-name $ENDPOINT_NAME \
  -f green-deployment.yml

# Test green isolert
az ml online-endpoint invoke --name $ENDPOINT_NAME \
  --deployment-name green \
  --request-file sample.json

# Allokér 10% trafikk til green
az ml online-endpoint update --name $ENDPOINT_NAME \
  --traffic "blue=90 green=10"

# Monitorér, deretter 100% til green
az ml online-endpoint update --name $ENDPOINT_NAME \
  --traffic "blue=0 green=100"

# Slett blue deployment
az ml online-deployment delete --name blue \
  --endpoint-name $ENDPOINT_NAME --yes
```

**Fordeler:**
- Null downtime
- Enkel rollback (bare bytt trafikk tilbake)
- Tester mot reell produksjonstrafikk
- Støtter gradvis rollout

**Ulemper:**
- Krever dobbelt ressurskapasitet under rullering
- Komplisert ved stateful components (database migrations)

**Referanse:** [Safe rollout for real-time inference](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-safely-rollout-online-endpoints?view=azureml-api-2)

---

### 3. Canary Deployment

**Canary deployment** er en variant av progressive exposure der en liten "kanari-gruppe" av brukere får tilgang til den nye versjonen først. Dette kan være interne brukere, beta-testere, eller en geografisk region.

**Workflow:**
1. Deploy ny versjon til subset av infrastruktur (f.eks. én AKS-node)
2. Route 5-10% av trafikk til canary
3. Samle metrics og feedback fra canary-gruppen
4. Utvid gradvis til 25%, 50%, 100%
5. Rulle tilbake hvis canary viser feil

**Azure implementering:**
- For **AKS deployments**: Bruk Kubernetes Deployment Stamps pattern
- For **Managed Endpoints**: Samme som blue-green, men fokus på små initial percentages

**Eksempel (Azure DevOps Pipelines):**
```yaml
# Deploy canary with 10% traffic
- task: KubernetesManifest@1
  inputs:
    action: 'deploy'
    strategy: 'canary'
    percentage: '10'
    manifests: 'manifests/deployment.yml'
```

**Fordeler:**
- Tidlig feil-deteksjon
- Begrenset blast radius ved feil
- God for testing av nye features med ekte brukere

**Ulemper:**
- Krever sofistikert traffic routing (feature flags, load balancer)
- Kan være vanskelig å isolere canary-trafikk for debugging

**Referanse:** [Canary deployment for Kubernetes](https://learn.microsoft.com/en-us/azure/devops/pipelines/ecosystems/kubernetes/canary-demo?view=azure-devops)

---

### 4. Shadow Deployment (Traffic Mirroring)

**Shadow deployment** kopierer en prosentandel av live trafikk til en ny deployment uten å returnere resultater til klienten. Dette lar deg validere ny modell mot reell produksjonsdata uten å påvirke brukere.

**Nøkkelkonsept:**
- **Mirror traffic** = Kopier requests til shadow deployment
- Klienten får alltid svar fra primær deployment (blue)
- Shadow deployment (green) logger metrics, men påvirker ikke response
- Maks 50% mirror traffic (bandwidth quota limits)

**Eksempel (Python SDK):**
```python
# Mirror 10% av trafikk til green
endpoint.mirror_traffic = {"green": 10}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()

# Invoke endpoint flere ganger (trafikk går til blue, 10% mirrors til green)
for i in range(100):
    ml_client.online_endpoints.invoke(
        endpoint_name=endpoint_name,
        request_file="sample.json"
    )

# Sjekk green logs for validering
ml_client.online_deployments.get_logs(
    name="green",
    endpoint_name=endpoint_name,
    lines=100
)

# Disable mirroring
endpoint.mirror_traffic = {"green": 0}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()
```

**Begrensninger:**
- **Ikke støttet** for Kubernetes online endpoints
- Maks 50% mirror traffic (p.g.a. endpoint bandwidth quota)
- Kun én deployment kan motta mirrored traffic
- En deployment kan **ikke** motta både live og mirrored traffic

**Use cases:**
- Validere latency for ny modell
- Sjekke for HTTP errors før live traffic
- Sammenligne predictions mellom modeller (offline analysis)

**Referanse:** [Traffic mirroring documentation](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-safely-rollout-online-endpoints?view=azureml-api-2#test-the-deployment-with-mirrored-traffic)

---

### 5. A/B Testing

**A/B testing** router trafikk mellom to (eller flere) modellversjoner for å sammenligne performance metrics, conversion rates, eller brukeropplevelse.

**Implementering i Azure ML:**
```python
# 50/50 split mellom v1 og v2
endpoint.traffic = {"model-v1": 50, "model-v2": 50}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()
```

**Viktige poeng:**
- Total traffic **må** summere til 100% (eller 0% for disable)
- Bruk Application Insights for å tracke metrics per deployment
- Samle nok data før konklusjon (statistisk signifikans)

**Advanced: Target specific deployment via HTTP header:**
```python
# Klient kan overstyre traffic routing med header:
# azureml-model-deployment: model-v2
```

**Referanse:** [Controlled rollout for online endpoints](https://learn.microsoft.com/en-us/azure/machine-learning/concept-model-management-and-deployment?view=azureml-api-2#model-registration,-packaging,-and-deployment)

---

## Arkitekturmønstre

### Mønster 1: Progressive Rollout for Managed Endpoints

**Scenario:** Du har en produksjonsmodell (v1) og vil deploye v2 med minimal risiko.

**Steg:**
1. **Deploy v2 med 0% traffic**
   ```bash
   az ml online-deployment create --name v2 \
     --endpoint-name prod-endpoint -f v2-deployment.yml
   ```

2. **Test isolert**
   ```bash
   az ml online-endpoint invoke --name prod-endpoint \
     --deployment-name v2 --request-file test-data.json
   ```

3. **Mirror 10% trafikk for validation** (valgfritt)
   ```bash
   az ml online-endpoint update --name prod-endpoint \
     --mirror-traffic "v2=10"
   ```
   **Bake time:** 6-12 timer. Sjekk logs for errors, latency, HTTP 500s.

4. **Start live traffic med 10%**
   ```bash
   az ml online-endpoint update --name prod-endpoint \
     --traffic "v1=90 v2=10" --mirror-traffic "v2=0"
   ```
   **Bake time:** 24 timer. Monitorér Application Insights metrics.

5. **Øk gradvis til 25%, 50%, 100%**
   ```bash
   # 50/50 split
   az ml online-endpoint update --name prod-endpoint \
     --traffic "v1=50 v2=50"

   # Full rollout
   az ml online-endpoint update --name prod-endpoint \
     --traffic "v1=0 v2=100"
   ```
   **Bake time:** Øk mellom hver fase (24-48 timer for 50%, 72 timer før 100%).

6. **Fjern v1 deployment**
   ```bash
   az ml online-deployment delete --name v1 \
     --endpoint-name prod-endpoint --yes
   ```

**Health checks per fase:**
- HTTP error rate < 0.1%
- p95 latency < SLA threshold
- Model prediction drift innenfor toleranse
- No increase in retry/timeout errors

---

### Mønster 2: Blue-Green med Database Migrations

**Utfordring:** Stateful components (database schema endringer) kompliserer rollback.

**Løsning: Backward-compatible schema migrations**

**Steg:**
1. **Deploy database schema v2 (backward compatible)**
   - Nye kolonner har default values
   - Gamle kolonner beholdes (deprecated, ikke fjernet)
   - Applikasjonen kan kjøre mot begge schemas

2. **Deploy blue (v1) og green (v2) parallelt**
   - Begge deployments bruker samme database
   - v1 ignorerer nye kolonner
   - v2 populerer nye kolonner

3. **Gradvis trafikk-bytte (som tidligere)**

4. **Cleanup fase (etter 100% green)**
   - Kjør datamigrasjon script for å fylle nye kolonner (for gamle rader)
   - Etter 1-2 uker, fjern deprecated kolonner

**Rollback-strategi:**
- Hvis feil oppdages før cleanup: Bare bytt trafikk tilbake til blue
- Hvis feil oppdages etter cleanup: Krever restore fra backup (derfor lang bake time)

---

### Mønster 3: Multi-Region Deployment with Canary

**Scenario:** Global produksjonsmodell med brukere i Europa, USA, Asia.

**Arkitektur:**
```
Azure Front Door (global load balancer)
├── Region: West Europe
│   ├── Endpoint: eu-prod-endpoint
│   │   ├── Deployment: blue (v1)
│   │   └── Deployment: green (v2) [canary]
├── Region: East US
│   └── Endpoint: us-prod-endpoint
│       └── Deployment: blue (v1)
└── Region: Southeast Asia
    └── Endpoint: asia-prod-endpoint
        └── Deployment: blue (v1)
```

**Rollout plan:**
1. **Deploy green til West Europe endpoint** (10% trafikk)
2. **Bake time:** 48 timer (dekker ulike tidssoner i Europa)
3. **Hvis OK:** Øk til 100% i West Europe
4. **Deploy green til East US** (10% trafikk)
5. **Bake time:** 48 timer
6. **Hvis OK:** Øk til 100% i East US
7. **Deploy green til Southeast Asia** (10% trafikk)
8. **Final bake:** 48 timer, deretter 100%

**Fordel:** Begrenser blast radius til én region. Hvis West Europe feiler, USA og Asia er upåvirket.

---

## Beslutningsveiledning

### Når bruke hvilken strategi?

| Strategi | Bruk når... | Ikke bruk når... |
|----------|-------------|------------------|
| **Blue-Green** | - Kritisk produksjonsmodell<br>- Trenger rask rollback<br>- Kan doble infrastruktur midlertidig | - Svært stateful (kompleks database)<br>- Knappe ressurser (cost constraints) |
| **Canary** | - Ny feature med ukjent impact<br>- Interne brukere kan teste først<br>- Geografisk segmenterte brukere | - Alle brukere må få samme versjon<br>- Real-time consistency krav |
| **Shadow Deployment** | - Validere ytelse før live traffic<br>- Sammenligne modellpredictions offline<br>- Testing av latency/throughput | - Bandwidth quotas er trange<br>- Trenger immediate feedback fra brukere |
| **A/B Testing** | - Business-critical decision (f.eks. recommendation model)<br>- Trenger statistisk signifikant sammenligning | - Raskt behov for rollout<br>- Ikke nok trafikk for statistisk kraft |
| **Progressive Rollout** | - Standard for alle produksjonsdeployments<br>- Alltid kombinert med en av strategiene over | - (Alltid bruk progressive rollout!) |

---

### Beslutningstre

```
START: Skal deploye ny modellversjon?
│
├─ Er dette første produksjonsdeployment?
│  └─ JA → Deploy single deployment (100% traffic) → Ferdig
│
├─ Har du stateful components (database)?
│  ├─ JA → Implementer backward-compatible migrations først
│  └─ NEI → Fortsett
│
├─ Trenger du sammenligne to versjoner for business metrics?
│  ├─ JA → A/B Testing (50/50 eller annen split)
│  └─ NEI → Fortsett
│
├─ Er modellen kritisk (høy blast radius ved feil)?
│  ├─ JA → Shadow deployment først (mirror 10-50%)
│  │      → Deretter Blue-Green med canary percentages (10% → 25% → 50% → 100%)
│  └─ NEI → Blue-Green med standard rollout (10% → 100%)
│
└─ Er brukerbasen geografisk spredt?
   ├─ JA → Multi-region canary (én region om gangen)
   └─ NEI → Single-region progressive rollout
```

---

## Integrasjon med Microsoft-stakken

### 1. Azure DevOps Pipelines

**CI/CD for ML model deployment:**

```yaml
# azure-pipelines.yml
trigger:
  branches:
    include:
      - main

stages:
  - stage: Build
    jobs:
      - job: TrainModel
        steps:
          - task: AzureCLI@2
            inputs:
              scriptType: 'bash'
              scriptLocation: 'inlineScript'
              inlineScript: |
                az ml job create -f training-job.yml

  - stage: DeployCanary
    dependsOn: Build
    jobs:
      - deployment: DeployGreen
        environment: 'production'
        strategy:
          runOnce:
            deploy:
              steps:
                - task: AzureCLI@2
                  displayName: 'Deploy green (0% traffic)'
                  inputs:
                    scriptType: 'bash'
                    inlineScript: |
                      az ml online-deployment create --name green \
                        --endpoint-name prod-endpoint -f green.yml

  - stage: Canary10Percent
    dependsOn: DeployCanary
    jobs:
      - job: UpdateTraffic
        steps:
          - task: AzureCLI@2
            displayName: 'Route 10% to green'
            inputs:
              scriptType: 'bash'
              inlineScript: |
                az ml online-endpoint update --name prod-endpoint \
                  --traffic "blue=90 green=10"
          - task: Delay@1
            inputs:
              delayForMinutes: '60'  # Bake time

  - stage: ValidateCanary
    dependsOn: Canary10Percent
    jobs:
      - job: CheckMetrics
        steps:
          - task: AzureCLI@2
            displayName: 'Query Application Insights'
            inputs:
              scriptType: 'bash'
              inlineScript: |
                # Sjekk error rate for green deployment
                ERROR_RATE=$(az monitor app-insights metrics show \
                  --app my-app-insights \
                  --metric "requests/failed" \
                  --filter "cloud/roleName eq 'green'" \
                  --aggregation avg --query value -o tsv)

                if (( $(echo "$ERROR_RATE > 0.01" | bc -l) )); then
                  echo "Error rate too high, failing pipeline"
                  exit 1
                fi

  - stage: RolloutFull
    dependsOn: ValidateCanary
    condition: succeeded()
    jobs:
      - deployment: FullRollout
        environment: 'production-approval'  # Manual approval gate
        strategy:
          runOnce:
            deploy:
              steps:
                - task: AzureCLI@2
                  inputs:
                    scriptType: 'bash'
                    inlineScript: |
                      az ml online-endpoint update --name prod-endpoint \
                        --traffic "blue=0 green=100"
```

**Approval gates:**
- **Environment protection rules** i Azure DevOps sikrer manuell godkjenning før full rollout
- Integrer med **Azure Monitor alerts** for automatisk rollback ved feil

---

### 2. Azure Monitor & Application Insights

**Health metrics for deployment validation:**

```python
# Python-script for å sjekke deployment health
from azure.monitor.query import MetricsQueryClient, MetricAggregationType
from azure.identity import DefaultAzureCredential
from datetime import timedelta

credential = DefaultAzureCredential()
client = MetricsQueryClient(credential)

# Hent metrics for green deployment (siste time)
response = client.query_resource(
    resource_uri=f"/subscriptions/{subscription_id}/resourceGroups/{rg}/providers/Microsoft.MachineLearningServices/workspaces/{ws}/onlineEndpoints/{endpoint}/deployments/green",
    metric_names=["RequestLatency", "RequestsPerSecond", "CpuUtilizationPercentage"],
    timespan=timedelta(hours=1),
    aggregations=[MetricAggregationType.AVERAGE, MetricAggregationType.P95]
)

for metric in response.metrics:
    print(f"{metric.name}: {metric.timeseries[0].data[0].average}")
```

**Alerts for automatic rollback:**
```bash
# Opprett alert rule for høy error rate
az monitor metrics alert create \
  --name "green-deployment-high-errors" \
  --resource-group myRG \
  --scopes /subscriptions/.../onlineEndpoints/prod-endpoint/deployments/green \
  --condition "avg requests/failed > 5" \
  --window-size 5m \
  --evaluation-frequency 1m \
  --action /subscriptions/.../actionGroups/rollback-webhook
```

---

### 3. Azure Machine Learning Registries (MLOps maturity)

**Shared model registry på tvers av workspaces:**

```python
# Register model i shared registry (én gang)
from azure.ai.ml import MLClient
from azure.ai.ml.entities import Model

registry_client = MLClient(credential, registry_name="company-ml-registry")

model = Model(
    name="heart-classifier",
    version="2.0",
    path="./model",
    type="mlflow_model",
    tags={"production-ready": "true"}
)
registry_client.models.create_or_update(model)

# Deploy fra registry i flere workspaces (dev, staging, prod)
prod_client = MLClient(credential, subscription_id, "prod-rg", "prod-ws")

deployment = ManagedOnlineDeployment(
    name="green",
    endpoint_name="prod-endpoint",
    model=f"azureml://registries/company-ml-registry/models/heart-classifier/versions/2.0",
    instance_type="Standard_DS3_v2",
    instance_count=2
)
prod_client.online_deployments.begin_create_or_update(deployment).result()
```

**Fordeler:**
- Én kilde til sannhet for produksjonsmodeller
- Deploy samme modell-artifact til dev/staging/prod (consistency)
- Støtter multi-region deployment med samme modellversjon

**Referanse:** [Machine Learning Registries for MLOps](https://learn.microsoft.com/en-us/azure/machine-learning/concept-machine-learning-registries-mlops)

---

### 4. MLflow for Model Packaging

**No-code deployment av MLflow-modeller:**

```python
# Registrer MLflow model (inkluderer dependencies)
import mlflow

mlflow.set_tracking_uri(workspace.get_mlflow_tracking_uri())

with mlflow.start_run():
    mlflow.sklearn.log_model(
        sk_model=model,
        artifact_path="model",
        registered_model_name="heart-classifier",
        signature=signature,
        conda_env=conda_env
    )

# Deploy uten scoring script (Azure ML genererer automatisk)
deployment = ManagedOnlineDeployment(
    name="green",
    endpoint_name="prod-endpoint",
    model="azureml:heart-classifier@latest",  # MLflow model
    instance_type="Standard_DS3_v2",
    instance_count=2
    # Ingen code_configuration eller environment nødvendig!
)
```

**Fordeler:**
- Raskere deployment (ingen custom scoring script)
- Built-in support for scikit-learn, TensorFlow, PyTorch
- Enklere rollback (bare endre model version)

**Referanse:** [Deploy MLflow models to online endpoints](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-deploy-mlflow-models-online-endpoints?view=azureml-api-2)

---

## Offentlig sektor (Norge)

### 1. Krav til endringshåndtering (Digdir)

**Utredningsinstruksen (2016) § 5:**
- Alle større IT-endringer (inkludert ML-modellutplasseringer) må dokumenteres med beslutningsgrunnlag
- **ADR (Architecture Decision Record)** bør inkludere valg av deployment strategy

**Eksempel ADR for deployment strategy:**
```markdown
# ADR-023: Blue-Green Deployment for Kredittscoring-modell

## Status
Akseptert (2026-02-04)

## Kontekst
Vi må deploye v2 av kredittscoring-modellen til produksjon. Modellen
påvirker 50 000 søknader per måned. Feil kan føre til feilaktige
kredittvurderinger med økonomiske og juridiske konsekvenser.

## Beslutning
Vi bruker **blue-green deployment** med følgende faser:
1. Shadow deployment (mirror 10%) i 48 timer
2. Live traffic 10% i 72 timer
3. Live traffic 50% i 72 timer
4. Live traffic 100%

## Konsekvenser
+ Redusert risiko for feil (gradvis rollout)
+ Rask rollback (bare bytt trafikk)
- Økte infrastrukturkostnader i rollout-perioden (2x compute)
- Krever 1 uke total rollout-tid

## Compliance
- Personvernforordningen (GDPR): Logging av alle modellpredictions
- Arkivloven: Bevaring av modellversjon-metadata i 5 år
```

---

### 2. Logging og Etterprøvbarhet

**Krav (GDPR Art. 22 + Arkivloven):**
- Alle automatiserte beslutninger må kunne etterprøves
- Ved modellbytte: Logg hvilken versjon som ga hver prediction

**Implementering:**
```python
# Custom scoring script med versjon-logging
import json
import logging
from datetime import datetime

def init():
    global model, model_version
    model = mlflow.pyfunc.load_model(model_path)
    model_version = os.getenv("MODEL_VERSION", "unknown")

def run(raw_data):
    data = json.loads(raw_data)
    predictions = model.predict(data["input"])

    # Logg hver prediction med modellversjon
    for i, pred in enumerate(predictions):
        logging.info(json.dumps({
            "timestamp": datetime.utcnow().isoformat(),
            "model_version": model_version,
            "deployment_name": os.getenv("DEPLOYMENT_NAME"),
            "input_hash": hashlib.sha256(str(data["input"][i]).encode()).hexdigest(),
            "prediction": float(pred),
            "user_id": data.get("user_id", [None])[i]
        }))

    return predictions.tolist()
```

**Log Analytics query for å finne alle predictions fra en deployment:**
```kql
AppTraces
| where TimeGenerated > ago(7d)
| extend LogData = parse_json(Message)
| where LogData.deployment_name == "green"
| project TimeGenerated, LogData.model_version, LogData.prediction, LogData.user_id
| summarize PredictionCount = count() by model_version
```

---

### 3. Risikovurdering (ROS-analyse)

**Trussel: Feil i ny modellversjon gir feilaktige beslutninger**

| Sannsynlighet | Konsekvens | Risiko | Tiltak |
|---------------|------------|--------|--------|
| Middels (3/5) | Høy (4/5) | 12 (Rød) | - Progressive rollout med 48t bake time<br>- Shadow deployment før live<br>- Automated rollback ved error rate > 0.1%<br>- Manual approval gate før 100% rollout |

**Implementering av tiltak:**
1. **Automated rollback** via Azure Monitor alert + Logic App
2. **Manual approval** via Azure DevOps environment protection
3. **Shadow deployment** i 48 timer (dekker helg + hverdag)

---

### 4. Kostnader for Progressive Rollout

**Scenario:** Blue-green deployment i 1 uke rollout-periode

| Fase | Blue Instances | Green Instances | Varighet | Cost (NOK/mnd)* |
|------|---------------|----------------|----------|-----------------|
| Shadow (mirror 10%) | 2x DS3_v2 | 2x DS3_v2 | 2 dager | ~520 NOK |
| Live 10% | 2x DS3_v2 | 2x DS3_v2 | 3 dager | ~780 NOK |
| Live 50% | 2x DS3_v2 | 2x DS3_v2 | 2 dager | ~520 NOK |
| Live 100% (cleanup) | 0 | 2x DS3_v2 | - | 0 NOK (baseline) |

**Total ekstra kostnad:** ~1 820 NOK for 1 ukes rollout (dobbelt kapasitet i 7 dager).

**Optimalisering:**
- Bruk **autoscaling** på green deployment (start med 1 instance, skaler ved behov)
- **Scheduled scaling**: Reducer instances utenfor kontortid (hvis batch-scoring)

*Basert på DS3_v2 = ~2 600 NOK/mnd (per instance)

---

## Kostnad og lisensiering

### 1. Compute-kostnader

**Managed Online Endpoints (Pay-as-you-go):**

| VM Type | vCPU | RAM | Cost (NOK/time)* | Anbefalt for |
|---------|------|-----|------------------|--------------|
| Standard_DS2_v2 | 2 | 7 GB | ~1,10 | Dev/test, små modeller |
| Standard_DS3_v2 | 4 | 14 GB | ~2,20 | Produksjon (medium load) |
| Standard_DS4_v2 | 8 | 28 GB | ~4,40 | Produksjon (høy load) |
| Standard_NC6s_v3 (GPU) | 6 | 112 GB | ~25,00 | Deep learning inferencing |

**Blue-green deployment cost multiplier:**
- Under rollout: **2x compute cost** (begge deployments kjører)
- Varighet: 1-2 uker (avhengig av bake times)
- **Total overhead:** ~5-10% av årlig compute-kostnad

**Eksempel:**
- Baseline produksjon: 2x DS3_v2 (24/7) = ~5 200 NOK/mnd
- Med 4 rollouts per år (1 uke each): 5 200 + (1 820 × 4/12) = ~5 807 NOK/mnd
- **Overhead: ~12%**

*Priser er estimat per jan 2026, Norway East region.

---

### 2. Bandwidth og Storage

**Endpoint bandwidth quota:**
- Default: **5 MBps per endpoint**
- Shadow deployment: Teller mot bandwidth (derfor 50% max mirror traffic)
- Overskridelse: Throttling (HTTP 429 errors)

**Kostnad ved throttling:**
- Ikke direkte kostnad, men **reduced throughput**
- Løsning: Øk quota (support ticket) eller optimaliser payload size

**Model registry storage:**
- Gratis for første 10 GB
- Deretter: ~0,50 NOK/GB/mnd
- Ved mange modellversjoner: Implementer retention policy (slett gamle versjoner)

---

### 3. Lisensiering

**Azure Machine Learning workspace:**
- Gratis (betaler kun for underliggende compute/storage)
- Alle deployment-features (blue-green, mirroring, A/B) inkludert

**MLflow:**
- Open source, gratis
- Azure ML har innebygd MLflow tracking (ingen ekstra kostnad)

**Azure DevOps:**
- **Gratis tier:** 1 hosted pipeline (Microsoft-hosted agent)
- **Basic plan:** ~50 NOK/bruker/mnd + pipeline minutes
- Deployment-pipelines krever parallel jobs (ekstra cost hvis mange pipelines)

---

## For arkitekten (Cosmo)

### 1. Checklist før du velger deployment strategy

**Spørsmål å stille stakeholders:**

1. **Hva er maksimal akseptabel downtime?**
   - 0 minutter → Blue-Green eller Canary
   - <30 minutter → In-place deployment med rolling update

2. **Hvor kritisk er modellen for business?**
   - Kritisk (påvirker revenue/compliance) → Shadow først, deretter gradvis rollout
   - Medium → Blue-Green med 10% → 100%
   - Lav → Direct deployment med basic smoke test

3. **Har du stateful components (database)?**
   - Ja → Implementer backward-compatible migrations først
   - Nei → Enklere rollback-strategi

4. **Trenger dere sammenligne modellversjoner for metrics?**
   - Ja → A/B testing (50/50 eller annen split)
   - Nei → Blue-Green

5. **Hva er budget for ekstra compute under rollout?**
   - Begrenset → Canary (én node om gangen)
   - Fleksibelt → Blue-Green (full parallell kapasitet)

6. **Hvor lang tid har dere for å rulle ut?**
   - 1-2 dager → Aggressiv rollout (10% → 100% raskt)
   - 1-2 uker → Konservativ (shadow + bake times)

---

### 2. Anti-patterns (hva du IKKE skal gjøre)

**❌ Direct swap uten testing:**
```python
# IKKE GJØR DETTE!
endpoint.traffic = {"blue": 0, "green": 100}  # 0% → 100% instant
ml_client.online_endpoints.begin_create_or_update(endpoint).result()
```
**Problem:** Ingen validering, ingen rollback-mulighet, høy blast radius.

**✅ Gjør dette isteden:**
```python
# Shadow først
endpoint.mirror_traffic = {"green": 10}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()
time.sleep(3600 * 24)  # 24 timer bake time

# Så gradvis live
endpoint.mirror_traffic = {"green": 0}
endpoint.traffic = {"blue": 90, "green": 10}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()
```

---

**❌ Ingen health metrics monitoring:**
- Deploye ny versjon uten å sjekke error rates, latency, throughput

**✅ Implementer automated health checks:**
```python
def check_deployment_health(deployment_name, threshold_error_rate=0.01):
    """Sjekk health metrics for deployment."""
    response = metrics_client.query_resource(
        resource_uri=f".../{deployment_name}",
        metric_names=["RequestLatency", "RequestsPerSecond", "RequestsFailed"],
        timespan=timedelta(hours=1)
    )

    error_rate = response.metrics["RequestsFailed"].average / response.metrics["RequestsPerSecond"].average
    if error_rate > threshold_error_rate:
        raise Exception(f"Error rate {error_rate:.2%} exceeds threshold {threshold_error_rate:.2%}")

    return True
```

---

**❌ Slett blue deployment for tidlig:**
- Fjerne blue deployment rett etter 100% green rollout

**✅ Behold blue i minst 1 uke:**
```python
# Vent 1 uke etter 100% rollout før cleanup
endpoint.traffic = {"blue": 0, "green": 100}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()

# Sett reminder: Cleanup blue deployment etter 2026-02-11
```

**Rasjonale:** Hvis kritisk bug oppdages etter 3 dager, kan du raskt rulle tilbake til blue uten redeployment.

---

### 3. Rollback-playbook

**Scenario: Green deployment viser økt error rate under 50% rollout**

**Steg:**
1. **Immediate action (< 5 min):**
   ```bash
   # Bytt tilbake til 100% blue
   az ml online-endpoint update --name prod-endpoint \
     --traffic "blue=100 green=0"
   ```

2. **Verifiser rollback (< 10 min):**
   ```bash
   # Sjekk at error rate går ned
   az monitor app-insights query \
     --app my-app-insights \
     --analytics-query "requests | where timestamp > ago(5m) | summarize ErrorRate = countif(success == false) / count()"
   ```

3. **Incident postmortem (< 24 timer):**
   - Hva var root cause? (sjekk logs: `az ml online-deployment get-logs --name green`)
   - Hvorfor fanget vi ikke dette i shadow phase?
   - Oppdater deployment checklist med ny validering

4. **Fix og redeploy (< 1 uke):**
   - Fix bug i kode/modell
   - Re-run training/testing
   - Start ny rollout fra steg 1 (shadow deployment)

---

### 4. Conversation starters med kunden

**Når kunden sier: "Vi vil bare deploye den nye modellen nå."**

**Cosmo:** "Jeg forstår at dere er klare for produksjon. La meg stille noen raske spørsmål for å sikre en trygg deployment:

1. Hvis den nye modellen viser seg å ha feil i produksjon, hvor raskt må vi kunne rulle tilbake? 5 minutter? 1 time? 1 dag?

2. Har dere monitoring satt opp for å oppdage feil? Hvilke metrics ser dere på – error rate, latency, modell-drift?

3. Er det OK å kjøre begge modellversjonene parallelt i 1-2 uker (dvs. dobbel infrastrukturkostnad)? Eller må vi optimalisere for kostnad?

Basert på svarene kan vi velge rett strategi – f.eks. blue-green med gradvis rollout hvis dere trenger rask rollback, eller canary hvis kostnadsoptimalisering er prioritet."

---

**Når kunden sier: "Vi har ikke tid til langsom rollout, vi må ha 100% i produksjon i morgen."**

**Cosmo:** "Jeg skjønner at time-to-market er kritisk. La oss se på risiko vs. hastighet:

**Rask rollout (1-2 dager):**
- Deploy green med 0% traffic i kveld
- Test isolert i natt (automated smoke tests)
- 50% traffic i morgen tidlig (kl 09:00)
- 100% traffic samme dag (kl 15:00) hvis ingen kritiske feil
- **Risiko:** Hvis feil oppdages kl 16:00, har 50% av brukere fått dårlig service hele dagen

**Balansert rollout (3-4 dager):**
- Shadow deployment i 24 timer (validere mot real traffic)
- 10% live traffic dag 2
- 50% live traffic dag 3
- 100% live traffic dag 4
- **Risiko:** Redusert blast radius (maks 10% brukere påvirket hvis feil)

Hva er konsekvensen hvis 50% av brukere får feil predictions i ett døgn? Hvis det er akseptabelt, kan vi kjøre rask rollout. Hvis ikke, anbefaler jeg balansert."

---

### 5. Teknisk deep-dive: Hvordan traffic routing fungerer

**Under panseret på Azure ML Online Endpoints:**

```
Client Request (HTTP POST)
    ↓
Azure Front Door (global load balancer)
    ↓
Endpoint (prod-endpoint.norwayeast.inference.ml.azure.com)
    ↓
Traffic Routing Logic:
    - Hvis HTTP header "azureml-model-deployment: green" → Route til green
    - Ellers: Bruk traffic percentage (f.eks. 90% blue, 10% green)
    ↓
Deployment (blue eller green)
    ↓
Scoring Container (Docker image med model + scoring script)
    ↓
Return Prediction
```

**Mirror traffic flow:**
```
Client Request
    ↓
Endpoint
    ├─→ Primary Deployment (blue) → Return Response til client
    └─→ Shadow Deployment (green) → Logg metrics, IKKE return response
```

**Viktig implementasjonsdetalje:**
- Traffic routing skjer **før** request når deployment container
- Mirror traffic er **async** (non-blocking for primary deployment)
- Hvis shadow deployment crasher, påvirker det **ikke** client response

---

## Kilder og verifisering

Denne kunnskapsreferansen er basert på følgende Microsoft Learn-artikler og code samples (verifisert 2026-02-04):

**Primære kilder:**
1. [Perform safe rollout of new deployments for real-time inference](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-safely-rollout-online-endpoints?view=azureml-api-2)
   → Komplett guide til blue-green deployment og traffic mirroring

2. [MLOps model management with Azure Machine Learning](https://learn.microsoft.com/en-us/azure/machine-learning/concept-model-management-and-deployment?view=azureml-api-2)
   → Oversikt over deployment capabilities og controlled rollout

3. [Online endpoint deployment for real-time inferencing](https://learn.microsoft.com/en-us/azure/machine-learning/concept-endpoints-online?view=azureml-api-2)
   → Konsepter: endpoints vs. deployments, traffic routing, mirroring

4. [Tutorial: Use a canary deployment strategy for Kubernetes](https://learn.microsoft.com/en-us/azure/devops/pipelines/ecosystems/kubernetes/canary-demo?view=azure-devops)
   → Canary deployment med Azure DevOps Pipelines

5. [Progressive rollout of MLflow models to Online Endpoints](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-deploy-mlflow-models-online-progressive?view=azureml-api-2)
   → MLflow-spesifikk progressive rollout

**Code samples:**
- [azureml-examples/sdk/python/endpoints/online/managed/online-endpoints-safe-rollout.ipynb](https://github.com/Azure/azureml-examples/blob/main/sdk/python/endpoints/online/managed/online-endpoints-safe-rollout.ipynb)
- [azureml-examples/cli/endpoints/online/managed/sample/](https://github.com/Azure/azureml-examples/tree/main/cli/endpoints/online/managed/sample)

**Well-Architected Framework:**
- [Architecture strategies for safe deployment practices](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/safe-deployments)
   → Progressive exposure model, bake times, rollback strategies

**Pricing (sist verifisert: 2026-02-04):**
- [Azure Machine Learning pricing](https://azure.microsoft.com/en-us/pricing/details/machine-learning/)
   → Compute costs for managed endpoints

**MCP-kall utført:** 8 (microsoft_docs_search × 5, microsoft_docs_fetch × 2, microsoft_code_sample_search × 1)

---

**Sist oppdatert:** 2026-02-04
**Neste review:** 2026-05-04 (eller ved større endringer i Azure ML deployment capabilities)
