Skip to content

Infrastructure as Code in ConnectSoft Microservice Template

Purpose & Overview

Infrastructure as Code (IaC) in the ConnectSoft Microservice Template provides a comprehensive framework for managing and provisioning cloud infrastructure using code instead of manual processes. The template embraces multiple IaC tools and patterns to enable automated, repeatable, version-controlled infrastructure deployments across cloud platforms and container orchestration systems.

Infrastructure as Code in the template provides:

  • Programmatic Infrastructure: Define infrastructure using familiar programming languages (C#, TypeScript, Python)
  • Multi-Cloud Support: Provision resources across Azure, AWS, and Kubernetes
  • Version Control: Infrastructure code versioned alongside application code
  • Reproducibility: Consistent infrastructure deployments across environments
  • Automation: Automated infrastructure provisioning through CI/CD pipelines
  • State Management: Reliable state tracking and management
  • Modularity: Reusable infrastructure components and stacks
  • Testing: Infrastructure code tested before deployment

Infrastructure as Code Philosophy

Infrastructure should be treated as code—defined, versioned, tested, and deployed just like application code. The ConnectSoft template supports multiple IaC tools (Pulumi, Terraform, Helm, Kubernetes YAMLs) to provide flexibility while maintaining consistency, enabling teams to manage infrastructure changes with the same rigor as application changes. Infrastructure definitions are the single source of truth for cloud resources.

Architecture Overview

IaC Tools and Layers

Infrastructure as Code Stack
├── Pulumi (Primary)
│   ├── Azure Resources
│   ├── AWS Resources
│   └── Kubernetes Resources
├── Terraform (Optional)
│   ├── Multi-Cloud Resources
│   └── Provider Abstraction
├── Helm (Kubernetes)
│   ├── Application Charts
│   └── Dependency Management
└── Kubernetes YAMLs
    ├── Native Resources
    └── Declarative Manifests

Infrastructure Provisioning Flow

Infrastructure Code (Git Repository)
CI/CD Pipeline
    ├── Validation
    ├── Testing
    └── Preview
IaC Tool (Pulumi/Terraform)
    ├── State Management
    ├── Resource Provisioning
    └── Dependency Resolution
Cloud Provider (Azure/AWS/Kubernetes)
    ├── Resource Creation
    ├── Configuration
    └── Validation
Deployed Infrastructure
    ├── Application Services
    ├── Databases
    ├── Storage
    └── Networking

Clean Architecture Integration

Infrastructure Layer
├── InfrastructureModel Project (Pulumi)
│   ├── Azure Infrastructure Stack
│   ├── AWS Infrastructure Stack
│   └── Kubernetes Infrastructure Stack
├── Terraform Modules (Optional)
│   └── Reusable Infrastructure Components
└── Helm Charts
    └── Kubernetes Application Packages

Supported IaC Tools

Pulumi (Primary)

Purpose: Modern Infrastructure as Code tool using general-purpose programming languages.

Advantages: - Language Choice: Use C#, TypeScript, Python, or Go - Programming Logic: Loops, conditionals, functions, abstractions - Multi-Cloud: Unified API across Azure, AWS, GCP, Kubernetes - Type Safety: Compile-time checking and IntelliSense - State Management: Built-in state management with Pulumi Cloud - Testing: Unit and integration testing support

Use Cases: - Azure resource provisioning - AWS resource provisioning - Kubernetes resource management - Multi-cloud deployments - Complex infrastructure with programming logic

Example (Creating Azure App Service):

using Pulumi;
using AzureNative = Pulumi.AzureNative;

public class AzureInfrastructureStack : Stack
{
    public AzureInfrastructureStack()
    {
        var config = new Config();
        var resourceGroupName = config.Require("resourceGroupName");
        var location = config.Get("location") ?? "eastus";

        var webApp = new AzureNative.Web.WebApp("webApp", new()
        {
            ResourceGroupName = resourceGroupName,
            Location = location,
            Name = config.Get("appName") ?? "myWebApp",
            ServerFarmId = config.Require("appServicePlanId"),
            SiteConfig = new AzureNative.Web.Inputs.SiteConfigArgs
            {
                NetFrameworkVersion = "v9.0",
                AlwaysOn = true,
                HttpsOnly = true
            }
        });

        this.WebAppUrl = webApp.DefaultHostName.Apply(host => 
            $"https://{host}");
    }

    [Output]
    public Output<string> WebAppUrl { get; set; }
}

Terraform (Optional)

Purpose: Declarative Infrastructure as Code tool using HCL (HashiCorp Configuration Language).

Advantages: - Declarative Syntax: Simple, readable configuration language - Multi-Cloud: Extensive provider ecosystem - State Management: Built-in state tracking - Maturity: Widely adopted, extensive documentation - Modules: Reusable infrastructure components

Use Cases: - Multi-cloud deployments - Legacy infrastructure migration - Provider-specific resources - Team familiarity with Terraform

Example (Creating Azure Resource Group):

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "main" {
  name     = "rg-microservice-template"
  location = "eastus"

  tags = {
    Environment = "Production"
    Project     = "ConnectSoft.MicroserviceTemplate"
  }
}

Helm (Kubernetes)

Purpose: Package manager for Kubernetes applications.

Advantages: - Templating: Dynamic Kubernetes manifests - Reusability: Shareable charts - Versioning: Chart versioning and dependencies - Rollbacks: Easy rollback to previous versions - Dependencies: Manage chart dependencies

Use Cases: - Kubernetes application deployment - Multi-environment deployments - Chart distribution and sharing - Application lifecycle management

Example (Helm Chart Structure):

# Chart.yaml
apiVersion: v2
name: microservice-template
description: ConnectSoft Microservice Template Helm Chart
version: 1.0.0
appVersion: "1.0.0"

# values.yaml
replicaCount: 3
image:
  repository: connectsoft/microservice-template
  tag: "1.0.0"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

Kubernetes YAMLs

Purpose: Declarative Kubernetes resource definitions.

Advantages: - Native: Direct Kubernetes API representation - Simple: No abstraction layers - Flexible: Full Kubernetes API support - GitOps: Easy integration with GitOps tools

Use Cases: - Simple Kubernetes deployments - Custom resource definitions - GitOps workflows - Educational purposes

Example (Deployment YAML):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: microservice-template
spec:
  replicas: 3
  selector:
    matchLabels:
      app: microservice-template
  template:
    metadata:
      labels:
        app: microservice-template
    spec:
      containers:
      - name: app
        image: connectsoft/microservice-template:1.0.0
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
          requests:
            cpu: 250m
            memory: 256Mi

Pulumi Implementation

Project Structure

The ConnectSoft.MicroserviceTemplate.InfrastructureModel project provides Pulumi-based infrastructure:

InfrastructureModel/
├── Program.cs                      # Pulumi program entry point
├── AzureInfrastructureStack.cs     # Azure infrastructure stack
├── AWSInfrastructureStack.cs       # AWS infrastructure stack (optional)
├── KubernetesInfrastructureStack.cs # Kubernetes infrastructure stack (optional)
├── Pulumi.yaml                     # Pulumi project configuration
├── Pulumi.dev.yaml                 # Development stack configuration
├── Pulumi.staging.yaml             # Staging stack configuration
├── Pulumi.prod.yaml                # Production stack configuration
└── *.csproj                        # Project file with Pulumi dependencies

Program.cs Entry Point

namespace ConnectSoft.MicroserviceTemplate.InfrastructureModel
{
    using System.Threading.Tasks;

    /// <summary>
    /// Pulumi program entry point for ConnectSoft.MicroserviceTemplate infrastructure.
    /// </summary>
    public static class Program
    {
        /// <summary>
        /// Main entry point for Pulumi infrastructure deployment.
        /// </summary>
        /// <returns>Returns 0 on success, non-zero on failure.</returns>
        public static Task<int> Main()
        {
            return Pulumi.Deployment.RunAsync<AzureInfrastructureStack>();
        }
    }
}

Azure Infrastructure Stack

using Pulumi;
using AzureNative = Pulumi.AzureNative;

/// <summary>
/// Azure infrastructure stack for ConnectSoft.MicroserviceTemplate.
/// </summary>
public class AzureInfrastructureStack : Stack
{
    /// <summary>
    /// Initializes a new instance of the AzureInfrastructureStack class.
    /// </summary>
    public AzureInfrastructureStack()
    {
        var config = new Config();

        // Reference shared infrastructure stack
        var infraStackReference = new StackReference(
            config.Require("infraStackReference"));

        var resourceGroupName = infraStackReference.GetOutput("resourceGroupName")
            .Apply(rg => rg.ToString());
        var location = infraStackReference.GetOutput("location")
            .Apply(loc => loc.ToString());
        var appServicePlanId = infraStackReference.GetOutput("appServicePlanId")
            .Apply(asp => asp.ToString());

        // Create Azure App Service
        var webApp = new AzureNative.Web.WebApp("webApp", new()
        {
            ResourceGroupName = resourceGroupName,
            Location = location,
            Name = config.Get("appName") ?? "microservice-template",
            ServerFarmId = appServicePlanId,
            SiteConfig = new AzureNative.Web.Inputs.SiteConfigArgs
            {
                NetFrameworkVersion = "v9.0",
                AlwaysOn = true,
                Http20Enabled = true,
                HttpsOnly = true,
                AppSettings = new[]
                {
                    new AzureNative.Web.Inputs.NameValuePairArgs
                    {
                        Name = "ASPNETCORE_ENVIRONMENT",
                        Value = config.Get("environment") ?? "Production"
                    }
                }
            }
        });

        // Create Application Insights
        var appInsights = new AzureNative.Insights.Component("appInsights", new()
        {
            ResourceGroupName = resourceGroupName,
            Location = location,
            ApplicationType = "web",
            Kind = "web"
        });

        // Link Application Insights to Web App
        var webAppSettings = new AzureNative.Web.WebAppApplicationSettings(
            "webAppSettings", new()
        {
            ResourceGroupName = resourceGroupName,
            Name = webApp.Name,
            Properties = new Dictionary<string, string>
            {
                ["APPINSIGHTS_INSTRUMENTATIONKEY"] = 
                    appInsights.InstrumentationKey.Apply(key => key.ToString())
            }
        });

        // Export outputs
        this.WebAppUrl = webApp.DefaultHostName.Apply(host => 
            $"https://{host}");
        this.AppInsightsInstrumentationKey = appInsights.InstrumentationKey;
    }

    [Output]
    public Output<string> WebAppUrl { get; set; }

    [Output]
    public Output<string> AppInsightsInstrumentationKey { get; set; }
}

Stack References

Stack references enable infrastructure stacks to reference outputs from other stacks:

// Reference shared infrastructure stack
var infraStackReference = new StackReference(
    config.Require("infraStackReference"));

// Get outputs from shared stack
var resourceGroupName = infraStackReference.GetOutput("resourceGroupName")
    .Apply(rg => rg.ToString());
var location = infraStackReference.GetOutput("location")
    .Apply(loc => loc.ToString());

Stack Reference Format: {organization}/{project}/{stack}

Example Configuration:

# Pulumi.dev.yaml
config:
  ConnectSoft.MicroserviceTemplate.InfrastructureModel:infraStackReference: 
    "myorg/shared-infrastructure/dev"

Pulumi Configuration

Pulumi.yaml (Project Configuration):

name: ConnectSoft.MicroserviceTemplate.InfrastructureModel
description: Infrastructure as code for ConnectSoft.MicroserviceTemplate
runtime: dotnet
config:
  pulumi:tags:
    value:
      pulumi:template: azure-csharp
      project: microservice-template

Stack Configuration (Pulumi.dev.yaml):

config:
  ConnectSoft.MicroserviceTemplate.InfrastructureModel:environment: "Development"
  ConnectSoft.MicroserviceTemplate.InfrastructureModel:appName: "microservice-template-dev"
  ConnectSoft.MicroserviceTemplate.InfrastructureModel:infraStackReference: 
    "myorg/shared-infrastructure/dev"

Setting Configuration:

# Set string value
pulumi config set environment Development

# Set secret value (encrypted)
pulumi config set --secret sqlAdminPassword "MyPassword123!"

# Set boolean value
pulumi config set enableHttps true

Infrastructure Resources

Azure Resources

App Service:

var webApp = new AzureNative.Web.WebApp("webApp", new()
{
    ResourceGroupName = resourceGroupName,
    Location = location,
    Name = appName,
    ServerFarmId = appServicePlanId,
    SiteConfig = new AzureNative.Web.Inputs.SiteConfigArgs
    {
        NetFrameworkVersion = "v9.0",
        AlwaysOn = true,
        HttpsOnly = true
    }
});

Application Insights:

var appInsights = new AzureNative.Insights.Component("appInsights", new()
{
    ResourceGroupName = resourceGroupName,
    Location = location,
    ApplicationType = "web",
    Kind = "web"
});

Azure SQL Database:

var sqlServer = new AzureNative.Sql.Server("sqlServer", new()
{
    ResourceGroupName = resourceGroupName,
    Location = location,
    AdministratorLogin = config.RequireSecret("sqlAdminLogin"),
    AdministratorLoginPassword = config.RequireSecret("sqlAdminPassword"),
    Version = "12.0"
});

var sqlDatabase = new AzureNative.Sql.Database("sqlDatabase", new()
{
    ResourceGroupName = resourceGroupName,
    ServerName = sqlServer.Name,
    Location = location,
    Sku = new AzureNative.Sql.Inputs.SkuArgs
    {
        Name = "Basic",
        Tier = "Basic"
    }
});

Azure Cosmos DB (MongoDB):

var cosmosAccount = new AzureNative.DocumentDB.DatabaseAccount("cosmosAccount", new()
{
    ResourceGroupName = resourceGroupName,
    Location = location,
    Kind = "MongoDB",
    ConsistencyPolicy = new AzureNative.DocumentDB.Inputs.ConsistencyPolicyArgs
    {
        DefaultConsistencyLevel = "Session"
    }
});

Azure Service Bus:

var serviceBusNamespace = new AzureNative.ServiceBus.Namespace("serviceBusNamespace", new()
{
    ResourceGroupName = resourceGroupName,
    Location = location,
    Sku = new AzureNative.ServiceBus.Inputs.SBSkuArgs
    {
        Name = "Standard",
        Tier = "Standard"
    }
});

Azure Key Vault:

var keyVault = new AzureNative.KeyVault.Vault("keyVault", new()
{
    ResourceGroupName = resourceGroupName,
    Location = location,
    Properties = new AzureNative.KeyVault.Inputs.VaultPropertiesArgs
    {
        TenantId = config.Require("tenantId"),
        Sku = new AzureNative.KeyVault.Inputs.SkuArgs
        {
            Family = "A",
            Name = "standard"
        }
    }
});

AWS Resources (Optional)

S3 Bucket:

using Pulumi.Aws;

var bucket = new S3.Bucket("myBucket", new()
{
    BucketName = "microservice-template-storage",
    Versioning = new S3.Inputs.BucketVersioningArgs
    {
        Enabled = true
    }
});

EC2 Instance:

var instance = new Ec2.Instance("webServer", new()
{
    Ami = "ami-0c55b159cbfafe1f0",
    InstanceType = "t2.micro",
    Tags = new Dictionary<string, string>
    {
        ["Name"] = "microservice-template-server"
    }
});

Kubernetes Resources

Deployment:

using Pulumi.Kubernetes.Apps.V1;

var deployment = new Deployment("appDeployment", new()
{
    Metadata = new Pulumi.Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
    {
        Name = "microservice-template"
    },
    Spec = new DeploymentSpecArgs
    {
        Replicas = 3,
        Selector = new LabelSelectorArgs
        {
            MatchLabels = new Dictionary<string, string>
            {
                ["app"] = "microservice-template"
            }
        },
        Template = new PodTemplateSpecArgs
        {
            Metadata = new Pulumi.Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
            {
                Labels = new Dictionary<string, string>
                {
                    ["app"] = "microservice-template"
                }
            },
            Spec = new PodSpecArgs
            {
                Containers = new[]
                {
                    new ContainerArgs
                    {
                        Name = "app",
                        Image = "connectsoft/microservice-template:1.0.0",
                        Ports = new[]
                        {
                            new ContainerPortArgs
                            {
                                ContainerPortValue = 80
                            }
                        }
                    }
                }
            }
        }
    }
});

State Management

Pulumi State

State Storage Options:

  1. Pulumi Cloud (Default):
  2. Managed state storage
  3. Automatic backups
  4. Team collaboration
  5. Stack history

  6. Self-Hosted Backend:

  7. Azure Blob Storage
  8. AWS S3
  9. Google Cloud Storage
  10. Local file system (development only)

Configure State Backend:

# Azure Blob Storage
pulumi login --cloud-url azblob://pulumi-state

# AWS S3
pulumi login --cloud-url s3://pulumi-state-bucket

# Local file system (development only)
pulumi login --local

State File Structure

State Contains: - Resource definitions and current state - Stack outputs - Configuration values (encrypted secrets) - Resource dependencies - Stack history

State Best Practices: - Never commit state files to source control - Use remote state storage in production - Enable state locking to prevent concurrent modifications - Regularly backup state files - Use separate state backends per environment

Deployment

Local Deployment

Prerequisites:

# Install Pulumi CLI
# Windows
choco install pulumi

# macOS
brew install pulumi

# Linux
curl -fsSL https://get.pulumi.com | sh

# Login to Pulumi Cloud
pulumi login

# Configure Azure credentials
az login

Deploy Stack:

# Select stack
pulumi stack select dev

# Preview changes (dry-run)
pulumi preview

# Deploy infrastructure
pulumi up

# Destroy infrastructure
pulumi destroy

CI/CD Integration

Azure DevOps Pipeline:

# azure-pipelines-infrastructure.yml
trigger:
  branches:
    include:
    - master
  paths:
    include:
    - ConnectSoft.MicroserviceTemplate.InfrastructureModel/**

steps:
- task: UseDotNet@2
  displayName: 'Install .NET SDK'
  inputs:
    version: '9.x'

- task: PulumiCLI@1
  displayName: 'Install Pulumi'
  inputs:
    versionSpec: 'latest'

- task: PulumiCLI@1
  displayName: 'Pulumi Preview'
  inputs:
    command: 'preview'
    stack: 'dev'
    cwd: 'ConnectSoft.MicroserviceTemplate.InfrastructureModel'

- task: PulumiCLI@1
  displayName: 'Pulumi Up'
  inputs:
    command: 'up'
    stack: 'dev'
    cwd: 'ConnectSoft.MicroserviceTemplate.InfrastructureModel'
    args: '--yes'
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))

GitHub Actions:

name: Infrastructure Deployment

on:
  push:
    branches: [master]
    paths:
      - 'ConnectSoft.MicroserviceTemplate.InfrastructureModel/**'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - uses: actions/setup-dotnet@v3
      with:
        dotnet-version: '9.x'

    - uses: pulumi/actions@v3
      with:
        pulumi-version: latest

    - name: Configure Azure Credentials
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: Deploy Infrastructure
      run: |
        cd ConnectSoft.MicroserviceTemplate.InfrastructureModel
        pulumi stack select dev
        pulumi up --yes
      env:
        PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}

Security and Compliance

Secrets Management

Pulumi Secrets:

// Store secrets securely
var password = config.RequireSecret("sqlAdminPassword");

// Secrets are encrypted in state
var sqlServer = new AzureNative.Sql.Server("sqlServer", new()
{
    AdministratorLoginPassword = password
});

Azure Key Vault Integration:

var keyVault = new AzureNative.KeyVault.Vault("keyVault", new()
{
    // ... configuration ...
});

// Store secrets in Key Vault
var secret = new AzureNative.KeyVault.Secret("connectionStringSecret", new()
{
    ResourceGroupName = resourceGroupName,
    VaultName = keyVault.Name,
    Properties = new AzureNative.KeyVault.Inputs.SecretPropertiesArgs
    {
        Value = connectionString
    }
});

Policy as Code

Pulumi Policy Packs:

// Policy to enforce resource tagging
using Pulumi.Policy;

Policy.Enforce(new PolicyConfig
{
    EnforcementLevel = EnforcementLevel.Mandatory,
    Rules = new[]
    {
        new PolicyRule
        {
            Name = "require-tags",
            Description = "All resources must have required tags",
            ValidateResource = (args, reportViolation) =>
            {
                if (!args.Resource.Tags?.ContainsKey("Environment"))
                {
                    reportViolation("Missing 'Environment' tag");
                }
                if (!args.Resource.Tags?.ContainsKey("Project"))
                {
                    reportViolation("Missing 'Project' tag");
                }
            }
        }
    }
});

RBAC and Access Control

Azure RBAC:

var roleAssignment = new AzureNative.Authorization.RoleAssignment("roleAssignment", new()
{
    PrincipalId = config.Require("principalId"),
    PrincipalType = "ServicePrincipal",
    RoleDefinitionId = "/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/{roleDefinitionId}",
    Scope = resourceGroup.Id
});

Testing

Unit Testing

Pulumi Testing:

using Pulumi.Testing;

[TestMethod]
public async Task Stack_ShouldCreateWebApp()
{
    // Arrange
    var mocks = new Mocks();
    var stack = new AzureInfrastructureStack();

    // Act
    var resources = await Testing.RunAsync(mocks, stack);

    // Assert
    var webApp = resources.OfType<AzureNative.Web.WebApp>().FirstOrDefault();
    Assert.IsNotNull(webApp);
    Assert.AreEqual("microservice-template", webApp.Name);
}

Integration Testing

Test Stack Deployment:

# Create test stack
pulumi stack init test

# Deploy test stack
pulumi up --yes

# Verify resources
az webapp list --query "[?name=='microservice-template-test']"

# Clean up
pulumi destroy --yes
pulumi stack rm test --yes

Static Analysis

Terraform Validation:

# Validate Terraform configuration
terraform validate

# Format Terraform files
terraform fmt -check

# Check for security issues
terraform plan | terraform-compliance -f policies/

Best Practices

Do's

  1. Version Control Infrastructure Code

    # ✅ GOOD - Infrastructure code in Git
    git add InfrastructureModel/
    git commit -m "Add Azure App Service infrastructure"
    

  2. Use Stack References for Shared Resources

    // ✅ GOOD - Reference shared infrastructure
    var infraStackReference = new StackReference(
        config.Require("infraStackReference"));
    

  3. Use Secrets for Sensitive Values

    // ✅ GOOD - Encrypted secrets
    var password = config.RequireSecret("sqlAdminPassword");
    

  4. Export Important Outputs

    // ✅ GOOD - Export outputs for use in other stacks
    [Output]
    public Output<string> WebAppUrl { get; set; }
    

  5. Use Environment-Specific Configuration

    # ✅ GOOD - Separate config files per environment
    # Pulumi.dev.yaml
    # Pulumi.staging.yaml
    # Pulumi.prod.yaml
    

  6. Preview Before Deploying

    # ✅ GOOD - Always preview changes
    pulumi preview
    pulumi up
    

  7. Modularize Infrastructure

    // ✅ GOOD - Create reusable components
    public class AppServiceComponent
    {
        public AppServiceComponent(/* parameters */)
        {
            // Create App Service with standard configuration
        }
    }
    

