Terraform申请云主机资源

时间:July 23, 2019 分类:

目录:

Terraform介绍

Terraform是一种开源工具,用于安全高效地预配和管理云基础结构。

  • 用代码维护资源,通过CLI的方式将配置文件部署到云上,并对其进行版本控制。
  • 编写了描述云资源拓扑的配置文件中的基础结构,例如虚拟机,存储账户和网络接口

优势

  • 将基础结构部署到多个云 适用于多云的方案,将类似结构部署到云上,或者本地数据中心,可以使用相同的工具和类似的配置文件管理不同的云提供商的资源
  • 自动化管理基础结构 可以创建配置文件模板,可以多次部署相同的模板,构建相同的开发,测试和生产环境
  • 基础架构即代码 用代码维护资源,允许保存基础设施状态,允许跟踪对系统中不同组件的更改,并与其他人共享这些配置
  • 降低成本 按需构建环境的成本

Terraform安装

下载页面

$ wget https://releases.hashicorp.com/terraform/0.12.2/terraform_0.12.2_linux_amd64.zip
$ unzip terraform_0.12.2_linux_amd64.zip
$ mv terraform /usr/local/bin/
$ terraform 
Usage: terraform [-version] [-help] <command> [args]

The available commands for execution are listed below.
The most common, useful commands are shown first, followed by
less common or more advanced commands. If you're just getting
started with Terraform, stick with the common commands. For the
other commands, please read the help and docs before usage.

Common commands:
    apply              Builds or changes infrastructure
    console            Interactive console for Terraform interpolations
    destroy            Destroy Terraform-managed infrastructure
    env                Workspace management
    fmt                Rewrites config files to canonical format
    get                Download and install modules for the configuration
    graph              Create a visual graph of Terraform resources
    import             Import existing infrastructure into Terraform
    init               Initialize a Terraform working directory
    output             Read an output from a state file
    plan               Generate and show an execution plan
    providers          Prints a tree of the providers used in the configuration
    refresh            Update local state file against real resources
    show               Inspect Terraform state or plan
    taint              Manually mark a resource for recreation
    untaint            Manually unmark a resource as tainted
    validate           Validates the Terraform files
    version            Prints the Terraform version
    workspace          Workspace management

All other commands:
    0.12upgrade        Rewrites pre-0.12 module source code for v0.12
    debug              Debug output management (experimental)
    force-unlock       Manually unlock the terraform state
    push               Obsolete command for Terraform Enterprise legacy (v1)
    state              Advanced state management

可以在云上创建Terraform的账户,并创建AccessKey,通过环境变量存放认证信息

常用操作

terraform init   # 初始化工作目录,也是我们第一个要执行的命令
terraform plan   # 生成计划
terraform appy   # 提交请求
terraform state  # 查看资源状态
terraform graph  # 生成执行计划图

Terraform的资源概念

Terraform管理的是云资源

基础设施和服务统称为资源,如私有网络、子网、物理机、虚拟机、镜像、专线、NAT网关等等都可以称之为资源,也是开发和运维人员经常要打交道要维护的东西。

资源分为两种resource和data

resource

这类资源一般是抽象的真正的云服务资源,支持增删改,如私有网络、NAT网关、虚拟机实例

resource "资源类名" "映射到本地的唯一资源名" {
  参数 = 值
  ...
}

data

这类资源一般是固定的一些可读资源,如可用区列表、镜像列表。大部分情况下,resource资源也会封装一个data source方法,用于资源查询

data "资源类名" "映射到本地的唯一资源名" {
  参数 = 值
  ...
}

Terraform配置

providers索引页

以下以腾讯云为示例

创建用户

腾讯云 访问管理->用户->用户列表

png01

进行新建用户,自定义创建

png02

对用户进行授权

png03

在这个页面创建秘钥

公共配置

### 公共配置
provider "tencentcloud" {
  secret_id  = "AKIDpUyFXke12slT6nNGyWxGSXSHvqeM7Fbo"
  secret_key = "PCQSJzURK3mHqlFanvCMQuEbsytOHKFz"
  region     = "ap-guangzhou"
}

也可以直接通过环境变量方式

export TENCENTCLOUD_SECRET_ID="AKIDpUyFXke12slT6nNGyWxGSXSHvqeM7Fbo"
export TENCENTCLOUD_SECRET_KEY="PCQSJzURK3mHqlFanvCMQuEbsytOHKFz"
export TENCENTCLOUD_REGION="ap-guangzhou"

查询资源

把资源依赖的上游资源,先查询出来,便宜后面引用

