This is a submission for the Pulumi Deploy and Document Challenge: Fast Static Website Deployment
What I Built
A sample Pulumi project that demonstrates how to deploy a Blazor WebAssembly using Azure Static Web Apps. The project is designed to be simple and easy to understand, making it a great starting point for anyone looking to learn about deploying static web apps with Pulumi.
Live Demo Link
It may not be available in the future, so I uploaded a recording here
Project Repo
Fast Static Web App deployment using Pulumi
This repository contains a sample Pulumi project that demonstrates how to deploy a static web app using Azure Static Web Apps. The project is designed to be simple and easy to understand, making it a great starting point for anyone looking to learn about deploying static web apps with Pulumi.
Architecture Overview
The diagram shows a complete deployment pipeline with the following components:
- GitHub Repository: Source code is stored in GitHub for version control
- Azure Pipelines: Handles CI/CD processes
- Azure Identity/Service Principal: Manages access to Azure resources and assigned to Azure Pipelines
- Azure Static Web App: Hosting platform for the Blazor application
- Azure Key Vault: Securely stores secrets including the Static Web App deployment token
- Pulumi: Infrastructure as Code (IaC) tool used to manage the deployment of the Azure resources
Worklow
- Developers write code and push it to GitHub
- GitHub triggers Azure Pipelines…
My Journey
As a .NET developer, I recently began using Pulumi to provision infrastructure. Although I'm new to Pulumi, I didn’t face many significant challenges thanks to my development background. The Pulumi SDK for C# made the transition easier, as it allows developers to use familiar language features while performing tasks typically handled by DevOps or platform engineers.
Setting up the stack
I successfully set up a Pulumi stack and ran it locally without issues. The execution logs are clear and informative, which made it easy to understand what was happening during deployments. When I encountered issues, I was able to debug my Pulumi project using the launch.json
configuration in Visual Studio Code—this was a big help in quickly identifying and fixing problems.
"configurations": [
{
"type": "pulumi",
"request": "launch",
"name": "pulumi preview",
"command": "preview",
"workDir": "${workspaceFolder}/infra/pulumi/Blazor.Infra.Pulumi"
}
]
CI/CD Pipeline Integration
One challenge I faced was integrating Pulumi into the CI/CD pipeline. The Pulumi CLI did not work properly with Azure Workload Identity, which caused deployment failures. I resolved this by switching to the Pulumi task available in the Azure DevOps Marketplace, which worked seamlessly.
- task: Pulumi@1
inputs:
azureSubscription: $(ado.azureServiceConnection)
command: up
cwd: infra/pulumi/Blazor.Infra.Pulumi
stack: $(environment)
args: "--yes"
Managing State
Pulumi’s approach to storing infrastructure state is helpful for visualizing changes over time. It allows me to track the history of deployed resources and view their outputs in a centralized and structured manner.
Using Pulumi
In this project, I leveraged Pulumi with C# to create and manage Azure infrastructure as code (IaC) for my Blazor application. As a .NET developer, Pulumi's C# SDK offered a familiar programming model while allowing me to define cloud resources with strongly-typed constructs.
Stack Architecture
My StaticWebAppStack.cs creates several Azure resources:
- Resource Group - Container for all project resources
- Static Web App - Hosting platform for my Blazor application
- Key Vault - Secure storage for deployment tokens
- Key Vault Secret - Storing the Static Web App deployment token
Benefits of Using Pulumi
1. Native Language Experience:
Using C# meant I could apply my existing .NET skills:
var staticWebApp = new Az.Web.StaticSite(staticWebAppName, new()
{
ResourceGroupName = resourceGroup.Name,
Location = resourceGroup.Location,
Sku = new Az.Web.Inputs.SkuDescriptionArgs
{
Tier = "Free",
Name = "Free"
},
// ...
});
2. Secret Management:
I could programmatically retrieve and securely store tokens:
var deploymentToken = staticWebAppSecrets.Apply(secrets =>
{
return secrets.Properties.Where(x => x.Key == "apiKey").FirstOrDefault().Value;
});
var staticWebAppTokenSecret = new Az.KeyVault.Secret("staticWebAppTokenSecret", new()
{
ResourceGroupName = resourceGroup.Name,
VaultName = keyVault.Name,
SecretName = "swaDeploymentToken",
Properties = new Az.KeyVault.Inputs.SecretPropertiesArgs
{
Value = deploymentToken,
ContentType = "text/plain",
}
});
3. Using Stack Outputs for CI/CD integration:
I defined outputs to expose important information for CI/CD:
[Output("keyVaultName")]
public Output<string> KeyVaultName { get; private set; }
Using Pulumi's outputs for next deployment stage
- script: |
pulumi stack select $(environment)
KEYVAULT_NAME=$(pulumi stack output keyVaultName)
echo "##vso[task.setvariable variable=keyVaultName;isOutput=true]$KEYVAULT_NAME"
displayName: "Set stack outputs as variables"
workingDirectory: infra/pulumi/Blazor.Infra.Pulumi
name: "setOutputs"
4. Stack for Environment-based configuration:
Using stack references for environment-specific configurations:
var stackName = Deployment.Instance.StackName;
var projectName = Deployment.Instance.ProjectName;
var fullStackName = $"{projectName}-{stackName}";
5. Integration with CI/CD:
Easily integrating with Azure Pipelines using the Pulumi task:
- task: Pulumi@1
inputs:
azureSubscription: $(ado.azureServiceConnection)
command: up
cwd: infra/pulumi/Blazor.Infra.Pulumi
stack: $(environment)
args: "--yes"
Conclusion
Pulumi's approach to IaC using familiar programming languages significantly improved my development workflow. Instead of treating infrastructure as a separate concern with its own syntax and tools, I could apply the same software engineering principles I use in application development to my infrastructure code.