华为云-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 的工作区能够让你在同一个项目里管理多个独立的状态。你可以为不同的环境(像 dev
、rc
)创建不同的工作区。
创建和切换工作区的命令:
# 创建 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网段划分和互联互通方式等。
- 网络架构:
- VPC:CIDR 为
10.0.0.0/16
,用于统一管理私有网络 - 按照业务模块子网划分:
- 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
)
- Web 层:
- DNS:使用自定义 DNS 服务器
10.0.0.2
和10.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 与子网 优化 ¶
- 使用 flatten 函数将所有 VPC 下的子网信息展平成一个列表。
- 在这个列表的基础上,使用 for 表达式将其转换为一个映射,键为 {vpc_name}-,值为包含 vpc_name 和 subnet 信息的对象。
- 将这个映射赋给 for_each 参数,以此来循环创建子网资源。
- 在 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