{"id":2006,"date":"2018-10-29T13:54:48","date_gmt":"2018-10-29T05:54:48","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/iotdev\/?p=2006"},"modified":"2019-02-15T10:27:06","modified_gmt":"2019-02-15T02:27:06","slug":"create-a-ci-cd-pipeline-for-your-iot-edge-solution-with-azure-devops","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/iotdev\/create-a-ci-cd-pipeline-for-your-iot-edge-solution-with-azure-devops\/","title":{"rendered":"Create a CI\/CD pipeline for your IoT Edge solution with Azure DevOps"},"content":{"rendered":"<div style=\"font-size: 12pt\"><a href=\"https:\/\/azure.microsoft.com\/en-us\/services\/iot-edge\/\"><span style=\"color: blue;font-family: Segoe UI;font-size: 12pt;text-decoration: underline\">Azure IoT Edge<\/span><\/a><span style=\"font-family: Segoe UI;font-size: 12pt\"> is a fully managed service that delivers cloud intelligence locally by deploying and running artificial intelligence (AI), Azure services, and custom logic directly on cross-platform IoT devices. You can build your Azure IoT Edge solution using C#, Python, Node.js, C and Java and containerize your code with Windows or Linux containers. Or you can bring Azure services such as Functions, Stream Analytics, and Machine Learning to the edge.<\/span><\/div>\n<div style=\"font-size: 12pt\"><span style=\"font-family: Segoe UI;font-size: 12pt\">\n<\/span><span style=\"font-family: Segoe UI;font-size: 12pt\">Modern software moves fast and demands more from developers than ever. Tools and concepts around CI\/CD help developers deliver value faster and more transparently. For Azure IoT Edge, we provide two tools to create CI\/CD pipeline. In this post, we would introduce <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=vsc-iot.iot-edge-build-deploy\" target=\"_blank\" rel=\"noopener\"><span style=\"color: blue;text-decoration: underline\">Azure IoT Edge for DevOps<\/span><\/a>. (You can find another post about <a href=\"https:\/\/blogs.msdn.microsoft.com\/iotdev\/2018\/09\/24\/announcing-azure-iot-edge-jenkins-plugin\/\"><span style=\"color: blue;text-decoration: underline\">Jenkins<\/span><\/a>)\n<\/span><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/cd.png\" alt=\"CI and CD\" \/>&nbsp;<\/p>\n<p><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=vsc-iot.iot-edge-build-deploy\" target=\"_blank\" rel=\"noopener\"><span style=\"color: blue;font-family: Segoe UI;font-size: 12pt;text-decoration: underline\">Azure IoT Edge for DevOps<\/span><\/a><span style=\"font-family: Segoe UI;font-size: 12pt\"> was initially released on April, 2018 and recently has an important update with new version 1.1.0. Here&#8217;s some big changes in this version:\n<\/span><\/p>\n<ul>\n<li><span style=\"font-family: Segoe UI;font-size: 12pt\">Support to put deploy task in the release pipeline and use artifact to pass the deployment.json\n<\/span><\/li>\n<li><span style=\"font-family: Segoe UI;font-size: 12pt\">Integrate with iotedgedev CLI to do docker related work\n<\/span><\/li>\n<li><span style=\"font-family: Segoe UI;font-size: 12pt\">Suppport to use Windows Build Agent(Hosted VS2017) which will use Windows Container to build docker image\n<\/span><\/li>\n<li><span style=\"font-family: Segoe UI;font-size: 12pt\">Automatically fill in docker credentials in deployment.json with the corresponding docker credentials set in build pipeline\n<\/span><\/li>\n<\/ul>\n<p><span style=\"font-family: Segoe UI;font-size: 12pt\">The most important change is that now deployment task can be defined and executed in release pipeline, which will provide convenience for users to deploy to a set of stages of environment(Dev environment\/ QA test\/ Production).\n<\/span><\/p>\n<p><span style=\"font-family: Segoe UI;font-size: 12pt\">Previously user has to set the both build and deploy task in build pipeline. You can still use the old way to set up your CI\/CD pipeline, but we recommend to separate the build\/deploy task in build\/release pipeline. It&#8217;s easier to manage your environment in this way. Now let&#8217;s go through the process to setup a brand new CI\/CD pipeline for Edge project.\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h2>Prepare Azure DevOps account and extension<\/h2>\n<ol>\n<li><span style=\"font-family: Segoe UI;font-size: 12pt\">Prepare your Edge solution. If you don&#8217;t have one, you can refer to <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/iot-edge\/how-to-ci-cd\"><span style=\"color: blue;text-decoration: underline\">this guide<\/span><\/a> to create a new one.\n<\/span><\/li>\n<li><span style=\"font-family: Segoe UI;font-size: 12pt\">Sign into your Azure DevOps organization (<strong>https:\/\/<\/strong><em>your-account<\/em><strong>.visualstudio.com<\/strong>) and open the project where you checked in the sample app.<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD1.png\" alt=\"\" \/>\n<\/span><\/li>\n<li>\n<div><span style=\"font-family: Segoe UI;font-size: 12pt\">Visit <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=vsc-iot.iot-edge-build-deploy\"><span style=\"color: blue;text-decoration: underline\">Azure IoT Edge For Azure DevOps<\/span><\/a> on Azure DevOps Marketplace. Click <strong>Get it free<\/strong> and follow the wizard to install this extension to your Azure DevOps organization or download to your TFS.\n<\/span><\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD2.png\" alt=\"\" \/><span style=\"font-family: Segoe UI;font-size: 12pt\">\n<\/span><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h2>Setup build pipeline<\/h2>\n<ol>\n<li>\n<div><span style=\"font-family: Segoe UI;font-size: 12pt\">In your Azure DevOps, open the <strong>Build &amp; Release<\/strong> hub and, in the <strong>Builds<\/strong> tab, choose <strong>+ New pipeline<\/strong>. Or, if you already have build pipelines, choose the <strong>+ New<\/strong> button.\n<\/span><\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD3.png\" alt=\"\" \/><span style=\"font-family: Segoe UI;font-size: 12pt\">\n<\/span><\/li>\n<li>\n<div><span style=\"font-family: Segoe UI;font-size: 12pt\">If prompted, select the <strong>Azure DevOps Git<\/strong> source type; then select the project, repository, and branch where your code is located. Choose <strong>Continue<\/strong>.\n<\/span><\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD4.png\" alt=\"\" \/><span style=\"font-family: Segoe UI;font-size: 12pt\">\n<\/span><\/p>\n<p><span style=\"font-family: Segoe UI;font-size: 12pt\">In <strong>Select a template<\/strong> window, choose <strong>start with an Empty process<\/strong>.<\/span>\n<span style=\"font-family: Segoe UI;font-size: 12pt\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD5.png\" alt=\"\" \/><\/span><\/li>\n<li><span style=\"font-family: Segoe UI;font-size: 12pt\">In the pipeline editor, choose the agent pool.\n<\/span><\/p>\n<ul style=\"margin-left: 36pt\">\n<li><span style=\"font-family: Segoe UI;font-size: 12pt\">If you would like to build your modules in platform amd64, choose <strong>Hosted Linux Preview\n<\/strong><\/span><\/li>\n<li><span style=\"font-family: Segoe UI;font-size: 12pt\">If you would like to build your modules in platform windows-amd64, choose <strong>Hosted VS2017<\/strong>\n<\/span><\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD6.png\" alt=\"\" \/><span style=\"font-family: Segoe UI;font-size: 12pt\">\n<\/span><\/li>\n<li>\n<div>In Agent job, click &#8220;+&#8221; to add 2 tasks in the build pipeline.<\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD7.png\" alt=\"\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD8.png\" alt=\"\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD9.png\" alt=\"\" \/><\/li>\n<li>\n<div><span style=\"color: black;background-color: white\">In the first Azure IoT Edge task, update the <strong>Display name<\/strong> to <strong>Module Build and Push<\/strong>, and in the <strong>Action<\/strong> dropdown list, select <strong>Build and Push<\/strong>. In the <strong>Module.json File<\/strong> textbox, add below path to it. Then choose <strong>Container Registry Type<\/strong>, make sure you configure and select the same registry in your code. This task will build and push all your modules in the solution and publish to the container registry you specified. If your modules will be pushed to different registries, you can have multiple <strong>Module Build and Push<\/strong> tasks.<\/span>\n<span style=\"color: black;background-color: white\">In some cases, the Edge solution is not under the root of the code repository. You can specify <strong>Path of Edge solution root<\/strong> in build definition.<span style=\"font-family: Segoe UI\">\n<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD10.png\" alt=\"\" \/><\/span><\/span><\/div>\n<\/li>\n<li>\n<div>In Publish Build Artifacts task, you would specify the deployment file generated by the build task. Set the <strong>Path to publish <\/strong>to &#8220;config\/deployment.json&#8221;. If you set <span style=\"color: black;background-color: white\"><strong>Path of Edge solution root <\/strong>in the last task, you will have to join the root path here. For example, if path of Edge solution root is &#8220;.\/edgesolution&#8221;, then the <\/span><strong>Path to publish<\/strong><span style=\"color: black;background-color: white\"> should be &#8220;.\/edgesolution\/config\/deployment.json&#8221;.<\/span><\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD11.png\" alt=\"\" \/><\/li>\n<li>\n<div>Open the <strong>Triggers<\/strong> tab and turn on the <strong>Continuous integration<\/strong> trigger. Make sure the branch containing your code is included.<\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD12.png\" alt=\"\" \/>\nSave the new build pipeline. Click the <strong>Save<\/strong> button.<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h2>Setup release pipeline<\/h2>\n<ol>\n<li>\n<div><span style=\"font-family: Segoe UI;font-size: 12pt\">In the <strong>Releases<\/strong> tab, choose <strong>+ New pipeline<\/strong>. Or, if you already have build pipelines, choose the <strong>+ New<\/strong> button.\n<\/span><\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD13.png\" alt=\"\" \/><\/p>\n<div><span style=\"font-family: Segoe UI;font-size: 12pt\">In <strong>Select a template<\/strong> window, choose <strong>start with an Empty job<\/strong>.\n<\/span><\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD14.png\" alt=\"\" \/><\/li>\n<li>\n<div>Then the release pipeline would initialize with one stage: <strong>Stage 1<\/strong>. For a real scenario, usually exists multiple stages. Let&#8217;s rename the <strong>Stage 1<\/strong> to <strong>QA<\/strong> and treat it as a test environment.<\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD15.png\" alt=\"\" \/><\/li>\n<li>\n<div>Link the release to the build artifacts. Click <strong>Add<\/strong> in artifacts area.<\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD16.png\" alt=\"\" \/><\/p>\n<p>In <strong>Add an artifact <\/strong>page, choose <strong>Source type Build<\/strong>. Then select the project and the build pipeline we just created. Then Click <strong>Add.\n<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD17.png\" alt=\"\" \/><\/p>\n<p>Open continuous deployment trigger,<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD18.png\" alt=\"\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD19.png\" alt=\"\" \/><\/li>\n<li>\n<div>Then we edit <strong>QA stage<\/strong> and configure it with the task<\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD20.png\" alt=\"\" \/><\/p>\n<p>Deployment task is platform-insensitive. So you can choose either &#8220;Hosted VS2017&#8221; or &#8220;Hosted Linux Preview&#8221; in the <strong>Agent pool<\/strong>.<\/p>\n<p>Click &#8220;+&#8221; and add 1 task.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD21.png\" alt=\"\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD22.png\" alt=\"\" \/><\/li>\n<li>\n<div>In the Azure IoT Edge task, in the <strong>Action<\/strong> dropdown list, select <strong>Deploy to IoT Edge device<\/strong>. Select your Azure subscription and input your IoT Hub name. You can specify an IoT Edge deployment ID and the deployment priority. You can also choose to deploy to single or multiple devices. If you are deploying to multiple devices, you need to specify the device target condition. For example, if you want to use device Tags as the condition, you need to update your corresponding devices Tags before the deployment.<\/div>\n<p>Here the stage is QA, so we deploy to devices with environment property set to &#8220;qa&#8221;.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD23.png\" alt=\"\" \/><\/p>\n<div>Save the new release pipeline. Click the <strong>Save<\/strong> button. And then click <strong>Pipeline<\/strong> to go back to the pipeline.<\/div>\n<\/li>\n<li>\n<div>Next we add a new stage &#8220;PROD&#8221;. We can simply clone the Stage QA and make some changes.<\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD24.png\" alt=\"\" \/><\/p>\n<p>We rename cloned stage to <strong>PROD<\/strong>, and then edit the tasks.<\/p>\n<p>We deploy to devices with environment property set to &#8220;prod&#8221;, and set the deployment id as &#8220;deploy-prod&#8221;. Click the Save button. And then click <strong>Pipeline<\/strong> to go back to the pipeline.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD25.png\" alt=\"\" \/><\/li>\n<li>\n<div>Currently, our build artifact will be triggered continuously on QA stage and then PROD stage. But most of the times we need some manual test on the QA devices and approve the new version manually to PROD environment. So we can setup an approval in PROD stage.<\/div>\n<p>We set <strong>Enabled <\/strong>in <strong>Pre-deployment approvals<\/strong>. And fill in the <strong>Approvers<\/strong> input. Then click <strong>Save<\/strong>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD26.png\" alt=\"\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD27.png\" alt=\"\" \/><\/li>\n<li>\n<div>Now our release pipeline completed and it should be looked like this<\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD28.png\" alt=\"\" \/><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h2>Have a try!<\/h2>\n<div>Now let&#8217;s trigger a build to make the CI\/CD pipeline work. You can either <strong>push a commit to source code repository <\/strong>or <strong>manually trigger one<\/strong>.<\/div>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD29.png\" alt=\"\" \/><\/p>\n<p>The successful build would trigger a release to <strong>QA stage<\/strong>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD30.png\" alt=\"\" \/><\/p>\n<p>The successful deployment to <strong>QA stage<\/strong> would trigger a notification to the approver.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD31.png\" alt=\"\" \/><\/p>\n<p>After the approver approve this change, it can be deployed to <strong>PROD<\/strong>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD32.png\" alt=\"\" \/><\/p>\n<p>Then we succeed!<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/iotdev\/wp-content\/uploads\/sites\/24\/2018\/10\/102618_0713_CreateaCICD33.png\" alt=\"\" \/><\/p>\n<p>As always, we would love to get your feedback via comments below. You can also email vsciet@microsoft.com to let us know what you think.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Modern software moves fast and demands more from developers than ever. Tools and concepts around CI\/CD help developers deliver value faster and more transparently. For Azure IoT Edge, we provide two tools to create CI\/CD pipeline. In this post, we would introduce Azure IoT Edge for DevOps.<\/p>\n","protected":false},"author":628,"featured_media":2005,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[5,6,17,20],"class_list":["post-2006","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-iot-dev","tag-azure","tag-azure-iot","tag-iot","tag-iot-edge"],"acf":[],"blog_post_summary":"<p>Modern software moves fast and demands more from developers than ever. Tools and concepts around CI\/CD help developers deliver value faster and more transparently. For Azure IoT Edge, we provide two tools to create CI\/CD pipeline. In this post, we would introduce Azure IoT Edge for DevOps.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/iotdev\/wp-json\/wp\/v2\/posts\/2006","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/iotdev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/iotdev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/iotdev\/wp-json\/wp\/v2\/users\/628"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/iotdev\/wp-json\/wp\/v2\/comments?post=2006"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/iotdev\/wp-json\/wp\/v2\/posts\/2006\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/iotdev\/wp-json\/wp\/v2\/media\/2005"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/iotdev\/wp-json\/wp\/v2\/media?parent=2006"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/iotdev\/wp-json\/wp\/v2\/categories?post=2006"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/iotdev\/wp-json\/wp\/v2\/tags?post=2006"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}