Add Vultr VPS Terraform template and modules

This commit is contained in:
shenlan 2025-11-21 07:37:21 +08:00
parent 5f9843ef1f
commit e87d9a267a
13 changed files with 798 additions and 0 deletions

View File

@ -0,0 +1,36 @@
# Vultr VPS Terraform Standard
此目录在保持 AWS 模板目录结构的同时,提供 Vultr VPS 的等效实现,方便在 Vultr 上快速落地基础设施。模板包含引导阶段bootstrap、环境示例envs与模块库modules`aws-cloud`/`gcp-cloud` 目录一一对应。
## AWS → Vultr 资源映射
- **VPC (aws_vpc)**`vultr_vpc`:创建私网并自定义 IPv4 段。
- **EC2 (aws_instance)**`vultr_instance`:创建 VPS/计算实例,支持自定义镜像与云初始化脚本。
- **S3 (aws_s3_bucket)**`vultr_object_storage`:提供 S3 兼容对象存储,可用于远端状态与应用资产。
- **IAM (aws_iam_user/role + aws_key_pair)**`vultr_user` + `vultr_ssh_key`:管理子账号权限与 SSH 公钥分发。
- **RDS (aws_db_instance)**`vultr_database`托管数据库MySQL/PostgreSQL/Redis支持自动备份与高可用套餐。
## 目录结构
- `bootstrap-object-storage/`:初始化 Vultr 对象存储集群与访问密钥,可作为 Terraform 远端状态桶。
- `bootstrap-iam/`:创建子账号与 SSH Key实现最小权限访问与实例登录。
- `config/`:包含通用的 `backend.tf``provider.tf`,用于配置 S3 兼容后端与 Vultr Provider。
- `modules/`核心模块实现vpc、compute、storage、iam、data_store接口与 AWS 模块命名保持一致。
- `envs/`:示例环境(`dev`)展示如何组合模块。
## 使用方式
1. 在 `config/backend.tf` 中填写 Vultr 对象存储的 endpoint、bucket、访问密钥`config/provider.tf` 设置 `vultr_api_key` 与默认 region。
2. 使用引导模板创建状态桶与基础身份:
```bash
terraform -chdir=bootstrap-object-storage init
terraform -chdir=bootstrap-object-storage apply
terraform -chdir=bootstrap-iam init
terraform -chdir=bootstrap-iam apply
```
3. 根据需要复制 `envs/dev`,调整变量后运行:
```bash
terraform -chdir=envs/dev init
terraform -chdir=envs/dev apply
```
4. 模块可单独在 `envs` 下拆分(如 `dev-vpc`, `dev-compute`),以匹配 AWS 目录的分环境实践。
> 本目录只新增 Vultr 代码,不改动既有 AWS/GCP 模板。

View File

@ -0,0 +1,70 @@
terraform {
required_version = ">= 1.5"
required_providers {
vultr = {
source = "vultr/vultr"
version = "~> 2.19"
}
}
}
provider "vultr" {
api_key = var.vultr_api_key
}
resource "vultr_user" "readonly" {
email = var.user_email
api_enabled = true
acls = var.acls
password = var.user_password
}
resource "vultr_ssh_key" "bootstrap" {
name = var.ssh_key_name
ssh_key = var.public_key
}
output "user_id" {
value = vultr_user.readonly.id
description = "最小权限 API 子账号 ID"
}
output "ssh_key_id" {
value = vultr_ssh_key.bootstrap.id
description = "上传到 Vultr 的 SSH 公钥 ID"
}
variable "vultr_api_key" {
description = "管理账号 API Key"
type = string
sensitive = true
}
variable "user_email" {
description = "子账号邮箱"
type = string
}
variable "user_password" {
description = "子账号初始密码"
type = string
sensitive = true
}
variable "acls" {
description = "授予子账号的权限集合,例如 [\"subscriptions\", \"support\"]"
type = list(string)
default = ["subscriptions", "support", "billing"]
}
variable "ssh_key_name" {
description = "SSH Key 的名称标签"
type = string
default = "bootstrap-key"
}
variable "public_key" {
description = "SSH 公钥内容"
type = string
}

View File

