《Terraform 101 從入門到實踐》 第一章 Terraform初相識

2023-02-09 12:03:57

《Terraform 101 從入門到實踐》這本小冊在南瓜慢說官方網站GitHub兩個地方同步更新,書中的範例程式碼也是放在GitHub上,方便大家參考檢視。


初聞不知Terraform,再聞已是雲中人。

什麼叫基礎設施即程式碼?

在以前,當我們需要把應用部署在伺服器時,需要購買多臺伺服器和機房、組裝交換機和網路、不間斷電源UPS等。隨著雲時代的到來,我們可以在IaaS(Infrastructure as a Service)平臺直接購買所有的基礎設施,包括伺服器、專用網路、DNS、負載均衡等,而你只需要專注於應用層面即可。

IaaS(Infrastructure as a Service)的意思是基礎設施即服務,它是雲服務的基礎。著名的IaaS廠商有亞馬遜、微軟、谷歌和阿里雲等。

雲廠商為我們解決了許多運維問題:我們不再需要自己管理物理機器,而且能夠根據需要隨時建立和銷燬雲機器,還能根據業務和效能要求指定建立伺服器的設定和數量。這種便利對於創業型的小公司和個人開發者尤其重要。

隨時公司業務的良好發展,所需要的硬體資源越來越多,架構越來越複雜。通過介面操作手工建立伺服器、資料庫等資源的方式帶來越來越多的問題。首先,只要是人工操作,都會有失誤的可能,沒有人能保證自己不會犯錯;而人工操作在軟體行業發生事故的案例屢見不鮮。其次,為保證正確率,人工操作一般只能序列,資源多的時候時間會很長。最後,如果我需要根據開發環境的設定再建立一個測試環境和生產環境,人工操作可能會造成差異和錯誤。

因此,對於這種複雜需要,最佳的方式是通過程式碼來建立所有硬體資源。這種思想就是基礎設施即程式碼(Infrastructure as Code,很簡稱IaC),通過程式碼與定義、部署、更新和銷燬基礎設施。把硬體對映為軟體,而開發和運維人員通過管理程式碼來管理硬體。

IaC的好處有:

  • 自動化:與軟體代替人工,實現自動化,減少風險和安全問題;
  • 效率高:軟體可以並行建立資源,大大提高效率;
  • 記錄與追蹤:通過程式碼與執行情況,記錄硬體變更,出問題也可以追溯;
  • 重用與複製:抽取公共模組實現重用,如建立一個Kubernetes叢集的資源可以封裝成一個模組。

最終,實現快速安全地應用部署交付(Devivery)。

IaC工具

在IaC這方面的優秀工具還是非常多的,而且不同的工具完成不同的職責,下面列出一些比較常見的工具:

圖示 工具名 GitHub STAR數
Ansible 50.9k
Terraform 30.2k
Vagrant 23k
Chef 6.8k
Puppet 6.4k
AWS CloudFormation
Azure Resource Manager
Google Cloud Deployment Manager

其中,Ansible在設定自動化應該是領頭羊的地位。而Terraform則在服務開通上的事實標準。這裡並不想給各個工具做具體介紹,感興趣的可以去官網或GitHub瞭解。

注:有些文章或書籍會把Docker和Kubernetes也列為IaC工具,它們的主要職責是在容器與服務編排方面。

Terraform隆重登場

Terraform是什麼

我們的主角Terraform終於登場了。它是由HashiCorp公司研發的開源的IaC工具,它是由GO語言編寫的,可以在各個平臺上執行,支援Linux、Mac、Windows等。它簡單易用,即使沒有太多程式碼經驗的人,也能讀懂Terraform的設定程式碼HCL。

HCL,即HashiCorp Configuration Language,是HashiCorp公司開發的設定語言。後續我們會介紹一些常用語法。

Terraform是一個安全高效的用於對基礎設施進行建立和變更且進行版本控制的工具。它支援私有云和公有云,如AWS、Azure、GCP和阿里雲等。它的官方網站為https://www.terraform.io

