Pulumi — Infrastructure as Code bằng C# trên .NET 10: Quản lý Cloud như viết phần mềm

Posted on: 4/21/2026 8:21:27 AM

Tại sao Infrastructure as Code lại quan trọng?

Trong kỷ nguyên cloud-native, việc quản lý hạ tầng bằng tay qua console là một anti-pattern nghiêm trọng. Một lần click chuột sai trên AWS Console có thể xóa sạch production database. Một thay đổi security group không được track có thể mở cổng cho attacker. Infrastructure as Code (IaC) giải quyết triệt để vấn đề này: mọi thay đổi hạ tầng đều được version control, review, và reproducible.

Tuy nhiên, phần lớn .NET developer vẫn đang phải học thêm HCL (HashiCorp Configuration Language) cho Terraform hoặc Bicep DSL cho Azure — những ngôn ngữ chuyên biệt xa lạ với ecosystem C# quen thuộc. Pulumi thay đổi cuộc chơi: bạn viết infrastructure bằng chính C#, dùng Visual Studio/Rider với IntelliSense, NuGet packages, xUnit tests — mọi thứ bạn đã biết.

150+ Cloud Providers hỗ trợ
76% Thị phần IaC thuộc Terraform
45% Tăng trưởng YoY của Pulumi
$2.1B Quy mô thị trường IaC 2026

Pulumi là gì? Kiến trúc tổng quan

Pulumi là một nền tảng Infrastructure as Code cho phép bạn định nghĩa, deploy và quản lý cloud infrastructure bằng các ngôn ngữ lập trình quen thuộc — TypeScript, Python, Go, Java, và đặc biệt là C# / .NET. Khác với Terraform (dùng HCL) hay Bicep (DSL riêng cho Azure), Pulumi tận dụng toàn bộ sức mạnh của general-purpose programming language.

