AI-300 Part 1: MLOps Infrastructure

Domain 1 of 5 — 15–20% of the AI-300 exam. This domain covers designing and implementing MLOps infrastructure: Azure ML workspace architecture, identity and access, network isolation, infrastructure as code, CI/CD pipelines, data assets, environments, and MLflow integration.

Exam Objectives

The official skill outline breaks this domain into four areas:

Set up and manage Azure Machine Learning workspaces

  • Create and configure an Azure ML workspace and associated resources
  • Manage workspace hubs and projects (Azure AI Foundry model)
  • Configure compute targets: clusters, instances, serverless, and attached compute
  • Implement RBAC using built-in and custom roles for ML workspaces
  • Configure managed identities for the workspace and compute resources
  • Configure network isolation using private endpoints and VNet injection

Implement infrastructure as code and CI/CD

  • Provision workspaces using Bicep or ARM templates
  • Implement GitHub Actions workflows for model training and deployment
  • Implement multi-stage Azure DevOps pipelines for ML workloads
  • Apply approval gates between pipeline stages

Manage data assets and environments

  • Register and version data assets: URIFolder, URIFile, MLTable
  • Configure datastores pointing to Azure storage, ADLS Gen2, and SQL
  • Build and manage environments: curated vs. custom, conda YAML, Docker base images

Integrate MLflow for experiment tracking

  • Use MLflow autolog and custom logging in training scripts
  • Register models from training runs to the MLflow model registry
  • Configure MLflow tracking URI to point to an Azure ML workspace

Azure ML Workspace Architecture

An Azure Machine Learning workspace is the top-level resource for all ML activities. When you create a workspace, Azure automatically provisions several associated resources: an Azure Storage Account (for artifacts and data), an Azure Container Registry (for environment images), Azure Key Vault (for secrets), and Application Insights (for logging). These four resources are tightly coupled to the workspace and should be co-located in the same resource group.

Azure AI Foundry introduces a hub-and-project model. A hub is a shared governance layer — it holds the managed network configuration, shared compute, and a shared Key Vault and Storage Account. Projects are child workspaces that inherit the hub's network policy and identity settings but maintain their own experiment runs, models, and endpoints. This pattern allows an enterprise MLOps team to manage one network boundary while data science teams work in isolated project namespaces.

Compute Types

Choosing the right compute is one of the most commonly tested topics in Domain 1. Azure ML offers four categories of compute, each optimized for different workload patterns.

Compute Type Use Case Billing Key Characteristics
Compute Cluster Training, batch scoring Per-node/hour; scales to 0 Min/max node count, autoscale, supports GPU; shared by team
Compute Instance Interactive development (notebooks, IDE) Per-hour; must be stopped manually Single user, managed notebook server, supports scheduled auto-shutdown
Serverless Compute On-demand training and pipeline jobs Per-second; no idle cost No cluster management; Azure picks VM; cold start latency applies
Attached Compute Kubernetes inference, on-prem training Varies (AKS, Arc-enabled K8s) Bring your own cluster; AML manages jobs, not the infra

Exam tip: Know when to use each compute type. Compute clusters auto-scale to zero and are cost-effective for pipeline jobs. Compute instances are per-user developer environments that run continuously unless stopped. Serverless compute removes infrastructure management but has cold start latency — unsuitable for latency-sensitive batch work. Attached Kubernetes is used when your organization requires on-premises or regulated infrastructure.

RBAC for Azure ML Workspaces

Azure ML workspaces use Azure RBAC for access control. The exam focuses heavily on knowing which built-in role grants which specific capability, and when to build a custom role rather than using a built-in one.

Built-in Role Can Submit Jobs Can Manage Compute Can Deploy Endpoints Can Read Only
AzureML Data Scientist Yes No No
AzureML Compute Operator No Yes (start/stop) No
Contributor Yes Yes Yes
Reader No No No Yes

