Add Alibaba Cloud Terraform template and modules

This commit is contained in:
shenlan 2025-11-21 07:38:13 +08:00
parent 5f9843ef1f
commit b80888cbd9
28 changed files with 1082 additions and 0 deletions

View File

@ -0,0 +1,31 @@
# Alibaba Cloud Terraform Standard
该目录提供与 AWS 目录对应的阿里云版本,用于在阿里云上快速引导基础设施。结构与 AWS 模板保持一致,包含引导阶段 (bootstrap)、环境示例 (envs) 与模块库 (modules)。
## AWS → Alibaba Cloud 映射
- **S3 → OSS**`bootstrap-oss` 创建远端状态桶,开启版本化与服务器端加密。
- **DynamoDB → TableStore (OTS)**`bootstrap-ots` 创建状态锁表,用于 Terraform 后端锁定。
- **IAM → RAM**`bootstrap-ram` 建立基础访问控制RAM 角色、策略与用户)。
- **VPC**`modules/vpc` 使用专有网络与交换机,替代 AWS VPC/Subnet。
- **ALB / NLB**`modules/alb` 和 `modules/nlb` 分别映射到应用型负载均衡 (ALB) 与传统负载均衡 (SLB/NLB)。
- **EC2 → ECS**`modules/ecs` 提供计算实例与安全组。
- **S3 → OSS**`modules/oss` 作为通用对象存储模块。
- **IAM → RAM**`modules/ram` 封装 RAM 角色与策略创建。
- **RDS / Redis / MSK**`modules/rds`、`modules/redis` 提供 ApsaraDB 数据库与缓存Kafka 类似需求可通过云消息队列/中间件扩展。
## 使用方式
1. 在 `config/backend.tf` 中配置远端状态OSS 桶与可选 OTS 锁表)。
2. 在 `config/provider.tf` 中设置 `region`、`access_key`、`secret_key` 或 RAM 角色扮演信息,可通过环境变量传入。
3. 运行引导阶段:
```bash
terraform -chdir=bootstrap-oss init && terraform -chdir=bootstrap-oss apply
terraform -chdir=bootstrap-ots init && terraform -chdir=bootstrap-ots apply
terraform -chdir=bootstrap-ram init && terraform -chdir=bootstrap-ram apply
```
4. 按需修改 `envs/dev` 下的示例,执行:
```bash
terraform -chdir=envs/dev init
terraform -chdir=envs/dev apply
```
本目录仅新增阿里云模板,不改动现有 AWS/GCP 代码。

View File

@ -0,0 +1,29 @@
terraform {
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = ">= 1.210.0"
}
}
}
provider "alicloud" {
region = var.region
}
resource "alicloud_oss_bucket" "state" {
bucket = var.state_bucket
acl = var.acl
versioning {
status = "Enabled"
}
server_side_encryption_rule {
sse_algorithm = "AES256"
}
}
output "bucket" {
value = alicloud_oss_bucket.state.bucket
}

View File

@ -0,0 +1,16 @@
variable "region" {
description = "Alibaba Cloud region for OSS"
type = string
default = "cn-hangzhou"
}
variable "state_bucket" {
description = "Name of the OSS bucket used for remote state"
type = string
}
variable "acl" {
description = "ACL for the OSS bucket"
type = string
default = "private"
}

View File

@ -0,0 +1,35 @@
terraform {
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = ">= 1.210.0"
}
}
}
provider "alicloud" {
region = var.region
}
resource "alicloud_ots_instance" "this" {
instance_name = var.instance_name
description = "Terraform state locking"
accessed_by = "Any"
}
resource "alicloud_ots_table" "lock" {
instance_name = alicloud_ots_instance.this.name
table_name = var.table_name
time_to_live = -1
max_version = 1
primary_key {
name = "LockID"
type = "STRING"
}
}
output "lock_table" {
value = alicloud_ots_table.lock.table_name
}

View File

