Skip to content

Commit da5e1ec

Browse files
committed
Configure Azure Developer Pipeline
1 parent 5888961 commit da5e1ec

10 files changed

Lines changed: 590 additions & 13 deletions

File tree

‎.github/workflows/azure-dev.yml‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: Deploy App
2+
3+
on:
4+
workflow_dispatch:
5+
workflow_run:
6+
workflows: ["Run Tests"]
7+
branches: [main]
8+
types: [completed]
9+
10+
permissions:
11+
id-token: write
12+
contents: read
13+
14+
jobs:
15+
deploy-staging:
16+
runs-on: ubuntu-latest
17+
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
18+
environment: staging
19+
concurrency:
20+
group: deploy-${{ github.ref }}-staging
21+
cancel-in-progress: true
22+
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- name: Install azd
27+
uses: Azure/setup-azd@v2
28+
29+
- name: Log in with Azure (Federated Credentials)
30+
run: |
31+
azd auth login \
32+
--client-id "${{ vars.AZURE_CLIENT_ID }}" \
33+
--federated-credential-provider "github" \
34+
--tenant-id "${{ vars.AZURE_TENANT_ID }}"
35+
36+
- name: Provision and deploy to staging
37+
run: azd up --environment staging --no-prompt
38+
env:
39+
AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
40+
AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
41+
AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
42+
43+
deploy-production:
44+
runs-on: ubuntu-latest
45+
needs: deploy-staging
46+
environment: production
47+
concurrency:
48+
group: deploy-${{ github.ref }}-production
49+
cancel-in-progress: false
50+
51+
steps:
52+
- uses: actions/checkout@v4
53+
54+
- name: Install azd
55+
uses: Azure/setup-azd@v2
56+
57+
- name: Log in with Azure (Federated Credentials)
58+
run: |
59+
azd auth login \
60+
--client-id "${{ vars.AZURE_CLIENT_ID }}" \
61+
--federated-credential-provider "github" \
62+
--tenant-id "${{ vars.AZURE_TENANT_ID }}"
63+
64+
- name: Provision and deploy to production
65+
run: azd up --environment production --no-prompt
66+
env:
67+
AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
68+
AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
69+
AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}

‎.gitignore‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,5 @@ htmlcov/
4141

4242
# playwright
4343
client/test-results/
44-
client/playwright-report/
44+
client/playwright-report/
45+
.azure

‎azure.yaml‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
2+
3+
name: pets-workshop
4+
metadata:
5+
template: azd-init@1.23.7
6+
services:
7+
client:
8+
project: client
9+
host: containerapp
10+
language: ts
11+
docker:
12+
path: Dockerfile
13+
server:
14+
project: server
15+
host: containerapp
16+
language: python
17+
resources:
18+
client:
19+
type: host.containerapp
20+
port: 4321
21+
server:
22+
type: host.containerapp
23+
port: 80

‎content/github-actions/6-deploy-azure.md‎

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Let's set up the Azure Developer CLI and scaffold the infrastructure for our pro
5757
azd init --from-code
5858
```
5959

60-
4. Follow the prompts, accepting the defaults provided by the tool. When asked for a namespace, choose something unique (this will be used to name your Azure resources).
60+
4. Follow the prompts, accepting the defaults provided by the tool.
6161
5. By default, `azd` generates infrastructure in memory at deploy time. To customize the infrastructure, persist it to disk by running:
6262

6363
```bash
@@ -198,27 +198,24 @@ Let's walk through the key parts:
198198

199199
## Set up Azure authentication
200200

