DEV Community

Cover image for Terraform on Alibaba Cloud: Building Repeatable Infrastructure as Code
Raphael Gab-Momoh
Raphael Gab-Momoh

Posted on Originally published at raphaelgmomoh.pages.dev

Terraform on Alibaba Cloud: Building Repeatable Infrastructure as Code

Part 1 of the Alibaba Cloud Engineering Lab Series.

TL;DR

This isn't "Terraform lets you provision Alibaba Cloud" — that's true but generic. It's how to build repeatable Alibaba Cloud infrastructure with Terraform: a real multi-tier project, module structure, remote state, CI/CD, drift detection, and the boundary where Terraform's job ends and configuration management begins.

Git → Terraform code → plan → state → apply → VPC/ECS/OSS/ACK → Alibaba Cloud

Before the how, the what — three terms this guide leans on:

  • Infrastructure as Code (IaC) — describing your cloud infrastructure (networks, servers, databases) in text files instead of clicking through a console. The point isn't just automation — it's that the text file is a single, reviewable, version-controlled source of truth for what your infrastructure is supposed to look like, the same discipline you already apply to application code.
  • Terraform provider — a plugin that translates Terraform's generic language into calls against one specific cloud's API. aliyun/alicloud is the Alibaba Cloud provider; Azure and AWS each have their own. The provider is why the same Terraform workflow (write, plan, apply) works across completely different clouds — only the resource names and fields change.
  • Terraform state — a file Terraform keeps that records what it already created, so a second apply knows the difference between "create this new thing" and "this already exists, only two fields changed." Without state, every run would have no memory of previous runs — see Section 06 for why that file has to be handled carefully.

Every resource below is terraform validate-verified against the real aliyun/alicloud provider, not written from memory and assumed correct — the companion repo has the actual module structure, restructured from a single flat file into the modules/environments layout Section 04 describes below.


01 — Why This, and What "Repeatable" Actually Means

Alibaba Cloud is the dominant hyperscaler across China and much of Southeast Asia — a region most Azure- and AWS-trained IaC practitioners have never provisioned into. Alibaba's own Terraform documentation positions it as the IaC mechanism spanning ECS, VPC, OSS, ACK, RAM, PAI, and the rest of the platform — the same breadth Terraform covers on Azure or AWS.

                    Git
                     │
                     ▼
              Terraform Code
                     │
              terraform plan
                     │
                     ▼
              Terraform State
                     │
              terraform apply
                     │
        ┌────────────┼────────────┐
        ▼            ▼            ▼
       VPC          ECS          OSS
        │            │
        ▼            ▼
    Security       ACK
     Groups
        │
        └────────────┬────────────┘
                     ▼
                 Alibaba Cloud
Enter fullscreen mode Exit fullscreen mode

The rest of this article builds toward one concrete deliverable: a production-ready web application, fully reproducible from a Terraform project, not a series of disconnected resource snippets.


02 — Provider Setup: Be Explicit About the Source

The Terraform Registry currently lists two Alibaba Cloud providers — the Alibaba-maintained aliyun/alicloud and a legacy hashicorp/alicloud listing. Ambiguity here causes real init/version problems — always pin the source explicitly, not just the provider short name:

terraform {
  required_providers {
    alicloud = {
      source  = "aliyun/alicloud" # the actively Alibaba-maintained provider
      version = "~> 1.230"
    }
  }
  required_version = ">= 1.6.0"
}

provider "alicloud" {
  region = var.region
}
Enter fullscreen mode Exit fullscreen mode

Credentials via environment variables — Alibaba's documentation recommends environment-based credential configuration for local usage, never hardcoded in a provider block:

export ALICLOUD_ACCESS_KEY="..."
export ALICLOUD_SECRET_KEY="..."
export ALICLOUD_REGION="ap-southeast-1"
Enter fullscreen mode Exit fullscreen mode

Production CI/CD should go further than "environment variables instead of hardcoded" — use short-lived or managed credentials where the pipeline supports them, rather than a long-lived static AccessKey committed to a secrets store.


03 — The Project: A Production-Ready Web Application

Scenario: deploy a real multi-tier web application — VPC, VSwitch, security groups, ECS, OSS, SLB, a RAM role scoped to the app, optional RDS, and outputs a reader can actually reproduce.

Network foundation:

resource "alicloud_vpc" "main" {
  vpc_name   = "vpc-prod-apac"
  cidr_block = "10.10.0.0/16"
}

