跳转至

华为云-Terraform

Terraform 是什么?

Terraform 是由 HashiCorp 创建的开源“基础架构即代码”工具。通过 provider 调用云厂商的API进行资源管理

作为一种声明式编码工具,Terraform 使开发人员能够使用一种称为 HCL(HashiCorp 配置语言)的高级配置语言来描述运行应用程序所需的“最终状态”云或本地基础设施。然后,它会生成一个达到该最终状态的计划,并执行该计划来供应基础设施。

安装 terraform

wget https://releases.hashicorp.com/terraform/1.6.6/terraform_1.6.6_linux_amd64.zip
unzip terraform_1.6.6_linux_amd64.zip
mv terraform /usr/local/bin/
terraform -version

配置认证

Terraform支持编排华为云上的各种云资源,使用Terraform管理华为云资源前,您需要获取AK/SK,并在Terraform上进行配置,从而认证鉴权。

环境变量

推荐:在系统环境变量中将 region,AK/SK 等参数设置为环境变量的方式进行认证。

export HW_REGION_NAME="cn-north-1"
export HW_ACCESS_KEY="my-access-key"
export HW_SECRET_KEY="my-secret-key"

安装华为云 provider

下载华为云provider:https://github.com/huaweicloud/terraform-provider-huaweicloud/releases 如何加速下载华为云 provider:https://support.huaweicloud.com/terraform_faq/index.html

Terraform 项目管理(环境配置隔离)

1. 使用工作区(Workspaces)

Terraform 的工作区能够让你在同一个项目里管理多个独立的状态。你可以为不同的环境(像 devrc)创建不同的工作区。

创建和切换工作区的命令

# 创建 dev 工作区
terraform workspace new dev
# 切换到 dev 工作区
terraform workspace select dev
# 在 dev 工作区应用配置
terraform apply -var-file=dev.tfvars

2. 分离项目(不好用、不如分离云)

你可以为不同的环境创建独立的 Terraform 项目。这样每个项目都有自己独立的状态文件和配置,彼此不会相互影响。

# 项目结构示例
├── dev
│   ├── main.tf
│   ├── variables.tf
│   └── dev.tfvars
├── rc
│   ├── main.tf
│   ├── variables.tf
│   └── rc.tfvars

dev 目录下执行:

terraform init
terraform apply -var-file=dev.tfvars

rc 目录下执行:

terraform init
terraform apply -var-file=rc.tfvars

3. 手动管理状态

你可以手动备份和恢复状态文件,在应用不同环境的配置前先备份当前状态,应用完后再恢复。不过这种方法比较繁琐,容易出错。

# 备份当前状态
cp terraform.tfstate terraform.tfstate.dev_backup

# 应用 rc 环境配置
terraform apply -var-file=rc.tfvars

# 恢复 dev 环境状态
cp terraform.tfstate.dev_backup terraform.tfstate

官网方式使用 Terraform 创建华为云 VPC