201-
Now let's authenticate with Azure and let `azd` configure the pipeline credentials. Because the workflow file already exists, `azd` will configure OIDC and variables around it rather than generating a new one.
201+
Now let's let `azd` configure the pipeline credentials. Because the workflow file already exists, `azd` will configure OIDC and variables around it rather than generating a new one.
202202
203-
1. Authenticate with Azure:
204-
205-
```bash
206-
azd auth login
207-
```
208-
209-
2. Follow the prompts to complete the authentication (a browser window will open for you to sign in).
210-
3. Configure the deployment pipeline:
203+
1. Configure the deployment pipeline:
211204
212205
```bash
213206
azd pipeline config
214207
```
215208
216-
This command will:
209+
2. When prompted for an environment name, choose something unique (this will be used to name your Azure resources).
210+
3. Select your Azure **subscription** and **region** when prompted.
211+
4. When asked to authenticate to GitHub, follow the browser prompts to sign in.
212+
5. When asked how to authenticate the pipeline to Azure, select **federated service principal**. This is the OIDC approach — passwordless, short-lived tokens — that the workflow is configured to use.
213+
6. Follow the remaining prompts. This command will:
217214
- Create OIDC credentials in Azure for passwordless authentication
218215
- Store the necessary secrets and variables in your repository automatically
219216
- Detect your existing workflow file and configure it
220217
221-
4. When prompted to commit and push your local changes, say **yes**.
218+
7. When prompted to commit and push your local changes, say **yes**.
222219
223220
> [!TIP]
224221
> After `azd pipeline config` completes, navigate to **Settings** > **Secrets and variables** > **Actions** > **Variables** tab to see the repository variables it created (like `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, etc.). These are the `vars.*` values your workflow references.

‎infra/abbreviations.json‎

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
{
2+
"aiFoundryAccounts": "aif",
3+
"analysisServicesServers": "as",
4+
"apiManagementService": "apim-",
5+
"appConfigurationStores": "appcs-",
6+
"appManagedEnvironments": "cae-",
7+
"appContainerApps": "ca-",
8+
"authorizationPolicyDefinitions": "policy-",
9+
"automationAutomationAccounts": "aa-",
10+
"blueprintBlueprints": "bp-",
11+
"blueprintBlueprintsArtifacts": "bpa-",
12+
"cacheRedis": "redis-",
13+
"cdnProfiles": "cdnp-",
14+
"cdnProfilesEndpoints": "cdne-",
15+
"cognitiveServicesAccounts": "cog-",
16+
"cognitiveServicesFormRecognizer": "cog-fr-",
17+
"cognitiveServicesTextAnalytics": "cog-ta-",
18+
"computeAvailabilitySets": "avail-",
19+
"computeCloudServices": "cld-",
20+
"computeDiskEncryptionSets": "des",
21+
"computeDisks": "disk",
22+
"computeDisksOs": "osdisk",
23+
"computeGalleries": "gal",
24+
"computeSnapshots": "snap-",
25+
"computeVirtualMachines": "vm",
26+
"computeVirtualMachineScaleSets": "vmss-",
27+
"containerInstanceContainerGroups": "ci",
28+
"containerRegistryRegistries": "cr",
29+
"containerServiceManagedClusters": "aks-",
30+
"databricksWorkspaces": "dbw-",
31+
"dataFactoryFactories": "adf-",
32+
"dataLakeAnalyticsAccounts": "dla",
33+
"dataLakeStoreAccounts": "dls",
34+
"dataMigrationServices": "dms-",
35+
"dBforMySQLServers": "mysql-",
36+
"dBforPostgreSQLServers": "psql-",
37+
"devicesIotHubs": "iot-",
38+
"devicesProvisioningServices": "provs-",
39+
"devicesProvisioningServicesCertificates": "pcert-",
40+
"documentDBDatabaseAccounts": "cosmos-",
41+
"documentDBMongoDatabaseAccounts": "cosmon-",
42+
"eventGridDomains": "evgd-",
43+
"eventGridDomainsTopics": "evgt-",
44+
"eventGridEventSubscriptions": "evgs-",
45+
"eventHubNamespaces": "evhns-",
46+
"eventHubNamespacesEventHubs": "evh-",
47+
"hdInsightClustersHadoop": "hadoop-",
48+
"hdInsightClustersHbase": "hbase-",
49+
"hdInsightClustersKafka": "kafka-",
50+
"hdInsightClustersMl": "mls-",
51+
"hdInsightClustersSpark": "spark-",
52+
"hdInsightClustersStorm": "storm-",
53+
"hybridComputeMachines": "arcs-",
54+
"insightsActionGroups": "ag-",
55+
"insightsComponents": "appi-",
56+
"keyVaultVaults": "kv-",
57+
"kubernetesConnectedClusters": "arck",
58+
"kustoClusters": "dec",
59+
"kustoClustersDatabases": "dedb",
60+
"logicIntegrationAccounts": "ia-",
61+
"logicWorkflows": "logic-",
62+
"machineLearningServicesWorkspaces": "mlw-",
63+
"managedIdentityUserAssignedIdentities": "id-",
64+
"managementManagementGroups": "mg-",
65+
"migrateAssessmentProjects": "migr-",
66+
"networkApplicationGateways": "agw-",
67+
"networkApplicationSecurityGroups": "asg-",
68+
"networkAzureFirewalls": "afw-",
69+
"networkBastionHosts": "bas-",
70+
"networkConnections": "con-",
71+
"networkDnsZones": "dnsz-",
72+
"networkExpressRouteCircuits": "erc-",
73+
"networkFirewallPolicies": "afwp-",
74+
"networkFirewallPoliciesWebApplication": "waf",
75+
"networkFirewallPoliciesRuleGroups": "wafrg",
76+
"networkFrontDoors": "fd-",
77+
"networkFrontdoorWebApplicationFirewallPolicies": "fdfp-",
78+
"networkLoadBalancersExternal": "lbe-",
79+
"networkLoadBalancersInternal": "lbi-",
80+
"networkLoadBalancersInboundNatRules": "rule-",
81+
"networkLocalNetworkGateways": "lgw-",
82+
"networkNatGateways": "ng-",
83+
"networkNetworkInterfaces": "nic-",
84+
"networkNetworkSecurityGroups": "nsg-",
85+
"networkNetworkSecurityGroupsSecurityRules": "nsgsr-",
86+
"networkNetworkWatchers": "nw-",
87+
"networkPrivateDnsZones": "pdnsz-",
88+
"networkPrivateLinkServices": "pl-",
89+
"networkPublicIPAddresses": "pip-",
90+
"networkPublicIPPrefixes": "ippre-",
91+
"networkRouteFilters": "rf-",
92+
"networkRouteTables": "rt-",
93+
"networkRouteTablesRoutes": "udr-",
94+
"networkTrafficManagerProfiles": "traf-",
95+
"networkVirtualNetworkGateways": "vgw-",
96+
"networkVirtualNetworks": "vnet-",
97+
"networkVirtualNetworksSubnets": "snet-",
98+
"networkVirtualNetworksVirtualNetworkPeerings": "peer-",
99+
"networkVirtualWans": "vwan-",
100+
"networkVpnGateways": "vpng-",
101+
"networkVpnGatewaysVpnConnections": "vcn-",
102+
"networkVpnGatewaysVpnSites": "vst-",
103+
"notificationHubsNamespaces": "ntfns-",
104+
"notificationHubsNamespacesNotificationHubs": "ntf-",
105+
"operationalInsightsWorkspaces": "log-",
106+
"portalDashboards": "dash-",
107+
"powerBIDedicatedCapacities": "pbi-",
108+
"purviewAccounts": "pview-",
109+
"recoveryServicesVaults": "rsv-",
110+
"resourcesResourceGroups": "rg-",
111+
"searchSearchServices": "srch-",
112+
"serviceBusNamespaces": "sb-",
113+
"serviceBusNamespacesQueues": "sbq-",
114+
"serviceBusNamespacesTopics": "sbt-",
115+
"serviceEndPointPolicies": "se-",
116+
"serviceFabricClusters": "sf-",
117+
"signalRServiceSignalR": "sigr",
118+
"sqlManagedInstances": "sqlmi-",
119+
"sqlServers": "sql-",
120+
"sqlServersDataWarehouse": "sqldw-",
121+
"sqlServersDatabases": "sqldb-",
122+
"sqlServersDatabasesStretch": "sqlstrdb-",
123+
"storageStorageAccounts": "st",
124+
"storageStorageAccountsVm": "stvm",
125+
"storSimpleManagers": "ssimp",
126+
"streamAnalyticsCluster": "asa-",
127+
"synapseWorkspaces": "syn",
128+
"synapseWorkspacesAnalyticsWorkspaces": "synw",
129+
"synapseWorkspacesSqlPoolsDedicated": "syndp",
130+
"synapseWorkspacesSqlPoolsSpark": "synsp",
131+
"timeSeriesInsightsEnvironments": "tsi-",
132+
"webServerFarms": "plan-",
133+
"webSitesAppService": "app-",
134+
"webSitesAppServiceEnvironment": "ase-",
135+
"webSitesFunctions": "func-",
136+
"webStaticSites": "stapp-"
137+
}

‎infra/main.bicep‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
targetScope = 'subscription'
2+
3+
@minLength(1)
4+
@maxLength(64)
5+
@description('Name of the environment that can be used as part of naming resource convention')
6+
param environmentName string
7+
8+
@minLength(1)
9+
@description('Primary location for all resources')
10+
param location string
11+
12+
13+
param clientExists bool
14+
param serverExists bool
15+
16+
@description('Id of the user or app to assign application roles')
17+
param principalId string
18+
19+
@description('Principal type of user or app')
20+
param principalType string
21+
22+
// Tags that should be applied to all resources.
23+
//
24+
// Note that 'azd-service-name' tags should be applied separately to service host resources.
25+
// Example usage:
26+
// tags: union(tags, { 'azd-service-name': <service name in azure.yaml> })
27+
var tags = {
28+
'azd-env-name': environmentName
29+
}
30+
31+
// Organize resources in a resource group
32+
resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = {
33+
name: 'rg-${environmentName}'
34+
location: location
35+
tags: tags
36+
}
37+
38+
module resources 'resources.bicep' = {
39+
scope: rg
40+
name: 'resources'
41+
params: {
42+
location: location
43+
tags: tags
44+
principalId: principalId
45+
principalType: principalType
46+
clientExists: clientExists
47+
serverExists: serverExists
48+
}
49+
}
50+
output AZURE_CONTAINER_REGISTRY_ENDPOINT string = resources.outputs.AZURE_CONTAINER_REGISTRY_ENDPOINT
51+
output AZURE_RESOURCE_CLIENT_ID string = resources.outputs.AZURE_RESOURCE_CLIENT_ID
52+
output AZURE_RESOURCE_SERVER_ID string = resources.outputs.AZURE_RESOURCE_SERVER_ID

‎infra/main.parameters.json‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {
5+
"environmentName": {
6+
"value": "${AZURE_ENV_NAME}"
7+
},
8+
"location": {
9+
"value": "${AZURE_LOCATION}"
10+
},
11+
"clientExists": {
12+
"value": "${SERVICE_CLIENT_RESOURCE_EXISTS=false}"
13+
},
14+
"serverExists": {
15+
"value": "${SERVICE_SERVER_RESOURCE_EXISTS=false}"
16+
},
17+
"principalId": {
18+
"value": "${AZURE_PRINCIPAL_ID}"
19+
},
20+
"principalType": {
21+
"value": "${AZURE_PRINCIPAL_TYPE}"
22+
}
23+
}
24+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
param exists bool
2+
param name string
3+
4+
resource existingApp 'Microsoft.App/containerApps@2023-05-02-preview' existing = if (exists) {
5+
name: name
6+
}
7+
8+
output containers array = exists ? existingApp!.properties.template.containers : []

0 commit comments

Comments
 (0)