resource "alicloud_vswitch" "app" {
  vswitch_name = "vsw-app-tier"
  vpc_id       = alicloud_vpc.main.id
  cidr_block   = "10.10.1.0/24"
  zone_id      = "ap-southeast-1a"
}

resource "alicloud_vswitch" "data" {
  vswitch_name = "vsw-data-tier"
  vpc_id       = alicloud_vpc.main.id
  cidr_block   = "10.10.2.0/24"
  zone_id      = "ap-southeast-1b"
}
Enter fullscreen mode Exit fullscreen mode

A VSwitch is bound to a single zone at creation, unlike an Azure subnet spanning a region — plan zone placement deliberately for availability.

Security groups:

resource "alicloud_security_group" "app_sg" {
  security_group_name = "sg-app-tier"
  vpc_id = alicloud_vpc.main.id
}

resource "alicloud_security_group_rule" "allow_https" {
  type              = "ingress"
  ip_protocol       = "tcp"
  nic_type          = "intranet"
  policy            = "accept"
  port_range        = "443/443"
  priority          = 1
  security_group_id = alicloud_security_group.app_sg.id
  cidr_ip           = "0.0.0.0/0"
}
Enter fullscreen mode Exit fullscreen mode

Compute:

resource "alicloud_instance" "app_server" {
  instance_name              = "ecs-app-01"
  instance_type              = "ecs.g6.large"
  image_id                   = "aliyun_3_x64_20G_alibase_20240628.vhd"
  vswitch_id                 = alicloud_vswitch.app.id
  security_groups            = [alicloud_security_group.app_sg.id]
  internet_max_bandwidth_out = 5
  system_disk_category       = "cloud_essd"

  tags = { environment = "production", managed_by = "terraform" }
}
Enter fullscreen mode Exit fullscreen mode

Storage (OSS):

resource "alicloud_oss_bucket" "app_assets" {
  bucket = "app-static-assets-prod"
}

# ACL is a separate resource as of provider 1.220+ — "private" is also
# the bucket's default, but set it explicitly rather than relying on it.
resource "alicloud_oss_bucket_acl" "app_assets" {
  bucket = alicloud_oss_bucket.app_assets.bucket
  acl    = "private"
}
Enter fullscreen mode Exit fullscreen mode

Load balancing:

resource "alicloud_slb_load_balancer" "app_lb" {
  load_balancer_name = "slb-app-prod"
  vswitch_id          = alicloud_vswitch.app.id
  load_balancer_spec  = "slb.s2.small"
}

resource "alicloud_slb_listener" "https" {
  load_balancer_id = alicloud_slb_load_balancer.app_lb.id
  backend_port     = 443
  frontend_port    = 443
  protocol         = "tcp"
  bandwidth        = 10
}
Enter fullscreen mode Exit fullscreen mode

A RAM role scoped to what the app actually needs — read access to its own OSS bucket, nothing account-wide:

resource "alicloud_ram_role" "app_role" {
  role_name                 = "app-server-role"
  assume_role_policy_document = jsonencode({
    Statement = [{
      Action    = "sts:AssumeRole"
      Effect    = "Allow"
      Principal = { Service = ["ecs.aliyuncs.com"] }
    }]
    Version = "1"
  })
}
Enter fullscreen mode Exit fullscreen mode

Data tier (optional RDS), scoped to the app-tier CIDR only:

resource "alicloud_db_instance" "primary" {
  engine           = "MySQL"
  engine_version   = "8.0"
  instance_type    = "rds.mysql.s2.large"
  instance_storage = 100
  vswitch_id       = alicloud_vswitch.data.id
  instance_name    = "rds-prod-primary"
  security_ips     = ["10.10.1.0/24"]
}
Enter fullscreen mode Exit fullscreen mode

Outputs, so the deployment hands back what a consumer actually needs:

output "load_balancer_ip" {
  value = alicloud_slb_load_balancer.app_lb.address
}
output "oss_bucket_name" {
  value = alicloud_oss_bucket.app_assets.bucket
}
Enter fullscreen mode Exit fullscreen mode

04 — Repository Structure, and Why It's Shaped This Way

terraform-alibaba/
├── main.tf
├── provider.tf
├── variables.tf
├── outputs.tf
├── versions.tf
├── terraform.tfvars
├── modules/
│   ├── network/
│   ├── ecs/
│   ├── security/
│   └── storage/
└── environments/
    ├── dev/
    ├── staging/
    └── production/
