Coder Social home page Coder Social logo

pulumi-azure-workshop's Introduction

Getting Started Provisioning Infrastructure on Azure with Pulumi

Prerequisites

Installations & configurations

  • Azure Subscription
  • Azure CLI
  • Pulumi CLI
  • Your preferred language runtime
  • Your favorite IDE

This page in the documentation covers all you need to do to set up your environment.

Note

You can use the OS, language, and IDE you want for this workshop. Yet for the sake of simplicity, the samples in the tutorial won't cover every possible configuration. That should not prevent you from choosing the technologies and tools you are already familiar with to complete this workshop.

On Windows for instance, you can set up you environment using PowerShell and Windows Package Manager like this:

# Install Azure CLI using winget
winget install -e --id Microsoft.AzureCLI

# Install Pulumi CLI using winget
winget install -e --id=Pulumi.Pulumi

# Log in to Azure
# You can specify the -t option with your tenant identifier if you have multiple tenants
az login

# (Optional) List your available subscriptions and grab the identifier of the subscription you want to use
az account list --query "[].{id:id, name:name}"

# (Optional) Set the correct subscription identifier, "79400867-f366-4ec9-84ba-d1dca756beb5 in the example below
az account set -s 79400867-f366-4ec9-84ba-d1dca756beb5
az account show

# (Optional) Install the .NET SDK
winget install Microsoft.DotNet.SDK.7

Choose a backend

As Pulumi is a declarative IaC solution that uses a state to manage the cloud resources, a place to store this state is needed: the "backend". An encryption provider is also needed to encrypt that will be used. You can check this article in the documentation to see the different backends and encryption providers available.

The most convenient way of doing this workshop without worrying about configuring a backend or an encryption provider is to use Pulumi Cloud which is free for individuals. You can just create an account here (or sign in using your GitHub/GitLab account) and that's it.

If you don't want to use Pulumi Cloud, that's totally fine too, check the documentation or this article that demonstrates how to use Pulumi with Azure Blob Storage as the backend and Azure Key Vault as the encryption provider (script to configure these resources is available at the end of the article).

Pulumi fundamentals

Create a basic Pulumi project

  1. Create a new directory
mkdir infra; cd infra
  1. List the available templates
pulumi new -l

There are several azure templates (prefixed by azure) that are already configured to provision resources to Azure, but for the purpose of this workshop you will start a project from scratch to better understand how everything works.

  1. Create a new Pulumi project using an empty template (corresponding to the language of your choice)
pulumi new csharp -n PulumiAzureWorkshop -s dev -d "Workshop to learn Pulumi with Azure fundamentals"

The -s dev option is used to initialize the project with a stack named dev. A stack is an independently configurable instance of a Pulumi program. Stacks are mainly use to have a different instance for each environment (dev, staging, preprod, prod ...). or for each developer making changes to the infrastructure.

Note

You will problably be prompted to log in to Pulumi Cloud when running this command. Just use your GitHub/GitLab account or the credentials of the account you previously created. If you use a selfhosted backend, log in with the appropriate backend url before running the pulumi new command.

Open the project in your favorite IDE to browse the files.

Deploy a stack

Use pulumi up to deploy the stack

The command will first display a preview of the changes and then ask you wether or not you want to apply the changes. Select yes.

As there are currenlty no resources in the Pulumi program, only the stack itself will be created in the state, no cloud resources will be provisioned.

However, the Pulumi program contains an output "outputKey" that is displayed once the command is executed. Outputs can be used to retrieve information from a Pulumi stack like URL from provisioned cloud resources.

Handle stack configuration, stack outputs, and secrets

Configuration allows you to configure resources with different settings depending on the stack you are using. A basic use case is to have the pricing tier of a resource in the configuration to have less expensive/powerful machines in the development environmenet than in production.

  1. Add a setting named AppServiceSku with the value F1 to the the stack configuration using the command pulumi config set
Command
pulumi config set AppServiceSku F1

The new setting is displayed in the dev stack configuration file: Pulumi.dev.yaml.

  1. Modify the code to retrieve the AppServiceSku setting and put it in the ouputs (cf. doc).
Code to retrieve the configuration
var config = new Config();
var appServiceSku = config.Get("AppServiceSku");

return new Dictionary<string, object?>
{
   ["outputKey"] = "outputValue",
   ["appServiceSku"] = appServiceSku
};

Note

Run pulumi up -y (the -y option is to automatically approve the preview) to update the stack and verify your code is working as expected. This will not always be specified in the rest of the workshop.

Pulumi has built-in supports for secrets that are encrypted in the state.

  1. Add a new secret setting ExternalApiKey with the value SecretToBeKeptSecure to the configuration and to the outputs.
Command and code
pulumi config set --secret ExternalApiKey SecretToBeKeptSecure
 var config = new Config();
 var appServiceSku = config.Get("AppServiceSku");
 var externalApiKey = config.RequireSecret("ExternalApiKey");

 return new Dictionary<string, object?>
 {
    ["outputKey"] = "outputValue",
    ["appServiceSku"] = appServiceSku,
    ["apiKey"] = externalApiKey
 };

You can see that the secret is masked in the logs and that you have to use the command pulumi stack output --show-secrets to display it.

Provision Azure resources

Configure the program to use the Azure provider

Providers are the packages that allow you to provision resources in cloud providers or SaaS. Each resource provider is specific to a cloud provider/SaaS.

  1. Add the Azure Native Provider package to the project.
Command
dotnet add package Pulumi.AzureNative

Azure providers allows to to configure a default location for Azure resources so that you don't need to specify it each time you create a new resource.

  1. Configure the default location for your Azure resources.
Command
pulumi config set azure-native:location westeurope