@ -0,0 +1,85 @@
terraform {
required_version = ">= 1.5"
required_providers {
vultr = {
source = "vultr/vultr"
version = "~> 2.19"
}
}
}
provider "vultr" {
api_key = var.vultr_api_key
}
resource "vultr_object_storage" "state" {
region = var.region
cluster_id = var.cluster_id
label = var.name
smtp_enabled = false
minio_access = true
minio_secret = var.seed_secret
bucket_name = var.bucket
}
resource "vultr_object_storage_key" "state" {
object_storage_id = vultr_object_storage.state.id
description = "terraform-state"
}
output "bucket" {
description = "对象存储桶名称"
value = vultr_object_storage.state.bucket_name
}
output "endpoint" {
description = "S3 兼容 Endpoint"
value = vultr_object_storage.state.s3_hostname
}
output "access_key" {
description = "访问密钥 Access Key"
value = vultr_object_storage_key.state.access_key
sensitive = true
}
output "secret_key" {
description = "访问密钥 Secret Key"
value = vultr_object_storage_key.state.secret_key
sensitive = true
}
variable "vultr_api_key" {
description = "Vultr API Key"
type = string
sensitive = true
}
variable "region" {
description = "Vultr 区域代码"
type = string
}
variable "cluster_id" {
description = "对象存储集群 ID例如 ewr1"
type = string
}
variable "bucket" {
description = "对象存储桶名称"
type = string
}
variable "name" {
description = "资源标签"
type = string
default = "terraform-state"
}
variable "seed_secret" {
description = "可选的初始密钥种子,确保生成的 secret 可追踪"
type = string
default = ""
sensitive = true
}

View File

@ -0,0 +1,46 @@
terraform {
backend "s3" {
endpoint = var.object_storage_endpoint
bucket = var.state_bucket
key = var.state_key
region = var.region
access_key = var.access_key
secret_key = var.secret_key
skip_credentials_validation = true
skip_region_validation = true
skip_requesting_account_id = true
force_path_style = true
}
}
variable "object_storage_endpoint" {
description = "Vultr 对象存储的 S3 兼容 Endpoint (例如 https://ewr1.vultrobjects.com)"
type = string
}
variable "state_bucket" {
description = "用于存储 Terraform state 的对象存储桶"
type = string
}
variable "state_key" {
description = "state 文件路径,例如 vpc/dev/terraform.tfstate"
type = string
}
variable "region" {
description = "Vultr 区域代码,例如 ewr、sgp、fra"
type = string
}
variable "access_key" {
description = "对象存储访问密钥 Access Key"
type = string
sensitive = true
}
variable "secret_key" {
description = "对象存储访问密钥 Secret Key"
type = string
sensitive = true
}

View File

@ -0,0 +1,21 @@
terraform {
required_version = ">= 1.5"
required_providers {
vultr = {
source = "vultr/vultr"
version = "~> 2.19"
}
}
}
provider "vultr" {
api_key = var.vultr_api_key
rate_limit = 700
}
variable "vultr_api_key" {
description = "Vultr API Key建议通过环境变量 VULTR_API_KEY 提供"
type = string
sensitive = true
}

View File

@ -0,0 +1,6 @@
#cloud-config
package_update: true
package_upgrade: true
runcmd:
- echo "Hello from Vultr dev environment" > /etc/motd
- systemctl enable ssh

View File

@ -0,0 +1,80 @@
terraform {
required_version = ">= 1.5"
required_providers {
vultr = {
source = "vultr/vultr"
version = "~> 2.19"
}
}
}
provider "vultr" {
api_key = var.vultr_api_key
}
module "vpc" {
source = "../modules/vpc"
region = var.region
description = var.vpc_description
v4_subnet = var.v4_subnet
v4_subnet_size = var.v4_subnet_size
}
module "iam" {
source = "../modules/iam"
users = var.users
ssh_keys = var.ssh_keys
}
module "storage" {
source = "../modules/storage"
region = var.region
cluster_id = var.cluster_id
object_bucket = var.object_bucket
enable_block = var.enable_block
block_size_gb = var.block_size_gb
label = "${var.name_prefix}-storage"
}
module "compute" {
source = "../modules/compute"
label = "${var.name_prefix}-vm"
region = var.region
plan = var.plan
os_id = var.os_id
enable_ipv6 = true
backups = true
tags = [var.name_prefix, "dev"]
vpc_id = module.vpc.vpc_id
ssh_key_ids = values(module.iam.ssh_key_ids)
user_data = file(var.user_data_file)
}
module "data_store" {
source = "../modules/data_store"
label = "${var.name_prefix}-db"
region = var.region
engine = var.db_engine
plan = var.db_plan
dbname = var.dbname
username = var.db_username
password = var.db_password
ha = var.db_ha
}
output "vpc_id" {
value = module.vpc.vpc_id
}
output "instance_ip" {
value = module.compute.main_ip
}
output "bucket" {
value = module.storage.bucket_name
}
output "database_dsn" {
value = module.data_store.dsn
}