Enter fullscreen mode Exit fullscreen mode
  • modules/ isolates each infrastructure concern (network, compute, security, storage) so a change to how ECS is provisioned doesn't require touching network code.
  • environments/ keeps dev/staging/production as separate root configurations calling the same modules with different variables — the environment differs in scale and CIDR ranges, not in the underlying architecture.
  • versions.tf pins the provider source and Terraform CLI version separately from main.tf, so a version bump is a one-file, reviewable diff.

This is the difference between "knows Terraform syntax" and "can structure a Terraform project" — the second is what actually gets evaluated in a real engineering review.


05 — The Terraform Lifecycle

WRITE
  ↓
terraform fmt
  ↓
terraform validate
  ↓
terraform plan
  ↓
CODE REVIEW
  ↓
terraform apply
  ↓
STATE
  ↓
DRIFT DETECTION
  ↓
UPDATE
Enter fullscreen mode Exit fullscreen mode

Alibaba's documentation covers init, plan, apply, and destroy, with plan previewing changes before they're applied. Two commands worth treating as non-negotiable in a professional workflow, beyond that baseline:

terraform fmt -check    # enforce consistent formatting, fail CI if not run
terraform validate      # catch syntax/config errors before a plan even runs
Enter fullscreen mode Exit fullscreen mode

Skipping these two doesn't save time — it just moves the failure from a 2-second local check to a slower, more visible CI failure or a bad plan output nobody trusts.


06 — State Management

Why does Terraform need state at all? Because it has to answer one question before every apply: "what did I create previously?"

Terraform configuration
        +
Terraform state
        +
Actual Alibaba Cloud infrastructure
        ↓
Terraform determines the difference
Enter fullscreen mode Exit fullscreen mode

Without state, every apply would have no way to distinguish "create this new resource" from "this resource already exists, only these two fields changed." State is the memory that makes incremental, non-destructive updates possible.

What a serious state practice covers:

  • Remote state — an OSS bucket, never a local .tfstate file, and never committed to Git (it can contain sensitive values in plain text).
  • State locking — prevents two people running apply simultaneously from corrupting state; pair the OSS backend with Table Store for lock coordination.
  • State backup — versioning enabled on the state bucket, so a bad apply's prior state is recoverable.
  • Sensitive information — database passwords and similar values that land in state should be sourced from a secrets manager reference, not a plaintext variable default.
  • Team collaboration — remote state with locking is what makes concurrent team usage safe at all.
  • State isolation between environments — dev, staging, and production each need their own state file; one shared state file across environments is how a terraform destroy in dev takes down production by accident.
terraform {
  backend "oss" {
    bucket = "terraform-state-prod-apac"
    key    = "network/terraform.tfstate"
    region = "ap-southeast-1"
  }
}
Enter fullscreen mode Exit fullscreen mode

07 — Terraform vs. the Alibaba Cloud Console

Task Console Terraform
One-off VM Excellent Overkill
Repeat environment Poor Excellent
Version control Limited Excellent
Code review Limited Excellent
Multi-environment Manual Excellent
Disaster recovery Manual Strong
Large infrastructure Difficult Strong
Learning curve Low Higher

Alibaba's own documentation draws essentially this same distinction — Terraform earns its complexity budget at the point where an environment needs to be repeatable, reviewable, or reproduced more than once. A single throwaway test VM doesn't need a Terraform module; a production environment always does.


08 — Modules: From Script to Architecture

module "network" {
  source      = "./modules/network"
  vpc_cidr    = var.vpc_cidr
  environment = var.environment
}
Enter fullscreen mode Exit fullscreen mode

Resource → Module → Environment is the progression that turns Terraform from a scripting tool into reusable infrastructure architecture. The Registry already has community modules worth knowing about — the alibaba/vpc/alicloud module, for instance, wraps VPC, VSwitch, and route-entry resources into a single reusable call — worth evaluating before writing an equivalent module from scratch.


09 — Multi-Environment Design

                 Terraform Modules
                        │
             ┌──────────┼──────────┐
             ▼          ▼          ▼
            DEV       STAGING      PROD
             │          │          │
             ▼          ▼          ▼
           Alibaba Cloud environments
Enter fullscreen mode Exit fullscreen mode