在创建VPC之前,您需要根据具体的业务需求规划VPC的数量,子网的数量、IP网段划分和互联互通方式等。

  1. 网络架构
  2. VPC:CIDR 为 10.0.0.0/16,用于统一管理私有网络
  3. 按照业务模块子网划分:
    • Web 层:10.0.10.0/24(网关 10.0.10.1
    • 应用层:10.0.20.0/24(网关 10.0.20.1
    • 数据层:10.0.40.0/24(网关 10.0.40.1
  4. DNS:使用自定义 DNS 服务器 10.0.0.210.0.0.3

将服务器划分到不同的安全组中,按需设置访问控制策略,满足高安全场景。

1. 在工作目录下创建 "versions.tf" 文件,指定华为云Provider的registry源和版本,文件内容如下:

terraform {
  required_providers {
    huaweicloud = {
      source = "huaweicloud/huaweicloud"
      version = ">= 1.20.0"
    }
  }
}

2. 创建“main.tf”文件,配置华为云Provider并创建一个VPC,文件内容如下:

# Configure the HuaweiCloud Provider
resource "huaweicloud_vpc" "vpc" {
  name = "vpc-web"
  cidr = "192.168.0.0/16"
}
resource "huaweicloud_vpc_subnet" "subnet1" {
  name       = "subnet-web"
  cidr       = "192.168.10.0/24"
  gateway_ip = "192.168.10.1"
  vpc_id     = huaweicloud_vpc.vpc.id
  dns_list   = ["100.125.1.250", "100.125.129.250"]
}
resource "huaweicloud_vpc_subnet" "subnet2" {
  name       = "subnet-app"
  cidr       = "192.168.20.0/24"
  gateway_ip = "192.168.20.1"
  vpc_id     = huaweicloud_vpc.vpc.id
  dns_list   = ["100.125.1.250", "100.125.129.250"]
}
resource "huaweicloud_vpc_subnet" "subnet3" {
  name       = "subnet-db"
  cidr       = "192.168.40.0/24"
  gateway_ip = "192.168.40.1"
  vpc_id     = huaweicloud_vpc.vpc.id
  dns_list   = ["100.125.1.250", "100.125.129.250"]
}

3. 执行如下命令初始化。

terraform init

4.执行如下命令查看要创建的资源。

terraform plan

5. 执行如下命令创建资源。

terraform apply

如果我们有多个环境多个 VPC ,使用上面那种方法需要创建多个和修改文件 main.tf ,有点繁琐,使用下面方式优化一点,可以简单管理,每次只修改对应环境的 dev.tfvars 文件填写参数,结构文件可以共用。

VPC 与子网 优化

  1. 使用 flatten 函数将所有 VPC 下的子网信息展平成一个列表。
  2. 在这个列表的基础上,使用 for 表达式将其转换为一个映射,键为 {vpc_name}-,值为包含 vpc_name 和 subnet 信息的对象。
  3. 将这个映射赋给 for_each 参数,以此来循环创建子网资源。
  4. 在 for_each 中,我们明确指定了 subnet_config.key => subnet_config,确保键是 key(即 "rc_vpc_1-rc-subnet-1-1"),而不是默认的索引。

移除了不必要的 k, v 循环,直接使用 subnet_config 来引用嵌套对象。

main.tf

# 创建 VPC 资源
resource "huaweicloud_vpc" "vpc" {
  for_each = var.vpcs
  name     = each.value.name
  cidr     = each.value.cidr
}

# 创建子网资源
resource "huaweicloud_vpc_subnet" "subnet" {
  for_each = {
    for subnet_config in flatten([
      for vpc_name, vpc in var.vpcs : [
        for subnet in vpc.subnets : {
          key      = "${vpc_name}-${subnet.name}"
          vpc_name = vpc_name
          subnet   = subnet
        }
      ]
    ]) : subnet_config.key => subnet_config
  }
  name       = each.value.subnet.name
  cidr       = each.value.subnet.cidr
  gateway_ip = each.value.subnet.gateway_ip
  vpc_id     = huaweicloud_vpc.vpc[each.value.vpc_name].id
  dns_list   = each.value.subnet.dns_list
}

variables.tf

variable "vpcs" {
  type = map(object({
    name    = string
    cidr    = string
    subnets = list(object({
      name       = string
      cidr       = string
      gateway_ip = string
      dns_list   = list(string)
    }))
  }))
}

dev.tfvars

vpcs = {
  dev_vpc_1 = {
    name    = "dev-vpc-1"
    cidr    = "10.0.0.0/16"
    subnets = [
      {
        name       = "dev-subnet-1-1"
        cidr       = "10.0.10.0/24"
        gateway_ip = "10.0.10.1"
        dns_list   = ["10.0.0.2", "10.0.0.3"]
      },
      {
        name       = "dev-subnet-1-2"
        cidr       = "10.0.20.0/24"
        gateway_ip = "10.0.20.1"
        dns_list   = ["10.0.0.2", "10.0.0.3"]
      }
    ]
  },
  dev_vpc_2 = {
    name    = "dev-vpc-2"
    cidr    = "10.1.0.0/16"
    subnets = [
      {
        name       = "dev-subnet-2-1"
        cidr       = "10.1.10.0/24"
        gateway_ip = "10.1.10.1"
        dns_list   = ["10.0.0.2", "10.0.0.3"]
      }
    ]
  }
}

安全组优化

main.tf

# 创建安全组
resource "huaweicloud_networking_secgroup" "security_group" {
  for_each = var.security_groups
  name        = each.value.name
  description = each.value.description
}

# 创建安全组规则
resource "huaweicloud_networking_secgroup_rule" "security_group_rule" {
  for_each = {
    for rule_config in flatten([
      for sg_name, sg in var.security_groups : [
        for idx, rule in sg.rules : {
          key = "${sg_name}-rule-${idx}"
          sg_name = sg_name
          rule = rule
        }
      ]
    ]) : rule_config.key => rule_config
  }

  direction         = each.value.rule.direction
  ethertype         = each.value.rule.ethertype
  protocol          = each.value.rule.protocol
  port_range_min    = each.value.rule.port_range_min
  port_range_max    = each.value.rule.port_range_max
  remote_ip_prefix  = each.value.rule.remote_ip_prefix
  security_group_id = huaweicloud_networking_secgroup.security_group[each.value.sg_name].id
}

variables.tf

variable "security_groups" {
  type = map(object({
    name        = string
    description = string
    rules = list(object({
      direction        = string
      ethertype        = string
      protocol         = string
      port_range_min   = number
      port_range_max   = number
      remote_ip_prefix = string
    }))
  }))
}

dev.tfvars

security_groups = {
  dev_sg_1 = {
    name        = "dev-security-group-1"
    description = "ingress 安全组"
    rules = [
      {
        direction        = "ingress"
        ethertype        = "IPv4"
        protocol         = "tcp"
        port_range_min   = 80
        port_range_max   = 80
        remote_ip_prefix = "0.0.0.0/0"
      },
      {
        direction        = "ingress"
        ethertype        = "IPv4"
        protocol         = "tcp"
        port_range_min   = 443
        port_range_max   = 443
        remote_ip_prefix = "0.0.0.0/0"
      }
    ]
  },
  dev_sg_2 = {
    name        = "dev-security-group-2"
    description = "app 安全组"
    rules = [
      {
        direction        = "ingress"
        ethertype        = "IPv4"
        protocol         = "tcp"
        port_range_min   = 222
        port_range_max   = 222
        remote_ip_prefix = "0.0.0.0/0"
      }
    ]
  }
}

弹性公网 ip 优化

main.tf

# 创建弹性公网 IP
resource "huaweicloud_vpc_eip" "eip" {
  for_each = var.eips
  publicip {
    type = each.value.type
  }
  bandwidth {
    name        = each.value.bandwidth_name
    size        = each.value.bandwidth_size
    share_type  = each.value.bandwidth_share_type
    charge_mode = each.value.bandwidth_charge_mode
  }
}

variables.tf

variable "eips" {
  type = map(object({
    type                  = string
    bandwidth_name        = string
    bandwidth_size        = number
    bandwidth_share_type  = string
    bandwidth_charge_mode = string
  }))
}

dev.tfvars

eips = {
  eip_1 = {
    type                  = "5_bgp"
    bandwidth_name        = "test"
    bandwidth_size        = 5
    bandwidth_share_type  = "PER"
    bandwidth_charge_mode = "traffic"
  },
  eip_2 = {
    type                  = "5_bgp"
    bandwidth_name        = "test1"
    bandwidth_size        = 5
    bandwidth_share_type  = "PER"
    bandwidth_charge_mode = "traffic"
  }
}

删除创建的所有资源

切换进入相应工作区,并删除所有资源,警告生产误用!!!!!!!!!

terraform workspace list && terraform workspace select dev

terraform destroy -var-file=dev.tfvars

terraform import -var-file=dev.tfvars 'huaweicloud_vpc.vpc["dev_vpc_1"]' 1d65383a-6f50-4434-a6a9-d86768126330

terraform import -var-file=dev.tfvars 'huaweicloud_vpc_subnet.subnet["dev_vpc_1-dev-subnet-1-1"]' 88b77480-21e7-46a4-9496-d34c06872362






terraform import -var-file=dev.tfvars 'huaweicloud_networking_secgroup.security_group["dev_sg_1"]' e673ad10-1f13-49e3-b97c-7f28c080112f


terraform import -var-file=dev.tfvars 'huaweicloud_networking_secgroup.security_group["dev_sg_2"]' a5d9f4b5-ce02-48f8-ae5f-500c4a4379e4