Developer Tools and DevOps

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

See the section bibliography for the reference material consulted while preparing these pages.

Examples on this page target Azure CLI 2.90.0 and the same Bookshelf resource names used throughout this section (rg-bookshelf, acrbookshelf, cae-bookshelf, aks-bookshelf); re-verify tool and extension versions against the linked documentation before relying on them, since IDE plugins, CLI extensions and emulator images each ship on their own release cadence, independent of the Azure CLI itself.

This page covers the tooling that sits around Azure, not a single Azure service: the IDE integrations Bookshelf’s developers install, the design principles behind every Azure SDK they call from code, the local emulators that let them run Storage/Cosmos DB/Functions/Service Bus workloads without an Azure subscription, the GitHub Actions deploy steps that ship catalog-api and orders-api to Container Apps and AKS, Azure’s own DevOps and cloud-development-environment offerings, GitHub Codespaces, and the DevSecOps practices (secret scanning, dependency scanning, unified posture across the pipeline) that keep all of it honest.

IDE Azure toolkits

VS Code

The Azure Tools extension pack (ms-vscode.vscode-node-azure-pack) bundles the Azure Account, Resources, Storage, App Service, Functions, Container Apps, Static Web Apps, Cosmos DB and Kubernetes extensions behind a single install, adding an Azure activity-bar icon that lists subscriptions and resources, deploys straight from the editor (right-click a folder → Deploy to Web App / Deploy to Function App / Deploy to Container Apps), and integrates with Azurite (covered below) and the Azure Resources extension’s resource explorer.

Visual Studio

The Azure development workload in the Visual Studio Installer adds Cloud Explorer, the Connected Services publish profiles for App Service/Container Apps/AKS, Azure Functions project templates and debugging, and Azure Resource Manager/Bicep language support (syntax highlighting, IntelliSense, what-if preview inline).

IntelliJ IDEA

The Azure Toolkit for IntelliJ plugin (JetBrains Marketplace) adds an Azure Explorer tool window, one-click deploy of a Spring Boot artifact to App Service/Functions/Container Apps/Spring Apps, an embedded Azurite/Cosmos DB emulator launcher, and Application Insights log streaming — the natural fit for Bookshelf’s catalog-api/orders-api Spring Boot modules.

Each toolkit authenticates the same way the CLI does — an interactive Entra ID sign-in cached locally, or a service principal/managed identity for headless use — rather than a separate credential store; see Identity and Access for how that authentication maps onto DefaultAzureCredential once the code itself needs a token.

Azure SDK design principles

Every current Azure SDK (azure-sdk-for-java, azure-sdk-for-net, azure-sdk-for-python, azure-sdk-for-js, azure-sdk-for-go) is built to the same four cross-language design pillars published by the Azure SDK team:

Pillar What it means in practice

Idiomatic

Each language’s client library follows that language’s own conventions (a Java client returns Mono/Flux or blocking calls, a .NET client exposes async/await and IAsyncEnumerable<T>) rather than a lowest-common- denominator API shape.

Consistent

The same concepts — constructing a client with a builder, passing DefaultAzureCredential, paging with PagedIterable/Pageable<T>, retrying with an exponential-backoff policy — work the same way across every Azure service’s SDK in a given language, so learning one client transfers to the next.

Approachable

A client builder ships predictable, secure-by-default behavior (TLS, retries, a sane default timeout) so a developer can be productive from the quickstart without first reading the wire protocol.

Diagnosable

Every client emits structured logging and distributed-tracing spans through the language’s standard observability hooks (java.util.logging/SLF4J bridge, ILogger, OpenTelemetry) so a failed call is debuggable without a support ticket.

Underneath those pillars, every SDK is built on a shared low-level package (azure-core for Java, Azure.Core for .NET, azure-core for Python) that supplies the same three building blocks regardless of which service client sits on top: an HttpPipeline of composable policies (retry, logging, telemetry, authentication) wrapping a pluggable HTTP transport; the TokenCredential abstraction that DefaultAzureCredential implements (see Identity and Access) so every client authenticates the same way whether it runs on a developer’s machine, in a Container App, or on an AKS pod with workload identity; and a Pageable/PagedIterable return type for any operation that lists a collection, so catalog-api iterates a container listing or a Cosmos DB query the same way it iterates any other paged Azure result. Long-running operations (a Key Vault certificate creation, an ACR build) follow the same poller pattern across services rather than each client inventing its own "is it done yet" loop.

Local emulators