@ -0,0 +1,17 @@
variable "region" {
description = "Alibaba Cloud region for OTS"
type = string
default = "cn-hangzhou"
}
variable "instance_name" {
description = "Name of the OTS instance"
type = string
default = "terraform-locks"
}
variable "table_name" {
description = "Name of the lock table"
type = string
default = "terraform-locks"
}

View File

@ -0,0 +1,104 @@
terraform {
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = ">= 1.210.0"
}
}
}
provider "alicloud" {
region = var.region
}
locals {
assume_principal = "acs:ram::${var.account_id}:root"
}
resource "alicloud_ram_role" "terraform" {
name = var.role_name
document = <<POLICY
{
"Version": "1",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"RAM": ["${local.assume_principal}"]
}
}
]
}
POLICY
description = "Role assumed by CI/CD or operators for Terraform"
force = true
}
resource "alicloud_ram_policy" "terraform_admin" {
name = var.policy_name
description = "Terraform administrative access"
document = <<POLICY
{
"Version": "1",
"Statement": [
{
"Action": [
"ecs:*",
"vpc:*",
"oss:*",
"ram:*",
"slb:*",
"alb:*",
"rds:*",
"kvstore:*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
POLICY
force = true
}
resource "alicloud_ram_role_policy_attachment" "role_attach" {
policy_name = alicloud_ram_policy.terraform_admin.name
policy_type = alicloud_ram_policy.terraform_admin.type
role_name = alicloud_ram_role.terraform.name
}
resource "alicloud_ram_user" "terraform" {
name = var.user_name
display_name = "terraform-automation"
force = true
}
resource "alicloud_ram_user_policy_attachment" "user_attach" {
policy_name = alicloud_ram_policy.terraform_admin.name
policy_type = alicloud_ram_policy.terraform_admin.type
user_name = alicloud_ram_user.terraform.name
}
resource "alicloud_ram_access_key" "terraform" {
user_name = alicloud_ram_user.terraform.name
}
output "ram_role_name" {
value = alicloud_ram_role.terraform.name
}
output "ram_user_name" {
value = alicloud_ram_user.terraform.name
}
output "access_key_id" {
value = alicloud_ram_access_key.terraform.id
description = "Access key ID for terraform user"
}
output "access_key_secret" {
value = alicloud_ram_access_key.terraform.secret
description = "Access key secret for terraform user"
sensitive = true
}

View File

@ -0,0 +1,28 @@
variable "region" {
description = "Alibaba Cloud region"
type = string
default = "cn-hangzhou"
}
variable "account_id" {
description = "Alibaba Cloud account ID used for trust policy"
type = string
}
variable "role_name" {
description = "Name of RAM role used by Terraform"
type = string
default = "TerraformExecutionRole"
}
variable "policy_name" {
description = "Custom policy name granting Terraform permissions"
type = string
default = "TerraformAdministrator"
}
variable "user_name" {
description = "Name of RAM user for Terraform automation"
type = string
default = "terraform"
}

View File

@ -0,0 +1,10 @@
terraform {
required_version = ">= 1.5.0"
backend "oss" {
bucket = var.state_bucket
prefix = var.state_prefix
region = var.region
tablestore_table = var.lock_table
}
}

View File

@ -0,0 +1,23 @@
terraform {
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = ">= 1.210.0"
}
}
}
provider "alicloud" {
region = var.region
access_key = var.access_key
secret_key = var.secret_key
security_token = var.security_token
dynamic "assume_role" {
for_each = var.ram_role_arn == null ? [] : [var.ram_role_arn]
content {
role_arn = assume_role.value
session_name = var.session_name
}
}
}

View File

@ -0,0 +1,54 @@
variable "region" {
description = "Default Alibaba Cloud region"
type = string
default = "cn-hangzhou"
}
variable "access_key" {
description = "Alibaba Cloud Access Key ID"
type = string
default = null
}
variable "secret_key" {
description = "Alibaba Cloud Access Key Secret"
type = string
default = null
sensitive = true
}
variable "security_token" {
description = "Optional security token when using STS credentials"
type = string
default = null
sensitive = true
}
variable "ram_role_arn" {
description = "Optional RAM role ARN to assume for operations"
type = string
default = null
}
variable "session_name" {
description = "Session name when assuming a RAM role"
type = string
default = "terraform"
}
variable "state_bucket" {
description = "OSS bucket used for Terraform remote state"
type = string
}
variable "state_prefix" {
description = "Prefix within the remote state bucket"
type = string
default = "terraform/state"
}
variable "lock_table" {
description = "OTS table used for state locking"
type = string
default = "terraform-locks"
}

View File

@ -0,0 +1,99 @@
terraform {
required_version = ">= 1.5.0"
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = ">= 1.210.0"
}
}
}
provider "alicloud" {
region = var.region
}
module "network" {
source = "../modules/vpc"
name = var.vpc_name
cidr_block = var.vpc_cidr
vswitches = var.vswitches
}
locals {
zone_mappings = [for key, cfg in var.vswitches : {
vswitch_id = module.network.vswitch_ids[key]
zone_id = cfg.az
}]
primary_vswitch = module.network.vswitch_ids[local.primary_vswitch_key]
primary_vswitch_key = keys(module.network.vswitch_ids)[0]
}
module "alb" {
source = "../modules/alb"
name = "dev-alb"
vpc_id = module.network.vpc_id
zone_mappings = local.zone_mappings
address_type = "Internet"
edition = "Standard"
protocol = "HTTP"
listener_port = 80
}
module "nlb" {
source = "../modules/nlb"
name = "dev-nlb"
vswitch_id = local.primary_vswitch
address_type = "Internet"
spec = "slb.s2.small"
protocol = "tcp"
frontend_port = 443
backend_port = 443
}
module "bucket" {
source = "../modules/oss"
name = var.bucket_name
enable_versioning = true
}
module "compute" {
source = "../modules/ecs"
name = "dev-ecs"
vpc_id = module.network.vpc_id
vswitch_id = local.primary_vswitch
instance_type = var.instance_type
image_id = var.image_id
key_name = var.key_name
internet_max_bandwidth_out = 50
}
module "database" {
source = "../modules/rds"
vpc_id = module.network.vpc_id
vswitch_id = local.primary_vswitch
engine = "MySQL"
engine_version = "8.0"
instance_type = var.rds_instance_type
account_password = var.rds_password
}
module "cache" {
source = "../modules/redis"
name = "dev-redis"
vpc_id = module.network.vpc_id
vswitch_id = local.primary_vswitch
password = var.redis_password
engine_version = "6.0"
}
output "vpc_id" {
value = module.network.vpc_id
}
output "alb_endpoint" {
value = module.alb.alb_id
}
output "ecs_instance" {
value = module.compute.instance_id
}

