Pulumi vs Terraform: IaC cho startup chạy trên VPS

Chia sẻ bài viết

Mục lục
TL;DR
  • Terraform dùng HCL (DSL riêng), ecosystem cực lớn 3000+ provider, state file local hoặc remote.
  • Pulumi dùng TypeScript/Python/Go thật, control flow tự nhiên, test bằng unit test thường.
  • Cả 2 đều quản lý được Cloud VPS, DNS, firewall, S3, K8s cluster.
  • Terraform thắng khi cần multi-cloud, hire dễ. Pulumi thắng khi team đã code TS/Python, muốn loop, condition.
  • Cho startup VN tự host VPS: Terraform an toàn, ổn định. Pulumi nếu muốn IaC + app cùng repo TypeScript.

Bạn đang quản lý 5-10 VPS, vài record DNS Cloudflare, S3 bucket cho backup, tay chỉnh từng cái qua web panel - mệt và dễ sai. Đến lúc cần IaC (Infrastructure as Code). Câu hỏi quen thuộc: chọn Terraform (HCL) hay Pulumi (TypeScript/Python)?

Cả 2 đều giải quyết bài toán: define infrastructure bằng code, version control, apply tự động, drift detection. Khác biệt nằm ở ngôn ngữ và triết lý. Bài này phân tích từng yếu tố cho startup VN tự host trên Cloud VPS - không phải enterprise dùng AWS hàng triệu USD.

Test case: quản lý 3 VPS (Cloud VPS TND), 5 DNS record Cloudflare, 1 R2 bucket, 1 user MySQL. Đo thời gian setup, code length, learning curve.

1. Bảng so sánh nhanh Pulumi vs Terraform

Tiêu chíTerraformPulumi
Ngôn ngữHCL (DSL)TS, Python, Go, C#, Java
Learning curve1 tuần (HCL syntax)1 ngày (nếu biết TS/Python)
Provider count3000+150+ (qua TF bridge)
State managementFile local hoặc remoteCloud (free tier) hoặc S3
Test unit codeKhó (terraform test mới có)Dễ (jest, pytest)
Loop, conditionalcount, for_each (giới hạn)JS for, if natural
PricingFree (open core)Free cho cá nhân
Hire dev biếtDễ (phổ biến hơn)Khó hơn
VPS provider VNCustom providerCustom resource

2. Terraform hello world: define 3 VPS DigitalOcean

# main.tf
terraform {
  required_providers {
    digitalocean = {
      source = "digitalocean/digitalocean"
      version = "~> 2.0"
    }
  }
}

variable "do_token" {}

provider "digitalocean" {
  token = var.do_token
}

resource "digitalocean_droplet" "web" {
  count    = 3
  image    = "ubuntu-24-04-x64"
  name     = "web-${count.index + 1}"
  region   = "sgp1"
  size     = "s-2vcpu-2gb"
  ssh_keys = [data.digitalocean_ssh_key.main.id]
}

data "digitalocean_ssh_key" "main" {
  name = "default-key"
}

output "ips" {
  value = digitalocean_droplet.web[*].ipv4_address
}
terraform init
terraform plan -var="do_token=$DO_TOKEN"
terraform apply -var="do_token=$DO_TOKEN" -auto-approve

# Output:
# ips = ["1.2.3.4", "1.2.3.5", "1.2.3.6"]

3. Pulumi tương đương bằng TypeScript

// index.ts
import * as pulumi from '@pulumi/pulumi';
import * as digitalocean from '@pulumi/digitalocean';

const sshKey = digitalocean.getSshKey({ name: 'default-key' });

const droplets = [];
for (let i = 1; i <= 3; i++) {
  droplets.push(new digitalocean.Droplet(`web-${i}`, {
    image: 'ubuntu-24-04-x64',
    name: `web-${i}`,
    region: 'sgp1',
    size: 's-2vcpu-2gb',
    sshKeys: [sshKey.then(k => k.id)],
  }));
}

export const ips = droplets.map(d => d.ipv4Address);
pulumi stack init dev
pulumi config set digitalocean:token $DO_TOKEN --secret
pulumi up

Code Pulumi cảm giác tự nhiên hơn với dev TypeScript. Loop dùng for thật, không cần học count/for_each.

4. State management - vấn đề lớn nhất của IaC

