如何有效檢測、識別和管理 Terraform 配置漂移?

作者|Krishnadutt Panchagnula
翻譯|Seal軟件
鏈接|https://betterprogramming.pub/detecting-identifying-and-managing-terraform-state-drift-997366a74537
?
在理想的 IaC 世界中,我們所有的基礎(chǔ)設(shè)施實現(xiàn)和更新都是通過將更新的代碼推送到 GitHub 來編寫和實現(xiàn)的,這將觸發(fā) Jenkins 或 Circle-Ci 中的 CI/CD 流水線,并且這些更改會反映在我們常用的公有云中。但現(xiàn)實并沒有這么順利,原因可能有很多,例如:
?
公司仍處于云自動化的初級階段;
不同團隊中的多個利益相關(guān)者正在通過控制臺開發(fā)概念驗證;
引入臨時手動熱修復(fù)以穩(wěn)定當(dāng)前生產(chǎn);
用戶并不知道 IaC 工具。
鑒于這些原因,系統(tǒng)中引入了不同類別的漂移,每種類別都有自己的補救措施。本文介紹了 Terraform 漂移、其類別、修復(fù)策略以及監(jiān)測 Terraform 漂移的工具。為了更好地理解這些概念,我們將會帶你探究什么是 Terraform 漂移以及在 Terraform 中如何檢測這種漂移。
?
什么是 Terraform 漂移?
當(dāng)我們使用 Terraform 創(chuàng)建資源(即 terraform apply)時,它會存儲有關(guān)當(dāng)前基礎(chǔ)設(shè)施的信息,本地或遠(yuǎn)程支持在名為 terraform.tfstate 。隨后 terraform apply 將根據(jù)基礎(chǔ)設(shè)施的當(dāng)前狀態(tài)進(jìn)行更新。但是,當(dāng)我們通過控制臺或 CLI 進(jìn)行手動更改時,這些更改會應(yīng)用到云環(huán)境中,但不會在狀態(tài)文件中看到。
?
Terraform 漂移可以理解為從 Terraform 中定義的基礎(chǔ)設(shè)施的實際狀態(tài)與云環(huán)境中存在的基礎(chǔ)設(shè)施狀態(tài)觀察到的漂移/差異。
?

