DEV Community

Cover image for Azure Developer CLI - How does it know that?
Christian Lechner
Christian Lechner

Posted on • Updated on

Azure Developer CLI - How does it know that?

"It's an energy field created by all living things. It surrounds us and penetrates us; it binds the galaxy together."
(Obi-Wan Kenobi)

The question

If you have made your first steps with the Azure Developer CLI, you will have seen that you can easily deploy the resources to Azure with different options for hosting you application code (like Azure Container Apps) and the deploy you application Code to exactly this hosting environment. You place this configuration into the azure.yaml file of your project.

But now let us take one step back. How does the Azure Developer CLI know into which Azure resource to deploy it into after you have provisioned it? What magic force keeps these things together? In this blog post I want to show you the connection (or to be precise the connections) between the hosting resource and your definition in the azure.yaml file.

First stop - the yaml schema

To walk through this, let us take the Static Web App sample app as example. The azure.yaml file looks like this:

# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json

name: todo-nodejs-mongo
metadata:
  template: todo-nodejs-mongo@0.0.1-beta
services:
  web:
    project: ./src/web
    dist: build
    language: js
    host: appservice
  api:
    project: ./src/api
    language: js
    host: appservice
Enter fullscreen mode Exit fullscreen mode

So let us first take a closer look at the schema used for the yaml language server as this gives some more information of what parameters and options are available for this configuration. Here we find the following information under "services":

 "resourceName": {
                        "type": "string",
                        "title": "Name of the Azure resource that implements the service",
                        "description": "Optional. If not specified, the resource name will be constructed from current environment name concatenated with service name (<environment-name><resource-name>, for example 'prodapi')."
                    },
Enter fullscreen mode Exit fullscreen mode

The title already says it all: "Name of the Azure resource that implements the service". So we have found that there is an optional parameter where we can specify the name of the resource. That is a finding, but the question remains:

  • The sample does not have this parameter set.
  • When following the sample, this name is dynamically generated and, hence we only know it after it is created. That 's a dead end.
  • Generally it is probably not the best way to hard code the resource name.

Okay, what else can we find? The description of the parameter gives us some more information about the determination logic of the name i.e., "if not specified, the resource name will be constructed from current environment name concatenated with service name (, for example 'prodapi'".

Okay that already looks like a more convenient way to create the name and can also serve as a guideline for conventions in projects using the Azure Developer CLI. Although giving more flexibility it does not feel as the golden path for linking the resources and the deployment together. In addition this would not work in case of the sample app as I did not follow this naming convention when executing the azd up command. There must be another way to bring things together. But which one.

๐Ÿ“ Remark - The schema file for azure.yaml is in general a good place to take a look at as there is more useful information available in this file.

It is all in the tags

The last place where there can then be a connection is the definition of the resource in the resources.bicep file. Taking a closer look at the resource definition that is relevant of hosting the web frontend we find:

resource web 'Microsoft.Web/sites@2022-03-01' = {
  name: '${abbrs.webSitesAppService}web-${resourceToken}'
  location: location
  tags: union(tags, { 'azd-service-name': 'web' })
  kind: 'app,linux'
Enter fullscreen mode Exit fullscreen mode

The tags property seems to be the answer to our question. There is this tag that stands out a bit: 'azd-service-name': 'web' This matches the service name of the frontend defined in the azure.yaml file. Let us do a cross check for the api service:

resource api 'Microsoft.Web/sites@2022-03-01' = {
  name: '${abbrs.webSitesAppService}api-${resourceToken}'
  location: location
  tags: union(tags, { 'azd-service-name': 'api' })
  kind: 'app,linux'
Enter fullscreen mode Exit fullscreen mode

Bingo, here we have the same pattern: a tag 'azd-service-name': 'api' that matches the service name of the api. And indeed the official documentation confirms that (link step 6 - not too prominent in my opinion, so hopefully this will be added at least to the FAQ section).

The most convenient way to enable the azd CLI to identify the resources that hosts you application is via the tag 'azd-service-name':. This is, at least in my opinion, the most elegant and flexible way to bring the different bits and pieces together. So question answered!

What about terraform?

Since mid of September version 0.2.0 of the Azure Developer CLI was released. With this version the CLI officially supports Terraform as Infrastructure as Code besides the already existing support for Bicep. The connection between the application and the target resource follows the same mechanism as described above. The tagging is done in accordance to the Terraform syntax. Taking the new Static Web App sample with Terraform you can find the tagging in the apps.tf file:

  • For the web app
  resource "azurerm_linux_web_app" "web" {
  name                = azurecaf_name.web_name.result
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  service_plan_id     = azurerm_service_plan.plan.id
  https_only          = true
  tags                = merge(local.tags, { azd-service-name : "web" })
Enter fullscreen mode Exit fullscreen mode
  • For the api
  resource "azurerm_linux_web_app" "api" {
  name                = azurecaf_name.appi_name.result
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  service_plan_id     = azurerm_service_plan.plan.id
  https_only          = true
  tags                = merge(local.tags, { "azd-service-name" : "api" })
Enter fullscreen mode Exit fullscreen mode

So nothing special concerning this aspect in case you are using Terraform

๐Ÿ“ Remark - Of course there are other specifics you must consider for Terraform that are described in the documentation.

Summary

The Azure Developer CLI allows you three ways to connect the application code and the resource that hosts your application in Azure:

  1. Explicitly setting the resourceName in the azure.yaml file
  2. Following the naming convention of constructing the resource name from current environment name concatenated with service name () which will be used by azd to auto detect the resource
  3. Using the tag azd-service-name in the bicep file describing the Azure resource.

The golden path in my opinion is option 3 with the tags. Option 2 might be a fair approach in some setups but comes with drawbacks. I personally would discourage the usage of option 1 as I do not see any pros for it.

I hope this blog post supports you in your journey with the Azure Developer CLI and makes your start with the CLI a smooth one.

References

Top comments (2)

Collapse
 
kaiwalter profile image
Kai Walter

Would you want to link your YT playlist on Az Developer CLI? youtube.com/playlist?list=PLmZLSvJ...

Collapse
 
lechnerc77 profile image
Christian Lechner

Done, thanks for the hint!