graph TB
    subgraph Developer["Developer Workspace"]
        A["C# Program
.NET 10 Project"] --> B["Pulumi SDK
NuGet Packages"] end subgraph Engine["Pulumi Engine"] B --> C["Language Host
dotnet runtime"] C --> D["Deployment Engine
Resource Graph"] D --> E["State Backend
Pulumi Cloud / S3 / Azure Blob"] end subgraph Providers["Cloud Providers"] D --> F["AWS Provider"] D --> G["Azure Native"] D --> H["Kubernetes"] D --> I["Cloudflare / GCP / ..."] end style A fill:#e94560,stroke:#fff,color:#fff style D fill:#2c3e50,stroke:#fff,color:#fff style E fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style F fill:#ff9800,stroke:#fff,color:#fff style G fill:#0078d4,stroke:#fff,color:#fff style H fill:#326ce5,stroke:#fff,color:#fff style I fill:#f48120,stroke:#fff,color:#fff
Kiến trúc tổng quan Pulumi — từ C# code đến cloud resources

Điểm mấu chốt

Pulumi không generate Terraform hay ARM template bên dưới. Nó có engine riêng để quản lý resource graph, state, và giao tiếp trực tiếp với cloud provider APIs. Điều này nghĩa là bạn có full control, không bị giới hạn bởi DSL trung gian.

Pulumi vs Terraform vs Bicep: So sánh chi tiết

Đây là câu hỏi mà mọi team DevOps đều phải đối mặt khi chọn IaC tool. Mỗi công cụ có strengths riêng, và lựa chọn phụ thuộc vào context của team.

Tiêu chí Pulumi Terraform Bicep
Ngôn ngữ C#, TypeScript, Python, Go, Java HCL (DSL riêng) Bicep DSL (Azure-only)
Multi-cloud ✅ AWS, Azure, GCP, K8s, 150+ providers ✅ 4800+ providers ❌ Chỉ Azure
Testing xUnit, NUnit, MSTest — unit + integration Terratest (Go), terraform test What-if preview, hạn chế
IDE support Full IntelliSense, refactoring, debugging HCL extension (cơ bản) VS Code extension (tốt cho Azure)
State management Pulumi Cloud (managed), S3, Azure Blob, local Terraform Cloud, S3, local Azure Resource Manager (implicit)
Reusability NuGet packages, OOP, interfaces Modules (HCL) Modules (Bicep)
Learning curve (.NET dev) ⭐ Thấp — dùng C# quen thuộc ⭐⭐⭐ Phải học HCL ⭐⭐ Phải học Bicep syntax
AI Assistant Pulumi Neo (enterprise agent) Terraform AI (beta) Copilot for Azure
Open Source ✅ Apache 2.0 ⚠️ BSL (OpenTofu fork = true OSS) ✅ MIT

Khi nào chọn Pulumi?

Team .NET/C# muốn quản lý multi-cloud infrastructure mà không phải học ngôn ngữ mới. Đặc biệt mạnh khi cần logic phức tạp (loops, conditions, async), testing nghiêm túc, và tái sử dụng code qua NuGet packages. Nếu team đã invest vào Terraform và hạ tầng ổn định, việc migrate có thể không đáng — Pulumi hỗ trợ import từ Terraform state nhưng cost chuyển đổi vẫn tồn tại.

Bắt đầu với Pulumi + .NET 10

Cài đặt và khởi tạo project

Pulumi CLI hoạt động cross-platform trên Windows, macOS, và Linux. Sau khi cài đặt, bạn khởi tạo project C# chỉ với một lệnh:

# Cài Pulumi CLI
curl -fsSL https://get.pulumi.com | sh

# Hoặc trên Windows qua Chocolatey
choco install pulumi

# Khởi tạo project C# cho Azure
pulumi new azure-csharp --name my-infra --stack dev

# Cấu trúc thư mục được tạo:
# my-infra/
# ├── Pulumi.yaml          # Project metadata
# ├── Pulumi.dev.yaml      # Stack config (dev)
# ├── Program.cs            # Entry point
# └── my-infra.csproj       # .NET project file

Ví dụ thực tế: Deploy web app lên Azure

Dưới đây là một ví dụ hoàn chỉnh — tạo Resource Group, App Service Plan, và Web App trên Azure, tất cả bằng C# thuần:

Program.cs — Azure Web App Infrastructure
using Pulumi;
using Pulumi.AzureNative.Resources;
using Pulumi.AzureNative.Web;
using Pulumi.AzureNative.Web.Inputs;

return await Deployment.RunAsync(() =>
{
    var resourceGroup = new ResourceGroup("rg-production", new()
    {
        ResourceGroupName = "rg-myapp-production",
        Location = "southeastasia"
    });

    var appServicePlan = new AppServicePlan("plan-production", new()
    {
        ResourceGroupName = resourceGroup.Name,
        Kind = "Linux",
        Reserved = true,
        Sku = new SkuDescriptionArgs
        {
            Name = "P1v3",
            Tier = "PremiumV3"
        }
    });

    var webApp = new WebApp("app-production", new()
    {
        ResourceGroupName = resourceGroup.Name,
        ServerFarmId = appServicePlan.Id,
        SiteConfig = new SiteConfigArgs
        {
            LinuxFxVersion = "DOTNETCORE|10.0",
            AlwaysOn = true,
            MinTlsVersion = "1.2",
            HttpsOnly = true,
            AppSettings = new[]
            {
                new NameValuePairArgs
                {
                    Name = "ASPNETCORE_ENVIRONMENT",
                    Value = "Production"
                }
            }
        },
        HttpsOnly = true
    });

    return new Dictionary<string, object?>
    {
        ["endpoint"] = webApp.DefaultHostName
            .Apply(h => $"https://{h}"),
        ["resourceGroup"] = resourceGroup.Name
    };
});

Nhận thấy sự khác biệt?

Đây là C# thuần túy — var, new(), Dictionary, lambda expressions. Không cần học syntax mới. IntelliSense trong Visual Studio/Rider sẽ auto-complete mọi property, giúp bạn khám phá API mà không cần đọc docs liên tục.

Ví dụ: AWS S3 + CloudFront CDN

Pulumi không giới hạn ở Azure. Đây là ví dụ tạo static website hosting trên AWS với S3 bucket và CloudFront distribution:

Program.cs — AWS Static Site với CDN
using Pulumi;
using Pulumi.Aws.S3;
using Pulumi.Aws.CloudFront;
using Pulumi.Aws.CloudFront.Inputs;

return await Deployment.RunAsync(() =>
{
    var bucket = new BucketV2("site-bucket", new()
    {
        BucketPrefix = "mysite-"
    });

    var bucketWebsite = new BucketWebsiteConfigurationV2(
        "site-config", new()
    {
        Bucket = bucket.Id,
        IndexDocument = new BucketWebsiteConfigurationV2IndexDocumentArgs
        {
            Suffix = "index.html"
        },
        ErrorDocument = new BucketWebsiteConfigurationV2ErrorDocumentArgs
        {
            Key = "404.html"
        }
    });

    var oac = new OriginAccessControl("site-oac", new()
    {
        OriginAccessControlOriginType = "s3",
        SigningBehavior = "always",
        SigningProtocol = "sigv4"
    });

    var cdn = new Distribution("site-cdn", new()
    {
        Enabled = true,
        DefaultRootObject = "index.html",
        Origins = new DistributionOriginArgs[]
        {
            new()
            {
                OriginId = "s3Origin",
                DomainName = bucket.BucketRegionalDomainName,
                OriginAccessControlId = oac.Id
            }
        },
        DefaultCacheBehavior = new DistributionDefaultCacheBehaviorArgs
        {
            TargetOriginId = "s3Origin",
            ViewerProtocolPolicy = "redirect-to-https",
            AllowedMethods = new[] { "GET", "HEAD" },
            CachedMethods = new[] { "GET", "HEAD" },
            Compress = true,
            CachePolicyId = "658327ea-f89d-4fab-a63d-7e88639e58f6"
        },
        ViewerCertificate = new DistributionViewerCertificateArgs
        {
            CloudfrontDefaultCertificate = true
        },
        Restrictions = new DistributionRestrictionsArgs
        {
            GeoRestriction = new DistributionRestrictionsGeoRestrictionArgs
            {
                RestrictionType = "none"
            }
        }
    });

    return new Dictionary<string, object?>
    {
        ["cdnUrl"] = cdn.DomainName.Apply(d => $"https://{d}"),
        ["bucketName"] = bucket.Id
    };
});

Patterns nâng cao cho Production

Component Resources — Tái sử dụng như NuGet Package

Sức mạnh thực sự của Pulumi nằm ở khả năng tạo abstraction bằng OOP. Bạn có thể đóng gói một tập hợp resources thành Component Resource, rồi publish lên NuGet cho toàn team sử dụng:

SecureWebApp.cs — Custom Component Resource
using Pulumi;
using Pulumi.AzureNative.Web;
using Pulumi.AzureNative.Web.Inputs;

public class SecureWebAppArgs : ResourceArgs
{
    [Input("resourceGroupName", required: true)]
    public Input<string> ResourceGroupName { get; set; } = null!;

    [Input("planId", required: true)]
    public Input<string> PlanId { get; set; } = null!;

    [Input("dotnetVersion")]
    public Input<string>? DotnetVersion { get; set; }

    [Input("customDomain")]
    public Input<string>? CustomDomain { get; set; }
}

public class SecureWebApp : ComponentResource
{
    [Output("endpoint")]
    public Output<string> Endpoint { get; private set; } = null!;

    [Output("principalId")]
    public Output<string> PrincipalId { get; private set; } = null!;

    public SecureWebApp(string name, SecureWebAppArgs args,
        ComponentResourceOptions? options = null)
        : base("custom:azure:SecureWebApp", name, options)
    {
        var dotnetVer = args.DotnetVersion ?? "DOTNETCORE|10.0";

        var app = new WebApp($"{name}-app", new()
        {
            ResourceGroupName = args.ResourceGroupName,
            ServerFarmId = args.PlanId,
            HttpsOnly = true,
            Identity = new ManagedServiceIdentityArgs
            {
                Type = Pulumi.AzureNative.Web.ManagedServiceIdentityType
                    .SystemAssigned
            },
            SiteConfig = new SiteConfigArgs
            {
                LinuxFxVersion = dotnetVer,
                AlwaysOn = true,
                MinTlsVersion = "1.2",
                FtpsState = "Disabled",
                Http20Enabled = true
            }
        }, new() { Parent = this });

        Endpoint = app.DefaultHostName
            .Apply(h => $"https://{h}");
        PrincipalId = app.Identity
            .Apply(i => i?.PrincipalId ?? "");

        RegisterOutputs();
    }
}

Sử dụng component này giống như dùng một class bình thường:

var api = new SecureWebApp("api-service", new()
{
    ResourceGroupName = rg.Name,
    PlanId = plan.Id,
    DotnetVersion = "DOTNETCORE|10.0"
});

var frontend = new SecureWebApp("frontend", new()
{
    ResourceGroupName = rg.Name,
    PlanId = plan.Id,
    DotnetVersion = "NODE|22-lts"
});

Stack References — Multi-stack Architecture

Trong production, bạn thường tách infrastructure thành nhiều stacks: networking, compute, database, monitoring. Pulumi Stack References cho phép các stacks tham chiếu outputs của nhau:

graph LR
    subgraph Network["Stack: Networking"]
        A["VNet / VPC
Subnets
NSG / Security Groups"] end subgraph Data["Stack: Database"] B["SQL Server
Connection String
Firewall Rules"] end subgraph Compute["Stack: Compute"] C["App Service
Container Apps
Functions"] end subgraph Monitor["Stack: Monitoring"] D["Application Insights
Log Analytics
Alerts"] end A -->|"vnetId, subnetIds"| C A -->|"subnetId"| B B -->|"connectionString"| C C -->|"appId"| D style A fill:#2c3e50,stroke:#fff,color:#fff style B fill:#e94560,stroke:#fff,color:#fff style C fill:#4CAF50,stroke:#fff,color:#fff style D fill:#ff9800,stroke:#fff,color:#fff
Multi-stack architecture — mỗi stack quản lý một layer, tham chiếu qua Stack References
Compute Stack — tham chiếu Network và Database stacks
var networkStack = new StackReference("org/networking/production");
var dbStack = new StackReference("org/database/production");

var vnetId = networkStack.RequireOutput("vnetId")
    .Apply(v => v.ToString()!);
var subnetId = networkStack.RequireOutput("appSubnetId")
    .Apply(v => v.ToString()!);
var connString = dbStack.RequireOutput("connectionString")
    .Apply(v => v.ToString()!);

var app = new WebApp("api", new()
{
    ResourceGroupName = rg.Name,
    ServerFarmId = plan.Id,
    VirtualNetworkSubnetId = subnetId,
    SiteConfig = new SiteConfigArgs
    {
        ConnectionStrings = new[]
        {
            new ConnStringInfoArgs
            {
                Name = "DefaultConnection",
                ConnectionString = connString,
                Type = ConnectionStringType.SQLAzure
            }
        }
    }
});

Testing Infrastructure bằng xUnit

Một trong những lợi thế lớn nhất của Pulumi so với Terraform: bạn viết unit test cho infrastructure bằng chính framework test quen thuộc. Pulumi cung cấp mocking framework để test logic mà không cần provision resources thật:

InfraTests.cs — Unit test infrastructure logic
using Pulumi;
using Pulumi.Testing;

public class InfraTests
{
    [Fact]
    public async Task WebApp_Must_Use_Https()
    {
        var resources = await Testing.RunAsync<MyStack>();

        var webApps = resources
            .OfType<Pulumi.AzureNative.Web.WebApp>();

        foreach (var app in webApps)
        {
            var httpsOnly = await app.HttpsOnly
                .GetValueAsync(whenUnknown: false);
            Assert.True(httpsOnly,
                $"WebApp {app.GetResourceName()} must enforce HTTPS");
        }
    }

    [Fact]
    public async Task All_Storage_Must_Be_Encrypted()
    {
        var resources = await Testing.RunAsync<MyStack>();

        var accounts = resources
            .OfType<Pulumi.AzureNative.Storage.StorageAccount>();

        Assert.All(accounts, async account =>
        {
            var encryption = await account.Encryption
                .GetValueAsync(whenUnknown: null);
            Assert.NotNull(encryption);
        });
    }
}

Policy as Code

Ngoài unit tests, Pulumi còn có CrossGuard — hệ thống Policy as Code chạy trước mỗi deployment. Bạn viết policies bằng C# để enforce standards: "mọi S3 bucket phải enable encryption", "không được tạo public subnet", "tag 'environment' là bắt buộc". Policies chạy ở Pulumi Cloud, block deployment nếu vi phạm.

Pulumi Neo — AI Agent cho Cloud Engineering

Đầu năm 2026, Pulumi ra mắt Pulumi Neo — AI agent chuyên biệt cho infrastructure management, kế thừa và vượt xa Pulumi Copilot trước đó. Không giống các AI coding assistant thông thường, Neo hiểu sâu về infrastructure dependencies và governance policies.

Pulumi Neo có thể làm gì?

  • Generate infrastructure code — "Tạo cho tôi một AKS cluster với 3 node pools, autoscaling, và Azure CNI" → Neo sinh ra C# code hoàn chỉnh
  • Debug deployment failures — phân tích error, đề xuất fix dựa trên context của stack
  • Cost optimization — quét resources đang chạy, gợi ý right-sizing và reserved instances
  • Drift detection — phát hiện khi cloud resources bị thay đổi ngoài Pulumi
  • Migration assistant — chuyển Terraform HCL sang Pulumi C# tự động

Pulumi Agent Skills cho AI Coding Assistants

Từ tháng 1/2026, Pulumi phát hành Agent Skills — tích hợp vào Claude Code, GitHub Copilot, Cursor, VS Code, và các AI coding tools khác. Skills cung cấp cho AI assistants kiến thức chuyên sâu về infrastructure patterns, giúp sinh code Pulumi chính xác hơn so với dùng AI vanilla.

# Cài Pulumi Agent Skills cho Claude Code
pulumi plugin install skills

# Trong Claude Code, bạn có thể hỏi:
# "Tạo Pulumi stack cho 3-tier architecture trên Azure
#  với App Service, SQL Database, và Redis Cache"

Kubernetes với Pulumi — Beyond YAML

Một use case đặc biệt mạnh của Pulumi là quản lý Kubernetes. Thay vì viết hàng trăm dòng YAML, bạn dùng C# với full type safety:

Kubernetes Deployment bằng C#
using Pulumi.Kubernetes.Apps.V1;
using Pulumi.Kubernetes.Core.V1;
using Pulumi.Kubernetes.Types.Inputs.Apps.V1;
using Pulumi.Kubernetes.Types.Inputs.Core.V1;
using Pulumi.Kubernetes.Types.Inputs.Meta.V1;

var appLabels = new InputMap<string> { { "app", "my-api" } };

var deployment = new Deployment("api-deployment", new DeploymentArgs
{
    Spec = new DeploymentSpecArgs
    {
        Replicas = 3,
        Selector = new LabelSelectorArgs
        {
            MatchLabels = appLabels
        },
        Template = new PodTemplateSpecArgs
        {
            Metadata = new ObjectMetaArgs { Labels = appLabels },
            Spec = new PodSpecArgs
            {
                Containers = new ContainerArgs[]
                {
                    new()
                    {
                        Name = "api",
                        Image = "myregistry.azurecr.io/api:latest",
                        Ports = new ContainerPortArgs[]
                        {
                            new() { ContainerPortValue = 8080 }
                        },
                        Resources = new ResourceRequirementsArgs
                        {
                            Requests =
                            {
                                { "cpu", "250m" },
                                { "memory", "256Mi" }
                            },
                            Limits =
                            {
                                { "cpu", "500m" },
                                { "memory", "512Mi" }
                            }
                        }
                    }
                }
            }
        }
    }
});

var service = new Service("api-service", new ServiceArgs
{
    Spec = new ServiceSpecArgs
    {
        Selector = appLabels,
        Ports = new ServicePortArgs[]
        {
            new() { Port = 80, TargetPort = 8080 }
        },
        Type = "LoadBalancer"
    }
});

CI/CD Integration

Pulumi tích hợp seamlessly vào CI/CD pipeline. Đây là workflow tiêu biểu cho GitHub Actions:

graph LR
    A["git push"] --> B["PR Created"]
    B --> C["pulumi preview
Show diff"] C --> D["Code Review
+ Infra Review"] D --> E["Merge to main"] E --> F["pulumi up
Apply changes"] F --> G["Stack Outputs
Update DNS/Config"] style A fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style C fill:#ff9800,stroke:#fff,color:#fff style F fill:#4CAF50,stroke:#fff,color:#fff style G fill:#2c3e50,stroke:#fff,color:#fff
Pulumi trong CI/CD — preview trên PR, deploy trên merge
.github/workflows/infra.yml
name: Infrastructure
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  id-token: write    # OIDC auth
  contents: read

jobs:
  preview:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'
      - uses: pulumi/actions@v6
        with:
          command: preview
          stack-name: org/dev
          comment-on-pr: true
        env:
          PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
          ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
          ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

  deploy:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'
      - uses: pulumi/actions@v6
        with:
          command: up
          stack-name: org/production
        env:
          PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
          ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
          ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

Secrets Management và Security

Pulumi có built-in secrets management — mọi secret được mã hóa trong state file. Bạn không bao giờ lưu plaintext password trong code hay config:

# Set secret cho stack
pulumi config set --secret dbPassword "S3cur3P@ss!"

# Trong C# code, đọc secret
var cfg = new Config();
var dbPassword = cfg.RequireSecret("dbPassword");
// Output<string> — luôn được mask trong logs

Pulumi hỗ trợ nhiều encryption providers: Pulumi Cloud (mặc định), AWS KMS, Azure Key Vault, Google Cloud KMS, hoặc passphrase-based encryption cho self-hosted state.

Lưu ý bảo mật

Khi dùng Pulumi với CI/CD, luôn sử dụng OIDC authentication (OpenID Connect) thay vì static credentials. GitHub Actions, GitLab CI, và Azure DevOps đều hỗ trợ OIDC — không cần lưu access keys dạng long-lived secrets. Pulumi ESC (Environments, Secrets, and Configuration) giúp centralize secrets management cross-stack.

Migration từ Terraform sang Pulumi

Nếu team đã có Terraform codebase, Pulumi cung cấp công cụ migration:

# Convert Terraform HCL sang Pulumi C#
pulumi convert --from terraform --language csharp

# Import existing Terraform state
pulumi import --from terraform ./terraform.tfstate

# Pulumi cũng có Terraform Bridge — wrap bất kỳ
# Terraform provider nào thành Pulumi provider

Quá trình migration thường diễn ra theo phases: bắt đầu bằng resources mới dùng Pulumi, rồi dần import existing resources từ Terraform state. Không cần big-bang migration.

Automation API — IaC trong Application Code

Đây là tính năng độc đáo chỉ có ở Pulumi: Automation API cho phép bạn nhúng Pulumi engine vào trong application code. Use cases: multi-tenant SaaS tự động provision infrastructure cho mỗi tenant, internal developer platform, hoặc self-service portals.

Automation API — Provision stack từ application code
using Pulumi.Automation;

// Tạo hoặc chọn stack
var stack = await LocalWorkspace.CreateOrSelectStackAsync(
    new InlineProgramArgs("org", "tenant-infra", "tenant-123",
        PulumiFn.Create(() =>
        {
            var rg = new ResourceGroup($"rg-tenant-123");
            var db = new Database($"db-tenant-123", new()
            {
                ResourceGroupName = rg.Name,
                // ... tenant-specific config
            });
            return new Dictionary<string, object?>
            {
                ["connectionString"] = db.ConnectionString
            };
        })));

// Preview trước
var preview = await stack.PreviewAsync();
Console.WriteLine($"Changes: {preview.ChangeSummary}");

// Deploy
var result = await stack.UpAsync();
var connStr = result.Outputs["connectionString"].Value;
Console.WriteLine($"Tenant DB: {connStr}");

Lộ trình phát triển Pulumi 2026

Tháng 1, 2026
Pulumi Agent Skills — tích hợp AI coding assistants (Claude Code, Copilot, Cursor) với infrastructure knowledge chuyên sâu
Tháng 2, 2026
Pulumi Neo GA — AI agent quản lý full lifecycle: provision, govern, optimize infrastructure ở enterprise scale
Q1 2026
Scheduled Deployments — tự động hóa operations (scale down đêm, refresh, destroy dev stacks cuối ngày) để tối ưu chi phí
Q2 2026
Pulumi ESC v2 — Environments, Secrets, and Configuration nâng cấp với dynamic credentials, OIDC everywhere, và integration với HashiCorp Vault

Kết luận

Pulumi mang đến một paradigm shift cho .NET developer: infrastructure IS software. Thay vì học thêm DSL mới, bạn tận dụng toàn bộ kiến thức C# — từ OOP và generics đến testing và NuGet ecosystem — để quản lý cloud infrastructure. Với sự xuất hiện của Pulumi Neo và Agent Skills, ranh giới giữa "viết code ứng dụng" và "viết code hạ tầng" ngày càng mờ nhạt.

Nếu bạn là .NET developer và đang bắt đầu hành trình IaC, Pulumi là lựa chọn tự nhiên nhất. Nếu team đã dùng Terraform ổn định, hãy cân nhắc dùng Pulumi cho projects mới thay vì migrate big-bang. Trong cả hai trường hợp, tư duy "infrastructure as software" sẽ nâng tầm cách bạn thiết kế và vận hành hệ thống cloud.

Bắt đầu nhanh

Truy cập pulumi.com/docs/iac/get-started để tạo project đầu tiên trong 10 phút. Pulumi có free tier không giới hạn cho individual developers, bao gồm state management trên Pulumi Cloud và 1 stack cho mỗi project.

Tài liệu tham khảo