View File

@ -0,0 +1,71 @@
variable "region" {
description = "Deployment region"
type = string
default = "cn-hangzhou"
}
variable "vpc_name" {
description = "VPC name"
type = string
default = "dev-vpc"
}
variable "vpc_cidr" {
description = "VPC CIDR"
type = string
default = "10.10.0.0/16"
}
variable "vswitches" {
description = "Map of vswitch definitions"
type = map(object({
cidr = string
az = string
}))
default = {
a = { cidr = "10.10.1.0/24", az = "cn-hangzhou-b" }
b = { cidr = "10.10.2.0/24", az = "cn-hangzhou-c" }
}
}
variable "instance_type" {
description = "ECS instance type"
type = string
default = "ecs.g6.large"
}
variable "image_id" {
description = "ECS image ID"
type = string
default = "aliyun_2_1903_x64_20G_alibase_20240223.vhd"
}
variable "key_name" {
description = "SSH key pair name"
type = string
default = null
}
variable "bucket_name" {
description = "OSS bucket name"
type = string
default = "dev-terraform-oss"
}
variable "rds_instance_type" {
description = "RDS instance type"
type = string
default = "rds.mysql.c1.large"
}
variable "rds_password" {
description = "RDS account password"
type = string
sensitive = true
}
variable "redis_password" {
description = "Redis password"
type = string
sensitive = true
}