In practice, a data science team typically receives AzureML Data Scientist on the workspace and Storage Blob Data Contributor on the associated storage account. The MLOps platform team holds Contributor or a custom role that includes endpoint management permissions.

Exam tip: The AzureML Data Scientist role deliberately cannot create or manage compute. That separation of duties means data scientists cannot provision expensive GPU clusters — an AzureML Compute Operator or Contributor must do that. Exam scenarios often test this boundary.

Managed Identity for ML Workspaces

Azure ML workspaces use managed identities to access associated resources without storing credentials. Two managed identities matter for the exam.

The workspace system-assigned managed identity (MSI) is created automatically when the workspace is provisioned. Azure ML uses it to pull images from the Container Registry, read secrets from Key Vault, and write artifacts to Storage. You must assign the workspace MSI the following roles on associated resources: Storage Blob Data Contributor on the storage account, Key Vault Secrets User on Key Vault, and AcrPull on the Container Registry.

The compute cluster MSI is a separate system-assigned identity on each cluster node. Training scripts running on the cluster authenticate using this identity. Assign it Storage Blob Data Reader (or Contributor if the script writes outputs) on the data storage account. For workspaces with private endpoints and no internet access, the compute MSI also needs the ability to pull environment images, which requires AcrPull on the registry.

# Assign Storage Blob Data Contributor to the workspace MSI
WS_MSI=$(az ml workspace show -n my-workspace -g rg-ml --query identity.principalId -o tsv)

az role assignment create \
  --role "Storage Blob Data Contributor" \
  --assignee-object-id "$WS_MSI" \
  --scope "/subscriptions/<sub-id>/resourceGroups/rg-ml/providers/Microsoft.Storage/storageAccounts/saml"

Network Isolation

For regulated workloads, Azure ML workspaces must be isolated from the public internet. The platform supports two complementary network patterns.

Private Endpoints

A private endpoint for the Azure ML workspace places a network interface in your VNet with a private IP, and the workspace hostname resolves to that IP via a private DNS zone (privatelink.api.azureml.ms and privatelink.notebooks.azure.net). After the workspace endpoint is created, requests to the workspace API no longer traverse the public internet.

A critical exam point: the workspace private endpoint covers the control plane only. It does not automatically isolate the storage account, Key Vault, or Container Registry. Those resources require their own separate private endpoints. Failing to create private endpoints for all four resources leaves data paths open even though the workspace itself is private.

Managed VNet and VNet Injection

Azure ML's managed virtual network feature (introduced in 2023) automatically provisions a managed VNet for the workspace. Compute created in a workspace with a managed VNet is automatically injected into that VNet and uses the workspace's private endpoints to reach associated resources. This is the recommended approach for new workspaces because it eliminates the need to manually configure VNet peering, NSGs, and DNS for each compute resource.

Exam tip: A workspace private endpoint does NOT automatically make the associated Storage Account, Key Vault, or Container Registry private. Each of those services needs its own private endpoint. Exam scenarios that show a workspace with a private endpoint but public storage are asking you to identify this gap.

Infrastructure as Code for ML Workspaces

The exam may present Bicep or ARM template snippets and ask you to identify missing properties or correct configuration errors. The most important properties to know: storageAccount, keyVault, containerRegistry, applicationInsights, publicNetworkAccess, and managedNetwork.isolationMode.

// Bicep: create an Azure ML workspace with public network access disabled
resource workspace 'Microsoft.MachineLearningServices/workspaces@2024-04-01' = {
  name: 'mlw-prod'
  location: location
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    friendlyName: 'Production ML Workspace'
    storageAccount: storageAccount.id
    keyVault: keyVault.id
    containerRegistry: containerRegistry.id
    applicationInsights: appInsights.id
    publicNetworkAccess: 'Disabled'
    managedNetwork: {
      isolationMode: 'AllowOnlyApprovedOutbound'
    }
  }
}