?
在上述幾種情況下,在 Terraform 代碼之外進(jìn)行基礎(chǔ)架構(gòu)更改都會導(dǎo)致 Terraform 狀態(tài)文件的狀態(tài)與云環(huán)境的狀態(tài)截然不同。因此,當(dāng)我們下次應(yīng)用 Terraform 代碼時,我們會發(fā)現(xiàn) Terraform 漂移,這可能會導(dǎo)致 Terraform 資源更改或銷毀。因此,了解不同類型的漂移如何滲透到我們的基礎(chǔ)設(shè)施中可以幫助我們有效減輕此類風(fēng)險。
?
漂移類型
我們可以將 Terraform 配置漂移分為三類:
?
Emergent drift?—— 在 Terraform 生態(tài)系統(tǒng)之外進(jìn)行基礎(chǔ)設(shè)施更改時觀察到的漂移,該生態(tài)系統(tǒng)最初是通過 Terraform 應(yīng)用的(因此它們的狀態(tài)存在于 Terraform 狀態(tài)文件中)。
Pseudo drift?—— 由于列表中的訂購項目和其他提供商的特性而在計劃/應(yīng)用周期中看到的“變化”。
Introduced drift?—— 在 Terraform 之外創(chuàng)建的新基礎(chǔ)設(shè)施。
不過關(guān)于引入漂移(Introduced drift)是否應(yīng)當(dāng)被考慮進(jìn)來一直存在爭議,因為基礎(chǔ)設(shè)施完全是通過控制臺設(shè)置的。但使用 Terraform 是通過代碼完全自動化基礎(chǔ)設(shè)施流程,因此任何包含手動創(chuàng)建的基礎(chǔ)設(shè)施都被認(rèn)為是配置漂移。
?
管理 Emergent Drift
如前所述,當(dāng) Terraform 應(yīng)用和管理的基礎(chǔ)設(shè)施在 Terraform 生態(tài)系統(tǒng)之外進(jìn)行修改時,會觀察到浮現(xiàn)漂移(Emergent Drift)。這時我們可以根據(jù)習(xí)慣的首選狀態(tài)進(jìn)行管理:
?
基礎(chǔ)設(shè)施狀態(tài):如果我們的首選狀態(tài)是云中的狀態(tài),那么可以更改 Terraform 配置圖(通常是
main.tf
文件)及其依賴模塊,以便下次運行時?terraform apply
配置文件和 Terraform 狀態(tài)文件同步。配置狀態(tài):如果我們的首選狀態(tài)是配置文件中的狀態(tài),我們只需使用配置文件運行?
terraform apply?
即可。這將取消云中的所有更改并應(yīng)用 Terraform 配置文件中的配置。
管理 Pseudo Drift
當(dāng)配置文件中某些資源或資源的某些參數(shù)的順序與狀態(tài)文件中不同時,這就是偽漂移(Pseudo Drift)了。這種漂移并不常見。為了更好地理解這一點,我們以創(chuàng)建多可用區(qū) RDS 為例。
resource "aws_db_instance" "default" { ?
?allocated_storage = 10 ?
?engine = "mysql" ?
?engine_version = "5.7" ?
?instance_class = "db.t3.micro" ? ? ? ?
? ? ? ? availability_zone = ["us-east-1b","us-east-1c","us-east-1a"]# Us-east -1a was added later
? name = "mydb"?
?username = "foo" ?
?password = "foobarbaz" ?
?parameter_group_name = "default.mysql5.7" ?
?skip_final_snapshot = true
}
起初我們只需要 east-1b 和 1c,但后來添加了 1a。當(dāng)我們應(yīng)用此配置時,它運行成功。作為細(xì)心的 SRE 工程師,我們通過運行terraform plan
來確認(rèn)一切都是正常進(jìn)行的。但驚訝的是,我們可能會看到它通過“availability zone”行的更改再次添加此資源。當(dāng)我們再次應(yīng)用此更改時,此更改日志可以在后續(xù)生命周期terraform apply
中顯示。
?
為了便于管理,我們應(yīng)該運行terraform show
來顯示當(dāng)前的狀態(tài)文件。找到可用區(qū)參數(shù)并查看這些參數(shù)作為列表傳遞的順序,將這些值復(fù)制到 Terraform 配置文件中。
?
管理 Introduced Drift
當(dāng)在云上的 Terraform 生態(tài)系統(tǒng)之外配置新基礎(chǔ)設(shè)施時,就會出現(xiàn)引入漂移。這是最可怕的漂移類型,由于 Terraform 狀態(tài)文件中沒有跟蹤這些變化,因此需要工程師們認(rèn)真努力地進(jìn)行檢測和處理。引入漂移很難檢測,需要通過控制臺查看每個資源、讀取云監(jiān)視日志、檢查計費控制臺或向完成此更改的人詢問確認(rèn)。當(dāng)我們運行terraform destroy
時,某些資源無法銷毀,也會發(fā)生這種情況。
?
如果我們可以識別手動配置的資源,則根據(jù)其所在的環(huán)境有兩種方法進(jìn)行處理:
?
重新配置:如果資源不在生產(chǎn)級環(huán)境中,建議銷毀該資源,然后在 Terraform 配置文件中為其創(chuàng)建一個模塊。這樣,基礎(chǔ)設(shè)施就可以通過 Terraform 狀態(tài)文件進(jìn)行記錄、跟蹤和監(jiān)控,并且所有資源都是通過 Terraform 創(chuàng)建的。
Terraform 導(dǎo)入:如果資源存在于生產(chǎn)級環(huán)境中,則很難重新創(chuàng)建它。在本例中,我們使用“terraform import”導(dǎo)入資源。Terraform 導(dǎo)入幫助我們?yōu)橄嚓P(guān)資源創(chuàng)建 Terraform HCL 代碼。獲得此資源后,我們可以將此代碼復(fù)制到 Terraform 配置文件中,應(yīng)用該文件后,將使用與云中存在的狀態(tài)相同的配置來更新狀態(tài)文件。
漂移識別和監(jiān)控
只有當(dāng)我們能夠檢測到存在漂移時,才能完成所有這些漂移管理。在浮現(xiàn)漂移和偽漂移的情況下,我們可以使用terraform plan
命令來識別它們,該命令會將當(dāng)前狀態(tài)文件與云中的資源(之前使用 Terraform 創(chuàng)建)進(jìn)行比較。但在引入漂移的情況下會失敗,因為在 Terraform 生態(tài)系統(tǒng)之外創(chuàng)建的資源沒有狀態(tài)。因此,如果我們可以提前檢測到這種漂移并通過 IaC 工具實現(xiàn)自動化那就再好不過了。這里我們列出了以下兩種工具來提前檢測引入漂移。
?
CloudQuery
如果您喜歡使用以數(shù)據(jù)為中心的方法和可視化儀表板,那么此解決方案很適合您。CloudQuery 是一個開源工具,它將狀態(tài)文件與我們所需的云提供商中的資源進(jìn)行比較,然后格式化該數(shù)據(jù)并將其加載到 PostgreSQL 數(shù)據(jù)庫中。由于漂移檢測命令是在 PostgreSQL 之上創(chuàng)建的,并且具有托管或非托管列,因此我們可以使用此標(biāo)志作為篩選器,在我們最喜歡的儀表板解決方案(例如 Tableau 或 Power BI)中進(jìn)行可視化,以監(jiān)控基礎(chǔ)設(shè)施狀態(tài)漂移。
?
有關(guān)更多信息,請參閱?https://www.cloudquery.io/docs/cli/commands/cloudquery。
?
providers: ?
# provider configurations ?
- name: aws ? ?
configuration: ? ? ?
accounts: ? ? ? ? ? ? ?
- id: <UNIQUE ACCOUNT IDENTIFIER> ? ? ?
# Optional. Role ARN we want to assume when accessing this account ? ? ?
# role_arn: < YOUR_ROLE_ARN > ? ? ?
# Named profile in config or credential file from where CQ should grab credentials ? ? ?
local_profile = default ? ? ?
# By default assumes all regions ? ? ? ? ? ?
regions: ? ? ? ? ? ? ?
- us-east-1 ? ? ? ? ? ? ?
- us-west-2 ? ? ? ? ? ?
# The maximum number of times that a request will be retried for failures. ? ? ? ? ? ?max_retries: 5 ? ?
# The maximum back off delay between attempts. The backoff delays exponentially with a jitter based on the number of attempts. Defaults to 30 seconds. ? ? ?
max_backoff: 20 ? ? ?
# ? ?
# list of resources to fetch ? ? ? ? ? ?
resources: ? ? ? ? ? ? ?
- "*"
?
Driftctl
如果您偏向使用終端的 CLI,那么 DriftCtl 很適合您。該工具可以幫助我們跟蹤和檢測單個命令可能發(fā)生的托管和非托管漂移。
?