View File

@ -0,0 +1,49 @@
resource "alicloud_alb_load_balancer" "this" {
load_balancer_name = var.name
address_type = var.address_type
load_balancer_edition = var.edition
vpc_id = var.vpc_id
address_allocated_mode = "Dynamic"
dynamic "zone_mappings" {
for_each = var.zone_mappings
content {
vswitch_id = zone_mappings.value.vswitch_id
zone_id = zone_mappings.value.zone_id
}
}
}
resource "alicloud_alb_server_group" "this" {
server_group_name = "${var.name}-sg"
vpc_id = var.vpc_id
protocol = var.protocol
}
resource "alicloud_alb_listener" "http" {
load_balancer_id = alicloud_alb_load_balancer.this.id
listener_port = var.listener_port
listener_protocol = var.protocol
default_actions {
type = "ForwardGroup"
forward_group_config {
server_group_tuples {
server_group_id = alicloud_alb_server_group.this.id
}
}
}
}
output "alb_id" {
value = alicloud_alb_load_balancer.this.id
}
output "listener_id" {
value = alicloud_alb_listener.http.id
}
output "server_group_id" {
value = alicloud_alb_server_group.this.id
}

View File

@ -0,0 +1,41 @@
variable "name" {
description = "ALB name"
type = string
}
variable "vpc_id" {
description = "VPC ID for the ALB"
type = string
}
variable "address_type" {
description = "Address type: Internet or Intranet"
type = string
default = "Internet"
}
variable "edition" {
description = "Load balancer edition"
type = string
default = "Standard"
}
variable "protocol" {
description = "Listener protocol"
type = string
default = "HTTP"
}
variable "listener_port" {
description = "Listener port"
type = number
default = 80
}
variable "zone_mappings" {
description = "List of zone mappings with vswitch_id and zone_id"
type = list(object({
vswitch_id = string
zone_id = string
}))
}

View File

@ -0,0 +1,37 @@
resource "alicloud_security_group" "this" {
name = "${var.name}-sg"
vpc_id = var.vpc_id
}
resource "alicloud_security_group_rule" "ssh" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "intranet"
policy = "accept"
port_range = "22/22"
priority = 1
security_group_id = alicloud_security_group.this.id
cidr_ip = var.ssh_cidr
}
resource "alicloud_instance" "this" {
instance_name = var.name
host_name = var.name
image_id = var.image_id
instance_type = var.instance_type
vswitch_id = var.vswitch_id
security_groups = [alicloud_security_group.this.id]
system_disk_category = var.system_disk_category
system_disk_size = var.system_disk_size
internet_max_bandwidth_out = var.internet_max_bandwidth_out
key_name = var.key_name
user_data = var.user_data
}
output "instance_id" {
value = alicloud_instance.this.id
}
output "private_ip" {
value = alicloud_instance.this.private_ip
}

View File

@ -0,0 +1,62 @@
variable "name" {
description = "ECS instance name"
type = string
}
variable "vpc_id" {
description = "VPC ID for the ECS instance"
type = string
}
variable "vswitch_id" {
description = "VSwitch ID to place the instance"
type = string
}
variable "image_id" {
description = "Image ID"
type = string
default = "aliyun_2_1903_x64_20G_alibase_20240223.vhd"
}
variable "instance_type" {
description = "Instance type"
type = string
default = "ecs.g6.large"
}
variable "system_disk_category" {
description = "System disk category"
type = string
default = "cloud_essd"
}
variable "system_disk_size" {
description = "System disk size in GB"
type = number
default = 40
}
variable "internet_max_bandwidth_out" {
description = "Max outbound bandwidth"
type = number
default = 10
}
variable "key_name" {
description = "SSH key pair name"
type = string
default = null
}
variable "ssh_cidr" {
description = "CIDR allowed for SSH"
type = string
default = "0.0.0.0/0"
}
variable "user_data" {
description = "Optional user data"
type = string
default = null
}