Note

All azure locations can be listed using the following command: az account list-locations -o table

Work with Azure resources

You can explore all Azure resources in the documentation of the Azure API Native Provider to find the resources you want to create.

  1. Create a resource group named rg-workshop that will contain the resources you will create next.
Code
var resourceGroup = new ResourceGroup("workshop");   

When executing the pulumi up command, you will see that pulumi detects there is a new resource to create. Apply the update and verify the resource group is created.

Note

You don't have to specify a location for the resource group, by default it will use the location you previously specifed in the configuration.

  1. Configure the resource group to have the tag Type with the value Demo and the tag ProvisionedBy with the value Pulumi.
Code
var resourceGroup = new ResourceGroup("workshop", new()
{
    Tags =
    {
        { "Type", "Demo" },
        { "ProvisionedBy", "Pulumi" }
    }
});

When updating the stack, you will see that pulumi detects the resource group needs to be updated.

It's a good practice to follow a naming convention. Like the name rg-workshop-dev where:

  • rg is the abbreviation for the resource type "resource group"
  • workshop is the name of the application/workload
  • dev is the name of the environment/stack
  1. Update the resource group name to rg-workshop-dev for your resource group.
Code
  var stackName = Deployment.Instance.StackName;
  var resourceGroup = new ResourceGroup($"rg-workshop-{stackName}", new()
  {
      Tags =
      {
          { "Type", "Demo" },
          { "ProvisionedBy", "Pulumi" }
      }
  });

The stack name is directly retrieved from Pulumi to avoid hardcoding it.

When updating the stack, you will see that pulumi detects the resource group needs to be recreated (delete the one with the old name and create a new one with the new name). Indeed, when some input properties of a resource change, it triggers a replacement of the resource. The input properties concerned are always specified in the documentation of each resource.

Note

You have seen that depending on what you do, updating the stack will result in creating, updating, or deleting resources. Instead of executing the pulumi up command each time you want to see the result of your changes, you can use the pulumi watch command that will act as hot reload for your infrastructure code (each time you make a change and save your code file, pulumi will detect it, build the code, and deploy the changes ). You can use that for the rest of the workshop or continue using pulumi up -y if you prefer.

Sometimes it's not easy to find the correct type for the resource we want to create. You can use the pulumi ai web command to use natural-language prompts to generate Pulumi infrastructure-as-code.

  1. Use pulumi ai to provision a free Web App/App Service.
Command
pulumi ai web -l C# "Using Azure Native Provider, create a free App Service."
Code
  var appServicePlan = new AppServicePlan($"sp-workshop-{stackName}", new()
  {
      ResourceGroupName = resourceGroup.Name,
      Sku = new SkuDescriptionArgs()
      {
          Name = "F1",
      },
  });

  var appService = new WebApp($"app-workshop-{stackName}", new WebAppArgs
  {
      ResourceGroupName = resourceGroup.Name,
      ServerFarmId = appServicePlan.Id,
  });

An App Service Plan is needed to create an App Service.

Note

To access properties from other resources, you can just use variables.

  1. Update the infrastructure to use the AppServiceSku setting from the configuration instead of hard coding the SKU F1.
Code
  var appServiceSku = config.Require("AppServiceSku");
  var appServicePlan = new AppServicePlan($"sp-workshop-{stackName}", new()
  {
      ResourceGroupName = resourceGroup.Name,
      Sku = new SkuDescriptionArgs()
      {
          Name = appServiceSku,
      },
  });

Not only does the stack have outputs, but the resources themselves also have outputs, which are properties returned from the cloud provider. Since these values are only known once the resources have been provisioned, there are certain considerations to keep in mind when using them in your program (particularly when performing computations based on an output).

  1. Modify the program to make the stack only return one output, that is the URL of the app service.
Code
  var appService = new WebApp($"app-workshop-{stackName}", new WebAppArgs
  {
      ResourceGroupName = resourceGroup.Name,
      ServerFarmId = appServicePlan.Id,
  });
  return new Dictionary<string, object?>
  {
      ["AppServiceUrl"] = Output.Format($"https://{appService.DefaultHostName}")
  };

Sometimes, you need some data that are not available as properties of a resource. That's exactly what provider functions are for. For instance, the ListWebAppPublishingCredentials function can be use to retrieve the publishing credentials of an App Service

  1. Add 2 outputs to the stack PublishingUsername and PublishingUserPassword that are secrets that can be use to deploy a zip package to the App Service.
Code
  var publishingCredentials = ListWebAppPublishingCredentials.Invoke(new()  
  {  
      ResourceGroupName = resourceGroup.Name,  
      Name = appService.Name  
  });
  
  return new Dictionary<string, object?>
  {
      ["AppServiceUrl"] = Output.Format($"https://{appService.DefaultHostName}"),
      ["PublishingUsername"] = Output.CreateSecret(publishingCredentials.Apply(c => c.PublishingUserName)), 
      ["PublishingUserPassword"] = Output.CreateSecret(publishingCredentials.Apply(c => c.PublishingPassword)),
  };

As the function outputs are not marked as secrets, you have to manually do it.

Delete a stack

To delete all the resources in the stack you can run the command pulumi destroy.

To delete the stack itself with its configuration and deployment history you can run the command pulumi stack rm dev.

pulumi-azure-workshop's People

Contributors

techwatching avatar

Stargazers

Benedikt Brauneck avatar Xavier Mignot avatar  avatar Christophe Crémon avatar Amine Al Kaderi avatar Ludovic DELAVOIS avatar  avatar Anwar C avatar Jean-Benoit Paux avatar Pete Cook avatar Laurent Kempé avatar

Watchers

 avatar

Forkers

anwarchk

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.