特性

主要特性有:

  • 基礎設施即程式碼:通過設定語言HCL來描述基礎設施,也讓程式碼更好地共用和重用。
  • 變更計劃:在實際變更前可以根據程式碼和狀態生成即將要發生變更的計劃,它能告訴你將要生成、改變和銷燬哪些資源。這可以在執行變更前再做最好的檢查,為基礎設施提供多一層保護。
  • 資源檢視:可以根據依賴關係建立出資源檢視,可以直觀地檢視整個基礎設施的關係。
  • 自動化:無須人工干預就可以完成變更。

版本號

截至2021年12月02日,Terraform的最新版本為1.0.11,而它在2021年6月8日才正式釋出1.0.0版本。可見Terraform是如此年輕且有活力。而在Terraform還不是1.0.0版本的時候,已經有大量公司在生產環境上使用了。

架構與原理

Terraform是一個由Go語言編寫的程式,它會讀取HCL語言編寫的組態檔,然後將變更資訊通過RPC與外掛通訊,由外掛呼叫雲廠商的API完成變更操作。這就是Terraform的工作原理,架構圖如下:

基本概念

Terraform core:Terraform的核心元件,類似於指揮官,負責解析設定、管理狀態、模組等核心功能。

外掛Plugin:完成具體變更的元件,因為Terraform支援多種平臺,它並沒有把對所有平臺的支援都放到核心元件中實現,而是通過外掛的方式來提供這些功能。需要對接什麼平臺,就加入什麼平臺的外掛,非常方面。

模組module:可以將完成特定功能的HCL封裝成一個模組,以實現程式碼複用。類似於其它程式語言中的函數或方法。有入參和出參,一切都可自定義。

狀態state:狀態存在專門的狀態檔案裡,它是作用是記錄實際基礎設施的狀態。當再次執行變更請求時,Terraform會讀取狀態檔案,判斷是否真的需要變更實際的基礎設施。如果狀態檔案記錄的狀態與HCL描述的一致,就不用再執行變更操作了。

初體驗

下載安裝

Terraform就是一個二進位制的程式,只要下載並新增到PATH中去就可以了。各個系統的安裝方式沒有太大差異。這裡以Mac系統為例,做個簡單介紹。

下載程式:

可以直接到官網介面(https://www.terraform.io/downloads.html)去下載,請根據自己的系統選擇對應的檔案:

下載後進行解壓,並將該程式新增到環境變數中。

比如我的Terraform放在路徑/Users/larry/Software/terraform中,則新增到環境變數的命令如下:

export PATH=$PATH:/Users/larry/Software/terraform

為了讓它一直生效,我把上面命令放在home目錄下的.bash_profile檔案中。

檢查是否安裝成功如下:

$ terraform version
Terraform v1.0.11
on darwin_amd64

如果在純終端的環境下,也可以通過命令進行下載和解壓,命令如下:

# 下載安裝包
$ wget https://releases.hashicorp.com/terraform/1.0.11/terraform_1.0.11_darwin_amd64.zip
# 解壓
$ unzip terraform_1.0.11_darwin_amd64.zip

最簡單的任務:建立一個檔案

Terraform的主要應用場景是雲服務的基礎設施管理,但為了讓大家能快速的接觸與體驗Terraform,我會先選擇最簡單的一個外掛來入門,以免需要太多的環境設定。我們的任務是建立一個文字檔案,內容由我們來指定。可以通過外掛hashicorp/local來完成。

在當前目錄建立一個main.tf檔案,完整的程式碼如下:

terraform {
  required_version = "= v1.0.11"

  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "= 2.1.0"
    }
  }
}

resource "local_file" "terraform-introduction" {
  content  = "Hi guys, this the tutorial of Terraform from pkslow.com"
  filename = "${path.module}/terraform-introduction-by-pkslow.txt"
}

