Azure DevOps - Always Be Shipping!

How to configure Azure IoT Edge deployments in Azure DevOps pipeline?

This post was most recently updated on July 27th, 2022.

3 min read.

So some time ago, I needed to configure my first Azure DevOps pipeline for an Azure IoT Edge project. I needed to figure out which tasks to use, how to handle variables – all that good stuff. And let’s call it a learning experience.

Pro tip: AzureIoTEdge task is not the way to go :)

This article has actually been more than a year in the making, but as usual, it takes me a while to get around to polishing things into a publishable form. This time, it took until I went on 6-week paternity leave.


Azure IoT Edge has dedicated tasks for the most typical things you might need to accomplish in your Azure DevOps pipelines – building, pushing, and deploying modules. As a novice Azure IoT Edge developer, I opted to use these.

This turned out to be a bit more complicated than I expected, and I needed to find some workarounds.


So, using Azure IoT Edge Azure DevOps tasks, you should theoretically be building the pipeline using the built-in task called AzureIoTEdge. This would look somewhat like this (don’t use the YAML for anything, that’s just a sample to show you an idea):

- main

  azureSubscriptionEndpoint: Contoso


- task: AzureIoTEdge@2
  displayName: AzureIoTEdge - Build module images
    action: Build module images
    templateFilePath: deployment.template.json
    defaultPlatform: amd64

- task: AzureIoTEdge@2
  displayName: AzureIoTEdge - Push module images
    action: Push module images
    containerregistrytype: Azure Container Registry
    azureSubscriptionEndpoint: $(azureSubscriptionEndpoint)
    azureContainerRegistry: {"loginServer":"$(azureContainerRegistry)"}
    templateFilePath: deployment.template.json
    defaultPlatform: amd64
    fillRegistryCredential: true

- task: AzureIoTEdge@2
  displayName: AzureIoTEdge - Generate deployment manifest
    action: Generate deployment manifest
    templateFilePath: deployment.template.json
    defaultPlatform: amd64
    deploymentManifestOutputPath: $(System.DefaultWorkingDirectory)/config/deployment.json
    validateGeneratedDeploymentManifest: false

- task: AzureIoTEdge@2
  displayName: 'Azure IoT Edge - Deploy to IoT Edge devices'
    action: 'Deploy to IoT Edge devices'
    deploymentFilePath: $(System.DefaultWorkingDirectory)/config/deployment.json
    azureSubscription: $(azureSubscriptionEndpoint)
    iothubname: iothubname
    deploymentid: '$(System.TeamProject)-devops-deployment'
    priority: '0'
    deviceOption: 'Single Device'
    deviceId: deviceId

But with the AzureIoTEdge tasks, you’ll probably run into problems with authentication, building complicated images, pushing to ACR, deploying layered deployments, or actually doing anything at all.

Fear not, though! There are great replacements available 😅


So, let’s go through which steps you’ll (probably need)!

Time needed: 4 days, 5 hours and 30 minutes

How to replace AzureIoTEdge tasks in Azure DevOps with functional tasks?

  1. Instead of “AzureIoTEdge – Build module images” use Docker

    Using docker build instead the equivalent AzureIoTEdge task is going to do the same thing but save you a few grey hairs!

    The YAML will look somewhat like this:
    - task: Docker@2
    displayName: Build an image
    repository: $(imageName)
    command: build
    Dockerfile: app/Dockerfile

  2. Instead of “AzureIoTEdge – Push module images” use Docker

    Just like before – the AzureIoTEdge task is just going to be a less reliable and not-as-configurable version of the Docker task.

    Instead, you might want to use docker push – somewhat like below:
    - task: Docker@2
    displayName: Push image
    containerRegistry: |
    repository: $(imageName)
    command: push
    tags: |

  3. Instead of “AzureIoTEdge – Generate deployment manifest” have the manifest in version control

    You shouldn’t need to generate a deployment manifest in normal cases, so you shouldn’t need AzureIoTEdge – Generate deployment manifest task anyway – deployment manifests should probably be in your version control.

    If you need to have some secrets in them, you can replace them with tokens in the template and replace the tokens using this task:

    Alternatively, you could build a nifty PowerShell script to replace contents in your JSON file, if the task above is unavailable to you.

  4. Instead of “AzureIoTEdge – Deploy to IoT Edge devices” use the Azure CLI task

    Azure CLI task is far more configurable than the AzureIoTEdge task. So, let’s see what we do with it to replace the “Deploy to IoT Edge devices” task!

    How does this look, then? Well, it’s a bit more verbose than the AzureIoTEdge task, but the good thing is you can experiment right in Azure CLI to see what works for you, and just copy-paste that to Azure DevOps.

    A sample of something that works would look like this:
    – task: AzureCLI@2
    displayName: Create Edge Deployment using AZ CLI
    azureSubscription: $(serviceConnection)
    scriptType: ‘pscore’
    scriptLocation: ‘inlineScript’
    inlineScript: |
    az config set extension.use_dynamic_install=yes_without_prompt
    az account set –subscription “subName” $TargetCondition = “(tags.environment=’dev’ AND tags.location=’stockholm’)”
    az iot edge deployment create -d ‘unique-deployment-name’ -n ‘iot-hub-name’ –content ‘path-to-your-layered-deployment-manifest-file.json’ –layered –target-condition “$TargetCondition” –priority 10
    (Source: Sample of a layered deployment using az CLI in Azure DevOps pipeline YAML file)

    I know – it’s a lot! But you don’t actually need target conditions and –layered if you don’t do layered deployments, and instead just do a “full deployment” each time.

And here we are! Hope this was as useful as it would’ve been for me before embarking on my first major Azure DevOps pipeline configuration task for an Azure IoT Edge project.


0 0 votes
Article Rating
Notify of

Inline Feedbacks
View all comments