Back to Blog
5 min read

Azure Dev Box GA: Cloud-Powered Developer Workstations

Azure Dev Box is now generally available, providing cloud-based developer workstations that can be provisioned on-demand. Today, I will explore how Dev Box can transform developer productivity and onboarding.

What is Azure Dev Box?

Azure Dev Box provides self-service, high-performance, cloud-based workstations pre-configured for specific projects or teams:

┌─────────────────────────────────────────────────────┐
│                  Azure Dev Box                       │
├─────────────────────────────────────────────────────┤
│                                                      │
│  ┌─────────────┐    ┌─────────────────────────────┐ │
│  │   Admin     │───▶│  Dev Center                 │ │
│  │   Portal    │    │  - Projects                 │ │
│  └─────────────┘    │  - Pools                    │ │
│                     │  - Definitions              │ │
│                     └─────────────────────────────┘ │
│                              │                      │
│                              ▼                      │
│  ┌─────────────┐    ┌─────────────────────────────┐ │
│  │  Developer  │───▶│  Dev Box                    │ │
│  │  Portal     │    │  - Windows 11               │ │
│  └─────────────┘    │  - Pre-installed tools      │ │
│                     │  - Project repos            │ │
│                     └─────────────────────────────┘ │
│                                                      │
└─────────────────────────────────────────────────────┘

Setting Up Dev Center

Create Dev Center

# Create resource group
az group create --name devbox-rg --location eastus

# Create dev center
az devcenter admin devcenter create \
    --name mydevcenter \
    --resource-group devbox-rg \
    --location eastus

# Create network connection
az devcenter admin network-connection create \
    --name devbox-network \
    --resource-group devbox-rg \
    --location eastus \
    --subnet-id "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}" \
    --domain-join-type AzureADJoin

Create Dev Box Definitions

from azure.mgmt.devcenter import DevCenterMgmtClient
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()
client = DevCenterMgmtClient(credential, subscription_id)

# Create dev box definition
definition = client.dev_box_definitions.begin_create_or_update(
    resource_group_name="devbox-rg",
    dev_center_name="mydevcenter",
    dev_box_definition_name="frontend-dev",
    body={
        "location": "eastus",
        "properties": {
            "imageReference": {
                "id": "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.DevCenter/devcenters/mydevcenter/galleries/default/images/microsoftvisualstudio_visualstudioplustools_vs-2022-ent-general-win11-m365-gen2"
            },
            "sku": {
                "name": "general_i_8c32gb256ssd_v2"
            },
            "hibernateSupport": "Enabled"
        }
    }
).result()

print(f"Created definition: {definition.name}")

SKU Options

# Available Dev Box SKUs
dev_box_skus = {
    "general_i_8c32gb256ssd_v2": {
        "vcpus": 8,
        "memory_gb": 32,
        "storage_gb": 256,
        "use_case": "Standard development"
    },
    "general_i_8c32gb512ssd_v2": {
        "vcpus": 8,
        "memory_gb": 32,
        "storage_gb": 512,
        "use_case": "Standard with more storage"
    },
    "general_i_16c64gb256ssd_v2": {
        "vcpus": 16,
        "memory_gb": 64,
        "storage_gb": 256,
        "use_case": "Heavy workloads"
    },
    "general_i_32c128gb512ssd_v2": {
        "vcpus": 32,
        "memory_gb": 128,
        "storage_gb": 512,
        "use_case": "Large projects, ML development"
    }
}

Creating Custom Images

Using Azure Image Builder

{
  "type": "Microsoft.VirtualMachineImages/imageTemplates",
  "apiVersion": "2022-02-14",
  "location": "eastus",
  "properties": {
    "source": {
      "type": "PlatformImage",
      "publisher": "MicrosoftWindowsDesktop",
      "offer": "Windows-11",
      "sku": "win11-22h2-ent",
      "version": "latest"
    },
    "customize": [
      {
        "type": "PowerShell",
        "name": "InstallVisualStudio",
        "runElevated": true,
        "inline": [
          "choco install visualstudio2022enterprise -y",
          "choco install visualstudio2022-workload-azure -y",
          "choco install visualstudio2022-workload-netweb -y"
        ]
      },
      {
        "type": "PowerShell",
        "name": "InstallDevTools",
        "runElevated": true,
        "inline": [
          "choco install git -y",
          "choco install nodejs-lts -y",
          "choco install python3 -y",
          "choco install docker-desktop -y",
          "choco install azure-cli -y",
          "choco install vscode -y",
          "choco install postman -y"
        ]
      },
      {
        "type": "PowerShell",
        "name": "InstallVSCodeExtensions",
        "inline": [
          "code --install-extension ms-python.python",
          "code --install-extension ms-azuretools.vscode-docker",
          "code --install-extension ms-vscode.azure-account"
        ]
      },
      {
        "type": "WindowsRestart",
        "restartTimeout": "10m"
      }
    ],
    "distribute": [
      {
        "type": "SharedImage",
        "galleryImageId": "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Compute/galleries/devboxGallery/images/customDevImage",
        "runOutputName": "customDevImage",
        "replicationRegions": ["eastus"]
      }
    ]
  }
}