Cả 2 đều lưu state file (JSON) ghi nhớ resource đã tạo. State file cực kỳ quan trọng - mất là không quản lý được nữa.

  • Terraform: mặc định state local (terraform.tfstate). Cần config S3/R2 backend remote khi team chia sẻ. Có locking qua DynamoDB hoặc tùy backend.
  • Pulumi: mặc định state trên Pulumi Cloud (free cho cá nhân, có UI đẹp). Có thể chuyển sang S3, Azure Blob nếu muốn self-host.
# Terraform S3 backend
terraform {
  backend "s3" {
    bucket         = "my-tf-state"
    key            = "prod/terraform.tfstate"
    region         = "ap-southeast-1"
    dynamodb_table = "tf-lock"
    encrypt        = true
  }
}

# Pulumi S3 backend
pulumi login s3://my-pulumi-state?region=ap-southeast-1

5. Quản lý DNS Cloudflare và VPS provider VN

Cả 2 đều có provider Cloudflare chính chủ:

# Terraform Cloudflare
resource "cloudflare_record" "app" {
  zone_id = var.zone_id
  name    = "app"
  value   = digitalocean_droplet.web[0].ipv4_address
  type    = "A"
  proxied = true
  ttl     = 1
}

# Pulumi Cloudflare
import * as cloudflare from '@pulumi/cloudflare';

new cloudflare.Record('app', {
  zoneId: config.get('zoneId'),
  name: 'app',
  value: droplets[0].ipv4Address,
  type: 'A',
  proxied: true,
});

Với VPS provider VN (TND, BizflyCloud, Vinahost), không có official Terraform/Pulumi provider. Workaround: dùng http provider gọi API, hoặc local-exec chạy curl. Quản lý semi-manual.

6. Loop và conditional - Pulumi thắng tuyệt đối

# Terraform - phải dùng for_each
resource "digitalocean_droplet" "web" {
  for_each = {
    web1 = { size = "s-1vcpu-1gb" }
    web2 = { size = "s-2vcpu-2gb" }
    web3 = { size = "s-4vcpu-4gb" }
  }
  image  = "ubuntu-24-04-x64"
  name   = each.key
  region = "sgp1"
  size   = each.value.size
}

# Pulumi - loop bình thường
const sizes = [
  { name: 'web1', size: 's-1vcpu-1gb' },
  { name: 'web2', size: 's-2vcpu-2gb' },
  { name: 'web3', size: 's-4vcpu-4gb' },
];

const droplets = sizes.map(s => new digitalocean.Droplet(s.name, {
  image: 'ubuntu-24-04-x64',
  name: s.name,
  region: 'sgp1',
  size: s.size,
}));

Khi cần logic phức tạp (đọc CSV, gọi API external, transform data), Pulumi viết như app TypeScript thường. Terraform phải dùng locals, dynamic block, vòng vèo.

7. Testing infrastructure code

# Pulumi test với jest
import { describe, expect, test } from '@jest/globals';
import * as pulumi from '@pulumi/pulumi';

pulumi.runtime.setMocks({
  newResource: (args) => ({ id: 'mock-id', state: args.inputs }),
  call: () => ({}),
});

describe('infrastructure', () => {
  test('creates 3 droplets', async () => {
    const infra = await import('./index');
    expect(infra.ips.length).toBe(3);
  });
});

# Terraform test (mới ra v1.6+)
# tests/main.tftest.hcl
run "create_droplets" {
  assert {
    condition     = length(digitalocean_droplet.web) == 3
    error_message = "Expected 3 droplets"
  }
}

Pulumi test framework trưởng thành hơn vì là code thật. Terraform test feature còn mới, ít ví dụ.

8. CI/CD pipeline với GitHub Actions

# .github/workflows/iac.yml (Terraform)
name: Terraform
on: [push]
jobs:
  apply:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init
      - run: terraform plan -no-color
      - run: terraform apply -auto-approve
        if: github.ref == 'refs/heads/main'

# .github/workflows/iac.yml (Pulumi)
name: Pulumi
on: [push]
jobs:
  up:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm install
      - uses: pulumi/actions@v5
        with:
          command: up
          stack-name: dev

9. Pricing và self-host

  • Terraform: open source free hoàn toàn, có Enterprise tier paid (Terraform Cloud). State backend tự host trên S3.
  • Pulumi: CLI free, Pulumi Cloud free cho cá nhân/individual. Team 3+ user trả ~75 USD/user/tháng. Hoặc self-host state trên S3 miễn phí.

