Terraform 知幾何?
Terraform 是一個 IT 基礎(chǔ)架構(gòu)自動化編排工具,它的口號是 "Write, Plan, and create Infrastructure as Code", 基礎(chǔ)架構(gòu)即代碼。具體的說就是可以用代碼來管理維護(hù) IT 資源,比如針對 AWS,我們可以用它創(chuàng)建,修改,刪除 S3 Bucket, Lambda, EC2 實例,Kinesis, VPC 等各種資源。并且在真正運(yùn)行之前可以看到執(zhí)行計劃(即干運(yùn)行-dryrun)。由于狀態(tài)保存到文件中,因此能夠離線方式查看資源情況 -- 當(dāng)然,前提是不要在 Terraform 之外對資源進(jìn)行修改。
Terraform 配置的狀態(tài)除了能夠保存在本地文件中,也可以保存到 Consul, S3, azure, http, swift 等處。
Terraform 是一個高度可擴(kuò)展的工具,通過 Provider 來支持新的基礎(chǔ)架構(gòu),AWS 不過為目前官方內(nèi)建 68 個 Providers 中的一個。其他能用 Terraform 的地方有 Alicloud(阿里云, 實名制備案才能用), Google Cloud, Heroku, Kubernetes, Microsoft Azure, MySQL, RabbitMQ, Docker 等等。愿意的話可以寫自己的 Provider, 如搞個 Kafka 的話,用來管理 Topic 等的創(chuàng)建,維護(hù)工作。
Terraform 之前我們對 AWS 的操作用的是 awscli, 或 Serverless。awscli 什么都能做,但它是無狀態(tài)的,必須明確用不同的命令來創(chuàng)建,修改和刪除。Serverless 不是用來管理基礎(chǔ)架構(gòu)的,用它創(chuàng)建 Lambda 時創(chuàng)建資源都是很麻煩的事。AWS 提供的 CloudFormation 才是與 Terraform 較類似的工具,但是看到用法就頭疼。
下面從最簡單例子開始,看看怎么用 Terraform 創(chuàng)建,刪改,修改 S3 Bucket。
- Terraform 安裝
Linux操作系統(tǒng)安裝:
# 安裝依賴工具
sudo yum install wget unzip
# 下載terraform并安裝terraform
wget https://releases.hashicorp.com/terraform/0.11.10/terraform_0.11.10_linux_amd64.zip
unzip terraform_0.11.10_linux_amd64.zip
mv terraform /usr/local/bin/
Mac操作系統(tǒng)安裝:
brew install terraform
安裝后 shell 命令就是 terraform, 常用的是 terraform init, terraform plan, terraform apply
- 創(chuàng)建配置文件
像 git 一樣,每個 Terraform 項目需要自己單獨(dú)的目錄空間,所以我們創(chuàng)建一個 terraform-learning 目錄
mkdir terraform-learning
cd terraform-learning
該目錄下的所有 *.tf 文件都會被 Terraform 加載,在初始化 Terraform 工作空間之前必須至少要有一個 *.tf 文件。我們這里建立文件 main.tf, 內(nèi)容如下

