terraform是一个开源的自动化创建,自动化链接的,跨运营商应用。本质是一个IaC(Infrastructure as Code)工具,这里吐槽一句,为什么不叫C2I或者I2C这样明明更顺口,笔者想了一下可能和硬件通信协议IIC(I-squared-C)要做区分吧
这个东西只需要一个模板和简单命令就可以快速创建同配置的 实例,VPC,子网,磁盘……在工作中,我们经常需要快速部署多台同配置的实例,然则手动配置一则繁琐,二则可能出错,三是跨运营商设置,所以亟需按照统一模板快速批量创建,Terraform很好的胜任这个工作,接下来笔者以EC2为例一步步用Terraform创建。
非常推荐了解一下这个,因为Terraform本质是一个跨平台的资源编排工具,无论是洋人的AWS、国内的ALI、或者是老牌VMware、OpenStack都支持这个
Terraform用HCL语言配置,是HashiCorp旗下产品,支持许多云基础设施提供商,如亚马逊AWS,微软Azure,IBM Cloud,Serverspace,Google Cloud Platform,[9]DigitalOcean,[10]Oracle Cloud Infrastructure,Yandex.Cloud,[11]VMware vSphere和OpenStack
除了自己写外本人还参考了其他资料。
笔者文章只作为抛砖引玉,任何技术都推荐在官网系统性学习。
https://www.terraform.io/downloads
Terraform Registryhttps://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance
Terraform Registryhttps://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/instance
Terraform Registryhttps://registry.terraform.io/providers/huaweicloud/huaweicloud/latest/docs/resources/compute_instance
Terraform Registryhttps://registry.terraform.io/providers/hashicorp/vsphere/latest/docs
Terraform 使用声明性配置语言来描述所需的基础设施,而不是脚本式的命令。用户定义目标状态,而 Terraform 负责确保当前状态与目标状态一致。这句话什么意思呢?本质是说,Terraform会在本地维持一个信息控制远端服务器资源与本地一致,例如我们使用Terraform创了2个实例,然后又在服务器厂商提供的控制台改了这两个机器的配置,那么我们再次跑Terraform脚本的时候,Terraform会将远端配置更改。这样的好处是架构一旦确定,不会乱动。
Terraform 使用提供者来与不同的基础设施平台进行交互,如AWS、ALI Cloud、VMware等。每个提供者实现了与特定云服务提供商的 API 交互的功能。说白了就是Terraform虽然是一个跨平台的资源编排工具,但是其不同厂商的书写规范会有些许差异。我想这个无可厚非,毕竟各个厂商提供的服务本来也有差别。
Terraform 配置文件中的资源是用户希望在基础设施中创建或管理的实体,如虚拟机、存储桶、数据库等。每个资源都由其类型和具体配置参数定义。这个概念和instance有点像,总之就是Terraform可操作的资源。
模块是 Terraform 配置的可重用部分,允许将基础设施划分为较小的、更易管理的部分。模块可以包含资源、变量、输出等。这个是在说Terraform支持自写脚本后反复调用,这里引入一段HCL代码介绍一下,总之看个人习惯,如果机器多tf拆开写方便,机器少tf写成一个方便。
# 注意此代码是多个分立的文件。
# s3-module/main.tf 在 s3-module 目录中创建模块的配置文件。
provider "aws" {
region = "us-east-1" # 修改为你的 AWS region
}
resource "aws_s3_bucket" "my_bucket" {
bucket = var.bucket_name
acl = "private"
}
# s3-module/variables.tf 在 s3-module 目录中创建输入变量的定义文件。
variable "bucket_name" {
description = "The name of the S3 bucket"
type = string
}
# s3-module/outputs.tf 在 s3-module 目录中创建输出值的定义文件。
output "bucket_id" {
description = "The ID of the created S3 bucket"
value = aws_s3_bucket.my_bucket.id
}
# main.tf 在 main 目录中创建主 Terraform 配置文件,引用模块。这个是真正的程序主入口
provider "aws" {
region = "us-east-1" # AWS 区域
}
module "my_s3_bucket" {
source = "./s3-module" # 指定模块的路径,这里是相对路径
bucket_name = "my-unique-bucket-name" # 传递输入变量
}
output "my_s3_bucket_id" {
value = module.my_s3_bucket.bucket_id # 引用模块的输出值
}
Terraform 允许通过变量来参数化配置,使其更具灵活性和可重用性。变量可以在配置文件中定义,也可以通过外部传递的值进行设置。在上面的例子中,我们使用了一个变量文件variables.tf,可以往上翻一下看看。
输出定义了从 Terraform 管理的基础设施中提取的值。这些值可以在后续的配置文件中使用,或者通过 Terraform 命令行工具输出。
Terraform 使用状态文件来追踪当前基础设施的状态。状态文件记录了当前基础设施中所有资源的信息,以便在执行操作时可以进行计划和对比。通常以文件名 terraform.tfstate
或者是由 backend
配置指定的文件名保存
在 Terraform 中,用户通过执行 terraform plan
命令来查看计划,这将显示计划的变更。然后,通过执行 terraform apply
命令来将计划应用到基础设施中。这个东西不是计划任务,而是正式变更前,可以敲一下这个命令看一下基础设施会如何更改,防止出问题。
创建一个main.tf文件,作为编排入口(不一定要叫main,可以随便起)
!!!注意:terraform会默认扫描工作目录(./)下的所有tf文件,所以请确保tf文件间不会干扰!!!
配置AK/SK作为鉴权,设置region作为机器地域落位。
provider "aws" {
region = "us-east-1"
access_key = ""
secret_key = ""
}
PS:注意格式{},缩进不严格,默认应该是 key="value";而对于一些特别的值,比如安全组是 [];变量需要${};子项,tags或root_block_device是一个map故{} 。也就是说[]和{}(列表和字典)沿袭了常用的语法
##创建实例,create instance
##只需要更改“helloword”后大括号的部分即可,更多参数请看https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance
resource "aws_instance" "helloworld" {
ami = "ami-blabla"
instance_type = "t2.micro"
count = "1"
#标签项: Key = "value"
#机器名字,这里采用前缀加递增数字,名字本身可以递归,下面给出了一个例子(注释),会生成test-1,test-2……
tags = {
Name = "test"
#Name = "test-${count.index+1}"
CodeName = "blabla"
}
########################如果有新参数,请参照
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance
#add ur codes below,添加新的代码,格式:key="value",缩进不严格
subnet_id = "subnet-123123f"
availability_zone = "us-east-1c"
#private_ip = "172.31.10.${count.index +1}"
#注意安全组是一个list,需要写上中括号
#security_groups = ["launch-1"]
vpc_security_group_ids = ["sg-0ce786"]
key_name = "key-123123"
#这里是磁盘设置(GB)
#类型:standard, gp2, gp3, io1, io2, sc1, or st1.默认gp2
root_block_device {
volume_size = "8"
volume_type = "standard"
}
#磁盘标签
volume_tags = {
CodeName = "test-disk"
}
credit_specification {
cpu_credits = "unlimited"
}
/* #这里是开机后执行的命令
user_data = <<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install apache2 -y
sudo systemctl start apache2
sudo bash -c 'echo your very first web server > /var/www/html/index.html'
EOF
*/
###################################################
}
如果你需要额外的配置,请参照文首的网址,寻找关键词以及格式添加到大括号内,如下:
terraform支持对生成后的实例,进行查询信息回返,这里以回返IP,ID为例,可以写成循环
#回返IP return pub&pri ip,会打印每一个机器的ID,公私IP,NAME
output "id_ip" {
value = {
for index, droplet in aws_instance.helloworld :
droplet.id => {
public-ip = droplet.public_ip
private-ip = aws_instance.helloworld[index].private_ip
#id = aws_instance.helloworld[index].id
Name = aws_instance.helloworld[index].tags.Name
}
}
}
#这一行会打印 end and success
output "answer"{
value = "end and success"
}
系统盘设置设置 root_block_device是resource下的一个子项,但注意,root_block_device后没有“ = ”
磁盘标签 volume_tags并不写在root_block_device内,而是resource的一个子项map,并且需要“ = ”
如果创建时发现错误400,提示not support请查看机器类型合适与否。
常用命令有3个,这三个也是包括了实例从创建到销毁的整个生命周期。
创建好模板后,先使用 init命令(如果第一次运行),后使用plan和apply,最后destory销毁
第一次运行terraform需要初始化,terraform会下载运营商提供的依赖,在工作目录生成一个.terraform文件夹
terraform init
PS:如果需要更改工作路径:terraform -chdir=./path init
根据模板创建机器,需要yes确认,如果懒得点yes,请用echo yes | terraform apply 替代。
如果希望更改terraform工作目录,请用如下命令,其中./aws是新的工作目录(由于terraform会默认扫描工作目录的所有tf文件,故常用此命令区别)
PS:更改路径 terraform -chdir=./path apply
PPS:强制apply:echo yes | terraform -chdir=./path apply
terraform apply
· apply后会生成三个文件如下图,这三个文件用于后续修改或者销毁,所以如果你需要另外创建机器,请删除这三个文件,否则terraform会默认修改之前的机器配置。
· 另外:如果您要更换运营商创建机器,也应该删除这些文件,否则terraform会认为你是在修改机器,但是之前的机器运营商不同,故而会报错
terraform destroy
销毁之前创建的机器,依赖于上面的文件。
由于非技术因素,华为的模板需要额外添加此项,否则会初始化失败,
另外:谷歌搜索huawei terraform instance 无结果,文档入口请看文首的链接,并且有理由怀疑可能未来terraform会下架,请注意保存相关页面和provider
##华为从terraform官网找不到了,需要添加下面这一项保证初始化成功
terraform {
required_providers {
huaweicloud = {
source = "huaweicloud/huaweicloud"
version = ">= 1.20.0"
}
}
required_version = ">= 0.13"
}
##认证,login account
##region对应地区,并写好AK/SK
provider "huaweicloud" {
region = "ap-southeast-3"
access_key = ""
secret_key = ""
}
##下面是具体的机器配置,缩进不严格,但注意有些项目有子项,需要大括号{}
resource "huaweicloud_compute_instance" "ecs" {
name = "QAQ"
admin_pass = "password_123123"
#image_id = ""
image_name = "镜像名或者镜像ID二选一"
flavor_id = "s6.large.2"
#可用区代号查询https://developer.huaweicloud.com/endpoint
availability_zone = "ap-southeast-3c"
#security_groups = ["kubg"]
security_group_ids = ["13dcf94"]
count = "1"
##企业项目ID号
enterprise_project_id = "123123"
network {
#UUID是子网ID
uuid = "21231212-1234-1234-1234-123412311232"
access_network = "true"
}
tags = {
#这里可以添加自定义的标签,格式已给出
CodeName = "pepper"
}
#系统盘选项,类型有SAS,SSD,GPSSD,ESSD
system_disk_type = "SAS"
system_disk_size = "40"
########################如果有新参数,请参照
#https://registry.terraform.io/providers/huaweicloud/huaweicloud/latest/docs/resources/compute_instance
#add ur codes below,添加新的代码,格式:key="value",缩进不严格
########################
}
##华为的机器需要手动绑定公网IP,下面这一项是创建EIP用的
#https://registry.terraform.io/providers/huaweicloud/huaweicloud/latest/docs/resources/vpc_eip
resource "huaweicloud_vpc_eip" "myeip" {
publicip {
type = "5_bgp"
}
bandwidth {
name = "test"
size = "5"
#share_type可选PER或者WHOLE
share_type = "PER"
#下面这个付费类型traffic或者bandwidth
charge_mode = "traffic"
}
count = length(huaweicloud_compute_instance.ecs)
#企业项目ID号
#enterprise_project_id = "11231214-1236-1230-1212-123012312321"
}
##华为的机器需要手动绑定公网IP,下面这一项是绑定机器用的
resource "huaweicloud_compute_eip_associate" "associated" {
count = length(huaweicloud_compute_instance.ecs)
public_ip = huaweicloud_vpc_eip.myeip[count.index].address
instance_id = huaweicloud_compute_instance.ecs[count.index].id
}
#回返IP return pub&pri ip,会打印每一个机器的ID,公私IP,NAME
output "id_ip" {
value = {
for index, droplet in huaweicloud_compute_instance.ecs :
#droplet.tags.Name => {
droplet.id => {
public-ip = huaweicloud_vpc_eip.myeip[index].address
private-ip = huaweicloud_compute_instance.ecs[index].access_ip_v4
Name = huaweicloud_compute_instance.ecs[index].name
}
}
}
output "answer"{
#value = [for i in alicloud_instance.instance: i.public_ip] # 这个代码有点久了,我不确定为什么alicloud会在这里出现,但总的来说是一个可迭代对象,换成华为对应的即可。
value = "end and success"
}
这个错误很难定位
##认证,login account
##region对应地区,并写好AK/SK
##阿里region表 https://help.aliyun.com/document_detail/40654.html
provider "alicloud" {
access_key = "输入你的ak"
secret_key = "输入你的sk"
region = "cn-hongkong"
}
resource "alicloud_instance" "instance" {
image_id = "win2016.vhd"
instance_type = "ecs.t5-c1m2.large"
security_groups = ["sg-111","sg-222"]
instance_name = "ali-test-1"
password = "pass_11223344"
vswitch_id = "vsw-123"
count = "1"
##网络设置
##此项已弃用internet_max_bandwidth_in = "200"
internet_max_bandwidth_out = "100"
##磁盘设置,
##类型可选ephemeral_ssd,cloud_efficiency,cloud_ssd,cloud_essd,cloud
system_disk_size = "20"
system_disk_category = "cloud_efficiency" #默认是效率云盘
system_disk_name = "mydick"
#标签项,可自由添加
tags = {
CodeName = "game"
}
########################如果有新参数,请参照
#https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/instance
#add ur codes below,添加新的代码,格式:key="value",缩进不严格
availability_zone = "cn-hongkong-c"
host_name = "i12jZ"
##付费类型两种PrePaid, PostPaid默认PostPaid,写为prepaid要指定订购时间,默认自动续订
##renewal_status为是否自动续费,AutoRenewal,Normal,NotRenewal,默认Normal
##unit可选Week,Month
##period是自动续费间隔
instance_charge_type = "PrePaid"
renewal_status = "Normal"
period_unit = "Month"
period = "1"
#spot策略可选NoSpot,SpotWithPriceLimit,SpotAsPriceGo
spot_strategy = "NoSpot"
#########################
}
#回返IP return pub&pri ip,会打印每一个机器的ID,公私IP,NAME
output "id_ip" {
value = {
for index, droplet in alicloud_instance.instance :
droplet.id => {
public-ip = droplet.public_ip
private-ip = alicloud_instance.instance[index].private_ip
#id = alicloud_instance.instance[index].id
Name = alicloud_instance.instance[index].instance_name
}
}
}
output "answer" {
#value = [for i in alicloud_instance.instance: i.public_ip]
value = "end and success"
}