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-ifpreview 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-apiSpring 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 |
Consistent |
The same concepts — constructing a client with a builder, passing |
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 ( |
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.
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-apidev box, anorders-apidev 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.xmlpulls 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: GitHub Docs — About secret scanning, GitHub Docs — Protecting pushes with secret scanning (push protection), GitHub Docs — About Dependabot alerts, GitHub Docs — About dependency review, Overview of Microsoft Defender for Cloud DevOps security, Reference table for DevOps security recommendations.
Related pages
-
Git & GitHub covers day-to-day Git and GitHub usage — commits, branches, pull requests — that this page’s GitHub Actions and Codespaces examples build on.
-
Docker CI/CD with GitHub Actions covers the build/push half of the workflows extended above.
-
Identity and Access covers the federated-credential identity setup those same workflows authenticate with.
-
Container Apps and Deploying Microservices on AKS cover the resources the deploy steps above target.
-
Storage Accounts, Cosmos DB and Azure DocumentDB and Messaging and Integration Services cover the real Azure services the local emulators above stand in for.
-
Governance and Compliance covers Microsoft Defender for Cloud’s broader posture management beyond the DevOps-specific slice on this page.
References
-
Use the Azurite emulator for local Azure Storage development
-
Announcing general availability of the Azure Cosmos DB vNext emulator
-
Access a private AKS cluster using command invoke or Run command
-
Create an Azure Resource Manager service connection with workload identity federation
-
GitHub Docs — Protecting pushes with secret scanning (push protection)