?
由于這是一個基于 CLI 的工具,因此可以輕松集成到 Jenkins 管道中編寫的 CI/CD 流水線中,并且結(jié)果可以作為輸出推送到 GitHub 中的 PR。如果你對這款工具不感興趣,請將其作為系統(tǒng)中的 cron 作業(yè)運行。創(chuàng)建一個日志組來收集日志,然后使用日志監(jiān)控解決方案(例如 Fleuentd 或 Prometheus/graphana 包)來進(jìn)行可視化并創(chuàng)建警報解決方案。
?
了解更多工具相關(guān)信息,請閱讀?https://docs.driftctl.com/0.35.0/installation
?
#to scan local filedriftctl scan
# To scan backend in AWS S3
driftctl scan --from tfstate+s3://my-bucket/path/to/state.tfstate
?
結(jié) 論
最后,我想就編寫更好的代碼和采用更優(yōu)的編碼實踐總結(jié)幾點我的思考:
始終嘗試構(gòu)建自動化基礎(chǔ)設(shè)施。即使您執(zhí)行手動步驟,也請嘗試將它們導(dǎo)入 Terraform 腳本,然后進(jìn)行應(yīng)用。
漸進(jìn)地、逐步地增加編寫和應(yīng)用的代碼,避免一次性編寫和應(yīng)用超長代碼。
實施帶有自定義警報系統(tǒng)的漂移跟蹤系統(tǒng),確保該系統(tǒng)將向 SRE 發(fā)送有關(guān)觀察到的基礎(chǔ)漂移的信息。