The difference between environment = "dev" and environment = "production" isn't just a variable value — it's isolation: separate state files, separate VPC CIDR ranges (so they can never accidentally peer), separate credentials with separate permission scopes, and in most orgs, a manual-approval gate on production apply that doesn't exist for dev. Environment isolation is a security and blast-radius boundary, not a naming convention.


10 — CI/CD

Developer
    │
    ▼
Git push
    │
    ▼
CI Pipeline
    │
    ├── terraform fmt
    ├── terraform validate
    ├── security scan
    └── terraform plan
             │
             ▼
        Pull Request
             │
          Approval
             │
             ▼
       terraform apply
             │
             ▼
       Alibaba Cloud
Enter fullscreen mode Exit fullscreen mode

This is the step that turns isolated Terraform knowledge into an actual DevOps practice: plan output posted to the pull request for human review, apply gated behind approval, and a security scan (tfsec/checkov) catching a public 0.0.0.0/0 security-group rule or an unencrypted OSS bucket before it merges — the same gate a CI pipeline enforces on application code, applied to infrastructure code.


11 — Drift Detection

The scenario every team eventually hits: someone opens the Alibaba Cloud console and manually changes a security group rule "just to fix something quickly" — port 22 gets opened where Terraform's configuration says it should stay restricted.

Terraform configuration says:  Port 443 = allowed, Port 22 = restricted
Actual infrastructure says:    Port 22 = open
Enter fullscreen mode Exit fullscreen mode
terraform plan
Enter fullscreen mode Exit fullscreen mode

This single command surfaces the exact drift — Terraform reads the real infrastructure state and diffs it against configuration, and the plan output shows the manual change as something Terraform intends to revert. This is one of the strongest arguments for IaC over console-driven changes: the drift isn't just detected, it's specifically named, in a way a manual audit would take far longer to catch.


12 — What Terraform Doesn't Manage

Terraform is excellent for infrastructure lifecycle management — it is not a full configuration-management system. Alibaba's own Terraform provider documentation is explicit that Terraform manages infrastructure resources, not system-level operational tasks like installing software or managing OS updates.

Terraform
    ↓
Infrastructure
    ↓
ECS / VPC / SLB / OSS
    ↓
Ansible / cloud-init / containers
    ↓
Application configuration
Enter fullscreen mode Exit fullscreen mode

Knowing this boundary is a maturity signal — a common mistake is trying to force Terraform's null_resource + remote-exec into doing configuration management that a purpose-built tool (Ansible, cloud-init, or a container image) handles far more reliably.


13 — Connecting to the AI Infrastructure Article

This isn't an isolated tutorial — it's the infrastructure layer underneath this series' AI Infrastructure article:

Terraform
    │
    ├── VPC
    ├── ECS GPU
    ├── OSS
    ├── Security
    │
    ▼
Alibaba Cloud Infrastructure
    │
    ▼
PAI
    │
    ├── DSW
    ├── DLC
    └── EAS
    │
    ▼
AI Application
Enter fullscreen mode Exit fullscreen mode

Real-world scenario: deploying an AI application on Alibaba Cloud needs GPU ECS, a VPC with a private subnet, OSS for model storage, PAI, a load balancer, security groups, and a CI/CD pipeline gating all of it. Terraform establishes every piece of that infrastructure layer before PAI's DSW/DLC/EAS ever touches a workload — the two articles are one continuous engineering path, not two separate topics that happen to both mention Alibaba Cloud.


Final Takeaways

The value here isn't "learn a fourth cloud provider's resource names" — it's proving that a well-formed Terraform practice transfers: the resources differ, the naming differs, but modular structure, remote state with locking, environment isolation, CI-gated plan/apply, and drift detection are identical disciplines regardless of which cloud sits above the API.

My recommendation: treat Terraform on Alibaba Cloud exactly like Terraform anywhere else — pin the provider source explicitly, never let state live locally, gate production apply behind review, and stop at the boundary where configuration management should take over. Get that discipline right once, and it ports to the next provider almost unchanged.

GitHub Repository: terraform-alibaba-cloud-lab — the full modular project: network/security/ecs/storage modules composed into a production environment, ready to run.

Reviewed against current Alibaba Cloud Terraform documentation and the Terraform Registry as of September 2026.

Terraform · Alibaba Cloud · Multi-Cloud IaC · State Management · Modules · CI/CD · Drift Detection


Originally published on my portfolio.

Top comments (0)