View File

@ -0,0 +1,34 @@
resource "alicloud_slb_load_balancer" "this" {
name = var.name
address_type = var.address_type
load_balancer_spec = var.spec
vswitch_id = var.vswitch_id
internet_charge_type = "paybytraffic"
}
resource "alicloud_slb_server_group" "this" {
load_balancer_id = alicloud_slb_load_balancer.this.id
name = "${var.name}-sg"
}
resource "alicloud_slb_listener" "tcp" {
load_balancer_id = alicloud_slb_load_balancer.this.id
backend_port = var.backend_port
frontend_port = var.frontend_port
bandwidth = -1
protocol = var.protocol
health_check {
health_check_interval = 5
healthy_threshold = 3
unhealthy_threshold = 3
}
}
output "nlb_id" {
value = alicloud_slb_load_balancer.this.id
}
output "listener_id" {
value = alicloud_slb_listener.tcp.id
}

View File

@ -0,0 +1,39 @@
variable "name" {
description = "SLB/NLB name"
type = string
}
variable "vswitch_id" {
description = "VSwitch ID for the load balancer"
type = string
}
variable "address_type" {
description = "Address type"
type = string
default = "Internet"
}
variable "spec" {
description = "Load balancer specification"
type = string
default = "slb.s2.small"
}
variable "protocol" {
description = "Listener protocol"
type = string
default = "tcp"
}
variable "frontend_port" {
description = "Frontend listener port"
type = number
default = 80
}
variable "backend_port" {
description = "Backend server port"
type = number
default = 80
}

View File

@ -0,0 +1,16 @@
resource "alicloud_oss_bucket" "this" {
bucket = var.name
acl = var.acl
versioning {
status = var.enable_versioning ? "Enabled" : "Suspended"
}
server_side_encryption_rule {
sse_algorithm = var.sse_algorithm
}
}
output "bucket" {
value = alicloud_oss_bucket.this.bucket
}

View File

@ -0,0 +1,22 @@
variable "name" {
description = "OSS bucket name"
type = string
}
variable "acl" {
description = "Bucket ACL"
type = string
default = "private"
}
variable "enable_versioning" {
description = "Enable bucket versioning"
type = bool
default = true
}
variable "sse_algorithm" {
description = "Server-side encryption algorithm"
type = string
default = "AES256"
}

View File

@ -0,0 +1,45 @@
locals {
principals = [for principal in var.assume_principals : "acs:ram::${principal}:root"]
}
resource "alicloud_ram_role" "this" {
name = var.role_name
document = jsonencode({
Version = "1"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = { RAM = local.principals }
}]
})
description = var.description
force = true
}
resource "alicloud_ram_policy" "this" {
name = var.policy_name
description = "Custom RAM policy"
document = jsonencode({
Version = "1"
Statement = [{
Action = var.actions
Effect = "Allow"
Resource = var.resource
}]
})
force = true
}
resource "alicloud_ram_role_policy_attachment" "attachment" {
policy_name = alicloud_ram_policy.this.name
policy_type = alicloud_ram_policy.this.type
role_name = alicloud_ram_role.this.name
}
output "role_name" {
value = alicloud_ram_role.this.name
}
output "policy_name" {
value = alicloud_ram_policy.this.name
}

View File

@ -0,0 +1,31 @@
variable "role_name" {
description = "RAM role name"
type = string
}
variable "policy_name" {
description = "Policy name"
type = string
}
variable "assume_principals" {
description = "List of account IDs allowed to assume the role"
type = list(string)
}
variable "actions" {
description = "Actions allowed by the policy"
type = list(string)
}
variable "resource" {
description = "Resource ARN(s)"
type = string
default = "*"
}
variable "description" {
description = "Role description"
type = string
default = "Custom RAM role"
}