The isolationMode property controls the managed network behaviour. Disabled means no managed network. AllowInternetOutbound allows outbound internet from compute (useful for pulling public packages). AllowOnlyApprovedOutbound is the strictest option — all egress must go through explicitly approved outbound rules, which is required for air-gapped or regulated deployments.

CI/CD Pipelines for ML

GitHub Actions — Train and Register on Data Change

A production MLOps workflow should trigger retraining automatically when source data or training code changes. The following GitHub Actions workflow detects changes to src/ or data/ paths, submits an Azure ML pipeline job, waits for completion, and then registers the model if metrics pass threshold.

name: Train and Register Model

on:
  push:
    branches: [main]
    paths: ['src/**', 'data/**', 'pipelines/**']

jobs:
  train:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Azure login
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Submit training pipeline
        run: |
          az ml job create \
            --file pipelines/train-pipeline.yml \
            --workspace-name ${{ vars.AML_WORKSPACE }} \
            --resource-group ${{ vars.AML_RG }} \
            --stream  # wait for completion

      - name: Register model if metrics pass
        run: python scripts/register_if_better.py

Azure DevOps — Multi-Stage ML Pipeline

Azure DevOps multi-stage pipelines allow environment-specific approval gates. A three-stage pipeline (train → validate → deploy) is the canonical pattern: the training stage submits the Azure ML pipeline job; the validate stage runs quality gates and requires a human approver; the deploy stage promotes the model to the production endpoint.

stages:
  - stage: Train
    jobs:
      - job: SubmitPipeline
        steps:
          - task: AzureCLI@2
            inputs:
              azureSubscription: 'arm-connection'
              scriptType: bash
              inlineScript: |
                az ml job create --file pipelines/train.yml \
                  --workspace-name $(AML_WORKSPACE) \
                  --resource-group $(AML_RG) --stream

  - stage: Validate
    dependsOn: Train
    jobs:
      - deployment: ApproveModel
        environment: ml-validation    # environment has approval gate in Azure DevOps
        strategy:
          runOnce:
            deploy:
              steps:
                - script: python scripts/evaluate_model.py

  - stage: Deploy
    dependsOn: Validate
    jobs:
      - job: DeployEndpoint
        steps:
          - task: AzureCLI@2
            inputs:
              azureSubscription: 'arm-connection'
              scriptType: bash
              inlineScript: |
                az ml online-deployment create \
                  --file deployments/prod-deployment.yml \
                  --workspace-name $(AML_WORKSPACE) \
                  --resource-group $(AML_RG) \
                  --all-traffic

Data Assets and Datastores

Azure ML distinguishes between datastores (connection metadata pointing to storage services) and data assets (versioned references to specific data paths). Both are critical for reproducible training.

Datastores

A datastore stores the connection information for Azure Blob Storage, Azure Data Lake Storage Gen2, Azure Files, or Azure SQL Database. The workspace has a default datastore (workspaceblobstore) backed by the associated storage account. You can register additional datastores pointing to production data lakes. Datastores support either account key authentication or credential-less access (using the compute MSI).

Data Asset Types

Asset Type Points To Typical Use
uri_folder A folder/prefix in storage Training data directory, model artifacts directory
uri_file A single file in storage A specific CSV, parquet, or model file
mltable An MLTable spec file + data files Tabular data with schema, column types, and transformations defined

Data assets are versioned automatically each time you register them. You reference a specific version in a job YAML (my-dataset:3) to ensure training reproducibility. You can also use @latest to always pull the most recent version.

Exam tip: Understand the distinction between uri_folder and uri_file versus mltable. URI assets are simple path references — they do not carry schema. MLTable assets include a YAML spec that defines how to read the data (file format, column types, header row). Use MLTable when the training component needs typed tabular input; use URI assets when the script handles its own data loading.

Environment Management