Terraform 配置的語法是該公司 HashiCorp 獨(dú)創(chuàng)的 HCL(HashiCorp configuration language), 它可以兼容 JSON 格式。
上面 tf 文件在 Vim 中的語法加亮是安裝的 hashivim/vim-terraform 插件。
我們寫好了 *.tf 文件后可以調(diào)用 terraform fmt 對配置文件進(jìn)行格式化,它比較喜歡被 Java 棄用的等號對齊的格式。
- 配置文件介紹
從正式跨入 terraform 命令正題之前先來大概的介紹一下上面那個 main.tf 文件。
- provider "aws" 部分,它指定選用什么 provider, 以及驗證信息。aws 既允許指定 access_key 和 secret_key
provider "aws" {
region = "us-east-1"
access_key = "your-access-key-here"
secret_key = "your-secret-key-here"
}
也能夠指定證書文件中的 profile
provider "aws" {
region = "us-east-1"
shared_credentials_file = "~/.aws/credentials" //不指定的話,默認(rèn)值是 "~/.aws/credentials"
profile = "yanbin" //不指定的話,默認(rèn)值是 "default"
}
如果是使用 shared_credentials_file 中的 profile, 請確定您以預(yù)先生成好的 credentials 文件及有效的 profile。
更多關(guān)于 AWS Provider 的配置請參考 https://www.terraform.io/docs/providers/aws/index.html
- resource "aws_s3_bucket" "s3_bucket" 部分
這只是我們今天舉的一個小例子,點(diǎn)擊鏈接 aws_s3_bucket 查看 S3 Bucket 所有的配置項。Terraform 能夠管理的所有 AWS 資源也能從前面那個鏈接中看到。
如果 bucket yanbin-test-bucket 不存在的話,運(yùn)行 terraform apply 將會創(chuàng)建它,否則試圖更新該 bucket。此例子只指定了 bucket 的 acl 和 tag 信息。terraform destroy 用來刪除已存在的 bucket。
注意:terraform 配置文件中只指定要管理的資源對象,并不關(guān)心操作資源的行為--創(chuàng)建,修改,刪除操作。操作行為與 Terraform 的狀態(tài)有關(guān)系,無則創(chuàng)建,有則修改,更名會拆分為除舊立新兩個操作,terraform destroy 用于顯式刪除資源。后面實例操作時會講到。
注:resource "aws_s3_bucket" "s3_bucket" { 中,resource 后第一個是 type, 即資源名,第二個參是 name。其實 "s3_bucket" 在這里沒什么用,只是一個描述或助記符而已。(2017-08-28): 更正一下,在作為變量引用的時候就要用到它,例如在后面要為 Lambda 創(chuàng)建一個 S3 Event 的 Trigger, 就要寫成 event_source_arn = "${aws_s3_bucket.s3_bucket.arn}", 引用時不需要知道實際的名稱。
- 初始化工作目錄
在初始化 Terraform 工作目錄之前, 其他命令如 apply, plan 多是不可用的,提示需要初始化工作目錄,命令是
terraform init
它要做的事情像是 git init 加上 npm install,執(zhí)行完了 terraform init 之后會在當(dāng)前目錄中生成 .terraform 目錄,并依照 *.tf 文件中的配置下載相應(yīng)的插件。
- 執(zhí)行 Terraform 管理命令
有了前面的準(zhǔn)備之后,終于可以開始運(yùn)行 Terraform 的管理命令了。Terraform 在正式執(zhí)行之前提供了預(yù)覽執(zhí)行計劃的機(jī)會,讓我們清楚的了解將要做什么
terraform plan

由此計劃還能知道關(guān)于 aws_s3_bucket 有些什么配置項,比如配置中可以加上 acceleration_status = "Enabled"
terraform apply

這樣便在 AWS 上創(chuàng)建了一個 S3 bucket "yanbin-test-bucket", 同時會在當(dāng)前目錄中生成一個狀態(tài)文件 terraform.tfstate, 它是一個標(biāo)準(zhǔn)的 JSON 文件。這個文件對 Terraform 來說很重要,它會影響 terraform plan 的決策,雖然不會影響到實際的執(zhí)行效果。我們可以把它存到遠(yuǎn)端,如 S3 或 Consul。terraform state [list|mv|pull|push|rm|show] 用來操作狀態(tài)文件。
此時什么也不改,再次執(zhí)行 terraform plan, 會顯示沒什么要做的
aws_s3_bucket.s3_bucket: Refreshing state... (ID: yanbin-test-bucket)
No changes. Infrastructure is up-to-date.
如果對 main.tf 作點(diǎn)小改,改個 tag 屬性,再次 terraform plan
~ aws_s3_bucket.s3_bucket
tags.Name: "Created by Terraform" => "sCreated by Terraform"
Plan: 0 to add, 1 to change, 0 to destroy.
為什么說 terraform plan 是基于狀態(tài)文件 terraform.tfstate 作出的呢?我們可以刪除這個狀態(tài)文件,然后執(zhí)行 terraform plan 看看
+ aws_s3_bucket.s3_bucket
.....
bucket: "yanbin-test-bucket"
......
tags.Environment: "QA"
......
Plan: 1 to add, 0 to change, 0 to destroy.
Terraform 由于缺乏 terraform.tfstate 對比,所以認(rèn)為是要添加一個 bucket, 但是實際執(zhí)行 terraform apply 時,連接到遠(yuǎn)端 AWS, 發(fā)現(xiàn)該 bucket 已存在就只是進(jìn)行更新。terraform apply 總能給出正確的操作結(jié)果。同理如果狀態(tài)文件中說有那個 bucket, terraform plan 會說是更新,但 AWS 沒有那個 bucket,實際執(zhí)行 terraform apply 也會進(jìn)行添加的。
資源更名
如果把 main.tf 中的
bucket = "yanbin-test-bucket"
改成
bucket = "yanbin-test-bucket-rename"
即欲為 bucket 更名,用 terraform plan 看下計劃

實際上 terraform apply 也是先刪除舊的,再創(chuàng)建新的。Terraform 像 git 一樣用不同顏色和 +/- 號來顯示變動操作
最后是 terraform destroy 命令,把 *.tf 文件中配置的所有資源從 AWS 上清理掉。
- Terraform 工作目錄中文件命名
Terraform 運(yùn)行時會讀取工作目錄中所有的 *.tf, *.tfvars 文件,所以我們不必把所有的東西都寫在單個文件中去,應(yīng)按職責(zé)分列在不同的文件中,例如:
provider.tf -- provider 配置
terraform.tfvars -- 配置 provider 要用到的變量
varable.tf -- 通用變量
resource.tf -- 資源定義
data.tf -- 包文件定義
output.tf -- 輸出
以此篇最簡單的入門出發(fā),以后可以深入了解 Lambda, Lambda 觸發(fā)器,及 API Gateway, EC2 實例怎么用 Terraform 來管理,也知曉了資源的可用屬性應(yīng)該到哪里去查。
vpc123的小提示:在執(zhí)行像 terraform plan 或 terraform apply 等命令的時候,可以按下 ctrl + c 讓控制臺輸出詳細(xì)的日志信息。