# 查询可用区信息
data "tencentcloud_availability_zones" "favorate_zones" {}
# 查询镜像
data "tencentcloud_image" "my_favorate_image" {
  filter {
    name = "image-type"
    values = ["PUBLIC_IMAGE"]
  }
}

后面我们创建的子网和虚拟机,需要用到可用区和镜像,所以这里先用data查询

创建资源

创建一个私有网络

resource "tencentcloud_vpc" "main" {
  name = "979137_test_vpc"
  cidr_block = "10.6.0.0/16"
}

创建私有网络,在Terraform中name为main

创建子网

子网在私网下

resource "tencentcloud_subnet" "main_subnet" {
  vpc_id = "${tencentcloud_vpc.main.id}"
  name = "979137_test_subnet"
  cidr_block = "10.6.7.0/24"
  availability_zone = "${data.tencentcloud_availability_zones.favorate_zones.zones.0.name}"
}

这边创建使用的可用区是data搜索到的name,是随机的,可以加过滤条件

创建弹性IP用于关联到NAT网关

resource "tencentcloud_eip" "eip_dev_dnat" {
  name = "979137_test_eip"
}
resource "tencentcloud_eip" "eip_test_dnat" {
  name = "979137_test_eip"
}

被依赖资源要优先创建

创建NAT网关,用于给CVM提供外网能力

resource "tencentcloud_nat_gateway" "my_nat" {
  vpc_id = "${tencentcloud_vpc.main.id}"
  name = "979137_test_nat"
  max_concurrent = 3000000
  bandwidth = 500
  assigned_eip_set = [
    "${tencentcloud_eip.eip_dev_dnat.public_ip}",
    "${tencentcloud_eip.eip_test_dnat.public_ip}",
  ]
}

创建安全组并配置安全组规则

resource "tencentcloud_security_group" "my_sg" {
  name = "979137_test_sg"
  description = "979137_test_sg"
}
# 放通80,443端口
resource "tencentcloud_security_group_rule" "web" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "0.0.0.0/0"
  ip_protocol = "tcp"
  port_range = "80,443"
  policy = "accept"
}
# 放通常用web端口
resource "tencentcloud_security_group_rule" "sg_web" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "0.0.0.0/0"
  ip_protocol = "tcp"
  port_range = "80,443,8080"
  policy = "accept"
}
# 放通内网ssh登录
resource "tencentcloud_security_group_rule" "sg_ssh" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "10.65.0.0/16"
  ip_protocol = "tcp"
  port_range = "22"
  policy = "accept"
}
# 拒绝所有访问
resource "tencentcloud_security_group_rule" "sg_drop" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "0.0.0.0/0"
  ip_protocol = "tcp"
  port_range = "ALL"
  policy = "drop"
}

内容整合

# 公共资源
provider "tencentcloud" {
  secret_id  = "AKIDpUyFXke12slT6nNGyWxGSXSHvqeM7Fbo"
  secret_key = "PCQSJzURK3mHqlFanvCMQuEbsytOHKFz"
  region     = "ap-guangzhou"
}

# 查询可用区信息
data "tencentcloud_availability_zones" "favorate_zones" {}
# 查询镜像
data "tencentcloud_image" "my_favorate_image" {
  filter {
    name = "image-type"
    values = ["PUBLIC_IMAGE"]
  }
}
# 查询机型
data "tencentcloud_instance_types" "my_favorate_instance_types" {
  filter {
    name   = "instance-family"
    values = ["S1"]
  }

  cpu_core_count = 1
  memory_size    = 1
}

resource "tencentcloud_vpc" "main" {
  name = "979137_test_vpc"
  cidr_block = "10.6.0.0/16"
}

resource "tencentcloud_subnet" "main_subnet" {
  vpc_id = "${tencentcloud_vpc.main.id}"
  name = "979137_test_subnet"
  cidr_block = "10.6.7.0/24"
  availability_zone = "${data.tencentcloud_availability_zones.favorate_zones.zones.0.name}"
}

resource "tencentcloud_eip" "eip_dev_dnat" {
  name = "979137_test_eip"
}

resource "tencentcloud_eip" "eip_test_dnat" {
  name = "979137_test_eip"
}

resource "tencentcloud_nat_gateway" "my_nat" {
  vpc_id = "${tencentcloud_vpc.main.id}"
  name = "979137_test_nat"
  max_concurrent = 3000000
  bandwidth = 500
  assigned_eip_set = [
    "${tencentcloud_eip.eip_dev_dnat.public_ip}",
    "${tencentcloud_eip.eip_test_dnat.public_ip}",
  ]
}