Running Bookshelf’s data-plane dependencies locally, without provisioning anything in rg-bookshelf, keeps the inner dev loop fast and free. Each emulator below is a container or CLI tool that speaks the same wire protocol as its Azure service, so catalog-api/orders-api connect with the same SDK client, just pointed at localhost; running one locally in Docker creates no durable Azure resource, so none of them needs a == Clean up step.

Azurite (Storage)

Azurite emulates Blob, Queue and Table (preview) endpoints for Storage Accounts and Blob Storage. It ships three ways: the Azurite VS Code extension (install and run from the Command Palette), bundled automatically with Visual Studio 2022, or standalone via npm or Docker:

# npm (Node.js already installed)
npm install -g azurite
azurite --silent --location ./azurite-data --debug ./azurite-data/debug.log

# Docker -- ports 10000/10001/10002 are Blob/Queue/Table
docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 \
  mcr.microsoft.com/azure-storage/azurite

catalog-api points its AzureWebJobsStorage/ConnectionString at Azurite’s fixed well-known development account (UseDevelopmentStorage=true, or the explicit http://127.0.0.1:10000/devstoreaccount1 connection string with Azurite’s published well-known key) instead of a real storage account connection string.

Azure Cosmos DB emulator

The current Cosmos DB emulator is the Linux-based vNext emulator, a single cross-platform (x64/ARM64) Docker image that reached general availability in 2026, replacing the older Windows-only emulator:

docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-latest
docker run --detach --publish 8081:8081 --publish 8080:8080 --publish 1234:1234 \
  --name cosmos-emulator mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-latest

Port 8081 serves the Cosmos DB endpoint and its (self-signed, browsable) Data Explorer; orders-api’s Cosmos SDK client points at `https://localhost:8081 with the emulator’s published well-known key rather than an Entra ID token, since local emulator auth is key-based even where the real service uses data-plane RBAC. See that page for the account/database/container model the emulator reproduces.

Azure Functions Core Tools

Azure Functions Core Tools provides the func CLI that runs, debugs and packages Functions projects locally — the same local runtime VS Code’s Azure Functions extension and Visual Studio’s Functions project templates drive under the hood:

npm install -g azure-functions-core-tools@4 --unsafe-perm true
# or on macOS: brew tap azure/functions && brew install azure-functions-core-tools@4

func init bookshelf-notifier-trigger --worker-runtime dotnet-isolated
cd bookshelf-notifier-trigger
func start

func start hosts the functions locally against local.settings.json (never committed — it is where a local Service Bus/Storage connection string or emulator endpoint lives), reachable at http://localhost:7071 for HTTP triggers. See App Service and Azure Functions for the hosting plans and trigger/binding model this local host reproduces.

Azure Service Bus emulator

The Service Bus emulator runs as a Docker Compose stack — the emulator container plus a required SQL Server Linux (or SQL Edge) container it uses for message persistence — configured from a Config.json that declares the queues and topics/subscriptions to pre-create (matching what Messaging and Integration Services provisions for real with az servicebus queue/topic create):

git clone https://github.com/Azure/azure-service-bus-emulator-installer.git
cd azure-service-bus-emulator-installer/ServiceBus-Emulator
# Config.json here declares the notifier-orders queue Bookshelf's notifier job consumes
docker compose -f docker-compose.yml up -d

The notifier worker’s Spring Cloud Azure Service Bus client connects with a fixed development connection string (Endpoint=sb://localhost;…​;UseDevelopmentEmulator=true;) instead of DefaultAzureCredential, since the emulator has no Entra ID of its own to authenticate against; that gap is exactly why the emulator is for local development only, never a substitute for a real namespace in any shared environment.

GitHub Actions: deploying Bookshelf with OIDC

Identity and Access sets up the identity side of this pipeline — the bookshelf-github-actions-deploy app registration, its role assignment, and the federated credential subject that lets azure/login exchange GitHub’s own OIDC token for an Entra ID access token with no stored client secret — and Docker CI/CD with GitHub Actions covers the workflow mechanics common to any image build: setup-buildx-action, metadata-action tags, build-push-action, test-before-push and caching. This section picks up exactly where those two leave off: the deploy step(s) that take an image already built and pushed to acrbookshelf and roll it out to a running Container App or AKS deployment.

sequenceDiagram participant GH as GitHub Actions job participant Entra as Microsoft Entra ID (OIDC token endpoint) participant Login as azure/login participant ACR as acrbookshelf participant CAE as cae-bookshelf (Container Apps) participant AKS as aks-bookshelf (AKS) GH->>Entra: Exchange GitHub OIDC token for Entra ID access token (federated credential) Entra-->>GH: Short-lived Azure access token, no client secret involved GH->>Login: azure/login authenticates the job with that token GH->>ACR: az acr build (or docker/build-push-action) pushes the new image tag alt Deploying to Container Apps GH->>CAE: az containerapp update --image ... (new revision) else Deploying to AKS GH->>AKS: kubectl apply / helm upgrade against the cluster end

Deploying to Container Apps

Once the image is pushed, az containerapp update --image rolls a new revision for catalog-api or orders-api — no separate az containerapp create needed, since the app already exists from Container Apps:

# .github/workflows/deploy-container-apps.yml (excerpt -- continues the build/push job from
# ci-cd-with-github-actions.adoc)
permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    needs: build-and-push          # the job covered on ci-cd-with-github-actions.adoc
    steps:
      - uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Deploy the new image to Container Apps
        run: |
          az containerapp update \
            --name catalog-api \
            --resource-group rg-bookshelf \
            --image acrbookshelf.azurecr.io/com.example.bookshelf/catalog-api:${{ github.sha }}

az containerapp update --image creates a new revision from the app’s existing configuration (CPU/memory, ingress, scaling rules, secrets) with only the image reference changed; Multiple revisions mode and traffic splitting, covered on Container Apps, apply the same way to a revision created this way as to one created through the portal or az containerapp up. The service principal driving this step needs the Container Apps Contributor role (or the narrower AcrPull role on acrbookshelf if it only deploys, never builds), assigned the same way as the identity-and-access.adoc role assignment.

Deploying to AKS

For a cluster reachable from the runner — a GitHub-hosted runner against a public API server, or a self-hosted runner inside vnet-bookshelf against a private one, per VPN Gateway and Hybrid Connectivity — azure/aks-set-context plus kubectl/helm is the direct, recommended path, exactly as shown end to end on Deploying Microservices on AKS (Helm upgrade against aks-bookshelf):

      - uses: azure/aks-set-context@v4
        with:
          resource-group: rg-bookshelf
          cluster-name: aks-bookshelf

      - name: Deploy the new image
        run: |
          kubectl -n bookshelf set image deployment/catalog-api \
            catalog-api=acrbookshelf.azurecr.io/com.example.bookshelf/catalog-api:${{ github.sha }}
          kubectl -n bookshelf rollout status deployment/catalog-api

When the cluster is private and the runner has no network path to its API server at all — no self-hosted runner in the VNet, no Bastion/VPN/ExpressRoute reachable from the pipeline — az aks command invoke runs kubectl/helm against the cluster through the Azure Resource Manager API instead, without ever needing network connectivity to the API server:

az aks command invoke \
  --resource-group rg-bookshelf \
  --name aks-bookshelf \
  --command "kubectl -n bookshelf set image deployment/catalog-api catalog-api=acrbookshelf.azurecr.io/com.example.bookshelf/catalog-api:$GITHUB_SHA"

Microsoft’s own guidance is that command invoke is designed for occasional/administrative access to a private cluster, not as the primary channel for routine automated deployments — its 512 kB output cap and 60-second scheduling timeout make it a poor fit for anything beyond a single kubectl/helm invocation, so a self-hosted runner with real network access to the cluster (via a private endpoint or the VPN Gateway/ExpressRoute path on VPN Gateway and Hybrid Connectivity) is the better long-term answer for a private aks-bookshelf.

Azure DevOps

Azure DevOps is Microsoft’s own alternative to GitHub for the same end-to-end flow, organized as four services under one project: Boards (work items, sprints, Kanban boards), Repos (Git repositories, pull requests, branch policies), Pipelines (YAML-based CI/CD, conceptually equivalent to a GitHub Actions workflow but with its own task marketplace, including an AzureCLI@2 task and Azure service-connection-based OIDC federation for the same passwordless deploy pattern shown above), and Artifacts (package feeds for Maven, npm, NuGet and Python, playing the same role GitHub Packages/GHCR plays for this section’s Bookshelf examples). An organization already invested in GitHub for Bookshelf has no reason to add Azure DevOps alongside it — the two are alternatives, not complements — but a team migrating an existing Azure DevOps estate keeps its Boards and Pipelines while still deploying to the same Container Apps/AKS resources this section covers.

Cloud-hosted development environments

Microsoft Dev Box

A managed, network-joined Windows developer workstation ("dev box") provisioned from a dev-center image, sized per role (a catalog-api dev box, an orders-api dev box) and billed like any other Azure compute resource. Microsoft Dev Box is retiring: its closing-down period began 2026-09-14, and it retires fully at 17:00 UTC on 2028-09-18; Microsoft’s stated recommended replacement is Windows 365, which is not a one-to-one feature match, so any new investment in cloud-hosted developer workstations should start there or with a validated alternative rather than with Dev Box.

Azure Deployment Environments

Lets a developer self-service a short-lived, policy-compliant environment (a scratch AKS namespace, a temporary resource group mirroring rg-bookshelf) from a catalog of Bicep/Terraform templates a platform team curates, without needing subscription Owner/Contributor access themselves. Azure Deployment Environments is also retiring, on 2027-02-22 — a separate timeline from Dev Box even though the two services are often used together, so a team relying on both needs two separate migration plans, not one.

Azure DevTest Labs

Pre-dates both of the above: self-service VM labs with cost controls (auto-shutdown, per-user VM quotas, formulas/artifacts for repeatable images), aimed at short-lived test/training VMs rather than a persistent developer workstation or an ephemeral application environment. It remains a supported option today and is one of the paths Microsoft points Dev Box customers toward during that migration, alongside Azure Virtual Desktop and Windows 365.

GitHub Codespaces

GitHub Codespaces provisions a container-based, browser- or VS-Code-reachable development environment straight from a repository, configured by a .devcontainer/devcontainer.json that pins the base image, installed tools (the Azure CLI, kubectl, azd) and VS Code extensions (including the Azure Tools pack from earlier on this page) so every contributor to Bookshelf’s repositories opens an identical, disposable environment instead of reproducing one by hand:

{
  "name": "bookshelf-dev",
  "image": "mcr.microsoft.com/devcontainers/java:1-21-bookworm",
  "features": {
    "ghcr.io/devcontainers/features/azure-cli:1": {},
    "ghcr.io/devcontainers/features/docker-in-docker:2": {}
  },
  "customizations": {
    "vscode": {
      "extensions": ["ms-vscode.vscode-node-azure-pack"]
    }
  }
}

A codespace authenticates to Azure the same way a local machine does — az login interactively, or a federated workload identity when a codespace itself needs to run CI-like automation — and Docker-in-Docker inside it can run the Azurite/Cosmos DB/Service Bus emulators from earlier on this page exactly as a local machine would, making a codespace a viable substitute for a local dev box for Bookshelf’s contributors who prefer not to install the toolchain locally at all.

DevSecOps practices

Shifting security left in Bookshelf’s pipeline means catching a leaked secret, a vulnerable dependency, or a misconfigured template before it merges, not after it deploys — three practices cover most of that surface:

Secret scanning and push protection

GitHub’s secret scanning checks every push against several hundred provider-specific patterns (cloud keys, database connection strings, PATs); push protection goes further and blocks a push containing a detected secret before it ever reaches the repository’s history, rather than flagging it after the fact. It is on by default and free for public repositories; a private repository needs GitHub Advanced Security enabled to get the same coverage. Combined with the "never write real secrets, only placeholders" convention this whole section follows, push protection is a backstop against exactly the mistake this section’s examples are written to avoid.

Dependency and code scanning

Dependabot alerts (dependency graph plus vulnerability alerts, included on every GitHub plan) flag a vulnerable version of a dependency catalog-api’s or `orders-api’s `pom.xml pulls in; Dependabot security updates can open the fixing pull request automatically. Dependency review, a GitHub Advanced Security feature, adds the same check as a pull-request gate — diffing a PR’s dependency changes against known vulnerabilities before merge, rather than after Dependabot notices post-merge. CodeQL code scanning covers the application code itself, complementary to but distinct from dependency scanning.

Microsoft Defender for Cloud DevOps security

Connects a GitHub (or Azure DevOps) organization to Defender for Cloud so its code, secret and dependency findings — sourced from GitHub Advanced Security rather than a duplicate Microsoft-run scanner — surface alongside the rest of Bookshelf’s cloud security posture: exposed resources, container image vulnerabilities and Infrastructure-as-Code misconfigurations (Bicep/Terraform) correlated with the code that produced them, in one place instead of a separate dashboard per tool. This is the piece that ties this page’s GitHub-side scanning back to the Azure-side governance covered on Governance and Compliance.

References