Azure Developer CLI - How does it know that?
Tags: azure, cli, azd
Published: 2022-09-22 07:04:27

*"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](https://learn.microsoft.com/azure/developer/azure-developer-cli/overview), 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
# 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
```

So let us first take a closer look at the [schema](https://github.com/Azure/azure-dev/blob/main/schemas/v1.0/azure.yaml.json) 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":

```json
 "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')."
                    },
```

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 (<environment-name><resource-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:

```bicep
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'
```

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:

```bicep
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'
```

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](https://learn.microsoft.com/azure/developer/azure-developer-cli/make-azd-compatible?pivots=azd-create#add-bicep-files) 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](https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-september-2022-release/?WT.mc_id=AZ-MVP-5004195). 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

  ```terraform
  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" })
  ```

- For the api

  ```terraform
  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" })
  ```

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](https://learn.microsoft.com/azure/developer/azure-developer-cli/use-terraform-for-azd).

## 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 (<environment-name><resource-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

- [Official Documentation of azd](https://learn.microsoft.com/azure/developer/azure-developer-cli/overview)
- [Official Documentation - Make your project compatible with Azure Developer CLI (azd)](https://learn.microsoft.com/azure/developer/azure-developer-cli/make-azd-compatible?pivots=azd-create)
- [GitHub Repository of azd](https://github.com/Azure/azure-dev)
- Issue with question: [Deployment of Function - Targeting Function App](https://github.com/Azure/azure-dev/issues/635)
- Quickglance [YouTube Playlist on Azure Developer CLI](https://www.youtube.com/playlist?list=PLmZLSvJAm8FbFq2XhqaPZgIzl6kewz1HD)