Với startup VN tiết kiệm chi phí, cả 2 đều có thể chạy 100% free khi self-host state trên Cloudflare R2 (10GB free, 1 triệu read/tháng).

10. Migration từ Terraform sang Pulumi

Pulumi có tool tf2pulumi convert HCL sang TypeScript:

pulumi convert --from terraform --language typescript

# Đọc main.tf rồi sinh index.ts
# 80% syntax convert auto, phần còn lại fix tay

Migration ngược (Pulumi -> Terraform) khó hơn vì Pulumi dùng đầy đủ feature ngôn ngữ. Phải viết lại tay.

11. Quyết định cho startup VN

Chọn Terraform khi:

  • Team có DevOps hoặc SRE đã quen Terraform.
  • Cần multi-cloud (AWS + GCP + Azure).
  • Roadmap cần Terragrunt, Atlantis cho workflow phức tạp.
  • Muốn hire dev DevOps dễ (Terraform phổ biến hơn ở VN).

Chọn Pulumi khi:

  • Team đã code TS/Python, không có DevOps riêng.
  • Muốn IaC + app code cùng monorepo TypeScript.
  • Cần logic phức tạp: read CSV, gọi API, transform.
  • Test infrastructure quan trọng (audit, compliance).

12. Best practice IaC cho cả 2 tool

  • State backend luôn remote (S3/R2) với encryption + locking.
  • Secret không bao giờ commit - dùng env var hoặc Vault.
  • Plan trước apply, review trong PR.
  • Tag mọi resource: env=prod, owner=team-x, cost-center=eng.
  • Module hoá: 1 module = 1 component (VPS, DNS, DB).
  • CI/CD apply tự động khi merge main, manual approve.
  • Drift detection 1 lần/ngày qua cron.
Cloud VPS cho vibe coder

Quản lý VPS bằng IaC - tự động hóa từ ngày đầu

Cloud VPS TND sẵn AlmaLinux 9, Ubuntu 22/24, Debian 12/13. SSD CEPH, snapshot 1-click, backup hằng ngày, network 200Mbps trong nước. Provision VPS qua API, tích hợp Terraform/Pulumi qua custom resource.

Xem 8 cấu hình Cloud VPS →

FAQ

Pulumi có thật sự nhanh hơn Terraform khi apply không?

Tốc độ tương đương vì cả 2 đều gọi API provider giống nhau. Pulumi có lợi thế nhẹ ở parallel execution và compile time. Khác biệt < 10%, không đáng kể.

Có nên dùng Ansible thay cho Terraform/Pulumi không?

Ansible khác mục đích: nó là configuration management (cài app, sửa file trên VPS đã tồn tại). Terraform/Pulumi là provisioning (tạo VPS, DNS từ 0). Thường dùng cả 2: TF/Pulumi tạo VPS, Ansible cài app.

State file bị mất thì làm sao?

Khôi phục từ backup (S3 versioning) hoặc import từng resource thủ công: terraform import / pulumi import. Đau khổ nhưng làm được. Vì vậy LUÔN backup state file.

Có provider Terraform cho VPS VN không?

Chưa có official cho TND, BizflyCloud, Vinahost. Có thể viết custom provider hoặc dùng terraform-provider-http gọi REST API. Hỏi support TND để có docs API VPS.

Pulumi YAML có dùng được không nếu không biết code?

Có. Pulumi hỗ trợ YAML markup gần giống Terraform HCL. Phù hợp infra đơn giản. Tuy nhiên mất lợi thế lớn nhất của Pulumi là dùng code thật.

Terraform Cloud có free tier không?

Có. Free tier cho team <5 user, không giới hạn workspace. Hết free khi cần SSO, audit log, agent self-hosted. Lúc đó cân nhắc tự host state trên S3.

2009
15+ năm vận hành liên tục
10+
tập đoàn lớn tin dùng
100+
doanh nghiệp SMB Việt
30 ngày
đổi key lỗi miễn phí
Phần mềm bản quyền chính hãng chúng tôi cung cấp
Bản quyền chính hãng Hóa đơn VAT đầy đủ Đổi key lỗi 30 ngày Vận hành từ 2009 MST 0200994870 Hotline 0225.999.6666