View File

@ -0,0 +1,144 @@
variable "vultr_api_key" {
description = "Vultr API Key"
type = string
sensitive = true
}
variable "region" {
description = "部署区域"
type = string
default = "ewr"
}
variable "vpc_description" {
description = "VPC 描述"
type = string
default = "dev-vpc"
}
variable "v4_subnet" {
description = "VPC IPv4 段"
type = string
default = "10.20.0.0"
}
variable "v4_subnet_size" {
description = "掩码位数"
type = number
default = 22
}
variable "cluster_id" {
description = "对象存储集群 ID"
type = string
default = "ewr1"
}
variable "object_bucket" {
description = "对象存储桶名称"
type = string
default = "dev-app-bucket"
}
variable "enable_block" {
description = "是否创建块存储"
type = bool
default = true
}
variable "block_size_gb" {
description = "块存储大小"
type = number
default = 100
}
variable "name_prefix" {
description = "资源名前缀"
type = string
default = "demo"
}
variable "plan" {
description = "实例套餐"
type = string
default = "vc2-1c-1gb"
}
variable "os_id" {
description = "操作系统 ID"
type = number
default = 215
}
variable "users" {
description = "子账号配置"
type = list(object({
email = string
password = string
acls = list(string)
}))
default = [
{
email = "devops@example.com"
password = "ChangeMe123!"
acls = ["subscriptions", "support"]
}
]
}
variable "ssh_keys" {
description = "SSH 公钥列表"
type = list(object({
name = string
public = string
}))
default = [
{
name = "dev-key"
public = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKexamplegenerated dev@example"
}
]
}
variable "user_data_file" {
description = "cloud-init 脚本路径"
type = string
default = "cloud-init.yaml"
}
variable "db_engine" {
description = "数据库引擎"
type = string
default = "pg"
}
variable "db_plan" {
description = "数据库套餐"
type = string
default = "vultr-dbaas-startup-cc-1-7-5"
}
variable "dbname" {
description = "数据库名称"
type = string
default = "app"
}
variable "db_username" {
description = "数据库用户名"
type = string
default = "app"
}
variable "db_password" {
description = "数据库密码"
type = string
sensitive = true
default = "ChangeMeP@ssw0rd"
}
variable "db_ha" {
description = "启用数据库高可用"
type = bool
default = false
}

View File

@ -0,0 +1,84 @@
variable "label" {
description = "实例名称"
type = string
}
variable "region" {
description = "Vultr 区域代码"
type = string
}
variable "plan" {
description = "Vultr 计费套餐 (例如 vc2-1c-1gb)"
type = string
}
variable "os_id" {
description = "操作系统 ID参考 Vultr 文档 (例215 为 Ubuntu 22.04)"
type = number
}
variable "enable_ipv6" {
description = "是否启用 IPv6"
type = bool
default = true
}
variable "backups" {
description = "启用自动备份"
type = bool
default = false
}
variable "tags" {
description = "实例标签列表"
type = list(string)
default = []
}
variable "vpc_id" {
description = "可选的 VPC ID将实例加入私网"
type = string
default = null
}
variable "ssh_key_ids" {
description = "已上传的 SSH Key ID 列表"
type = list(string)
default = []
}
variable "user_data" {
description = "cloud-init 用户数据"
type = string
default = ""
}
resource "vultr_instance" "this" {
label = var.label
region = var.region
plan = var.plan
os_id = var.os_id
enable_ipv6 = var.enable_ipv6
backups = var.backups
tags = var.tags
vpc_ids = var.vpc_id == null ? [] : [var.vpc_id]
ssh_key_ids = var.ssh_key_ids
user_data = var.user_data
}
output "instance_id" {
value = vultr_instance.this.id
description = "实例 ID"
}
output "main_ip" {
value = vultr_instance.this.main_ip
description = "主公网 IP"
}
output "default_password" {
value = vultr_instance.this.default_password
description = "系统生成密码(如未使用 SSH Key 时)"
sensitive = true
}

View File