An Azure ML environment captures the software dependencies for a job or deployment. Environments are versioned and cached as Docker images in the workspace's Container Registry, so subsequent jobs using the same environment skip the build step.

Curated Environments

Azure ML provides curated environments — pre-built Docker images maintained by Microsoft for common frameworks: AzureML-sklearn-1.5-ubuntu22.04-py38-cpu, AzureML-pytorch-2.0-ubuntu20.04-py38-cuda11-gpu, etc. These are the fastest way to start a job and receive security patches automatically when a new version is published. Reference them by name in your job YAML.

Custom Environments

When curated environments don't meet your needs, define a custom environment using a conda YAML file or a Dockerfile. The conda YAML approach is simpler and portable — Azure ML builds the Docker image for you. The Dockerfile approach gives full control for complex system dependencies.

# environment.yml — custom conda-based environment
name: custom-training-env
channels:
  - conda-forge
  - defaults
dependencies:
  - python=3.10
  - pip:
      - azure-ai-ml==1.15.0
      - mlflow==2.14.0
      - scikit-learn==1.5.0
      - pandas==2.2.0
      - azureml-mlflow==1.56.0
# Register environment from conda YAML
az ml environment create \
  --name custom-training-env \
  --version 1 \
  --conda-file environment.yml \
  --image mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu22.04 \
  --workspace-name my-workspace \
  --resource-group rg-ml

MLflow Integration

MLflow is the open-source experiment tracking and model registry that Azure ML uses under the hood. When you run a job in Azure ML, the MLflow tracking server is automatically configured — you don't need to set the tracking URI in most cases. MLflow stores metrics, parameters, and artifacts in the workspace's default storage.

Autolog and Custom Logging

import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

# Azure ML automatically sets the tracking URI when running a job
mlflow.sklearn.autolog()  # autolog captures params, metrics, and model artifact

with mlflow.start_run():
    model = RandomForestClassifier(n_estimators=100, max_depth=5)
    model.fit(X_train, y_train)

    # Custom metrics beyond what autolog captures
    val_accuracy = model.score(X_val, y_val)
    mlflow.log_metric("val_accuracy", val_accuracy)
    mlflow.log_param("feature_count", X_train.shape[1])
    mlflow.log_artifact("feature_importance.png")

    # Register model to the workspace registry
    mlflow.sklearn.log_model(
        sk_model=model,
        artifact_path="model",
        registered_model_name="fraud-classifier"
    )

Model Registration from a Run

To register a model from a completed run (rather than inline during training), use mlflow.register_model() with the run URI. This is useful in CI/CD pipelines where the registration step runs after validation gates pass.

import mlflow

# Register after the run completes — useful in post-training CI/CD step
model_uri = f"runs:/{run_id}/model"
registered_model = mlflow.register_model(
    model_uri=model_uri,
    name="fraud-classifier"
)
print(f"Registered: version {registered_model.version}")

Exam tip: Azure ML's MLflow registry does not use the traditional MLflow stage names (Staging, Production, Archived) as of November 2024. Instead, use model tags and labels to track promotion status. Exam questions may reference "model stages" — understand that in Azure ML, this means tags/aliases, not the classic MLflow stage API.

Sharing Assets Across Workspaces with ML Registries

An Azure ML Registry is a centralized catalog for versioned models, datasets, and environments that can be shared across workspaces — and across regions. This is distinct from the workspace-local model registry: the local registry stores assets within one workspace, while a shared registry makes those assets available enterprise-wide without copying files manually.

Registry vs. Workspace-Local Storage

Aspect Workspace-local registry Shared ML Registry
Scope One workspace Enterprise-wide; multiple workspaces and regions
Use case Track models within a project or team Promote validated models from dev workspace to prod; share curated environments across teams
Multi-region replication No Yes — registry replicates assets across configured regions
RBAC Inherits workspace roles AzureML Registry Reader / AzureML Registry Contributor (separate from workspace roles)

