<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0"><channel><title>Pulumi Blog: Top 5 Things for Azure Developers Series</title><link>https://www.pulumi.com/blog/series/azure-top-5/</link><description>Pulumi blog posts: Top 5 Things for Azure Developers Series.</description><language>en-us</language><pubDate>Thu, 26 Aug 2021 00:00:00 +0000</pubDate><item><title>Top 5 Things an Azure Developer Needs to Know: DevOps</title><link>https://www.pulumi.com/blog/top-5-things-for-azure-devs-devops/</link><pubDate>Thu, 26 Aug 2021 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/top-5-things-for-azure-devs-devops/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/top-5-things-for-azure-devs-devops/index.png" /&gt;
&lt;p&gt;What comes to mind when you hear DevOps? Frequently, DevOps is described as a cultural practice that enables an organization to deliver high-quality applications quickly. The DevOps model emphasizes the &amp;ldquo;breaking down of silos&amp;rdquo; and combining development and operations into a single team. Developing, deploying, and maintaining an application is the responsibility of both developers and operators across the application lifecycle.&lt;/p&gt;
&lt;p&gt;DevOps processes rely on tooling to automate delivering and maintaining applications. This article demonstrates how to implement Azure Pipelines to build and deploy applications.&lt;/p&gt;
&lt;h2 id="azure-pipelines"&gt;Azure Pipelines&lt;/h2&gt;
&lt;p&gt;Azure Pipelines is a Continuous Integration/Continuous Delivery (CI/CD) system that builds and tests code. A key practice of DevOps is Continuous Integration (CI), which merges and tests code automatically. CI catches bugs with &lt;a href="https://www.pulumi.com/blog/infrastructure-testing-concepts/"&gt;automated testing&lt;/a&gt; before software is released, which decreases the cost to fix. The Azure DevOps Build process produces artifacts that drive small and frequent deployments. Continuous Delivery (CD) tests and deploys the artifacts in test or production environments. The automated release process updates existing systems with patches, bug fixes, and new features.&lt;/p&gt;
&lt;p&gt;CI/CD systems store environment-specific configurations for every artifact produced. They use this information to perform any changes to the environment when software is deployed. For example, these systems can refresh database connections or restart services on a deployment.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://azure.microsoft.com/en-us/services/devops/pipelines/"&gt;Azure Pipelines&lt;/a&gt; supports the following tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;version control systems&lt;/strong&gt; - Git and Team Foundation Version Control&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;languages&lt;/strong&gt; - Python, Java, JavaScript, PHP, Ruby, C#, C++, and Go&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;application types&lt;/strong&gt; - tasks to build .Net, Java, Node, Android, Xcode, and C++ applications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;deployment targets&lt;/strong&gt; - virtual machines, containers, on-premises and cloud platforms, or PaaS services&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;continuous testing&lt;/strong&gt; - automating build-deploy-test workflows with the technologies and frameworks you choose&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;package formats&lt;/strong&gt; - supports publishing NuGet, npm, or Maven packages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="deploy-code-with-pipelines"&gt;Deploy code with Pipelines&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s go step-by-step to create a pipeline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Sign in to your Azure DevOps organization or create one if you don&amp;rsquo;t have one.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-devops/devops_organization.png" alt="DevOps organization"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Create a project.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-devops/create_project.png" alt="Create a project"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Create a pipeline.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-devops/create_pipeline.png" alt="Create a pipeline"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Connect and select your repository.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-devops/select_repository.png" alt="Select repository"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Connect the pipeline to the repository on GitHub by approving the install.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-devops/connect_repository.png" alt="Connect repository"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: Examine the pipeline YAML and, if everything appears correct, select &lt;strong&gt;Save and run&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-devops/save_and_run.png" alt="Save and run"&gt;&lt;/p&gt;
&lt;p&gt;You can follow the &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/create-first-pipeline?"&gt;Azure DevOps Pipelines tutorial&lt;/a&gt;, which covers creating software artifacts. However, because we are deploying infrastructure and an application, we will need to expand pipeline tasks with an extension.&lt;/p&gt;
&lt;h2 id="the-pulumi-task-extension-for-azure-devops"&gt;The Pulumi task extension for Azure DevOps&lt;/h2&gt;
&lt;p&gt;The Pulumi task extension runs the Pulumi CLI in your CI/CD pipelines. The pipeline builds your application and deploys the infrastructure it runs on in the same pipeline. You can install the Pulumi task extension from the &lt;a href="https://marketplace.visualstudio.com/items?itemName=pulumi.build-and-release-task"&gt;Visual Studio Marketplace&lt;/a&gt; into your Azure DevOps Organization.&lt;/p&gt;
&lt;p&gt;The task has two requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The pipeline must connect to your Azure Subscription through a service connection.&lt;/li&gt;
&lt;li&gt;The build variable, &lt;code&gt;pulumi.access.token&lt;/code&gt; is mapped to the environment variable &lt;a href="https://app.pulumi.com/account/tokens"&gt;&lt;code&gt;PULUMI_ACCESS_TOKEN&lt;/code&gt;&lt;/a&gt;, which the CLI uses for non-interactive logins.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are two ways to run the pipeline. You can use the console to configure the pipeline or add an &lt;code&gt;azure-pipelines.yml&lt;/code&gt; file to your repository. Let&amp;rsquo;s look at an example YAML file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# A minimal Azure Pipelines build configuration file for running&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Pulumi apps that use the dotnet runtime and the Azure Native&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Nuget package.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;master&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;**/*&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;vmImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ubuntu-latest&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;**/*.sln&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;buildPlatform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Any CPU&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;buildConfiguration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Release&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;infrastructure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;NuGetToolInstaller@1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Pulumi@1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# To use an Azure Service Connection, un-comment the following line.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;azureSubscription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;$(ServiceConnectName)&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Pulumi will automatically build/restore the dotnet project.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Unless you are using a pre-built binary.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;preview&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;$(StackName)&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s focus on &lt;code&gt;jobs&lt;/code&gt;. The first step is to find, download, and install &lt;a href="https://www.nuget.org/"&gt;NuGet&lt;/a&gt;, which is required to build this C# application. The second task uses the Pulumi task extension to run a Pulumi &lt;code&gt;preview&lt;/code&gt; of the stack (&lt;code&gt;$(StackName)&lt;/code&gt;) located at the root of the Pulumi project. The complete example is available on &lt;a href="https://github.com/pulumi/pulumi-az-pipelines-task/tree/master/examples/azure-native-dotnet"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If we wanted to build and deploy the infrastructure, we could add another task. The &lt;code&gt;azure-pipelines.yml&lt;/code&gt; file would be similar to this.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;job&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;infrastructure&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;NuGetToolInstaller@1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Pulumi@1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# To use an Azure Service Connection, un-comment the following line.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;azureSubscription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;$(ServiceConnectName)&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Pulumi will automatically build/restore the dotnet project.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Unless you are using a pre-built binary.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;preview&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;$(StackName)&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Pulumi@1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# To use an Azure Service Connection, un-comment the following line.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;azureSubscription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;$(ServiceConnectName)&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Pulumi will automatically build/restore the dotnet project.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Unless you are using a pre-built binary.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;up&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;$(StackName)&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can chain tasks to run the build process, including building and deploying applications in the same pipeline. The Pulumi &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/azure-devops/"&gt;Continuous Delivery User Guide&lt;/a&gt; provides an in-depth walkthrough for configuring an Azure pipeline.&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;As a developer on a DevOps team, you may not be the person to configure a pipeline. However, it&amp;rsquo;s a good cloud engineering practice to understand how your application is built and deployed. Although we focus on Azure, the Pulumi task extension works with many other CI/CD systems. Check out our &lt;a href="https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/"&gt;User Guides&lt;/a&gt; for all the CI/CD systems Pulumi supports.&lt;/p&gt;</description><author>Sophia Parafina</author><category>azure</category><category>pipelines</category><category>devops</category></item><item><title>Top 5 Things an Azure Developer Needs to Know: Kubernetes Applications</title><link>https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-apps/</link><pubDate>Mon, 16 Aug 2021 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-apps/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/top-5-things-for-azure-devs-kubernetes-apps/index.png" /&gt;
&lt;p&gt;All modern software is cloud software, and it&amp;rsquo;s more than likely that it runs on Kubernetes. Developers are faced with the challenge of deploy applications composed of many microservices. And each microservice adds to the complexity of the deployment.&lt;/p&gt;
&lt;p&gt;This article reviews the different methods for deploying applications on Azure Kubernetes Service (AKS).&lt;/p&gt;
&lt;h2 id="a-quick-review-on-application-deployment"&gt;A quick review on application deployment&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re not familiar with deploying applications on Kubernetes, these articles cover the basic and advance cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part2"&gt;Getting Started With Kubernetes: Application Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part3"&gt;Getting Started With Kubernetes: Advanced Deployment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part4"&gt;Getting Started with Kubernetes: Stateful Applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="setting-up-the-aks-sandbox"&gt;Setting up the AKS sandbox&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll set up an AKS sandbox composed of an AKS cluster and Azure Container Registry (ACR) for this article. Make sure you have the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"&gt;Azure CLI&lt;/a&gt; installed, and you&amp;rsquo;re logged into Azure, e.g., &lt;code&gt;az login&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="create-a-container-registry"&gt;Create a container registry&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ll create a resource group first, followed by the registry.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az group create --resource-group aks-group --location westus2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az acr create --resource-group aks-group --name pulumipusContainerRegistry --sku Basic
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the registry is created, the Azure CLI returns JSON with metadata about the registry. Under the &lt;code&gt;id&lt;/code&gt; key, you&amp;rsquo;ll find the URL to the login server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;id&amp;#34;: &amp;#34;/subscriptions/fceb55a3-db15-4f3a-bffa-81271e7b7676/resourceGroups/myResourceGroup/providers/Microsoft.ContainerRegistry/registries/azContainerRegistryPulumi&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;identity&amp;#34;: null,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;location&amp;#34;: &amp;#34;eastus&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;loginServer&amp;#34;: &amp;#34;pulumipuscontainerregistry.azurecr.io&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;name&amp;#34;: &amp;#34;azContainerRegistryPulumi&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point, you can push and pull container images from your registry. If you want to try out the registry and push an image, you&amp;rsquo;ll need &lt;a href="https://docs.docker.com/get-docker/"&gt;Docker installed&lt;/a&gt;. This example pulls an image from Docker Hub and tags it with the URL to the Azure container registry. We then log into the registry and push the image. To verify the image, we use the Azure CLI to list the images in the registry.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker pull hello-world
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker tag hello-world pulumipuscontainerregistry.azurecr.io/hello-world:v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az acr login --name pulumipusContainerRegistry
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker push pulumipuscontainerregistry.azurecr.io/hello-world:v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az acr repository list --name pulumipusContainerRegistry
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;hello-world&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="create-an-aks-cluster"&gt;Create an AKS cluster&lt;/h3&gt;
&lt;p&gt;The previous article this series demonstrated how to create an AKS cluster with the Azure portal and code to illustrate creating an AKS cluster. For this example, we&amp;rsquo;ll use the CLI. In the example below, the first line creates a basic cluster, and the second line retrieves the cluster credentials that let us connect to it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az aks create --resource-group aks-group --name aks-cluster --node-count &lt;span class="m"&gt;3&lt;/span&gt; --generate-ssh-keys -s Standard_B2ms --disable-rbac
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az aks get-credentials -g aks-group -n aks-cluster
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="deploy-an-nginx-container-on-aks-with-helm"&gt;Deploy an NGINX container on AKS with Helm&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://helm.sh/"&gt;Helm&lt;/a&gt; is an application package manager for Kubernetes. Follow the directions on &lt;strong&gt;helm.sh&lt;/strong&gt; to &lt;a href="https://helm.sh/docs/intro/install/"&gt;install Helm&lt;/a&gt;. Helm can install packages from repositories such as &lt;a href="https://artifacthub.io/"&gt;ArtifactHUB&lt;/a&gt;, &lt;a href="https://bitnami.com/"&gt;Bitnami&lt;/a&gt;, and the &lt;a href="https://azuremarketplace.microsoft.com/en-us/marketplace/apps?search=helm%20charts"&gt;Azure Marketplace&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, we&amp;rsquo;ll add the Azure Marketplace repository to helm and update it. Next, we install the NGINX helm chart to our AKS cluster.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ helm repo add azure-marketplace https://marketplace.azurecr.io/helm/v1/repo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ helm repo update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ helm install my-release azure-marketplace/nginx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME: my-release
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LAST DEPLOYED: Mon Aug &lt;span class="m"&gt;16&lt;/span&gt; 13:58:26 &lt;span class="m"&gt;2021&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAMESPACE: default
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;STATUS: deployed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;REVISION: &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;TEST SUITE: None
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NOTES:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;The NGINX Ingress Controller has been installed.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To find the URL for our NGINX deployment, use &lt;code&gt;kubectl&lt;/code&gt; to get the external IP address.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME TYPE CLUSTER-IP EXTERNAL-IP PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt; AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubernetes ClusterIP 10.0.0.1 &amp;lt;none&amp;gt; 443/TCP 3h21m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;my-release-nginx LoadBalancer 10.0.212.197 20.72.78.59 80:31251/TCP 175m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="deploy-a-custom-container"&gt;Deploy a custom container&lt;/h2&gt;
&lt;p&gt;In the previous section, we used a Helm chart to deploy an application from a repository. But what if we want to deploy our custom application. In this example, we&amp;rsquo;ll build our NGINX container, push it to our registry, and deploy it on the AKS cluster.&lt;/p&gt;
&lt;h3 id="create-our-application-container"&gt;Create our application container&lt;/h3&gt;
&lt;p&gt;For this example, you will need Docker. We will replace the default NGINX page with our welcome page. Copy the sample below and save it as &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;AKS NGINX&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello from Azure AKS&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, we&amp;rsquo;ll make a Dockerfile to build our custom NGINX container. Copy and save the following to a file called Dockerfile.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;nginx:latest&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; ./index.html /usr/share/nginx/html/index.html&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Build and tag the image with this command and push it to the repository we created earlier.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker build -t pulumipuscontainerregistry.azurecr.io/my-nginx:v1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az acr login --name pulumipusContainerRegistry
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker push pulumipuscontainerregistry.azurecr.io/my-nginx:v1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="create-a-deployment-manifest"&gt;Create a deployment manifest&lt;/h3&gt;
&lt;p&gt;In the previous example, we deployed NGINX with Helm. Manifests are another way to deploy applications. A manifest contains a &lt;code&gt;deployment&lt;/code&gt; that defines &lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part2#pods"&gt;&lt;code&gt;pods&lt;/code&gt;&lt;/a&gt; that run a containerized application. It also contains &lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part2#services"&gt;&lt;code&gt;services&lt;/code&gt;&lt;/a&gt; that route traffic to &lt;code&gt;pods&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Copy and save the example below to a file named &lt;code&gt;manifest.yml&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;apps/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Deployment&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;creationTimestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-nginx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-nginx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;matchLabels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-nginx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;creationTimestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-nginx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumipuscontainerregistry.azurecr.io/my-nginx:v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-nginx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;containerPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Service&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-nginx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-nginx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;TCP&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-nginx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;LoadBalancer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="deploy-the-application-to-aks"&gt;Deploy the application to AKS&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ll use &lt;code&gt;kubectl&lt;/code&gt; to deploy the application with the manifest. But before we can do this, we need to attach the ACR &lt;code&gt;pulumipuscontainerregistry&lt;/code&gt; to the AKS cluster, &lt;code&gt;aks-cluster&lt;/code&gt;. Once the registry is added to the cluster configuration, we can deploy our application with &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az aks update --resource-group aks-group --name aks-cluster --attach-acr pulumipuscontainerregistry
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl create -f manifest.yml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use &lt;code&gt;kubectl get service&lt;/code&gt; to get the load balancer&amp;rsquo;s external IP as we did with the Helm example.&lt;/p&gt;
&lt;h2 id="deploy-with-pulumi"&gt;Deploy with Pulumi&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/"&gt;previous article&lt;/a&gt; in this series showed how to deploy AKS with code. Starting with the &lt;a href="https://github.com/pulumi/examples/tree/master/azure-py-aks"&gt;Python example&lt;/a&gt; from Github and add to it to create a complete solution&lt;/p&gt;
&lt;h3 id="create-a-container-registry-and-custom-container"&gt;Create a container registry and custom container&lt;/h3&gt;
&lt;p&gt;First, we create the image registry to hold our custom NGINX container. Put the &lt;code&gt;index.html&lt;/code&gt; and the &lt;code&gt;Dockerfile&lt;/code&gt; files in a directory called &lt;code&gt;app&lt;/code&gt;. The &lt;code&gt;app&lt;/code&gt; directory is the context Docker uses to build an image. Note that the Docker provider builds and pushes the image to our repository.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create a private ACR registry.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;azure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResourceGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;azure-native-py-aks&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;registry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;azure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;containerservice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Registry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pulumipuscontainerrepository&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;resource_group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;admin_enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Basic&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Get registry info (creds and endpoint).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;image_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;pulumipuscontainerrepository/my-nginx&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;registry_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ImageRegistry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login_server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;admin_username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;admin_password&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_docker&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;docker&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Build and publish the container image.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;my-image&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;image_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;image_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;registry_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="deploy-the-container"&gt;Deploy the container&lt;/h3&gt;
&lt;p&gt;The code below creates a Deployment and a LoadBalancer Service similar to the manifest we used earlier. The script exports the IP address of the LoadBalancer at the end of the script.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create a NGINX Deployment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app_labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;my-nginx&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app_dep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k8s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;apps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deployment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;my-aks-deployment&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;selector&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;matchLabels&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;app_labels&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;replicas&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;template&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;metadata&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;labels&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;app_labels&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;spec&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;containers&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;pulumipuscontainerrepository/my-nginx&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;image&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;my-nginx;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;ports&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;http&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;containerPort&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create a Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app_svc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k8s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;my-aks-service&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;labels&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;app_labels&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;LoadBalancer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;ports&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;port&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;targetPort&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;protocol&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TCP&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;selector&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;app_labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;application IP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loadbalancer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ingress&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This example provides a sketch of the process to create an AKS cluster and deploy a custom container. For a fully worked example, check out the &lt;a href="https://www.pulumi.com/registry/packages/kubernetes/how-to-guides/aks"&gt;&lt;code&gt;Azure Kubernetes Service (AKS) - Hello World!&lt;/code&gt;&lt;/a&gt; tutorial.&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;There are many ways to deploy applications on AKS, including &lt;a href="https://kubernetes.io/docs/concepts/configuration/configmap/"&gt;ConfigMaps&lt;/a&gt; and &lt;a href="https://kustomize.io/"&gt;Kustomize&lt;/a&gt; which were not discussed. We&amp;rsquo;ve covered deploying with Helm, manifests, and infrastructure as code. This article covers the basics of application deployment using Deployments and Services. To review, Deployments are declarative updates to a Pod such as specifying a container to run, and Services route traffic to Pods either within the cluster or permitting ingress with a LoadBalancer. We should note that templating methods such as Helm or manifests require file management, whereas using cloud engineering practices enables managing both infrastructure and application deployment in a versioned and repeatable way.&lt;/p&gt;
&lt;p&gt;The following article will wrap up the series. We&amp;rsquo;ll examine how to implement DevOps practices with Azure.&lt;/p&gt;</description><author>Sophia Parafina</author><category>kubernetes</category><category>azure</category><category>helm</category></item><item><title>Top 5 Things an Azure Developer Needs to Know: Kubernetes Infrastructure</title><link>https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/</link><pubDate>Thu, 12 Aug 2021 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/index.png" /&gt;
&lt;p&gt;History lesson time! In 2011, microservices debuted as an architectural style suited for the cloud. In 2013, Docker simplified building containers. Combining containers and microservices sparked a change in how applications were built and distributed in the cloud. As performance, scaling, and reliability became an increasing concern, container orchestration platforms became widely available. Kubernetes became the dominant container orchestration through community and corporate support, and some have suggested it was &lt;a href="https://elastisys.com/why-kubernetes-was-inevitable/"&gt;inevitable&lt;/a&gt;. Every major cloud service provider, including Azure, offers a version of Kubernetes.&lt;/p&gt;
&lt;p&gt;Kubernetes streamlines container deployment and management, making applications scale and accessible. This article demonstrates configuring and deploying Kubernetes with Azure.&lt;/p&gt;
&lt;h2 id="a-kubernetes-review"&gt;A Kubernetes Review&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re not familiar with Kubernetes concepts and terminology, the Getting Started with Kubernetes series can help get you up to speed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part1"&gt;Getting Started With Kubernetes: Clusters and Nodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part2"&gt;Getting Started With Kubernetes: Application Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part3"&gt;Getting Started With Kubernetes: Advanced Deployment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part4"&gt;Getting Started with Kubernetes: Stateful Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part5"&gt;Getting Started With Kubernetes: Networking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part6"&gt;Getting Started With Kubernetes: Day 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="azure-kubernetes-service"&gt;Azure Kubernetes Service&lt;/h2&gt;
&lt;p&gt;Azure Kubernetes Service (AKS) is a hosted Kubernetes service. Azure manages the Kubernetes master nodes, and you are responsible for managing the agent or worker nodes. You only pay for the worker nodes in your cluster that make up your application.&lt;/p&gt;
&lt;p&gt;Kubernetes nodes are the worker machines that can be either physical or virtual. AKS nodes use Azure virtual machines (VMs); and you can add storage, upgrade cluster components, or even run multiple node pools with mixed operating systems.&lt;/p&gt;
&lt;p&gt;You can create an AKS cluster with&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the Azure CLI,&lt;/li&gt;
&lt;li&gt;the Azure portal,&lt;/li&gt;
&lt;li&gt;PowerShell, and&lt;/li&gt;
&lt;li&gt;templates, such as Azure Resource Manager (ARM) templates.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aks-features"&gt;AKS features&lt;/h3&gt;
&lt;p&gt;Configuring and deploying Kubernetes can be complex. AKS provides many features to simplify the process, including the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cluster node and pod scaling adjust the number of nodes or pods as resource demand changes. &lt;a href="https://docs.microsoft.com/en-us/azure/aks/tutorial-kubernetes-scale?tabs=azure-cli"&gt;Pods can scale horizontally, and the cluster can also autoscale&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Kubernetes is a fast-moving open source project, and AKS supports multiple versions. You can &lt;a href="https://docs.microsoft.com/en-us/azure/aks/node-image-upgrade"&gt;upgrade the cluster nodes&lt;/a&gt; without interrupting the application.&lt;/li&gt;
&lt;li&gt;If you perform machine learning, AKS can create &lt;a href="https://docs.microsoft.com/en-us/azure/aks/gpu-cluster"&gt;GPU-enabled node pools&lt;/a&gt; for compute-intensive, graphics-intensive, and visualization workloads.&lt;/li&gt;
&lt;li&gt;AKS supports access control through &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/"&gt;Kubernetes RBAC&lt;/a&gt; and Azure &lt;a href="https://docs.microsoft.com/en-us/azure/aks/managed-aad"&gt;Active Directory&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Integrated logging and monitoring with &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/containers/container-insights-overview"&gt;Azure Monitor for Containers&lt;/a&gt; collects memory and processor metrics from containers, nodes, and controllers.&lt;/li&gt;
&lt;li&gt;AKS lets you mount &lt;a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-introduction"&gt;static or dynamic storage volumes&lt;/a&gt; for persistent data. Storage volumes use Azure Disks for single pod access or Azure Files for concurrent pod access.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/aks/concepts-network"&gt;Virtual networking&lt;/a&gt; for pods in the cluster and other nodes let you use a peered virtual network. The network also provides ingress for applications with HTTP application routing.&lt;/li&gt;
&lt;li&gt;Integration with development tools for Helm and a &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools"&gt;Visual Studio Code extension for Kubernetes&lt;/a&gt; improves the developer experience.&lt;/li&gt;
&lt;li&gt;Support for Docker images, including storage with &lt;a href="https://azure.microsoft.com/en-us/services/container-registry/"&gt;Azure Container Registry&lt;/a&gt;, makes deployment easier.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="create-an-aks-cluster-with-the-azure-portal"&gt;Create an AKS Cluster with the Azure Portal&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll use the Azure Portal to illustrate the steps to configure and deploy an AKS Cluster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Create a Kubernetes Service.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open the &lt;a href="https://portal.azure.com"&gt;Azure Portal&lt;/a&gt; and select &lt;strong&gt;Create Resource&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Containers &amp;gt; Kubernetes Service&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/kubernetes_service.png" alt="Create Kubernetes service"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Create an AKS cluster.&lt;/p&gt;
&lt;p&gt;For this example, we will configure several options in the &lt;strong&gt;Basic&lt;/strong&gt; window but use defaults for most options.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;Subscription&lt;/strong&gt;, select an &lt;strong&gt;Azure Subscription&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create or select a &lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/overview"&gt;Resource Group&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Cluster details&lt;/strong&gt;, set the &lt;strong&gt;Kubernetes cluster name&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Change the &lt;strong&gt;Region&lt;/strong&gt; if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use the default values for &lt;strong&gt;Primary node pool&lt;/strong&gt;, and select &lt;strong&gt;Next: node pools&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/create_aks_cluster.png" alt="Create AKS Cluster"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Configure node pools.&lt;/p&gt;
&lt;p&gt;A node pool is a logical grouping of nodes. Nodes in a pool can have different virtual machines, different Kubernetes versions, and other attributes. You can use different node pools for different purposes, such as grouping workflows, e.g., a node pool for production and one for dev or test.&lt;/p&gt;
&lt;p&gt;For this example, use the default values for node pools.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/node_pools.png" alt="Node pools"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Configure authentication.&lt;/p&gt;
&lt;p&gt;You can authenticate, authorize, secure, and control access to Kubernetes clusters with&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/"&gt;Kubernetes role-based access control&lt;/a&gt; (Kubernetes RBAC) to grant access to service accounts or&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/aks/managed-aad"&gt;Azure Active Directory integration&lt;/a&gt; that provides a multi-tenant, cloud-based directory and identity management service.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To configure &lt;strong&gt;Authentication&lt;/strong&gt; for this example, set the &lt;strong&gt;Authentication method&lt;/strong&gt; to &lt;strong&gt;System-assigned managed identity&lt;/strong&gt;. You can set &lt;strong&gt;Role-based access control (RBAC)&lt;/strong&gt; to enabled, but it&amp;rsquo;s unnecessary for the example. Use the default value for the &lt;strong&gt;Node pool OS disk encryption&lt;/strong&gt; type.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/authentication.png" alt="Authentication"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Configure networking&lt;/p&gt;
&lt;p&gt;AKS can use either &lt;code&gt;kubenet&lt;/code&gt; or &lt;code&gt;Azure CNI&lt;/code&gt; networking. Kubenet is the default configuration for AKS cluster creation.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;kubenet&lt;/code&gt;, Azure creates and configures the virtual network. However, only the nodes receive a routable IP address and pods use a NAT to communicate with resources outside the AKS cluster. This approach reduces the number of IP addresses you need to reserve in your network space for pods to use.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Azure CNI&lt;/code&gt;assigns an IP address to every pod, which makes them directly accessible. The IP addresses must be unique and planned in advance. Each node must be configured for the maximum number of pods to reserve IP addresses per node. Without accounting for the number of pods, the network can run out of IP addresses to allocate or necessitate the need to rebuild clusters with a larger subnet.&lt;/p&gt;
&lt;p&gt;For this example, we&amp;rsquo;ll use &lt;code&gt;kubenet&lt;/code&gt; for it&amp;rsquo;s simplicity, but in production &lt;code&gt;Azure CNI&lt;/code&gt; maybe the better choice for applications.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/networking.png" alt="Networking"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: Complete the deployment&lt;/p&gt;
&lt;p&gt;Select &lt;strong&gt;Review + create&lt;/strong&gt; to deploy. Deployment takes several minutes to complete. On completion, you can verify the &lt;strong&gt;Deployment details&lt;/strong&gt; or select &lt;strong&gt;Connect to cluster&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="deployment_complete.png" alt="Deployment complete"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 7&lt;/strong&gt;: Connect to the cluster&lt;/p&gt;
&lt;p&gt;You can manage your cluster with &lt;a href="https://kubernetes.io/docs/tasks/tools/#kubectl"&gt;&lt;code&gt;kubectl&lt;/code&gt;&lt;/a&gt;, a command line tool for managing Kubernetes. You can install &lt;code&gt;kubectl&lt;/code&gt; on &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-linux"&gt;linux&lt;/a&gt;, &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-macos"&gt;macOS&lt;/a&gt;, and &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-windows"&gt;Windows&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Copy and paste the commands to connect and authenticate to your cluster using the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"&gt;Azure CLI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/connect.png" alt="Connect"&gt;&lt;/p&gt;
&lt;p&gt;After connecting and authenticating to your cluster, you can use &lt;code&gt;kubectl&lt;/code&gt; to query your cluster.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get nodes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME STATUS ROLES AGE VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aks-agentpool-19694923-vmss000000 Ready agent 9m35s v1.20.7
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aks-agentpool-19694923-vmss000001 Ready agent 9m39s v1.20.7
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aks-agentpool-19694923-vmss000002 Ready agent 9m47s v1.20.7
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get all
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME TYPE CLUSTER-IP EXTERNAL-IP PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt; AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/kubernetes ClusterIP 10.0.0.1 &amp;lt;none&amp;gt; 443/TCP 11m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Your AKS cluster is deployed and running.&lt;/p&gt;
&lt;h2 id="deploying-an-aks-cluster-with-code"&gt;Deploying an AKS cluster with code&lt;/h2&gt;
&lt;p&gt;Now that we have reviewed the process for creating an AKS cluster using the Azure Portal, we can repeat the process using code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Create a &lt;code&gt;Resource group&lt;/code&gt; and a &lt;code&gt;Service principal&lt;/code&gt; for the cluster. Note that we used a &lt;code&gt;System-assigned managed identity&lt;/code&gt; in the Azure Portal example.&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="csharp,go,python,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;pre&gt;&lt;code&gt; // Create an Azure Resource Group
var resourceGroup = new ResourceGroup(&amp;quot;azure-cs-aks&amp;quot;);
// Create an AD service principal
var adApp = new Application(&amp;quot;aks&amp;quot;, new ApplicationArgs
{
DisplayName = &amp;quot;aks&amp;quot;
});
var adSp = new ServicePrincipal(&amp;quot;aksSp&amp;quot;, new ServicePrincipalArgs
{
ApplicationId = adApp.ApplicationId
});
// Generate random password
var password = new RandomPassword(&amp;quot;password&amp;quot;, new RandomPasswordArgs
{
Length = 20,
Special = true
});
// Create the Service Principal Password
var adSpPassword = new ServicePrincipalPassword(&amp;quot;aksSpPassword&amp;quot;, new ServicePrincipalPasswordArgs
{
ServicePrincipalId = adSp.Id,
Value = password.Result,
EndDate = &amp;quot;2099-01-01T00:00:00Z&amp;quot;
});
// Generate an SSH key
var sshKey = new PrivateKey(&amp;quot;ssh-key&amp;quot;, new PrivateKeyArgs
{
Algorithm = &amp;quot;RSA&amp;quot;,
RsaBits = 4096
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;pre&gt;&lt;code&gt; // Create an Azure Resource Group
resourceGroup, err := resources.NewResourceGroup(ctx, &amp;quot;azure-go-aks&amp;quot;, nil)
if err != nil {
return err
}
// Create an AD service principal.
adApp, err := azuread.NewApplication(ctx, &amp;quot;aks&amp;quot;, &amp;amp;azuread.ApplicationArgs{
DisplayName: pulumi.String(&amp;quot;aks&amp;quot;),
})
if err != nil {
return err
}
adSp, err := azuread.NewServicePrincipal(ctx, &amp;quot;aksSp&amp;quot;, &amp;amp;azuread.ServicePrincipalArgs{
ApplicationId: adApp.ApplicationId,
})
if err != nil {
return err
}
// Generate a random password.
password, err := random.NewRandomPassword(ctx, &amp;quot;password&amp;quot;, &amp;amp;random.RandomPasswordArgs{
Length: pulumi.Int(20),
Special: pulumi.Bool(true),
})
if err != nil {
return err
}
// Create the Service Principal Password.
adSpPassword, err := azuread.NewServicePrincipalPassword(ctx, &amp;quot;aksSpPassword&amp;quot;, &amp;amp;azuread.ServicePrincipalPasswordArgs{
ServicePrincipalId: adSp.ID(),
Value: password.Result,
EndDate: pulumi.String(&amp;quot;2099-01-01T00:00:00Z&amp;quot;),
})
if err != nil {
return err
}
// Generate an SSH key.
sshArgs := tls.PrivateKeyArgs{
Algorithm: pulumi.String(&amp;quot;RSA&amp;quot;),
RsaBits: pulumi.Int(4096),
}
sshKey, err := tls.NewPrivateKey(ctx, &amp;quot;ssh-key&amp;quot;, &amp;amp;sshArgs)
if err != nil {
return err
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;pre&gt;&lt;code&gt; # Create new resource group
resource_group = resources.ResourceGroup(&amp;quot;azure-native-py-aks&amp;quot;)
# Create an AD service principal
ad_app = azuread.Application(&amp;quot;aks&amp;quot;, display_name=&amp;quot;aks&amp;quot;)
ad_sp = azuread.ServicePrincipal(&amp;quot;aksSp&amp;quot;, application_id=ad_app.application_id)
# Generate random password
password = random.RandomPassword(&amp;quot;password&amp;quot;, length=20, special=True)
# Create the Service Principal Password
ad_sp_password = azuread.ServicePrincipalPassword(&amp;quot;aksSpPassword&amp;quot;,
service_principal_id=ad_sp.id,
value=password.result,
end_date=&amp;quot;2099-01-01T00:00:00Z&amp;quot;)
# Generate an SSH key
ssh_key = tls.PrivateKey(&amp;quot;ssh-key&amp;quot;, algorithm=&amp;quot;RSA&amp;quot;, rsa_bits=4096)
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;pre&gt;&lt;code&gt; // Create an Azure Resource Group
const resourceGroup = new resources.ResourceGroup(&amp;quot;azure-go-aks&amp;quot;);
// Create an AD service principal
const adApp = new azuread.Application(&amp;quot;aks&amp;quot;, {
displayName: &amp;quot;aks&amp;quot;,
});
const adSp = new azuread.ServicePrincipal(&amp;quot;aksSp&amp;quot;, {
applicationId: adApp.applicationId,
});
// Generate random password
const password = new random.RandomPassword(&amp;quot;password&amp;quot;, {
length: 20,
special: true,
});
// Create the Service Principal Password
const adSpPassword = new azuread.ServicePrincipalPassword(&amp;quot;aksSpPassword&amp;quot;, {
servicePrincipalId: adSp.id,
value: password.result,
endDate: &amp;quot;2099-01-01T00:00:00Z&amp;quot;,
});
// Generate an SSH key
const sshKey = new tls.PrivateKey(&amp;quot;ssh-key&amp;quot;, {
algorithm: &amp;quot;RSA&amp;quot;,
rsaBits: 4096,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Configure the AKS cluster&lt;/p&gt;
&lt;p&gt;We set the configuration options in &lt;code&gt;ManagedClusterAgentPoolProfileArgs&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Count&lt;/code&gt;: Number of virtual machines&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MaxPods&lt;/code&gt;: Maximum number of pods that can run on a node.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Mode&lt;/code&gt;: Sets the type of pool node, which can be &lt;a href="https://docs.microsoft.com/en-us/azure/aks/use-system-pools"&gt;system or user&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Name&lt;/code&gt;: Name of the pool node&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OsType&lt;/code&gt;: Specifies the OS type&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Type&lt;/code&gt;: Choose between a &lt;a href="https://docs.microsoft.com/en-us/azure/aks/use-system-pools"&gt;&lt;code&gt;VirtualMachineScaleSet&lt;/code&gt;&lt;/a&gt; or an &lt;a href="https://docs.microsoft.com/en-us/azure/aks/availability-zones"&gt;&lt;code&gt;AvailabilitySet&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VmSize&lt;/code&gt;: The virtual machine size used by the cluster.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The remaining parameters set the Kubernetes version, enables RBAC, and configures the Linux profile for the &lt;code&gt;ContainerService&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="csharp,go,python,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;pre&gt;&lt;code&gt; var cluster = new ManagedCluster(&amp;quot;my-aks&amp;quot;, new ManagedClusterArgs
{
ResourceGroupName = resourceGroup.Name,
AgentPoolProfiles =
{
new ManagedClusterAgentPoolProfileArgs
{
Count = 3,
MaxPods = 110,
Mode = &amp;quot;System&amp;quot;,
Name = &amp;quot;agentpool&amp;quot;,
OsDiskSizeGB = 30,
OsType = &amp;quot;Linux&amp;quot;,
Type = &amp;quot;VirtualMachineScaleSets&amp;quot;,
VmSize = &amp;quot;Standard_DS2_v2&amp;quot;,
}
},
DnsPrefix = &amp;quot;AzureNativeprovider&amp;quot;,
EnableRBAC = true,
KubernetesVersion = &amp;quot;1.18.14&amp;quot;,
LinuxProfile = new ContainerServiceLinuxProfileArgs
{
AdminUsername = &amp;quot;testuser&amp;quot;,
Ssh = new ContainerServiceSshConfigurationArgs
{
PublicKeys =
{
new ContainerServiceSshPublicKeyArgs
{
KeyData = sshKey.PublicKeyOpenssh,
}
}
}
},
NodeResourceGroup = $&amp;quot;MC_azure-cs_my_aks&amp;quot;,
ServicePrincipalProfile = new ManagedClusterServicePrincipalProfileArgs
{
ClientId = adApp.ApplicationId,
Secret = adSpPassword.Value
}
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;pre&gt;&lt;code&gt; // Create the Azure Kubernetes Service cluster.
cluster, err := containerservice.NewManagedCluster(ctx, &amp;quot;go-aks&amp;quot;, &amp;amp;containerservice.ManagedClusterArgs{
ResourceGroupName: resourceGroup.Name,
AgentPoolProfiles: containerservice.ManagedClusterAgentPoolProfileArray{
&amp;amp;containerservice.ManagedClusterAgentPoolProfileArgs{
Name: pulumi.String(&amp;quot;agentpool&amp;quot;),
Mode: pulumi.String(&amp;quot;System&amp;quot;),
OsDiskSizeGB: pulumi.Int(30),
Count: pulumi.Int(3),
VmSize: pulumi.String(&amp;quot;Standard_DS2_v2&amp;quot;),
OsType: pulumi.String(&amp;quot;Linux&amp;quot;),
},
},
LinuxProfile: &amp;amp;containerservice.ContainerServiceLinuxProfileArgs{
AdminUsername: pulumi.String(&amp;quot;testuser&amp;quot;),
Ssh: containerservice.ContainerServiceSshConfigurationArgs{
PublicKeys: containerservice.ContainerServiceSshPublicKeyArray{
containerservice.ContainerServiceSshPublicKeyArgs{
KeyData: sshKey.PublicKeyOpenssh,
},
},
},
},
DnsPrefix: resourceGroup.Name,
ServicePrincipalProfile: &amp;amp;containerservice.ManagedClusterServicePrincipalProfileArgs{
ClientId: adApp.ApplicationId,
Secret: adSpPassword.Value,
},
KubernetesVersion: pulumi.String(&amp;quot;1.18.14&amp;quot;),
})
if err != nil {
return err
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;pre&gt;&lt;code&gt; # Create cluster
managed_cluster_name = config.get(&amp;quot;managedClusterName&amp;quot;)
if managed_cluster_name is None:
managed_cluster_name = &amp;quot;azure-native-aks&amp;quot;
managed_cluster = containerservice.ManagedCluster(
managed_cluster_name,
resource_group_name=resource_group.name,
agent_pool_profiles=[{
&amp;quot;count&amp;quot;: 3,
&amp;quot;max_pods&amp;quot;: 110,
&amp;quot;mode&amp;quot;: &amp;quot;System&amp;quot;,
&amp;quot;name&amp;quot;: &amp;quot;agentpool&amp;quot;,
&amp;quot;node_labels&amp;quot;: {},
&amp;quot;os_disk_size_gb&amp;quot;: 30,
&amp;quot;os_type&amp;quot;: &amp;quot;Linux&amp;quot;,
&amp;quot;type&amp;quot;: &amp;quot;VirtualMachineScaleSets&amp;quot;,
&amp;quot;vm_size&amp;quot;: &amp;quot;Standard_DS2_v2&amp;quot;,
}],
enable_rbac=True,
kubernetes_version=&amp;quot;1.18.14&amp;quot;,
linux_profile={
&amp;quot;admin_username&amp;quot;: &amp;quot;testuser&amp;quot;,
&amp;quot;ssh&amp;quot;: {
&amp;quot;public_keys&amp;quot;: [{
&amp;quot;key_data&amp;quot;: ssh_key.public_key_openssh,
}],
},
},
dns_prefix=resource_group.name,
node_resource_group=f&amp;quot;MC_azure-native-go_{managed_cluster_name}_westus&amp;quot;,
service_principal_profile={
&amp;quot;client_id&amp;quot;: ad_app.application_id,
&amp;quot;secret&amp;quot;: ad_sp_password.value
})
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;pre&gt;&lt;code&gt; const cluster = new containerservice.ManagedCluster(managedClusterName, {
resourceGroupName: resourceGroup.name,
agentPoolProfiles: [{
count: 3,
maxPods: 110,
mode: &amp;quot;System&amp;quot;,
name: &amp;quot;agentpool&amp;quot;,
nodeLabels: {},
osDiskSizeGB: 30,
osType: &amp;quot;Linux&amp;quot;,
type: &amp;quot;VirtualMachineScaleSets&amp;quot;,
vmSize: &amp;quot;Standard_DS2_v2&amp;quot;,
}],
dnsPrefix: resourceGroup.name,
enableRBAC: true,
kubernetesVersion: &amp;quot;1.18.14&amp;quot;,
linuxProfile: {
adminUsername: &amp;quot;testuser&amp;quot;,
ssh: {
publicKeys: [{
keyData: sshKey.publicKeyOpenssh,
}],
},
},
nodeResourceGroup: `MC_azure-go_${managedClusterName}`,
servicePrincipalProfile: {
clientId: adApp.applicationId,
secret: adSpPassword.value,
},
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Export the &lt;code&gt;kubeconfig&lt;/code&gt; file&lt;/p&gt;
&lt;p&gt;A &lt;a href="https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/"&gt;&lt;code&gt;kubeconfig&lt;/code&gt;&lt;/a&gt; file organizes information about clusters and allows &lt;code&gt;kubectl&lt;/code&gt; connect to the cluster.&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="csharp,go,python,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;pre&gt;&lt;code&gt;...
// Export the KubeConfig
this.KubeConfig = Output.Tuple(resourceGroup.Name, cluster.Name).Apply(names =&amp;gt;
GetKubeConfig(names.Item1, names.Item2));
}
[Output]
public Output&amp;lt;string&amp;gt; KubeConfig { get; set; }
private static async Task&amp;lt;string&amp;gt; GetKubeConfig(string resourceGroupName, string clusterName)
{
var credentials = await ListManagedClusterUserCredentials.InvokeAsync(new ListManagedClusterUserCredentialsArgs
{
ResourceGroupName = resourceGroupName,
ResourceName = clusterName
});
var encoded = credentials.Kubeconfigs[0].Value;
var data = Convert.FromBase64String(encoded);
return Encoding.UTF8.GetString(data);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;pre&gt;&lt;code&gt; ctx.Export(&amp;quot;kubeconfig&amp;quot;, pulumi.All(cluster.Name, resourceGroup.Name, resourceGroup.ID()).ApplyT(func(args interface{}) (string, error) {
clusterName := args.([]interface{})[0].(string)
resourceGroupName := args.([]interface{})[1].(string)
creds, err := containerservice.ListManagedClusterUserCredentials(ctx, &amp;amp;containerservice.ListManagedClusterUserCredentialsArgs{
ResourceGroupName: resourceGroupName,
ResourceName: clusterName,
})
if err != nil {
return &amp;quot;&amp;quot;, err
}
encoded := creds.Kubeconfigs[0].Value
kubeconfig, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return &amp;quot;&amp;quot;, err
}
return string(kubeconfig), nil
}))
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;pre&gt;&lt;code&gt; # Export kubeconfig
encoded = creds.kubeconfigs[0].value
kubeconfig = encoded.apply(
lambda enc: base64.b64decode(enc).decode())
pulumi.export(&amp;quot;kubeconfig&amp;quot;, kubeconfig)
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;pre&gt;&lt;code&gt; const creds = pulumi.all([cluster.name, resourceGroup.name]).apply(([clusterName, rgName]) =&amp;gt; {
return containerservice.listManagedClusterUserCredentials({
resourceGroupName: rgName,
resourceName: clusterName,
});
});
const encoded = creds.kubeconfigs[0].value;
export const kubeconfig = encoded.apply(enc =&amp;gt; Buffer.from(enc, &amp;quot;base64&amp;quot;).toString());
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Connect to the AKS cluster&lt;/p&gt;
&lt;p&gt;We can use the &lt;code&gt;kubeconfig&lt;/code&gt; file connect to the cluster. It&amp;rsquo;s common practice to copy the &lt;code&gt;kubeconfig&lt;/code&gt; file to &lt;code&gt;~/.kube/config&lt;/code&gt;, which is the directory that &lt;code&gt;kubectl&lt;/code&gt; looks for the file. However, you can use any directory with the &lt;code&gt;--kubeconfig&lt;/code&gt; flag, e.g.,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl --kubeconfig /path/to/kubeconfig_file get pods
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As this example shows, deploying an AKS cluster requires setting parameters. This action can be done in the portal or with code. The advantage of code is that clusters can be created on demand without having to use the Azure portal. This setup is convenient when you have different environments, such as a dev/test environment and a production environment.&lt;/p&gt;
&lt;p&gt;The complete code for deploying AKS is available on GitHub for &lt;a href="https://github.com/pulumi/examples/tree/master/azure-ts-aks"&gt;Typescript&lt;/a&gt;, &lt;a href="https://github.com/pulumi/examples/tree/master/azure-py-aks"&gt;Python&lt;/a&gt;, &lt;a href="https://github.com/pulumi/examples/tree/master/azure-go-aks"&gt;Go&lt;/a&gt;, and &lt;a href="https://github.com/pulumi/examples/tree/master/azure-cs-aks"&gt;C#&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;Azure Kubernetes Service lets you deploy a Kubernetes cluster quickly and efficiently. An AKS deployment configures the worker nodes since the master nodes are provided by Azure. The Azure Portal provides a simplified interface for configuration, but if you want fine-grain control over the deployment, infrastructure as code is an option. This is particularly true for production deployments where the configuration requires tuning for an application deployment.&lt;/p&gt;
&lt;p&gt;In the next article in this series, we&amp;rsquo;ll deploy an application on an AKS cluster using different methods.&lt;/p&gt;</description><author>Sophia Parafina</author><category>kubernetes</category><category>aks</category><category>azure</category></item><item><title>Top 5 Things an Azure Developer Needs to Know: Static Websites</title><link>https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/</link><pubDate>Mon, 09 Aug 2021 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/top-5-things-for-azure-devs-static-websites/index.png" /&gt;
&lt;p&gt;Static web applications are a popular way to publish websites. There are many reasons for adopting static web applications, including speed, security, version control, scalability, and reduced cost.&lt;/p&gt;
&lt;p&gt;This article goes into depth about the two types of static web applications that Azure offers. The first uses Azure Blob Storage to serve static data. The second method is Azure Static Web Apps which follows the pattern of &lt;a href="https://jamstack.org"&gt;Jamstack&lt;/a&gt; applications that use a static website generator integrated with source control that publishes to a &lt;a href="https://en.wikipedia.org/wiki/Content_delivery_network"&gt;Content Delivery Network&lt;/a&gt;. We&amp;rsquo;ll take an in-depth look at both methods and consider the pros and cons of each.&lt;/p&gt;
&lt;h2 id="static-websites-with-azure-storage"&gt;Static Websites with Azure Storage&lt;/h2&gt;
&lt;p&gt;Hosting a static website on Azure Store is an option for serving web content without a web server. You can upload HTML, CSS, images, and JavaScript to an Azure storage container named &lt;code&gt;$web&lt;/code&gt;. Because the content is in a storage container, you can also use other PaaS services like Azure Functions or Azure CDN.&lt;/p&gt;
&lt;h3 id="azure-portal"&gt;Azure Portal&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s get started using the Azure Portal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Create a storage account (optional if you have an existing storage account)&lt;/p&gt;
&lt;p&gt;In the Azure Portal, navigate to &lt;strong&gt;Storage accounts&lt;/strong&gt;, and follow the defaults.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/image5.png" alt="Storage accounts"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: In the &lt;strong&gt;Storage account&lt;/strong&gt; page, select &lt;strong&gt;Data management &amp;gt; Static website&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/image2.png" alt="Static website"&gt;&lt;/p&gt;
&lt;p&gt;Select &lt;strong&gt;enabled&lt;/strong&gt; for the &lt;strong&gt;Static website&lt;/strong&gt;, and enter values for the &lt;strong&gt;Index document&lt;/strong&gt; and &lt;strong&gt;Error document&lt;/strong&gt; fields. Save the changes.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/image4.png" alt="Enable static website"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Upload files&lt;/p&gt;
&lt;p&gt;Here are example files to upload or you can use your own.&lt;/p&gt;
&lt;p&gt;index.html&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;This file is served from Blob Storage (courtesy of Pulumi!)&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;404.html&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;That&amp;#39;s a 404! Still, from the Blob Storage.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ll use &lt;strong&gt;Storage Explorer (preview)&lt;/strong&gt;, and select &lt;strong&gt;BLOB CONTAINERS &amp;gt; $web&lt;/strong&gt;. In the &lt;strong&gt;Upload blob&lt;/strong&gt; pane, add the &lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;404.html&lt;/code&gt; files, and select &lt;strong&gt;Upload&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/image1.png" alt="Storage explorer"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Get the URL&lt;/p&gt;
&lt;p&gt;Select &lt;strong&gt;Static website&lt;/strong&gt; in the overview pane, and the URL is the &lt;strong&gt;Primary endpoint&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/image3.png" alt="Endpoint"&gt;&lt;/p&gt;
&lt;h3 id="build-and-deploy-a-static-website-with-code"&gt;Build and deploy a static website with code&lt;/h3&gt;
&lt;p&gt;We can repeat the same process using a programming language. The process includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a storage account&lt;/li&gt;
&lt;li&gt;Enable &lt;code&gt;Static website&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Upload files&lt;/li&gt;
&lt;li&gt;Configure and publish endpoints&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can reproduce this process in code with C#, Go, Python, Typescript, or in any language Pulumi supports. Let&amp;rsquo;s step through the code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Create a &lt;code&gt;Resource group&lt;/code&gt; and &lt;code&gt;Storage account&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="csharp,go,python,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;pre&gt;&lt;code&gt; var resourceGroup = new Resources.ResourceGroup(&amp;quot;resourceGroup&amp;quot;);
var storageAccount = new Storage.StorageAccount(&amp;quot;storageaccount&amp;quot;, new Storage.StorageAccountArgs
{
Kind = Storage.Kind.StorageV2,
ResourceGroupName = resourceGroup.Name,
Sku = new Storage.Inputs.SkuArgs
{
Name = Storage.SkuName.Standard_LRS,
},
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;pre&gt;&lt;code&gt; pulumi.Run(func(ctx *pulumi.Context) error {
resourceGroup, err := resources.NewResourceGroup(ctx, &amp;quot;website-rg&amp;quot;, nil)
if err != nil {
return err
}
storageAccount, err := storage.NewStorageAccount(ctx, &amp;quot;sa&amp;quot;, &amp;amp;storage.StorageAccountArgs{
ResourceGroupName: resourceGroup.Name,
Kind: storage.KindStorageV2,
Sku: &amp;amp;storage.SkuArgs{
Name: storage.SkuName_Standard_LRS,
},
})
if err != nil {
return err
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;pre&gt;&lt;code&gt;resource_group = resources.ResourceGroup(&amp;quot;resourceGroup&amp;quot;)
storage_account = storage.StorageAccount(
&amp;quot;storageaccount&amp;quot;,
access_tier=storage.AccessTier.HOT,
enable_https_traffic_only=True,
encryption=storage.EncryptionArgs(
key_source=storage.KeySource.MICROSOFT_STORAGE,
services=storage.EncryptionServicesArgs(
blob=storage.EncryptionServiceArgs(
enabled=True,
),
file=storage.EncryptionServiceArgs(
enabled=True,
),
),
),
kind=storage.Kind.STORAGE_V2,
network_rule_set=storage.NetworkRuleSetArgs(
bypass=storage.Bypass.AZURE_SERVICES,
default_action=storage.DefaultAction.ALLOW,
),
resource_group_name=resource_group.name,
sku=storage.SkuArgs(
name=storage.SkuName.STANDARD_LRS,
))
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;pre&gt;&lt;code&gt;const resourceGroup = new resources.ResourceGroup(&amp;quot;resourceGroup&amp;quot;);
const storageAccount = new storage.StorageAccount(&amp;quot;storageaccount&amp;quot;, {
enableHttpsTrafficOnly: true,
kind: storage.Kind.StorageV2,
resourceGroupName: resourceGroup.name,
sku: {
name: storage.SkuName.Standard_LRS,
},
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Enable static website&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="csharp,go,python,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;pre&gt;&lt;code&gt;// Enable static website support
var staticWebsite = new Storage.StorageAccountStaticWebsite(&amp;quot;staticWebsite&amp;quot;, new Storage.StorageAccountStaticWebsiteArgs
{
AccountName = storageAccount.Name,
ResourceGroupName = resourceGroup.Name,
IndexDocument = &amp;quot;index.html&amp;quot;,
Error404Document = &amp;quot;404.html&amp;quot;,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;pre&gt;&lt;code&gt;// Enable static website support
staticWebsite, err := storage.NewStorageAccountStaticWebsite(ctx, &amp;quot;staticWebsite&amp;quot;, &amp;amp;storage.StorageAccountStaticWebsiteArgs{
AccountName: storageAccount.Name,
ResourceGroupName: resourceGroup.Name,
IndexDocument: pulumi.String(&amp;quot;index.html&amp;quot;),
Error404Document: pulumi.String(&amp;quot;404.html&amp;quot;),
})
if err != nil {
return err
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;pre&gt;&lt;code&gt;# Enable static website support
static_website = storage.StorageAccountStaticWebsite(
&amp;quot;staticWebsite&amp;quot;,
account_name=storage_account.name,
resource_group_name=resource_group.name,
index_document=&amp;quot;index.html&amp;quot;,
error404_document=&amp;quot;404.html&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;pre&gt;&lt;code&gt;// Enable static website support
const staticWebsite = new storage.StorageAccountStaticWebsite(&amp;quot;staticWebsite&amp;quot;, {
accountName: storageAccount.name,
resourceGroupName: resourceGroup.name,
indexDocument: &amp;quot;index.html&amp;quot;,
error404Document: &amp;quot;404.html&amp;quot;,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Upload content&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="csharp,go,python,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;pre&gt;&lt;code&gt;var index_html = new Storage.Blob(&amp;quot;index.html&amp;quot;, new Storage.BlobArgs
{
ResourceGroupName = resourceGroup.Name,
AccountName = storageAccount.Name,
ContainerName = staticWebsite.ContainerName,
Source = new FileAsset(&amp;quot;./wwwroot/index.html&amp;quot;),
ContentType = &amp;quot;text/html&amp;quot;,
});
var notfound_html = new Storage.Blob(&amp;quot;404.html&amp;quot;, new Storage.BlobArgs
{
ResourceGroupName = resourceGroup.Name,
AccountName = storageAccount.Name,
ContainerName = staticWebsite.ContainerName,
Source = new FileAsset(&amp;quot;./wwwroot/404.html&amp;quot;),
ContentType = &amp;quot;text/html&amp;quot;,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;pre&gt;&lt;code&gt;// Upload the files
_, err = storage.NewBlob(ctx, &amp;quot;index.html&amp;quot;, &amp;amp;storage.BlobArgs{
ResourceGroupName: resourceGroup.Name,
AccountName: storageAccount.Name,
ContainerName: staticWebsite.ContainerName,
Source: pulumi.NewFileAsset(&amp;quot;./wwwroot/index.html&amp;quot;),
ContentType: pulumi.String(&amp;quot;text/html&amp;quot;),
})
if err != nil {
return err
}
_, err = storage.NewBlob(ctx, &amp;quot;404.html&amp;quot;, &amp;amp;storage.BlobArgs{
ResourceGroupName: resourceGroup.Name,
AccountName: storageAccount.Name,
ContainerName: staticWebsite.ContainerName,
Source: pulumi.NewFileAsset(&amp;quot;./wwwroot/404.html&amp;quot;),
ContentType: pulumi.String(&amp;quot;text/html&amp;quot;),
})
if err != nil {
return err
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;pre&gt;&lt;code&gt;# Upload the files
index_html = storage.Blob(
&amp;quot;index_html&amp;quot;,
resource_group_name=resource_group.name,
account_name=storage_account.name,
container_name=static_website.container_name,
source=pulumi.FileAsset(&amp;quot;./wwwroot/index.html&amp;quot;),
content_type=&amp;quot;text/html&amp;quot;)
notfound_html = storage.Blob(
&amp;quot;notfound_html&amp;quot;,
resource_group_name=resource_group.name,
account_name=storage_account.name,
container_name=static_website.container_name,
source=pulumi.FileAsset(&amp;quot;./wwwroot/404.html&amp;quot;),
content_type=&amp;quot;text/html&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;pre&gt;&lt;code&gt;// Upload the files
[&amp;quot;index.html&amp;quot;, &amp;quot;404.html&amp;quot;].map(name =&amp;gt;
new storage.Blob(name, {
resourceGroupName: resourceGroup.name,
accountName: storageAccount.name,
containerName: staticWebsite.containerName,
source: new pulumi.asset.FileAsset(`./wwwroot/${name}`),
contentType: &amp;quot;text/html&amp;quot;,
}),
);
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Configure and publish endpoints&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="csharp,go,python,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;pre&gt;&lt;code&gt;// Web endpoint to the website
this.StaticEndpoint = storageAccount.PrimaryEndpoints.Apply(primaryEndpoints =&amp;gt; primaryEndpoints.Web);
// (Optional) Add a CDN in front of the storage account.
var profile = new Cdn.Profile(&amp;quot;profile&amp;quot;, new Cdn.ProfileArgs
{
ResourceGroupName = resourceGroup.Name,
Location = &amp;quot;global&amp;quot;,
Sku = new Cdn.Inputs.SkuArgs
{
Name = Cdn.SkuName.Standard_Microsoft,
},
});
var endpointOrigin = storageAccount.PrimaryEndpoints.Apply(pe =&amp;gt; pe.Web.Replace(&amp;quot;https://&amp;quot;, &amp;quot;&amp;quot;).Replace(&amp;quot;/&amp;quot;, &amp;quot;&amp;quot;));
[Output(&amp;quot;staticEndpoint&amp;quot;)]
public Output&amp;lt;string&amp;gt; StaticEndpoint { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;pre&gt;&lt;code&gt;endpointOrigin := storageAccount.PrimaryEndpoints.Web().ApplyT(func(endpoint string) string {
endpoint = strings.ReplaceAll(endpoint, &amp;quot;https://&amp;quot;, &amp;quot;&amp;quot;)
endpoint = strings.ReplaceAll(endpoint, &amp;quot;/&amp;quot;, &amp;quot;&amp;quot;)
return endpoint
}).(pulumi.StringOutput)
// Web endpoint to the website
ctx.Export(&amp;quot;staticEndpoint&amp;quot;, storageAccount.PrimaryEndpoints.Web())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;pre&gt;&lt;code&gt;endpoint_origin = storage_account.primary_endpoints.apply(
lambda primary_endpoints: primary_endpoints.web.replace(&amp;quot;https://&amp;quot;, &amp;quot;&amp;quot;).replace(&amp;quot;/&amp;quot;, &amp;quot;&amp;quot;))
# Web endpoint to the website
pulumi.export(&amp;quot;staticEndpoint&amp;quot;, storage_account.primary_endpoints.web)
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;pre&gt;&lt;code&gt;// Web endpoint to the website
export const staticEndpoint = storageAccount.primaryEndpoints.web;
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;The complete examples for &lt;a href="https://github.com/pulumi/examples/tree/master/azure-cs-static-website"&gt;C#&lt;/a&gt;, &lt;a href="https://github.com/pulumi/examples/blob/master/azure-go-static-website/"&gt;Go&lt;/a&gt;, &lt;a href="https://github.com/pulumi/examples/blob/master/azure-py-static-website/"&gt;Python&lt;/a&gt;, and &lt;a href="https://github.com/pulumi/examples/blob/master/azure-ts-static-website/index.ts"&gt;Typescript&lt;/a&gt; are on Github.&lt;/p&gt;
&lt;h2 id="azure-static-web-apps"&gt;Azure Static Web Apps&lt;/h2&gt;
&lt;p&gt;Azure Static Web Apps (SWA) builds and deploys web apps from a code repository. Azure works directly with GitHub or Azure DevOps to watch a branch on your repository. When you push a commit or accept a pull request, your app is built and deployed to Azure. When you build web apps with SWA, your static assets are deployed to a CDN that serves files from geographically distributed points.&lt;/p&gt;
&lt;p&gt;Static web apps can be built with popular frameworks that don&amp;rsquo;t require server-side rendering, such as React, Angular, and Vue. Web applications typically include HTML, JavaScript, images, and CSS. In addition to these assets, you can create API endpoints hosted in an Azure Function.&lt;/p&gt;
&lt;p&gt;The key thing to remember with SWAs is that you build the application from a repository.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s jump into Azure Static Web Apps!&lt;/p&gt;
&lt;h3 id="build-and-deploy"&gt;Build and deploy&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ll use Visual Studio Code&amp;rsquo;s &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps"&gt;Azure Static Web App Extension&lt;/a&gt; and a &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt; account.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps"&gt;Azure Web Static Web Apps&lt;/a&gt; extension.&lt;/p&gt;
&lt;p&gt;Follow the instructions to authorize Visual Studio Code to access your GitHub account.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Create a web application&lt;/p&gt;
&lt;p&gt;For convenience, we can use the Azure template for generating web applications. &lt;a href="https://github.com/staticwebdev/vanilla-basic"&gt;Open this link&lt;/a&gt; and click the &lt;strong&gt;Use this template&lt;/strong&gt; button to generate a basic React application.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/react-basic.png" alt="Generate app from template"&gt;&lt;/p&gt;
&lt;p&gt;Clone the repository to your computer.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ git clone https://github.com/spara/bookish-doodle.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Create a static web app with Visual Studio Code&lt;/p&gt;
&lt;p&gt;Open your repository with Visual Studio Code and activate the &lt;a href="https://code.visualstudio.com/docs/azure/extensions"&gt;Azure extension&lt;/a&gt;. On the &lt;strong&gt;APP SERVICE&lt;/strong&gt; item, select the &lt;strong&gt;+&lt;/strong&gt; to create a web app.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/static_web_app_vscode.png" alt="Create web app"&gt;&lt;/p&gt;
&lt;p&gt;Follow the prompts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a unique name.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/name.png" alt="Enter a name"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Select a project structure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/react.png" alt="Select project structure"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Select an application directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/project_location.png" alt="Select project directory"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Select a build directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/build_directory.png" alt="Select build directory"&gt;&lt;/p&gt;
&lt;p&gt;When VS Code completes configuring your application, you will be prompted to deploy.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/deploy_swa.png" alt="Deploy"&gt;&lt;/p&gt;
&lt;p&gt;You can view the application in the browser.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Change the code&lt;/p&gt;
&lt;p&gt;Edit &lt;code&gt;./src/app.js&lt;/code&gt; and change &lt;em&gt;World&lt;/em&gt; to &lt;em&gt;Cloud Engineers&lt;/em&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Cloud Engineers&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/div&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add, commit, and push your changes to GitHub.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ git add .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ git commit -m &lt;span class="s1"&gt;&amp;#39;changed message&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ git push
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Select the &lt;strong&gt;Actions&lt;/strong&gt; tab of your repository to see the workflows. Select the &lt;strong&gt;changed message&lt;/strong&gt;, and then select &lt;strong&gt;Build and Deploy Job&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/changed_message.png" alt="Commit"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/build_and_deploy_job.png" alt="Build and Deploy Job"&gt;&lt;/p&gt;
&lt;p&gt;To see the details of the deployment, select &lt;strong&gt;Build and Deploy&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/results.png" alt="Results"&gt;&lt;/p&gt;
&lt;p&gt;So what happened here? First, we used the Azure Static Web Apps for Visual Studio Code to authorize access to GitHub. Next, we created a deployment using the extension, created a GitHub Actions workflow, and deployed the application. We edited the code and pushed it to the repository. The push triggered the GitHub Action, rebuilt, and deployed the application.&lt;/p&gt;
&lt;p&gt;The Azure Static Web Apps service lets you create a complete DevOps workflow.&lt;/p&gt;
&lt;h3 id="build-and-deploy-with-code-and-pulumi"&gt;Build and deploy with code and Pulumi&lt;/h3&gt;
&lt;p&gt;Can we create a complete DevOps workflow with code? Of course, we can! The Pulumi Azure Native provider uses the same API as VS Code. In the example below, we can duplicate the process without using an extension or the Azure CLI.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;pulumi_azure_native&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;azure_native&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;static_site&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azure_native&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StaticSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;staticSite&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;branch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;master&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;build_properties&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;azure_native&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StaticSiteBuildPropertiesArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;api_location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;api&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;app_artifact_location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;build&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;app_location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;app&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;West US 2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;testStaticSite0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;repository_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;repoToken123&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;repository_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://github.com/username/RepoName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resource_group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;azure_native&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SkuDescriptionArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Basic&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Basic&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the example above, creating a static web app requires configuring the same parameters we used in the Visual Studio Code example. The difference is that we create a Pulumi Project with our application at the root of the project directory in a folder called &lt;code&gt;app&lt;/code&gt;. Once the static web app stack is created, you can push changes and trigger a deployment. One of the advantages of using infrastructure as code is that you can use the development environment and toolchain that you prefer. You are not bound to using a specific extension or development environment. We can be productive with our toolchain and create a complete deployment workflow using GitHub Actions with cloud engineering and Azure Static Web Apps.&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;This article demonstrates two ways to build static websites with Azure. The first way is to use Azure Storage to deploy the website. We showed how to use the Azure Portal and infrastructure as code to deploy. The other way to deploy a static website is to use the Azure Static Web Apps Service. We used the Visual Studio Code extension to configure GitHub Actions to deploy the React application in this example. We demonstrated how to deploy using code because the Pulumi Azure Native provider uses the Azure API. Infrastructure as code lets us choose our development environment where we are productive. In the next installment of this series, we’ll tackle deploying Kubernetes.&lt;/p&gt;</description><author>Sophia Parafina</author><category>azure</category><category>static-websites</category></item><item><title>Top 5 Things an Azure Developer Needs to Know: Serverless</title><link>https://www.pulumi.com/blog/top-5-things-for-azure-devs-serverless/</link><pubDate>Fri, 06 Aug 2021 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/top-5-things-for-azure-devs-serverless/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/top-5-things-for-azure-devs-serverless/index.png" /&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/"&gt;previous article&lt;/a&gt; was a deep dive into virtual machines. First, we used the Azure Portal to create and deploy a virtual machine; then, we repeated the process using infrastructure as code. We further demonstrated how to automate provisioning as part of cloud engineering&amp;rsquo;s build and deploy processes.&lt;/p&gt;
&lt;p&gt;This article will explore the other end of the cloud infrastructure with serverless, which is an on-demand, fully-managed cloud architecture.&lt;/p&gt;
&lt;h2 id="what-is-serverless-and-when-to-use-it"&gt;What is serverless, and when to use it?&lt;/h2&gt;
&lt;p&gt;Serverless is an event-driven architecture that executes code when triggered. Azure implements serverless with Azure Functions and Events. A function typically performs a single task, such as saving a log file. A function can perform multiple tasks, but in general, functions adhere to the principle of &amp;ldquo;you only had one job.&amp;rdquo; Functions can be written in any Azure supported language: C #, F#, JavaScript, PowerShell, Python, and Typescript.&lt;/p&gt;
&lt;p&gt;An Event calls a function to execute. It can be a webhook, an HTTP request, or a scheduled trigger. Azure provides many function templates with a range of triggers; furthermore, they can be customized to application requirements.&lt;/p&gt;
&lt;p&gt;Azure Functions are ideal for specific use cases that include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;when demand varies unpredictably, serverless can scale automatically&lt;/li&gt;
&lt;li&gt;when a service is used infrequently, serverless can reduce costs by only charging per use&lt;/li&gt;
&lt;li&gt;serverless can eliminate maintenance costs&lt;/li&gt;
&lt;li&gt;when you have client-heavy applications, where most of the business logic is in the client&lt;/li&gt;
&lt;li&gt;if you have high latency tasks like data processing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Serverless is not ideal if the application runs constantly, needs a quick response (otherwise known as the &lt;a href="https://www.pulumi.com/blog/aws-lambda-provisioned-concurrency-no-cold-starts/"&gt;cold start problem&lt;/a&gt;, or is a long-running process that can exceed the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-scale#timeout"&gt;timeout period&lt;/a&gt; for your execution plan.&lt;/p&gt;
&lt;p&gt;With those caveats, let&amp;rsquo;s jump into creating a serverless function using the Azure Portal to understand how to write a function and how the pieces work together.&lt;/p&gt;
&lt;h2 id="our-first-serverless-function"&gt;Our first serverless function&lt;/h2&gt;
&lt;p&gt;For this example, we&amp;rsquo;ll use &lt;a href="https://code.visualstudio.com/"&gt;Visual Studio Code&lt;/a&gt; and the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions"&gt;Azure Functions extension&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: With the Azure Functions extension installed, click on the Activity Bar and click on Create New Project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Select a folder for your project.&lt;/li&gt;
&lt;li&gt;Select a language, use Typescript.&lt;/li&gt;
&lt;li&gt;Select HTTP trigger.&lt;/li&gt;
&lt;li&gt;Name your function, e.g., myHttpTrigger.&lt;/li&gt;
&lt;li&gt;Set the Authorization level to Anonymous&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-serverless/image2.png" alt="New Project"&gt;&lt;/p&gt;
&lt;p&gt;When finished, you&amp;rsquo;ll have a template.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AzureFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HttpRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@azure/functions&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;httpTrigger&lt;/span&gt;: &lt;span class="kt"&gt;AzureFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;: &lt;span class="kt"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;: &lt;span class="kt"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;HTTP trigger function processed a request.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;responseMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Hello, &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;. This HTTP triggered function executed successfully.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// status: 200, /* Defaults to 200 */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;body&lt;/span&gt;: &lt;span class="kt"&gt;responseMessage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;httpTrigger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: (Optional) If you have Azure Functions Core tools installed, you can run the function locally. Press F5 or click on &lt;code&gt;Run&lt;/code&gt; &amp;gt; &lt;code&gt;Start debugging&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The service will run locally and provide you with a URL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Functions:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; myHttpTrigger: &lt;span class="o"&gt;[&lt;/span&gt;GET,POST&lt;span class="o"&gt;]&lt;/span&gt; http://localhost:7071/api/myHttpTrigger
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Navigate to the URL in a browser or use &lt;code&gt;curl&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl http://localhost:7071/api/myHttpTrigger
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;This HTTP triggered &lt;span class="k"&gt;function&lt;/span&gt; executed successfully. Pass a name in the query string or in the request body &lt;span class="k"&gt;for&lt;/span&gt; a personalized response.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Press &lt;code&gt;Control-C&lt;/code&gt; in the terminal to stop the debugger.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Publish the function to Azure.&lt;/p&gt;
&lt;p&gt;Make sure you are signed into Azure and click on &lt;code&gt;Deploy function app…&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-serverless/image3.png" alt="Deploy function"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Select &lt;code&gt;Create a new Function App in Azure&lt;/code&gt; and enter a name, &amp;ldquo;exampleHttpTrigger&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Select a runtime stack, &lt;code&gt;Node.js 14 LTS&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Select a location for new resources, East US&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the terminal pane, click on the &lt;code&gt;Output&lt;/code&gt; tab, and you&amp;rsquo;ll see the URL for the function. You can call the function with curl with the name parameter.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl https://myazurehttptrigger.azurewebsites.net/api/myhttptrigger?name&lt;span class="o"&gt;=&lt;/span&gt;Pulumipus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Hello, Pulumipus. This HTTP triggered &lt;span class="k"&gt;function&lt;/span&gt; executed successfully.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Don&amp;rsquo;t forget to delete the function in the Azure Portal!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-serverless/image1.png" alt="Azure Portal"&gt;&lt;/p&gt;
&lt;h2 id="deploying-azure-functions-with-code"&gt;Deploying Azure Functions with code&lt;/h2&gt;
&lt;p&gt;Creating and deploying an Azure Function is a bit more involved than using the Azure Function extension with VS Code. What goes on behind the scenes after you write the function is a process that includes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Creating a ResourceGroup&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Create a separate resource group for this example.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resourceGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResourceGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;functions-rg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Creating the storage account and code container that holds the function&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Storage account is required by Function App.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Also, we will upload the function code to the same storage account.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storageAccount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StorageAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;sa&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceGroupName&lt;/span&gt;: &lt;span class="kt"&gt;resourceGroup.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;: &lt;span class="kt"&gt;storage.SkuName.Standard_LRS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;: &lt;span class="kt"&gt;storage.Kind.StorageV2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Function code archives will be stored in this container.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;codeContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BlobContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;zips&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceGroupName&lt;/span&gt;: &lt;span class="kt"&gt;resourceGroup.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;accountName&lt;/span&gt;: &lt;span class="kt"&gt;storageAccount.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Uploading the function code as a zip file to the storage account. Note that the &lt;code&gt;source&lt;/code&gt; parameter points to the function&amp;rsquo;s directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Upload Azure Function&amp;#39;s code as a zip archive to the storage account.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;codeBlob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;zip&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceGroupName&lt;/span&gt;: &lt;span class="kt"&gt;resourceGroup.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;accountName&lt;/span&gt;: &lt;span class="kt"&gt;storageAccount.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;containerName&lt;/span&gt;: &lt;span class="kt"&gt;codeContainer.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;source&lt;/span&gt;: &lt;span class="kt"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FileArchive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./javascript&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setting the &lt;a href="https://azure.microsoft.com/en-us/pricing/details/functions/"&gt;Consumption Plan&lt;/a&gt; to determine how to bill when the function executes&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Define a Consumption Plan for the Function App.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// You can change the SKU to Premium or App Service Plan if needed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppServicePlan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;plan&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceGroupName&lt;/span&gt;: &lt;span class="kt"&gt;resourceGroup.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Y1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tier&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Dynamic&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the connection string to the storage account and the zip archive&amp;rsquo;s &lt;a href="https://docs.microsoft.com/en-us/rest/api/storageservices/delegate-access-with-shared-access-signature"&gt;Shared Access Signature (SAS)&lt;/a&gt; to grant rights to use the storage account. We will need these to create the function in Azure.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Build the connection string and zip archive&amp;#39;s SAS URL. They will go to Function App&amp;#39;s settings.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storageConnectionString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resourceGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;storageAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;codeBlobUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signedBlobReadUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;codeBlob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;codeContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;storageAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resourceGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now that we have all the parameters needed to deploy the function: the resource group,
the billing plan, the connection string to Azure storage, the Functions version (3), the runtime (Node.js), the runtime Node version (14.0), and the SAS url for the function code, we can build and deploy our Azure Function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WebApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;fa&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceGroupName&lt;/span&gt;: &lt;span class="kt"&gt;resourceGroup.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;serverFarmId&lt;/span&gt;: &lt;span class="kt"&gt;plan.id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;functionapp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;siteConfig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;appSettings&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;AzureWebJobsStorage&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;: &lt;span class="kt"&gt;storageConnectionString&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;FUNCTIONS_EXTENSION_VERSION&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;~3&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;FUNCTIONS_WORKER_RUNTIME&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;node&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;WEBSITE_NODE_DEFAULT_VERSION&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;~14&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;WEBSITE_RUN_FROM_PACKAGE&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;: &lt;span class="kt"&gt;codeBlobUrl&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;http20Enabled&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;nodeVersion&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;~14&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interpolate&lt;/span&gt;&lt;span class="sb"&gt;`https://&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultHostName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;/api/HelloNode?name=Pulumi`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At the very end of the script, we export the URL to the service for you to trigger.&lt;/p&gt;
&lt;h2 id="why-is-it-so-complicated"&gt;Why is it so complicated?&lt;/h2&gt;
&lt;p&gt;Isn&amp;rsquo;t infrastructure as code supposed to simplify infrastructure deployments? This seems more effort than using the Visual Studio Code extension or even &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"&gt;the Azure CLI&lt;/a&gt; on the surface. However, it&amp;rsquo;s important to note that this is &lt;em&gt;boiler-plate&lt;/em&gt; code that you can reuse to deploy multiple functions with different runtimes and Consumption Plans. The key to using infrastructure code is that it is repeatable, customizable, and a CI/CD pipeline can deploy changes automatically.&lt;/p&gt;
&lt;p&gt;Try out the complete example in either &lt;a href="https://github.com/pulumi/examples/tree/master/azure-ts-functions"&gt;Typescript&lt;/a&gt; or &lt;a href="https://github.com/pulumi/examples/tree/master/azure-ts-functions"&gt;C#&lt;/a&gt; to get familiar with Azure Functions. You can also learn how Functions are written in all supported languages by checking out the &lt;a href="https://github.com/pulumi/examples/tree/master/azure-ts-functions-many"&gt;Azure Functions in All Supported Languages&lt;/a&gt; example.&lt;/p&gt;
&lt;p&gt;In the following article, we&amp;rsquo;ll do a deep dive into Azure static websites, which is a popular option for &lt;a href="https://jamstack.org/"&gt;Jamstacks&lt;/a&gt;.&lt;/p&gt;</description><author>Sophia Parafina</author><category>azure</category><category>serverless</category><category>cloud-engineering</category></item><item><title>Top 5 Things an Azure Developer Needs to Know: VMs</title><link>https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/</link><pubDate>Wed, 04 Aug 2021 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/top-5-things-for-azure-devs-vm/index.png" /&gt;
&lt;p&gt;So you want to be an Azure dev and all-around infrastructure wizard? Let&amp;rsquo;s start with the basics, virtual machines! In the &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/"&gt;previous article&lt;/a&gt;, the common use case for virtual machines is migrating applications from dedicated hardware. You want full control of the machine to install required software for the application or configure storage and networking.&lt;/p&gt;
&lt;p&gt;Azure provides many ways to create and configure virtual machines ranging from &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"&gt;the Azure CLI&lt;/a&gt; to &lt;a href="https://azure.microsoft.com/en-us/features/azure-portal/"&gt;the Azure Portal&lt;/a&gt;. In this article, we&amp;rsquo;ll first create a virtual machine using the portal to understand the requirements and process; then, we&amp;rsquo;ll do it with code using &lt;a href="https://www.pulumi.com/registry/packages/azure/"&gt;Pulumi&amp;rsquo;s Azure Native provider&lt;/a&gt;, which is built directly from the Azure Resource Manager API.&lt;/p&gt;
&lt;h2 id="creating-a-vm-with-the-azure-portal"&gt;Creating a VM with the Azure Portal&lt;/h2&gt;
&lt;p&gt;When creating virtual machines, you should consider the operating system, storage requirements, and VM size with regard to CPU to memory ratio. Azure offers &lt;a href="https://docs.microsoft.com/en-us/azure/virtual-machines/sizes"&gt;many sizes for virtual machines&lt;/a&gt; depending on your workload. If you&amp;rsquo;re migrating a traditional n-tier application to the cloud, it&amp;rsquo;s best to start with virtual machines that match your current configuration.&lt;/p&gt;
&lt;p&gt;This article uses a simple example to deploy a static web application on a virtual machine to illustrate the process. To get started, sign in to the &lt;a href="https://portal.azure.com/"&gt;Azure Portal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Under &lt;code&gt;Azure Services&lt;/code&gt;, select &lt;code&gt;Virtual machines&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/image3.png" alt="Azure portal"&gt;&lt;/p&gt;
&lt;p&gt;Select &lt;code&gt;Create&lt;/code&gt; &amp;gt; &lt;code&gt;Virtual Machine&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/image8.png" alt="Create VM"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Create a Resource Group&lt;/p&gt;
&lt;p&gt;A Resource Group is a logical collection of virtual machines, storage, virtual networks, web apps, and databases. Users will commonly group an application&amp;rsquo;s related resources. We&amp;rsquo;ll create &lt;code&gt;myResourceGroup&lt;/code&gt; for our application.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/image6.png" alt="Resource group"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Configure the VM&lt;/p&gt;
&lt;p&gt;Next, we&amp;rsquo;ll provide details for the VM by giving it a name, &lt;code&gt;myVM&lt;/code&gt;, setting the &lt;code&gt;Region&lt;/code&gt; and &lt;code&gt;Availability options&lt;/code&gt; to &lt;code&gt;No infrastructure redundancy required&lt;/code&gt;. We&amp;rsquo;ll use an Ubuntu image and set the VM size &lt;code&gt;Standard_DS1_v2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/image2.png" alt="Configure VM"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Configure the Administrator Account&lt;/p&gt;
&lt;p&gt;Virtual machines are Infrastructure as a Service, which means you will have to perform provisioning, updates, and maintenance. You&amp;rsquo;ll need an administrator account to perform these tasks. To keep this example simple, we&amp;rsquo;ll use &lt;code&gt;Password&lt;/code&gt; as the &lt;code&gt;Authentication type&lt;/code&gt;, but in practice, you should use &lt;a href="https://en.wikipedia.org/wiki/Public_key_infrastructure"&gt;Public Key Infrastructure (PKI)&lt;/a&gt; because it is more secure than a password that can be brute-forced.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/image5.png" alt="Configure Admin"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Configure inbound ports&lt;/p&gt;
&lt;p&gt;You have to log into your virtual machine as well as allowing inbound requests to the static website. Select both &lt;code&gt;HTTP (80)&lt;/code&gt; and &lt;code&gt;SSH (22)&lt;/code&gt; then click on &lt;code&gt;Review + create&lt;/code&gt;. Note that you can also add storage by clicking on &lt;code&gt;Disks&lt;/code&gt;, but we&amp;rsquo;ll use the defaults for this example.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/image4.png" alt="Configure ingress"&gt;&lt;/p&gt;
&lt;p&gt;If your configuration is valid, you&amp;rsquo;ll see the following screen. Click &lt;code&gt;Create&lt;/code&gt; to instantiate the vm.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/image1.png" alt="Create VM"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: Enjoy your success&lt;/p&gt;
&lt;p&gt;You can go and check out your VM by clicking on &lt;code&gt;Go to resource&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/image7.png" alt="Complete deployment"&gt;&lt;/p&gt;
&lt;p&gt;Well, that seems simple and easy, but what if you had to deploy several virtual machines for the application that includes a web server, a worker to process requests, a message queuing system, and a database? What if your current system has multiple web servers and backend workers behind a load balancer? You&amp;rsquo;ll have to create, deploy, and maintain each VM because this is an IaaS.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a better way using infrastructure as code and cloud engineering methodologies to create an automated process for creating, provisioning, and maintaining virtual machines.&lt;/p&gt;
&lt;h2 id="cloud-engineering-to-the-rescue"&gt;Cloud Engineering to the Rescue!&lt;/h2&gt;
&lt;p&gt;Creating and provisioning one VM isn&amp;rsquo;t difficult, but migrating a traditional n-tier application often requires multiple virtual machines including those needed for horizontal scaling. This is where infrastructure as code excels. By using &lt;a href="https://www.pulumi.com/blog/what-exactly-is-cloud-engineering/"&gt;cloud engineering&lt;/a&gt;, we can automate &lt;a href="https://www.pulumi.com/blog/what-exactly-is-cloud-engineering#build"&gt;build&lt;/a&gt;, &lt;a href="https://www.pulumi.com/blog/what-exactly-is-cloud-engineering#deploy"&gt;deploy&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/blog/what-exactly-is-cloud-engineering#manage"&gt;manage&lt;/a&gt; process for any infrastructure or application.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at an example of deploying a web server using a virtual machine. The complete example is available in either &lt;a href="https://github.com/pulumi/examples/tree/master/azure-py-webserver"&gt;Python&lt;/a&gt; or &lt;a href="https://github.com/pulumi/examples/tree/master/azure-ts-webserver"&gt;Typescript&lt;/a&gt;. We will examine the Python code.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re using the Azure Native provider, which implements the best possible support for the Azure platform in Pulumi. It exposes the entire API surface of Azure to developers and operators. The native provider supports over 1,000 resource types, with more added as they are released by Azure.&lt;/p&gt;
&lt;p&gt;The script starts with importing the Pulumi Azure Native SDK modules and retrieving configuration parameters such as the username and password required to log into the server for provisioning. It also creates a resource group.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;base64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pulumi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;export&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_azure_native.compute&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;compute&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_azure_native.network&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_azure_native.resources&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;resources&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;resource_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResourceGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;server&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next part creates the networking resources, including a dynamically allocated public IP address for the server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VirtualNetwork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;server-network&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;resource_group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;resource_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;address_space&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddressSpaceArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;address_prefixes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;subnets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SubnetArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;address_prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.0.1.0/24&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;public_ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PublicIPAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;server-ip&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;resource_group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;resource_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;public_ip_allocation_method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IPAllocationMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DYNAMIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;network_iface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NetworkInterface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;server-nic&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;resource_group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;resource_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ip_configurations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NetworkInterfaceIPConfigurationArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;webserveripcfg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;subnet&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SubnetArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subnets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;private_ip_allocation_method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IPAllocationMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DYNAMIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;public_ip_address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PublicIPAddressArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;public_ip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here&amp;rsquo;s our web server and index page using Python&amp;rsquo;s &lt;code&gt;simpleHTTPServer&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;init_script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;echo &amp;#34;Hello, World!&amp;#34; &amp;gt; index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;nohup python -m SimpleHTTPServer 80 &amp;amp;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, here&amp;rsquo;s how we create the virtual machine. We add the VM to the resource group and associate the &lt;code&gt;network_profile&lt;/code&gt; to &lt;code&gt;network_iface&lt;/code&gt; that we defined previously. We set the &lt;code&gt;vm_size&lt;/code&gt;, set up the &lt;code&gt;os_profile&lt;/code&gt; with the hostname and username and password. In the example, we create a &lt;code&gt;storage profile&lt;/code&gt; and use Ubuntu for the image profile. The script ends by exporting the public IP address of the webserver.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;vm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VirtualMachine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;server-vm&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;resource_group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;resource_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;network_profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NetworkProfileArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;network_interfaces&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NetworkInterfaceReferenceArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;network_iface&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;hardware_profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HardwareProfileArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vm_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VirtualMachineSizeTypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STANDARD_A0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os_profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OSProfileArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;computer_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;hostname&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;admin_username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;admin_password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;custom_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;init_script&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ascii&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ascii&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;linux_configuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LinuxConfigurationArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;disable_password_authentication&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;storage_profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StorageProfileArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os_disk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OSDiskArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;create_option&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DiskCreateOptionTypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FROM_IMAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;myosdisk1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;image_reference&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ImageReferenceArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;publisher&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;canonical&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;offer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;UbuntuServer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;16.04-LTS&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;latest&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;combined_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;public_ip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resource_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;public_ip_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;combined_output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;lst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_public_ip_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;public_ip_address_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lst&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;resource_group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lst&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;public_ip&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;public_ip_addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On the face of it, this seems more complex than using the Azure Portal. The critical thing to remember is that this process is reproducible, so if you require additional virtual machines, you can add a loop to create the necessary number of VMs.&lt;/p&gt;
&lt;p&gt;But what about provisioning? Because this is code, you can write a &lt;a href="https://github.com/pulumi/examples/blob/master/aws-py-ec2-provisioners/__main__.py"&gt;provisioning script&lt;/a&gt; using Pulumi&amp;rsquo;s &lt;a href="https://www.pulumi.com/registry/packages/aws/how-to-guides/aws-py-dynamicresource/"&gt;dynamic provider&lt;/a&gt; that connects to the webserver, copies files, and executes commands. Here&amp;rsquo;s a code snippet of a dynamic provider that copies files to your VM using &lt;code&gt;scp&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CopyFileProvider implements the resource lifecycle for the CopyFile resource type below.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CopyFileProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProvisionerProvider&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ssh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;conn&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;scp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open_sftp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;scp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;src&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dest&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;scp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CopyFile is a provisioner step that can copy a file over an SSH connection.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CopyFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dynamic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ConnectionArgs&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResourceOptions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;conn contains information on how to connect to the destination, in addition to dependency information.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; src is the source of the file or directory to copy. It can be specified as relative to the current
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; working directory or as an absolute path. This cannot be specified if content is set.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;dest is required and specifies the absolute path on the target where the file will be copied to.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;CopyFileProvider&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;dep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;conn&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;src&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;dest&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;fileHash&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sha256sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;Although it&amp;rsquo;s relatively simple to create virtual machines using the Azure Portal or the Azure CLI, provisioning and maintaining them manually can be complex and error-prone. If we use code to build, deploy, and manage VMs and applications, we can automate the process making updates and maintenance repeatable processes and reduce errors. We can tear down existing VMs and replace them with updated and provisioned versions using infrastructure as code. This is a lot of information if you&amp;rsquo;re starting your Azure cloud journey, so try something fun and deploy &lt;a href="https://www.pulumi.com/blog/deploying-minecraft-on-azure/"&gt;Minecraft on Azure&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/image9.png" alt="Minecraft"&gt;&lt;/p&gt;</description><author>Sophia Parafina</author><category>azure</category><category>virtual-machines</category></item><item><title>Top 5 Things an Azure Developer Needs to Know: Introduction</title><link>https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/</link><pubDate>Mon, 02 Aug 2021 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/top-5-things-for-azure-devs-intro/index.png" /&gt;
&lt;p&gt;The Azure cloud platform includes over 200 products and cloud services. Wherever you are in your Microsoft cloud engineering journey, you should be familiar with these top 5 cloud tasks that are essential building blocks commonly used to deploy applications and infrastructure to the Azure cloud.&lt;/p&gt;
&lt;p&gt;In this series of articles, we&amp;rsquo;ll go in-depth on &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/"&gt;virtual machines&lt;/a&gt;, &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-serverless/"&gt;Azure Functions&lt;/a&gt;, &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/"&gt;static websites&lt;/a&gt;, &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/"&gt;building an Azure Kubernetes Service cluster&lt;/a&gt; and &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-apps/"&gt;deploying applications on AKS&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-devops/"&gt;DevOps with Azure App Service&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="azure---a-comprehensive-cloud-platform"&gt;Azure - a comprehensive cloud platform&lt;/h2&gt;
&lt;p&gt;With Azure, you can develop, test, deploy and manage your applications in an integrated cloud computing environment. With the Azure Portal, you can manage the cloud infrastructure for your applications. Azure gives you the choice of a portal for managing services or managing them programmatically using service APIs and templates.&lt;/p&gt;
&lt;p&gt;With over 200 services, knowing which one to use can be confusing. Deciding where to host your application is the first step. This series of articles covers the most commonly used Azure services such as virtual machines, serverless functions, static websites, Kubernetes, and Azure App Service. In addition, we&amp;rsquo;ll cover how to deploy applications using Azure DevOps.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;rsquo;ll match use cases to cloud services to help you navigate Azure.&lt;/p&gt;
&lt;h2 id="azure-virtual-machines"&gt;Azure Virtual Machines&lt;/h2&gt;
&lt;p&gt;A common cloud migration path is to use virtual machines if you have existing infrastructure or on-premise applications. It is especially true if you want complete control over the infrastructure and application environment.&lt;/p&gt;
&lt;p&gt;Azure provides Infrastructure as a Service (IaaS) for deploying your applications on either Linux or Windows VMs. IaaS includes all necessary support, such as Azure Virtual Network and storage. As with any IaaS solution, you are responsible for the installation of software, configuration, and maintenance of your application and any maintenance the VM might require, such as operating system patches.&lt;/p&gt;
&lt;p&gt;If your application doesn&amp;rsquo;t fit into a Platform as a Service (PaaS) model, consider using virtual machines to provide the fine-grained control required for your deployment.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/image3.png" alt="VM in Azure Portal"&gt;&lt;/p&gt;
&lt;h2 id="serverless"&gt;Serverless&lt;/h2&gt;
&lt;p&gt;At the opposite end of cloud infrastructure is serverless computing. Serverless eliminates the need to manage infrastructure and lets you focus on writing and deploying code. Azure automatically provisions, scales, and manages the infrastructure. You can write code that runs in response to events or on a schedule.&lt;/p&gt;
&lt;p&gt;Azure Functions lets you focus on the application&amp;rsquo;s business logic, and the code executes when called by a webhook, an HTTP or REST request, a schedule, or an event. Serverless is particularly appealing because you can use the development language of your choice, ranging from PHP, Python, Node.js, or .NET languages. Azure functions scale as needed, and consumption-based pricing means that you&amp;rsquo;re charged only when the code runs.&lt;/p&gt;
&lt;p&gt;If you don’t need a completely hosted project and only pay for what you use, choose Azure Functions triggered by web-based events, a schedule, or other Azure services.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/image2.png" alt="Serverless function"&gt;&lt;/p&gt;
&lt;h2 id="static-websites"&gt;Static websites&lt;/h2&gt;
&lt;p&gt;Static websites are quickly becoming the defacto way to publish content. Built from libraries and frameworks that don&amp;rsquo;t use server side rendering like React, Angular, or Vue, they include HTML, CSS, image assets, and Javascript in the application. Instead of serving assets from a server or servers scaled horizontally, the static assets are distributed through a Content Delivery Network (CDN). This reduces latency, resulting in faster websites and increased customer satisfaction.&lt;/p&gt;
&lt;p&gt;Azure provides two ways to deploy static websites. Azure lets you deploy a static web application with Azure App Service and the recently released Azure Static Web Apps. Azure App Service deploys websites by uploading the website to Azure storage configured to serve web content. Azure App Service automatically builds and deploys full stack web apps to Azure from a code repository, which follows the &lt;a href="https://jamstack.org/"&gt;Jamstack&lt;/a&gt; model for developing and deploying websites.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll look at both methods and discuss the pros and cons of both methods.&lt;/p&gt;
&lt;h2 id="kubernetes"&gt;Kubernetes&lt;/h2&gt;
&lt;p&gt;Kubernetes is the leading container orchestration service. Azure Kubernetes Service (AKS) is a hosted service that can deploy, scale, and manage containerized applications in a cluster. AKS fulfills many different use cases, for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you have an existing application, think n-tier applications, you can containerize the components and &amp;ldquo;lift and shift&amp;rdquo; your application to run in Kubernetes.&lt;/li&gt;
&lt;li&gt;You can deploy microservices on AKS to add horizontal scaling, load balancing, secrets management, and self-healing.&lt;/li&gt;
&lt;li&gt;Data scientists are training machine learning models on AKS using TensorFlow and Kubeflow.&lt;/li&gt;
&lt;li&gt;You can even use AKS as part of a build pipeline by pairing with a CI, such as Jenkins, to build containers for your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AKS supports many use cases by providing provisioning, scaling, and resource upgrades without requiring expertise in container orchestration. With AKS, the Kubernetes master nodes are managed by Azure, and you are only charged for the worker nodes in your cluster.&lt;/p&gt;
&lt;p&gt;We’ll do two separate deep dives into deploying AKS clusters and deploying applications in AKS in this series.&lt;/p&gt;
&lt;h3 id="deploy-aks"&gt;Deploy AKS&lt;/h3&gt;
&lt;p&gt;Azure provides many ways to deploy an AKS cluster, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/cli/azure/"&gt;Azure CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal"&gt;Azure portal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/overview"&gt;Azure Resource Manager templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure/bicep"&gt;Bicep&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/registry/packages/azure-native/how-to-guides/azure-cs-aks/"&gt;Infrastructure as Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you deploy an AKS Cluster, the worker nodes and Kubernetes master are configured with a basic configuration. You can additionally configure networking, storage, monitoring, and policies. We&amp;rsquo;ll cover configuring AKS in this series.&lt;/p&gt;
&lt;h3 id="deploy-applications"&gt;Deploy Applications&lt;/h3&gt;
&lt;p&gt;Deploying applications on AKS is equally flexible, and you can deploy using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#-strong-app-management-strong-"&gt;kubectl&lt;/a&gt; and YAML manifests&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/aks/kubernetes-helm"&gt;Helm&lt;/a&gt;, an open-source Kubernetes packaging tool&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/apps/cd/deploy-aks?view=azure-devops&amp;amp;tabs=java"&gt;Azure Pipelines&lt;/a&gt;
&lt;a href="https://www.pulumi.com/registry/packages/kubernetes/how-to-guides/configmap-rollout/"&gt;Infrastructure as Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;rsquo;ll examine these options and do a deep dive on application deployment in a follow-up article.&lt;/p&gt;
&lt;h2 id="devops-integration"&gt;DevOps integration&lt;/h2&gt;
&lt;p&gt;Before Continuous integration (CI) and Continuous Deployment (CD) became prevalent, applications were manually built, compiled, and maintained in a large codebase. CI/CD automation lets you build quickly, test, and deploy services. Both application fixes and new features are shipped quickly to your customers, and you can rapidly respond to changing customer demands. For example, if demand increases, you can quickly add resources to your application or add a serverless function that increases and decreases resources as needed.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/image1.png" alt="Devops architecture"&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re deploying applications on Azure Functions, virtual machines, AKS, or provisioning infrastructure, the build process should be automated. Azure offers a range of services such as Azure Container Registry, AKS, and Azure Cosmos DB that can integrate with popular CI/CD pipelines like Azure DevOps, Jenkins, Github, and TeamCity.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in using Azure DevOps to automate infrastructure and application delivery, stay tuned!&lt;/p&gt;
&lt;h2 id="lets-get-started"&gt;Let&amp;rsquo;s Get Started!&lt;/h2&gt;
&lt;p&gt;So here are the top 5 things essential to know as an Azure developer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;configuring and deploying virtual machines&lt;/li&gt;
&lt;li&gt;developing and deploying Azure Functions&lt;/li&gt;
&lt;li&gt;deploying static websites on Azure&lt;/li&gt;
&lt;li&gt;configuring Azure Kubernetes Service and deploying containerized applications&lt;/li&gt;
&lt;li&gt;using Azure DevOps to automate the building and deployment of infrastructure and applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First up and next in this series of articles is deploying Azure virtual machines with an application.&lt;/p&gt;</description><author>Sophia Parafina</author><category>azure</category><category>virtual-machines</category><category>serverless</category><category>aks</category><category>devops</category></item></channel></rss>