然後執行下面命令:

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/local versions matching "2.1.0"...
- Installing hashicorp/local v2.1.0...
- Installed hashicorp/local v2.1.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

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會自動幫我們去下載對應版本的外掛hashicorp/local,並做一些初始化的操作。

接著我們通過命令terraform plan來檢視將要執行的變更計劃:

$ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # local_file.terraform-introduction will be created
  + resource "local_file" "terraform-introduction" {
      + content              = "Hi guys, this the tutorial of Terraform from pkslow.com"
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "./terraform-introduction-by-pkslow.txt"
      + id                   = (known after apply)
    }

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

輸出紀錄檔中會提示需要建立、改變和銷燬多少資源。

Plan: 1 to add, 0 to change, 0 to destroy

這裡表示會建立一個資源。

廢話少說,我們直接執行變更:

$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # local_file.terraform-introduction will be created
  + resource "local_file" "terraform-introduction" {
      + content              = "Hi guys, this the tutorial of Terraform from pkslow.com"
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "./terraform-introduction-by-pkslow.txt"
      + id                   = (known after apply)
    }

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

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。我們直接輸入yes並按回車。

  Enter a value: yes

local_file.terraform-introduction: Creating...
local_file.terraform-introduction: Creation complete after 0s [id=f63c7933c953ea2d03820d1ec35a80c718bd4777]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

成功執行,建立了檔案。

$ ls -l
total 24
-rw-r--r--  1 larry  staff  344 Dec  3 00:01 main.tf
-rwxr-xr-x  1 larry  staff   55 Dec  3 00:13 terraform-introduction-by-pkslow.txt
-rw-r--r--  1 larry  staff  921 Dec  3 00:13 terraform.tfstate

上面還有一個tfstate檔案,是用來記錄狀態的,以後會詳細講這塊內容。

檢視一下檔案內容:

$ cat terraform-introduction-by-pkslow.txt 
Hi guys, this the tutorial of Terraform from pkslow.com

與我們預期的內容一致。

如果再次執行apply會不會再次建立一個檔案呢?還是建立失敗,因為檔案已存在?

帶著這樣的問題,我們再執行一次:

$ terraform apply
local_file.terraform-introduction: Refreshing state... [id=f63c7933c953ea2d03820d1ec35a80c718bd4777]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

發現提示不需要變更,不會執行任何操作。

大家可以思考一下為什麼,答案會在後面章節揭曉。

現在我不需要這個檔案呢,通過destroy命令可以刪除:

$ terraform destroy
local_file.terraform-introduction: Refreshing state... [id=f63c7933c953ea2d03820d1ec35a80c718bd4777]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # local_file.terraform-introduction will be destroyed
  - resource "local_file" "terraform-introduction" {
      - content              = "Hi guys, this the tutorial of Terraform from pkslow.com" -> null
      - directory_permission = "0777" -> null
      - file_permission      = "0777" -> null
      - filename             = "./terraform-introduction-by-pkslow.txt" -> null
      - id                   = "f63c7933c953ea2d03820d1ec35a80c718bd4777" -> null
    }

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

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

local_file.terraform-introduction: Destroying... [id=f63c7933c953ea2d03820d1ec35a80c718bd4777]
local_file.terraform-introduction: Destruction complete after 0s

Destroy complete! Resources: 1 destroyed.

一樣需要你確認是否真的需要刪除,輸入yes回車即可。

到這裡,就已經真正地帶大家體驗了一下Terraform是如何工作的,介紹了它的整個流程,也就是Terraform官網所說的Write, Plan, Apply。希望大家能真正動手實踐,包括後續的實驗,這跟學程式語言是一樣的。

最後,對於本次實驗我想提幾點:

  • 其中的plan命令不是必須的,它是展示即將發生的變更,你可以直接apply也是可以的;
  • 可以通過plan命令輸出計劃檔案,然後apply的時候指定計劃檔案;
  • 命令apply和destroy可以不必互動式輸入yes,通過新增引數-auto-approve即可。