View File

@ -0,0 +1,33 @@
resource "alicloud_db_instance" "this" {
engine = var.engine
engine_version = var.engine_version
instance_type = var.instance_type
db_instance_storage_type = var.storage_type
db_instance_storage = var.storage
instance_charge_type = "PostPaid"
vswitch_id = var.vswitch_id
vpc_id = var.vpc_id
security_ip_list = join(",", var.security_ips)
}
resource "alicloud_db_account" "this" {
db_instance_id = alicloud_db_instance.this.id
account_name = var.account_name
account_password = var.account_password
}
resource "alicloud_db_database" "this" {
count = var.create_database ? 1 : 0
db_instance_id = alicloud_db_instance.this.id
name = var.database_name
character_set = "utf8mb4"
description = "managed by terraform"
}
output "instance_id" {
value = alicloud_db_instance.this.id
}
output "connection_string" {
value = alicloud_db_instance.this.connection_string
}

View File

@ -0,0 +1,69 @@
variable "engine" {
description = "Database engine"
type = string
default = "MySQL"
}
variable "engine_version" {
description = "Engine version"
type = string
default = "8.0"
}
variable "instance_type" {
description = "RDS instance type"
type = string
default = "rds.mysql.c1.large"
}
variable "storage_type" {
description = "Storage type"
type = string
default = "cloud_essd"
}
variable "storage" {
description = "Storage size in GB"
type = number
default = 50
}
variable "vpc_id" {
description = "VPC ID"
type = string
}
variable "vswitch_id" {
description = "VSwitch ID"
type = string
}
variable "security_ips" {
description = "List of IPs allowed to access RDS"
type = list(string)
default = ["0.0.0.0/0"]
}
variable "account_name" {
description = "Database account name"
type = string
default = "terraform"
}
variable "account_password" {
description = "Database account password"
type = string
sensitive = true
}
variable "create_database" {
description = "Whether to create a database"
type = bool
default = true
}
variable "database_name" {
description = "Database name"
type = string
default = "appdb"
}

View File

@ -0,0 +1,17 @@
resource "alicloud_kvstore_instance" "this" {
instance_name = var.name
instance_class = var.instance_class
engine_version = var.engine_version
vswitch_id = var.vswitch_id
vpc_id = var.vpc_id
password = var.password
payment_type = "PostPaid"
}
output "instance_id" {
value = alicloud_kvstore_instance.this.id
}
output "connection_string" {
value = alicloud_kvstore_instance.this.connection_domain
}

View File

@ -0,0 +1,32 @@
variable "name" {
description = "Redis instance name"
type = string
}
variable "instance_class" {
description = "Instance class"
type = string
default = "redis.master.small.default"
}
variable "engine_version" {
description = "Redis engine version"
type = string
default = "6.0"
}
variable "vpc_id" {
description = "VPC ID"
type = string
}
variable "vswitch_id" {
description = "VSwitch ID"
type = string
}
variable "password" {
description = "Instance password"
type = string
sensitive = true
}

View File

@ -0,0 +1,20 @@
resource "alicloud_vpc" "this" {
name = var.name
cidr_block = var.cidr_block
}
resource "alicloud_vswitch" "this" {
for_each = var.vswitches
vpc_id = alicloud_vpc.this.id
cidr_block = each.value.cidr
zone_id = each.value.az
vswitch_name = "${var.name}-${each.key}"
}
output "vpc_id" {
value = alicloud_vpc.this.id
}
output "vswitch_ids" {
value = { for k, v in alicloud_vswitch.this : k => v.id }
}

View File

@ -0,0 +1,18 @@
variable "name" {
description = "Name of the VPC"
type = string
}
variable "cidr_block" {
description = "CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
}
variable "vswitches" {
description = "Map of vswitches with cidr and az, e.g. { a = { cidr = \"10.0.1.0/24\", az = \"cn-hangzhou-b\" } }"
type = map(object({
cidr = string
az = string
}))
}