Don'ts

  1. Don't Commit Secrets

    # ❌ BAD - Secrets in plain text
    sqlAdminPassword: "MyPassword123!"
    
    # ✅ GOOD - Use secret configuration
    pulumi config set --secret sqlAdminPassword "MyPassword123!"
    

  2. Don't Hardcode Values

    // ❌ BAD - Hardcoded values
    var location = "eastus";
    
    // ✅ GOOD - Configuration-driven
    var location = config.Get("location") ?? "eastus";
    

  3. Don't Skip State Management

    # ❌ BAD - No state management
    # State stored locally, not backed up
    
    # ✅ GOOD - Use Pulumi Cloud or self-hosted backend
    pulumi login
    

  4. Don't Deploy Without Testing

    # ❌ BAD - Deploy without preview
    pulumi up --yes
    
    # ✅ GOOD - Preview first
    pulumi preview
    pulumi up --yes
    

  5. Don't Mix Manual and Automated Changes

    # ❌ BAD - Manual changes to infrastructure
    # Manual changes can cause drift
    
    # ✅ GOOD - All changes through IaC
    # IaC is the single source of truth
    

Troubleshooting

Issue: Stack Reference Not Found

Symptoms: StackReference fails with "stack not found" error.

Solutions: - Verify stack reference format: org/project/stack - Ensure referenced stack exists: pulumi stack ls - Check stack permissions (if using Pulumi Cloud) - Verify stack reference in configuration

