A3 - CLI & bicep
- Azure CLI is the command-line interface that can be used instead of the Azure protal (GUI)
az group create \
--name rg-ai300-dev \
--location uksouth
-
portal, CLI, and bicep, all three are different ways of interacting with the same underlying platform
-
CLI is beneficial because it is:
- scripted
- repeated
- version-controlled
- run in CI/CD
- parameterised
-
the commands tend to follow a hierarchical pattern
az <group> <subgroup/action> [arguments]
- eg:
az group createmeans:
az
└── group
└── create
- there are also commands around Azure ML:
az ml workspace ...
az ml job ...
az ml model ...
az ml online-endpoint ...
>>> az login
You
↓
Azure CLI
↓
Microsoft Entra authentication
↓
access token
↓
Azure
↓
RBAC
↓
allowed operation?
-
to inspect/set the subscription:
az account showandaz account set --subscription <subscription> -
creating infrastructure using commands is called the imperative approach
-
it can also be done declaratively using bicep
# Conceptually
I want:
resource group:
rg-ai300-dev
storage:
ai300storage
ML workspace:
mlw-ai300-dev
# Bicep command
resource storage 'Microsoft.Storage/storageAccounts@2025-01-01' = {
name: 'ai300storage'
location: 'uksouth'
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}
# Meaning
resource storage
├── type = Storage Account
├── API version = ...
├── name = ai300storage
├── location = UK South
├── SKU = Standard_LRS
└── kind = StorageV2
-
Microsoft.Storage/storageAccounts@2025-01-01can be broken into:- resource provider:
Microsoft.Storage - type:
storageAccounts - API version
2025-01-01
- resource provider:
-
parameters are provided from outside the bicep deployment whereas variables are calculated/deployed inside the bicep file
-
eg:
environment = dev/prodis a parameter,var workspaceName= 'mlw-ai300-${environment}'is a variable -
sometimes deployment creates information that another process needs, called outputs, eg:
output workspaceId string = workspace.id -
bicep/ARM can infer many dependencies from references between resources
resource storage ... = {
...
}
resource workspace ... = {
...
storageAccount: storage.id # reference = dependency
}
-
dependencies can also be explicitly stated
-
suppose a bicep file is deployed once, and then again, so ARM compares the desired deployment with the existing resources and applies what is needed, which is called idempotency, wherein, repeatedly applying the same desired state should converge on that same state:
-
eg: bicep changed
- v1:
compute max nodes = 2deploy - git commit:
compute max nodes = 4deploy again - ARM can reconcile the current state with the desired state and make the required update, which is the heart of IaC
- v1:
-
infrastructure becomes something that can be:
- defined
- versioned
- reviewed
- deployed
- updated
- reproduced
-
Azure supports a what-if operation for ARM/Bicep deployments that previews expected changes without applying them
CURRENT
Storage
ML workspace
Key Vault
+
NEW BICEP
Storage
ML workspace (changed)
Key Vault
Container Registry (new)
↓
WHAT-IF
~ modify ML workspace
+ create Container Registry
- so infrastructure changes become reviewable like software changes
Pull request
↓
validate Bicep
↓
run WHAT-IF
↓
show expected infrastructure changes
↓
human review
↓
merge
↓
deploy
-
note that secrets must not be put in code, so do not do this:
param databasePassword string = 'Password123' -
note:
- dockerfile defines application/runtime environment, eg: python, dependencies, application, startup command
- bicep defines Azure infrastructure: storage, key vault, ML, networking, monitoring
-
CLI and bicep can be used together
-
eg: deploy a bicep definition using CLI:
az deployment group create \
--resource-group rg-ai300-dev \
--template-file main.bicep
# Meaning
Azure CLI
↓
"deploy this Bicep"
↓
Azure Resource Manager
↓
main.bicep
↓
desired infrastructure
↓
Azure resources
GitHub repository
│
│ push/merge
▼
GitHub Actions
│
│ authenticate via
│ workload identity
▼
Microsoft Entra
│
▼
Azure RBAC
│
▼
Azure CLI
│
▼
deploy Bicep
│
▼
Azure Resource Manager
│
▼
Azure infrastructure
- a realistic project structure:
ai300-project/
│
├── src/
│ ├── train.py
│ └── score.py
│
├── tests/
│
├── ml/
│ ├── train-job.yml
│ └── pipeline.yml
│
├── infra/
│ ├── main.bicep
│ ├── dev.bicepparam
│ └── prod.bicepparam
│
├── .github/
│ └── workflows/
│ ├── ci.yml
│ └── deploy.yml
│
├── Dockerfile
└── requirements.txt