@ -0,0 +1,72 @@
variable "label" {
description = "数据库实例标签"
type = string
default = "app-db"
}
variable "region" {
description = "Vultr 区域代码"
type = string
}
variable "engine" {
description = "数据库引擎 (mysql, pg, redis)"
type = string
}
variable "plan" {
description = "数据库套餐代号(如 vultr-dbaas-startup-cc-1-7-5"
type = string
}
variable "dbname" {
description = "数据库名称"
type = string
default = "app"
}
variable "username" {
description = "数据库用户名"
type = string
default = "app"
}
variable "password" {
description = "数据库密码"
type = string
sensitive = true
}
variable "ha" {
description = "启用高可用"
type = bool
default = false
}
resource "vultr_database" "this" {
label = var.label
region = var.region
plan = var.plan
engine = var.engine
replicas = var.ha ? 1 : 0
database = var.dbname
username = var.username
password = var.password
}
output "dsn" {
description = "标准连接串host:port/database"
value = "${vultr_database.this.hostname}:${vultr_database.this.port}/${vultr_database.this.database}"
}
output "username" {
value = vultr_database.this.username
description = "数据库用户名"
}
output "password" {
value = vultr_database.this.password
sensitive = true
description = "数据库密码"
}

View File

@ -0,0 +1,42 @@
variable "users" {
description = "需要创建的子账号列表"
type = list(object({
email = string
password = string
acls = list(string)
}))
default = []
}
variable "ssh_keys" {
description = "需要上传的 SSH 公钥列表"
type = list(object({
name = string
public = string
}))
default = []
}
resource "vultr_user" "this" {
for_each = { for u in var.users : u.email => u }
email = each.value.email
password = each.value.password
api_enabled = true
acls = each.value.acls
}
resource "vultr_ssh_key" "this" {
for_each = { for k in var.ssh_keys : k.name => k }
name = each.value.name
ssh_key = each.value.public
}
output "user_ids" {
value = { for k, v in vultr_user.this : k => v.id }
description = "创建的子账号 ID 映射"
}
output "ssh_key_ids" {
value = { for k, v in vultr_ssh_key.this : k => v.id }
description = "上传的 SSH Key ID 映射"
}

View File

@ -0,0 +1,80 @@
variable "region" {
description = "Vultr 区域代码"
type = string
}
variable "object_bucket" {
description = "对象存储桶名称"
type = string
}
variable "cluster_id" {
description = "对象存储集群 ID (如 ewr1)"
type = string
}
variable "enable_block" {
description = "是否同时创建块存储卷"
type = bool
default = false
}
variable "block_size_gb" {
description = "块存储大小 (GB)"
type = number
default = 100
}
variable "label" {
description = "资源标签"
type = string
default = "app-storage"
}
resource "vultr_object_storage" "bucket" {
region = var.region
cluster_id = var.cluster_id
label = var.label
bucket_name = var.object_bucket
minio_access = true
}
resource "vultr_object_storage_key" "bucket" {
object_storage_id = vultr_object_storage.bucket.id
description = "app-storage"
}
resource "vultr_block_storage" "volume" {
count = var.enable_block ? 1 : 0
region = var.region
label = "${var.label}-block"
size_gb = var.block_size_gb
block_type = "storage_opt"
}
output "bucket_name" {
value = vultr_object_storage.bucket.bucket_name
description = "创建的对象存储桶"
}
output "bucket_endpoint" {
value = vultr_object_storage.bucket.s3_hostname
description = "S3 兼容 Endpoint"
}
output "access_key" {
value = vultr_object_storage_key.bucket.access_key
sensitive = true
description = "对象存储 Access Key"
}
output "secret_key" {
value = vultr_object_storage_key.bucket.secret_key
sensitive = true
description = "对象存储 Secret Key"
}
output "block_volume_id" {
value = try(vultr_block_storage.volume[0].id, null)
description = "可选块存储卷 ID"
}

View File

@ -0,0 +1,32 @@
variable "region" {
description = "Vultr 区域代码"
type = string
}
variable "description" {
description = "VPC 描述标签"
type = string
default = "app-vpc"
}
variable "v4_subnet" {
description = "VPC 的 IPv4 子网,例如 10.10.0.0/22"
type = string
}
variable "v4_subnet_size" {
description = "子网掩码位数Vultr 需要单独传递"
type = number
}
resource "vultr_vpc" "this" {
region = var.region
description = var.description
v4_subnet = var.v4_subnet
v4_subnet_size = var.v4_subnet_size
}
output "vpc_id" {
value = vultr_vpc.this.id
description = "创建的 VPC ID"
}