resource "tencentcloud_security_group" "my_sg" {
  name = "979137_test_sg"
  description = "979137_test_sg"
}
# 放通80,443端口
resource "tencentcloud_security_group_rule" "web" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "0.0.0.0/0"
  ip_protocol = "tcp"
  port_range = "80,443"
  policy = "accept"
}
# 放通常用web端口
resource "tencentcloud_security_group_rule" "sg_web" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "0.0.0.0/0"
  ip_protocol = "tcp"
  port_range = "80,443,8080"
  policy = "accept"
}
# 放通内网ssh登录
resource "tencentcloud_security_group_rule" "sg_ssh" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "10.65.0.0/16"
  ip_protocol = "tcp"
  port_range = "22"
  policy = "accept"
}
# 拒绝所有访问
resource "tencentcloud_security_group_rule" "sg_drop" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "0.0.0.0/0"
  ip_protocol = "tcp"
  policy = "drop"
}

resource "tencentcloud_instance" "foo" {
  availability_zone = "${data.tencentcloud_availability_zones.favorate_zones.zones.0.name}"
  image_id = "${data.tencentcloud_image.my_favorate_image.image_id}"
  vpc_id = "${tencentcloud_vpc.main.id}"
  instance_type = "${data.tencentcloud_instance_types.my_favorate_instance_types.instance_types.0.instance_type}"
  system_disk_type = "CLOUD_PREMIUM"
  subnet_id = "${tencentcloud_subnet.main_subnet.id}"
  security_groups = [
    "${tencentcloud_security_group.my_sg.id}",
  ]
}

resource "tencentcloud_dnat" "dev_dnat" {
  vpc_id = "${tencentcloud_nat_gateway.my_nat.vpc_id}"
  nat_id = "${tencentcloud_nat_gateway.my_nat.id}"
  protocol = "tcp"
  elastic_ip = "${tencentcloud_eip.eip_dev_dnat.public_ip}"
  elastic_port = "80"
  private_ip = "${tencentcloud_instance.foo.private_ip}"
  private_port = "9001"
}
resource "tencentcloud_dnat" "test_dnat" {
  vpc_id = "${tencentcloud_nat_gateway.my_nat.vpc_id}"
  nat_id = "${tencentcloud_nat_gateway.my_nat.id}"
  protocol = "udp"
  elastic_ip = "${tencentcloud_eip.eip_test_dnat.public_ip}"
  elastic_port = "8080"
  private_ip = "${tencentcloud_instance.foo.private_ip}"
  private_port = "9002"
}

创建虚拟机

resource "tencentcloud_instance" "foo" {
  availability_zone = "${data.tencentcloud_availability_zones.favorate_zones.zones.0.name}"
  image_id = "${data.tencentcloud_image.my_favorate_image.image_id}"
  vpc_id = "${tencentcloud_vpc.main.id}"
  subnet_id = "${tencentcloud_subnet.main_subnet.id}"
  security_groups = [
    "${tencentcloud_security_group.my_sg.id}",
  ]
  # 付费类型(默认也是POSTPAID_BY_HOUR)
  instance_charge_type = "POSTPAID_BY_HOUR"
}

指定虚拟机的NAT网关

resource "tencentcloud_dnat" "dev_dnat" {
  vpc_id = "${tencentcloud_nat_gateway.my_nat.vpc_id}"
  nat_id = "${tencentcloud_nat_gateway.my_nat.id}"
  protocol = "tcp"
  elastic_ip = "${tencentcloud_eip.eip_dev_dnat.public_ip}"
  elastic_port = "80"
  private_ip = "${tencentcloud_instance.foo.private_ip}"
  private_port = "9001"
}
resource "tencentcloud_dnat" "test_dnat" {
  vpc_id = "${tencentcloud_nat_gateway.my_nat.vpc_id}"
  nat_id = "${tencentcloud_nat_gateway.my_nat.id}"
  protocol = "udp"
  elastic_ip = "${tencentcloud_eip.eip_test_dnat.public_ip}"
  elastic_port = "8080"
  private_ip = "${tencentcloud_instance.foo.private_ip}"
  private_port = "9002"
}

加载插件

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "tencentcloud" (terraform-providers/tencentcloud) 1.9.1...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.tencentcloud: version = "~> 1.9"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

生成计划

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