Python SDK: Registering a Model to a Shared Registry

from azure.ai.ml import MLClient
from azure.identity import DefaultAzureCredential
from azure.ai.ml.entities import Model
from azure.ai.ml.constants import AssetTypes

# Connect to the shared registry (not a workspace)
registry_client = MLClient(
    credential=DefaultAzureCredential(),
    registry_name="my-enterprise-registry"
)

# Register a model from a local path to the shared registry
model = Model(
    name="fraud-classifier",
    version="3",
    path="./model-output/",  # local artifacts
    type=AssetTypes.MLFLOW_MODEL,
    description="XGBoost fraud classifier — validated on staging 2026-05"
)
registry_client.models.create_or_update(model)

# From a different workspace: download the registry model for deployment
workspace_client = MLClient(
    credential=DefaultAzureCredential(),
    subscription_id="<sub-id>",
    resource_group_name="prod-rg",
    workspace_name="prod-workspace"
)

# Reference the registry model in a deployment
from azure.ai.ml.entities import ManagedOnlineDeployment, ManagedOnlineEndpoint

deployment = ManagedOnlineDeployment(
    name="fraud-v3",
    endpoint_name="fraud-endpoint",
    model=f"azureml://registries/my-enterprise-registry/models/fraud-classifier/versions/3",
    instance_type="Standard_DS3_v2",
    instance_count=1
)
workspace_client.online_deployments.begin_create_or_update(deployment)

Sharing Environments and Components via Registries

You can also register reusable pipeline components and custom environments in a shared registry. This ensures that all workspaces across your organisation use the same base environment image and the same validated component versions — reducing environment drift between teams.

from azure.ai.ml.entities import Environment

# Register a custom environment to the shared registry
env = Environment(
    name="ml-training-env",
    version="2",
    image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04",
    conda_file="conda.yaml"
)
registry_client.environments.create_or_update(env)

# In another workspace, reference it by registry path
env_ref = "azureml://registries/my-enterprise-registry/environments/ml-training-env/versions/2"

Exam note: The AI-300 exam tests the distinction between workspace-local model registration and shared ML Registry promotion. The typical pattern is: train in a dev workspace → register locally → validate → promote to shared registry → deploy from registry in production workspace. Know the RBAC roles: AzureML Registry Contributor can create/update registry assets; AzureML Registry Reader can download and reference them.

Exam Tips & Key Takeaways

Critical concepts to master for Domain 1:

  • Compute type selection — compute cluster scales to zero for batch workloads; compute instance is per-user and runs continuously; serverless removes cluster management but adds cold start; attached Kubernetes handles regulated on-prem workloads
  • RBAC boundaries — AzureML Data Scientist can submit jobs but cannot create compute; AzureML Compute Operator manages compute but cannot submit training jobs; know which role combination grants both
  • Private workspace scope — the workspace private endpoint only privatizes the control plane API; storage, Key Vault, and Container Registry each need a separate private endpoint to be fully isolated
  • Data asset typesuri_folder and uri_file are path references with no schema; mltable includes a YAML spec defining tabular structure and transformations
  • Managed network isolation modesAllowOnlyApprovedOutbound is the strictest and required for regulated environments; AllowInternetOutbound permits package downloads; Disabled means no managed VNet
  • MLflow in Azure ML — tracking URI is set automatically in Azure ML jobs; model stages have been replaced by tags/labels in Azure ML's MLflow registry
  • IaC properties — the Bicep workspace resource requires storageAccount, keyVault, containerRegistry, and applicationInsights; publicNetworkAccess: 'Disabled' together with managedNetwork.isolationMode creates a fully isolated workspace

Pro tip: Domain 1 exam questions often present an architecture scenario with a security gap (compute with public IP in a private workspace, or storage without a private endpoint). Train yourself to identify which specific resource is missing its private endpoint or MSI role assignment.

Further Learning – Microsoft Learn