PowerShell Setup Script

# setup-devbox.ps1
# Run as administrator during image build

# Install Chocolatey
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

# Refresh environment
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")

# Install development tools
$packages = @(
    "git",
    "gh",
    "nodejs-lts",
    "python3",
    "dotnet-sdk",
    "azure-cli",
    "terraform",
    "docker-desktop",
    "vscode",
    "postman",
    "7zip",
    "curl",
    "jq"
)

foreach ($package in $packages) {
    choco install $package -y --no-progress
}

# Configure Git
git config --global init.defaultBranch main
git config --global core.autocrlf true

# Install VS Code extensions
$extensions = @(
    "ms-python.python",
    "ms-azuretools.vscode-docker",
    "ms-azure-devops.azure-pipelines",
    "ms-vscode.azure-account",
    "ms-dotnettools.csharp",
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "hashicorp.terraform"
)

foreach ($ext in $extensions) {
    code --install-extension $ext
}

# Create standard directory structure
$dirs = @(
    "$env:USERPROFILE\repos",
    "$env:USERPROFILE\.ssh"
)

foreach ($dir in $dirs) {
    if (-not (Test-Path $dir)) {
        New-Item -ItemType Directory -Path $dir
    }
}

Write-Host "Dev Box setup complete!"

Project and Pool Setup

# Create project
project = client.projects.begin_create_or_update(
    resource_group_name="devbox-rg",
    project_name="frontend-project",
    body={
        "location": "eastus",
        "properties": {
            "devCenterId": f"/subscriptions/{sub}/resourceGroups/devbox-rg/providers/Microsoft.DevCenter/devcenters/mydevcenter",
            "description": "Frontend development project"
        }
    }
).result()

# Create pool
pool = client.pools.begin_create_or_update(
    resource_group_name="devbox-rg",
    project_name="frontend-project",
    pool_name="frontend-pool",
    body={
        "location": "eastus",
        "properties": {
            "devBoxDefinitionName": "frontend-dev",
            "networkConnectionName": "devbox-network",
            "licenseType": "Windows_Client",
            "localAdministrator": "Enabled",
            "stopOnDisconnect": {
                "status": "Enabled",
                "gracePeriodMinutes": 60
            }
        }
    }
).result()

print(f"Created pool: {pool.name}")

Developer Self-Service

from azure.developer.devcenter import DevCenterClient

# Developer creates their own dev box
dev_client = DevCenterClient(
    endpoint="https://devcenter-endpoint.azure.com",
    credential=DefaultAzureCredential()
)

# Create dev box
dev_box = dev_client.dev_boxes.begin_create_dev_box(
    project_name="frontend-project",
    user_id="me",
    dev_box_name="my-frontend-box",
    body={
        "poolName": "frontend-pool"
    }
).result()

print(f"Dev Box created: {dev_box.name}")
print(f"State: {dev_box.provisioning_state}")

# Get connection info
remote_connection = dev_client.dev_boxes.get_remote_connection(
    project_name="frontend-project",
    user_id="me",
    dev_box_name="my-frontend-box"
)

print(f"Web URL: {remote_connection.web_url}")
print(f"RDP URL: {remote_connection.rdp_connection_url}")

Lifecycle Management

# Stop dev box (hibernate)
dev_client.dev_boxes.begin_stop(
    project_name="frontend-project",
    user_id="me",
    dev_box_name="my-frontend-box",
    hibernate=True
)

# Start dev box
dev_client.dev_boxes.begin_start(
    project_name="frontend-project",
    user_id="me",
    dev_box_name="my-frontend-box"
)

# Delete dev box
dev_client.dev_boxes.begin_delete(
    project_name="frontend-project",
    user_id="me",
    dev_box_name="my-frontend-box"
)

Auto-Stop Policies

# Configure auto-stop schedule
schedule = client.schedules.begin_create_or_update(
    resource_group_name="devbox-rg",
    project_name="frontend-project",
    pool_name="frontend-pool",
    schedule_name="default",
    body={
        "properties": {
            "type": "StopDevBox",
            "frequency": "Daily",
            "time": "19:00",
            "timeZone": "America/Los_Angeles",
            "state": "Enabled"
        }
    }
).result()

Dev Box simplifies developer onboarding and ensures consistent development environments. Tomorrow, I will cover Azure Deployment Environments.

Resources

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.