data.tencentcloud_availability_zones.favorate_zones: Refreshing state...
data.tencentcloud_image.my_favorate_image: Refreshing state...

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # tencentcloud_dnat.dev_dnat will be created
  + resource "tencentcloud_dnat" "dev_dnat" {
      + elastic_ip   = (known after apply)
      + elastic_port = "80"
      + id           = (known after apply)
      + nat_id       = (known after apply)
      + private_ip   = (known after apply)
      + private_port = "9001"
      + protocol     = "tcp"
      + vpc_id       = (known after apply)
    }

  # tencentcloud_dnat.test_dnat will be created
  + resource "tencentcloud_dnat" "test_dnat" {
      + elastic_ip   = (known after apply)
      + elastic_port = "8080"
      + id           = (known after apply)
      + nat_id       = (known after apply)
      + private_ip   = (known after apply)
      + private_port = "9002"
      + protocol     = "udp"
      + vpc_id       = (known after apply)
    }

  # tencentcloud_eip.eip_dev_dnat will be created
  + resource "tencentcloud_eip" "eip_dev_dnat" {
      + id        = (known after apply)
      + name      = "979137_test_eip"
      + public_ip = (known after apply)
      + status    = (known after apply)
    }

  # tencentcloud_eip.eip_test_dnat will be created
  + resource "tencentcloud_eip" "eip_test_dnat" {
      + id        = (known after apply)
      + name      = "979137_test_eip"
      + public_ip = (known after apply)
      + status    = (known after apply)
    }

  # tencentcloud_instance.foo will be created
  + resource "tencentcloud_instance" "foo" {
      + availability_zone = "ap-guangzhou-3"
      + id                = (known after apply)
      + image_id          = "img-9qabwvbn"
      + instance_name     = "Terrafrom-CVM-Instance"
      + instance_status   = (known after apply)
      + key_name          = (known after apply)
      + private_ip        = (known after apply)
      + public_ip         = (known after apply)
      + security_groups   = (known after apply)
      + subnet_id         = (known after apply)
      + system_disk_size  = (known after apply)
      + system_disk_type  = (known after apply)
      + vpc_id            = (known after apply)

      + data_disks {
          + data_disk_size       = (known after apply)
          + data_disk_type       = (known after apply)
          + delete_with_instance = (known after apply)
        }
    }

  # tencentcloud_nat_gateway.my_nat will be created
  + resource "tencentcloud_nat_gateway" "my_nat" {
      + assigned_eip_set = (known after apply)
      + bandwidth        = 500
      + id               = (known after apply)
      + max_concurrent   = 3000000
      + name             = "979137_test_nat"
      + vpc_id           = (known after apply)
    }

  # tencentcloud_security_group.my_sg will be created
  + resource "tencentcloud_security_group" "my_sg" {
      + description = "979137_test_sg"
      + id          = (known after apply)
      + name        = "979137_test_sg"
    }

  # tencentcloud_security_group_rule.sg_drop will be created
  + resource "tencentcloud_security_group_rule" "sg_drop" {
      + cidr_ip           = "0.0.0.0/0"
      + id                = (known after apply)
      + ip_protocol       = "tcp"
      + policy            = "drop"
      + security_group_id = (known after apply)
      + type              = "ingress"
    }

  # tencentcloud_security_group_rule.sg_ssh will be created
  + resource "tencentcloud_security_group_rule" "sg_ssh" {
      + cidr_ip           = "10.65.0.0/16"
      + id                = (known after apply)
      + ip_protocol       = "tcp"
      + policy            = "accept"
      + port_range        = "22"
      + security_group_id = (known after apply)
      + type              = "ingress"
    }

  # tencentcloud_security_group_rule.sg_web will be created
  + resource "tencentcloud_security_group_rule" "sg_web" {
      + cidr_ip           = "0.0.0.0/0"
      + id                = (known after apply)
      + ip_protocol       = "tcp"
      + policy            = "accept"
      + port_range        = "80,443,8080"
      + security_group_id = (known after apply)
      + type              = "ingress"
    }

  # tencentcloud_security_group_rule.web will be created
  + resource "tencentcloud_security_group_rule" "web" {
      + cidr_ip           = "0.0.0.0/0"
      + id                = (known after apply)
      + ip_protocol       = "tcp"
      + policy            = "accept"
      + port_range        = "80,443"
      + security_group_id = (known after apply)
      + type              = "ingress"
    }

  # tencentcloud_subnet.main_subnet will be created
  + resource "tencentcloud_subnet" "main_subnet" {
      + availability_zone = "ap-guangzhou-3"
      + cidr_block        = "10.6.7.0/24"
      + id                = (known after apply)
      + name              = "979137_test_subnet"
      + vpc_id            = (known after apply)
    }

  # tencentcloud_vpc.main will be created
  + resource "tencentcloud_vpc" "main" {
      + cidr_block   = "10.6.0.0/16"
      + id           = (known after apply)
      + is_default   = (known after apply)
      + is_multicast = (known after apply)
      + name         = "979137_test_vpc"
    }

