Terraform Basic
入门
下载安装Terraform
Terraform 为一个二进制文件,只要下载下来放到PATH路径下即可使用.
Terraform基本使用: 在下载好tf文件之后,直接执行下面的命令即可部署,如果在当前路径下有多个tf文件,则按照字母顺序执行
Terraform 的基本配置
环境变量配置
Terraform可以配置环境变量,也可以不配置。如果配置环境变量的话,可以将环境变量保存到variables.tf这个文件中。变量可以指定不同的数据类型,比如list,set, map等格式,详情参考: https://www.terraform.io/docs/configuration/variables.html
示例配置文件
terraform中代码区间的说明
resource 指的是要创建什么资源,引用resource的输出,直接用resource.xxx就可以. 示例如下,引用name的时候需要指定 azurerm_resource_group.example_rg.name
data 指的是获取现有的配置的属性,引用data的输出,要使用data.xxx.xxx这种方式,示例如下,引用name的时候要指定 data.azurerm_ssh_public_key.pub_key.name
将结果通过output打印出来
如果想要获得resource执行的结果,那么可以通过output进行打印,在创建module的时候,也是通过 output来实现传参的
Terraform Doc
terraform-docs 是一个产生 terraform doc的很好的工具,在编写terraform module的时候,会根据 variable 以及 output,自动产生对应的文档。
Terraform Console
直接输入 terraform console 就可以进入 terraform 控制台界面,在这里可以进行调试。但是没办法在console里定义变量,所以需要先在当前路径下创建好 .tf 文件,在 .tf 文件里定义变量,此时对于调试来说,有点不方便。可以推荐 terraform-repl 这个第三方程序进行调试
terraform 使用技巧
验证tf文件是否有语法错误:terraform validate
调用其他workspace的state文件
列出workspace: terraform workspace list
控制日志 TF_LOG 控制terraform 的log
使用编程语言来更高级的使用tf:https://www.pulumi.com/
terraform module 开发
当频繁创建某些资源,且这些资源需要有相同的配置信息,或者要求创建的资源必须有某个tag。这种情况下,可以创建module,将配置信息写在module里面,这样调用module创建资源的时候,就自动复用了之前的代码,自动创建了tag。
module 还能规范资源的创建,比如在module里,指定创建资源的名字为 ${var.project}-${var.env}-${var.service},这样创建出来的资源名字就是这样的规范。
虽然module可以规范命名,但在后期维护的时候,有时候要对资源进行搜索,使用上述方法可能并不能直接搜到,所以如果创建resource的时候,有description的字段,在description字段里指定真实值。
开发一个module非常简单,按原来写创建resource的方式创建资源,只是资源的名字用某一个变量,而不给这个变量赋值。然后引用module的时候进行赋值即可。
通过创建一个 nginx docker 的module来进行测试。首先我们创建一个modules的文件夹,在这个文件夹下创建一个 docker_container 的文件夹,这个docker_container 文件夹会作为module的source名字被引入。在docker_container 文件夹下,可以创建 main.tf 和 variables.tf,将变量写到 variables.tf 文件中,将主代码写到main.tf 中。当然,实际上,也可以全部都放在一个文件中,文件名也可以随意写。
示例 variables.tf
示例main.tf
创建资源的时候,创建一个 test_container.tf,内容如下
之后用terraform plan和terraform apply执行。
开发module注意事项
将module的相关文件放在同一个文件夹内,然后在创建资源引用模块的时候,source里指定这个文件夹位置。
module 后面跟的名字是可以随便写的,引用的模块主要是source位置
module里尽量不要hard code一些变量,将变量都放到variables.tf里,然后在创建资源的时候通过参数传过去。另外module里不一定有 provider 信息,这样在创建资源的时候,会引用资源文件所在的目录里的 provider信息。
在写module的时候,如果在module文件的resource里,已经引用了某个参数,尽管这个参数在resource里是可选的,但如果 variables.tf 文件里并没有设置default值,这时候引用这个module的时候,这个参数就变成了required,必须指定值,否则会报错。这也就意味着,比如要求创建资源,必须有tag,那么只需要在module定义的时候,指定下tag,variables里也不需要给tag赋值,就达到了引用这个module必须指定tag的要求。
示例:module文件里指定了dns
variable文件里定义了dns,但没赋值
通过module创建资源的时候,必须指定dns
Terraform 对shell命令的操作
在使用terraform 的过程中,有时候需要和本地进行交互操作。比如有时候需要在本地创建个文件,文件中的内容有引用terraform的变量,且这个文件创建好之后需要执行shell命令,比如通过git命令上传到git repo里等。这时候可以用 local_file 来创建文件, 文件内容也可以引用 templatefile() 来进行模版化,之后再使用 terraform 的 local-exec provisoner执行shell命令,将文件上传到git repo。有关file的使用点击这里,有关local-exec使用点击这里
示例:创建一个空资源,调用本地的 aws cli 命令,将查询到的EC2信息保存到本地的describeEC2.txt 文件中
terraform 的if语句
terraform不是一个图灵完备的开发语言,没有办法直接实现if else,或者while ,case等语句,但可以通过count 来判断一个变量是否存在,如果存在,则count=1,即开始创建资源,否则count=0
或者
在资源创建的时候,可以用 count 做判断,但是如果只是给其中某一个变量赋值的时候做判断,此时要用 for_each做判断。参考下文 block 动态创建
Terraform 的for 循环
如果有两层for循环,第二层for循环,如果返回值是一个 map (看for循环后面是否有 => ,如果有,就是map),那么第一层for循环后面就一定要包含 map{} 的数据类型,当然也可以是map{}的超集,比如list(map{})。如果第二层for循环没有 =>即返回值不是map{},那么第一层for循环就不需要包含map,可以直接使用list[]
Terraform 有关block动态创建
进行逻辑判断,可以通过 dynamic 实现。dynamic 里面,要有一个 for_each 循环,但我们可以根据这个循环,加上逻辑判断,如果为true,则创建,否则则不创建。由于for_each是对一个list进行的操作,因此我们让返回值为一个 list [],里面存放任意一个元素就可以,比如存放为 ["true"],或者 ["abc"]都可以。另外,如果某一个resource里面的某个字段为 null,那么就相当于没有这个字段。如下面的示例, target_group_arn 和 "redirect" {} 是互斥字段,但如果 target_group_arn 有值,redirect 不创建出来;或者target_group_arn为null,但 redirect {} 创建出来,那么都是可以的
Terraform State
如果一个资源已经被terraform创建,但后期不想通过 terraform 管理,可以先通过 terraform state list将这个资源列出来,然后执行 terraform state rm 将其从state 文件中删除
如果创建一个资源的时候,不小心起错名字,但资源已经创建,后面如果改名,就需要重新创建,会比较麻烦。那么可以用 state mv 的方式,对资源名进行修改。比如
在新版本的terraform 中,对于state的管理,可以在 tf 文件里,通过 mv 命令进行管理,方便做 pr review
Terraform CLI Version管理
可以下载安装 tfenv 对多个terraform 客户端的版本进行管理
TFE State 迁移
将TFE workspace从一个organization迁移到另外一个organization
创建相同的workspace,要保证版本以及环境变量都一致,VCS也一致
最后更新于