Issue: Resource Creation Fails

Symptoms: pulumi up fails with resource creation errors.

Solutions: - Check Azure credentials: az account show - Verify resource quotas and limits - Check resource name availability (Azure requires unique names) - Review Azure service health status - Check resource provider registration: az provider list

Issue: State Locked

Symptoms: "stack is currently locked" error.

Solutions: - Wait for previous operation to complete - Force unlock (if safe): pulumi cancel - Check for stuck operations in Pulumi Cloud - Verify no other processes are using the stack

Issue: Configuration Not Found

Symptoms: Config.Require() throws exception.

Solutions: - Check stack configuration: pulumi config - Set missing configuration: pulumi config set key value - Verify configuration key name matches exactly - Check stack context: pulumi stack

Summary

Infrastructure as Code in the ConnectSoft Microservice Template provides:

  • Multiple Tools: Pulumi, Terraform, Helm, Kubernetes YAMLs
  • Multi-Cloud Support: Azure, AWS, Kubernetes
  • Programmatic IaC: Use familiar programming languages
  • State Management: Reliable state tracking and backup
  • Stack Management: Isolated infrastructure per environment
  • Stack References: Reusable shared infrastructure
  • Security: Secrets management and policy enforcement
  • Testing: Unit and integration testing support
  • CI/CD Integration: Automated infrastructure deployment

By implementing Infrastructure as Code, teams can:

  • Automate Provisioning: Reduce manual effort and human error
  • Ensure Consistency: Same infrastructure across environments
  • Version Control: Track infrastructure changes in Git
  • Enable Collaboration: Multiple team members can work safely
  • Maintain Traceability: Complete history of infrastructure changes
  • Reduce Errors: Infrastructure validated before deployment
  • Enable Rollbacks: Revert infrastructure changes when needed
  • Scale Infrastructure: Easily provision resources at scale

Infrastructure as Code is the foundation for reliable, repeatable, and scalable infrastructure deployments, enabling teams to manage cloud resources with the same rigor and automation as application code.