Plan: 13 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

执行计划

$ terraform apply
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

完整示例

terraform_tx/main.tf
# 公共资源
provider "tencentcloud" {
  secret_id  = "AKIDpUyFXke12slT6nNGyWxG************"
  secret_key = "PCQSJzURK3mHqlFanvC************"
  region     = "ap-guangzhou"
}

# 查询可用区信息
data "tencentcloud_availability_zones" "favorate_zones" {}
# 查询镜像
data "tencentcloud_image" "my_favorate_image" {
  filter {
    name = "image-type"
    values = ["PUBLIC_IMAGE"]
  }
}
# 查询机型
data "tencentcloud_instance_types" "my_favorate_instance_types" {
  filter {
    name   = "instance-family"
    values = ["S1"]
  }

  cpu_core_count = 1
  memory_size    = 1
}

resource "tencentcloud_vpc" "main" {
  name = "979137_test_vpc"
  cidr_block = "10.6.0.0/16"
}

resource "tencentcloud_subnet" "main_subnet" {
  vpc_id = "${tencentcloud_vpc.main.id}"
  name = "979137_test_subnet"
  cidr_block = "10.6.7.0/24"
  availability_zone = "${data.tencentcloud_availability_zones.favorate_zones.zones.0.name}"
}

resource "tencentcloud_eip" "eip_dev_dnat" {
  name = "979137_test_eip"
}

resource "tencentcloud_eip" "eip_test_dnat" {
  name = "979137_test_eip"
}

resource "tencentcloud_nat_gateway" "my_nat" {
  vpc_id = "${tencentcloud_vpc.main.id}"
  name = "979137_test_nat"
  max_concurrent = 3000000
  bandwidth = 500
  assigned_eip_set = [
    "${tencentcloud_eip.eip_dev_dnat.public_ip}",
    "${tencentcloud_eip.eip_test_dnat.public_ip}",
  ]
}

resource "tencentcloud_security_group" "my_sg" {
  name = "979137_test_sg"
  description = "979137_test_sg"
}
# 放通80,443端口
resource "tencentcloud_security_group_rule" "web" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "0.0.0.0/0"
  ip_protocol = "tcp"
  port_range = "80,443"
  policy = "accept"
}
# 放通常用web端口
resource "tencentcloud_security_group_rule" "sg_web" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "0.0.0.0/0"
  ip_protocol = "tcp"
  port_range = "80,443,8080"
  policy = "accept"
}
# 放通内网ssh登录
resource "tencentcloud_security_group_rule" "sg_ssh" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "10.65.0.0/16"
  ip_protocol = "tcp"
  port_range = "22"
  policy = "accept"
}
# 拒绝所有访问
resource "tencentcloud_security_group_rule" "sg_drop" {
  security_group_id = "${tencentcloud_security_group.my_sg.id}"
  type = "ingress"
  cidr_ip = "0.0.0.0/0"
  ip_protocol = "tcp"
  policy = "drop"
}

resource "tencentcloud_instance" "foo" {
  availability_zone = "${data.tencentcloud_availability_zones.favorate_zones.zones.0.name}"
  image_id = "${data.tencentcloud_image.my_favorate_image.image_id}"
  vpc_id = "${tencentcloud_vpc.main.id}"
  instance_type = "${data.tencentcloud_instance_types.my_favorate_instance_types.instance_types.0.instance_type}"
  system_disk_type = "CLOUD_PREMIUM"
  subnet_id = "${tencentcloud_subnet.main_subnet.id}"
  security_groups = [
    "${tencentcloud_security_group.my_sg.id}",
  ]
}

resource "tencentcloud_dnat" "dev_dnat" {
  vpc_id = "${tencentcloud_nat_gateway.my_nat.vpc_id}"
  nat_id = "${tencentcloud_nat_gateway.my_nat.id}"
  protocol = "tcp"
  elastic_ip = "${tencentcloud_eip.eip_dev_dnat.public_ip}"
  elastic_port = "80"
  private_ip = "${tencentcloud_instance.foo.private_ip}"
  private_port = "9001"
}
resource "tencentcloud_dnat" "test_dnat" {
  vpc_id = "${tencentcloud_nat_gateway.my_nat.vpc_id}"
  nat_id = "${tencentcloud_nat_gateway.my_nat.id}"
  protocol = "udp"
  elastic_ip = "${tencentcloud_eip.eip_test_dnat.public_ip}"
  elastic_port = "8080"
  private_ip = "${tencentcloud_instance.foo.private_ip}"
  private_port = "9002"
}