《Terraform 101 從入門到實踐》 第四章 States狀態管理

来源:https://www.cnblogs.com/larrydpk/archive/2023/02/10/17110224.html
-Advertisement-
Play Games

《Terraform 101 從入門到實踐》這本小冊在南瓜慢說官方網站和GitHub兩個地方同步更新,書中的示例代碼也是放在GitHub上,方便大家參考查看。 軍書十二捲,捲捲有爺名。 為什麼需要狀態管理 Terraform的主要作用是管理雲平臺上的資源,通過聲明式的HCL配置來映射資源,如果雲平臺 ...


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


軍書十二捲,捲捲有爺名。

為什麼需要狀態管理

Terraform的主要作用是管理雲平臺上的資源,通過聲明式的HCL配置來映射資源,如果雲平臺上沒有資源則需要創建,如果有則不用。那Terraform要實現這個功能有多種方式。

一種是每次執行apply命令時都調用API介面檢查一下遠程的雲資源是否與配置文件一致,如果沒有則創建,如果有但不同則需要修改,如果有且相同則不用變更。這種機制能保證雲平臺的資源與HCL配置是一致的。缺點也是非常明顯的,每次都需要調用API去檢查遠程資源,效率很低,特別是當資源特別多的場景。

另一種方式是每次變更資源的時候,都會創建一個映射文件,它保存雲平臺資源的狀態。這樣每次執行apply命令時,只需要檢查HCL配置與映射文件的差異即可。

Terraform選擇的是第二種方式,通過映射文件來保存資源狀態,在Terraform的世界里叫狀態文件。Terraform這樣做是基於以下考慮:

  • 雲平臺真實狀態的映射,解析狀態文件即可以知道真實情況。
  • 元數據存儲,如資源之間的依賴關係,需要通過依賴關係來知道創建或銷毀順序。
  • 提升性能,特別是在大規模雲平臺上,多次調用API去查詢資源狀態是很費時的。
  • 同步狀態,通過遠程狀態文件來同步狀態,這也是Terraform最佳的實踐。

講到這裡,已經回答了之前在第一章留下的思考題:

如果再次執行apply會不會再次創建一個文件呢?還是創建失敗,因為文件已存在?為什麼?

答案:不會創建,因為通過狀態文件記錄了變更,Terraform判斷不再需要創建了。

狀態管理的示例

為了更多註意力放在狀態管理上,我們還是使用最簡單的例子local_file,具體代碼如下:

resource "local_file" "terraform-introduction" {
  content  = "https://www.pkslow.com"
  filename = "${path.root}/terraform-guides-by-pkslow.txt"
}

我們以實際操作及現象來講解狀態文件的作用和工作原理:

操作 現象及說明
terraform apply 生成資源:第一次生成
terraform apply 沒有變化:狀態文件生成,不需要再創建
terraform destroy 刪除資源:根據狀態文件的內容刪除
terraform apply 生成資源:狀態顯示沒有資源,再次生成
刪除狀態文件 沒有變化
terraform apply 生成資源:沒有狀態文件,直接生成資源和狀態文件(插件做了容錯處理,已存在也會新生成覆蓋)
刪除狀態文件 沒有變化
terraform destroy 無法刪除資源,沒有資源存在的狀態

我們一直在講狀態文件,我們先來看一下它的真面目。首先它的預設文件名是terraform.tfstate,預設會放在當前目錄下。它是以json格式存儲的信息,示例中的內容如下:

{
  "version": 4,
  "terraform_version": "1.0.11",
  "serial": 1,
  "lineage": "acb408bb-2a95-65fd-02e6-c23487f7a3f6",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "local_file",
      "name": "test-file",
      "provider": "provider[\"registry.terraform.io/hashicorp/local\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "content": "https://www.pkslow.com",
            "content_base64": null,
            "directory_permission": "0777",
            "file_permission": "0777",
            "filename": "./terraform-guides-by-pkslow.txt",
            "id": "6db7ad1bbf57df0c859cd5fc62ff5408515b5fc1",
            "sensitive_content": null,
            "source": null
          },
          "sensitive_attributes": [],
          "private": "bnVsbA=="
        }
      ]
    }
  ]
}

可以看到它記錄了Terraform的版本信息,還有資源的詳細信息:包括類型、名字、插件、屬性等。有這些信息便可直接從狀態文件里解析出具體的資源。

狀態管理命令

可以通過terraform state做一些狀態管理:

顯示狀態列表:

$ terraform state list
local_file.test-file

查看具體資源的狀態信息:

$ terraform state show local_file.test-file
# local_file.test-file:
resource "local_file" "test-file" {
    content              = "https://www.pkslow.com"
    directory_permission = "0777"
    file_permission      = "0777"
    filename             = "./terraform-guides-by-pkslow.txt"
    id                   = "6db7ad1bbf57df0c859cd5fc62ff5408515b5fc1"
}

顯示當前狀態信息:

$ terraform state pull

重命名:

$ terraform state mv local_file.test-file local_file.pkslow-file
Move "local_file.test-file" to "local_file.pkslow-file"
Successfully moved 1 object(s).

$ terraform state list
local_file.pkslow-file

要註意這裡只是修改狀態文件的名字,代碼里的HCL並不會修改。

刪除狀態里的資源:

$ terraform state rm local_file.pkslow-file
Removed local_file.pkslow-file
Successfully removed 1 resource instance(s).

遠程狀態

狀態文件預設是在本地目錄上的terraform.tfstate文件,在團隊使用中,每個人的電腦環境獨立的,那麼需要保證每個人當前的狀態文件都是最新且與現實資源真實對應,簡直是天方夜譚。而狀態不一致所帶的災難也是極其可怕的。所以,狀態文件最好是要存儲在一個獨立的大家可共同訪問的位置。對於狀態的管理的配置,Terraform稱之為Backends

Backend是兩種模式,分別是localremotelocal模式很好理解,就是使用本地路徑來存儲狀態文件。配置示例如下:

terraform {
  backend "local" {
    path = "pkslow.tfstate"
  }
}

通過這樣配置後,不再使用預設的terraform.tfstate文件,而是使用自定義的文件名pkslow.tfstate

對於remote模式,則有多種配置方式,Terraform支持的有:

  • s3
  • gcs
  • oss
  • etcd
  • pg
  • http
  • kubernetes

等,能滿足主流雲平臺的需求。每一個配置可以參考官網,在本地我採用資料庫postgresql的方式,讓大家都能快速實驗。

我通過Docker的方式啟動PostgreSQL,命令如下:

$ docker run -itd \
    --name terraform-postgres \
    -e POSTGRES_DB=terraform \
    -e POSTGRES_USER=pkslow \
    -e POSTGRES_PASSWORD=pkslow \
    -p 5432:5432 \
    postgres:13

terraform塊中配置backend,這裡指定資料庫連接信息即可,更多參數請參考:https://www.terraform.io/language/settings/backends/pg

terraform {
  backend "pg" {
    conn_str = "postgres://pkslow:pkslow@localhost:5432/terraform?sslmode=disable"
  }
}

當然,把敏感信息直接放在代碼中並不合適,可以直接在命令行中傳入參數:

terraform init -backend-config="conn_str=postgres://pkslow:pkslow@localhost:5432/terraform?sslmode=disable"

執行init和apply之後,連接資料庫查看,會創建一個叫terraform_remote_state的Schema,在該Schema下有一張states表來存儲對應的狀態信息,如下:

表中欄位name是namespace,而data是具體的狀態信息,如下:

{
  "version": 4,
  "terraform_version": "1.0.11",
  "serial": 0,
  "lineage": "de390d13-d0e0-44dc-8738-d95b6d8f1868",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "local_file",
      "name": "test-file",
      "provider": "provider[\"registry.terraform.io/hashicorp/local\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "content": "https://www.pkslow.com",
            "content_base64": null,
            "directory_permission": "0777",
            "file_permission": "0777",
            "filename": "./terraform-guides-by-pkslow.txt",
            "id": "6db7ad1bbf57df0c859cd5fc62ff5408515b5fc1",
            "sensitive_content": null,
            "source": null
          },
          "sensitive_attributes": [],
          "private": "bnVsbA=="
        }
      ]
    }
  ]
}

Workspace 工作區

如果我們用Terraform代碼生成了dev環境,但現在需要uat環境,該如何處理呢?

首先,不同環境的變數一般是不一樣的,我們需要定義各種的變數文件如dev.tfvarsuat.tfvarsprod.tfvars等。但只有各自變數是不夠的,因為還有狀態。狀態也必須要隔離,而Workspace就是Terraform用來隔離狀態的方式。預設的工作區為default,如果沒有指定,則表示工作於default工作區中。而當指定了工作區,狀態文件就會與工作區綁定。

創建一個工作區並切換:

$ terraform workspace new pkslow

切換到已存在的工作區:

$ terraform workspace select pkslow

而當我們處於某個工作區時,是可以獲取工作區的名字的,引用為:${terraform.workspace},示例如下:

resource "aws_instance" "example" {
  count = "${terraform.workspace == "default" ? 5 : 1}"

  # ... other arguments
}

之前講過預設的狀態文件名為terraform.tfstate;而在多工作區的情況下(只要你創建了一個非預設工作區),狀態文件就會存在terraform.tfstate.d目錄下。而在遠程狀態的情況下,也會有一個映射,Key為工作區名,Value一般是狀態內容。

敏感數據

本地狀態文件都是明文存儲狀態信息的,所以要保護好自己的狀態文件。對於遠程狀態文件,有些存儲方案是支持加密的,會對敏感數據(sensitive)進行加密。

狀態鎖

本地狀態文件下不需要狀態鎖,因為只有一個人在變更。而遠程狀態的情況下,就可能出現競爭了。比如一個人在apply,而另一個人在destroy,那就亂了。而狀態鎖可以確保遠程狀態文件只能被一個人使用。但不是所有遠程狀態的方式都支持鎖的,一般常用的都會支持,如GCS、S3等。

所以,每當我們在執行變更時,Terraform總會先嘗試去拿鎖,如果拿鎖失敗,就該命令失敗。可以強制解鎖,但要非常小心,一般只建議在自己明確知道安全的時候才使用,比如死鎖了。

共用狀態-數據源

既然遠程狀態文件是可以共用的,那狀態信息也是可以共用的。這樣會帶來的一個好處是,即使兩個根模塊,也是可以共用信息的。比如我們在根模塊A創建了一個資料庫,而根模塊B需要用到資料庫的信息如IP,這樣通過遠程狀態文件就可以共用給根模塊B了。

註意這裡我強調的是根模塊,因為如果A和B在同一個根模塊下,那就不需要通過遠程狀態的方式來共用狀態了。

遠程狀態的示例:

data "terraform_remote_state" "vpc" {
  backend = "remote"

  config = {
    organization = "hashicorp"
    workspaces = {
      name = "vpc-prod"
    }
  }
}

resource "aws_instance" "foo" {
  # ...
  subnet_id = data.terraform_remote_state.vpc.outputs.subnet_id
}

本地狀態的示例:

data "terraform_remote_state" "vpc" {
  backend = "local"

  config = {
    path = "..."
  }
}

resource "aws_instance" "foo" {
  # ...
  subnet_id = data.terraform_remote_state.vpc.outputs.subnet_id
}

要註意的是,只有根模塊的輸出變數才能被共用,子模塊是不能被獲取的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 回顧第一篇文章中談到的組件庫的幾個方面,只剩下最後的、也是最重要的組件庫的打包構建、本地發佈、遠程發佈了。 1 組件庫構建 組件庫的入口是 packages/yyg-demo-ui,構建組件庫有兩個步驟: 添加 TypeScript 的配置文件: tsconfig.json 添加 vite.conf ...
  • 圖片資源,在我們的業務中可謂是占據了非常大頭的一環,尤其是其對帶寬的消耗是十分巨大的。 對圖片的性能優化及體驗優化在今天就顯得尤為重要。本文,就將從各個方面闡述,在各種新特性滿頭飛的今天,我們可以如何儘可能的對我們的圖片資源,進行性能優化及體驗優化。 圖片類型的選取及 Picture 標簽的使用 首 ...
  • TypeScript入門 ​ 一、什麼是TypeScript JavaScript的超集,可以編譯成JavaScript。添加了類型系統的JavaScript,可以適用於任何規模的項目。 TypeScript特性 類型系統 從 TypeScript 的名字就可以看出來,「類型」是其最核心的特性。 我 ...
  • Gossip是一種p2p的分散式協議。它的核心是在去中心化結構下,通過將信息部分傳遞,達到全集群的狀態信息傳播,傳播的時間收斂在O(Log(N))以內,其中N是節點的數量。基於gossip協議,可以構建出狀態一致的各種解決方案。 ...
  • 學習爬蟲第N天 今天想著將爬蟲獲取到的內容放在桌面,所以去學習了下 os 的操作。 學習如下: import os, os.path (經常性喜歡將文件放在桌面來查看內容是否正確,所以先創建一個變數存儲桌面的位置) desktop = fr"C:\Users\{os.getlogin()}\Desk ...
  • SpringMVC底層機制簡單實現-02 https://github.com/liyuelian/springmvc-demo.git 4.任務3-從web.xml動態獲取容器配置文件 4.1分析 任務3:MyDispatcherServlet (自定義的前端分發器)在創建並初始化自定義的spri ...
  • 這篇文章主要討論分散式系統中的分散式鎖問題,包括了三種不同的分散式鎖實現方式:基於資料庫的分散式鎖、基於緩存的分散式鎖和基於ZooKeeper的分散式鎖。 ...
  • 一、前言 上一篇我們完成了軟體的基本功能,如果想在用戶使用我們的app時,自動檢測新版本並讓自動完成安裝,這樣豈不是更好?本篇我們就來探究一下遠程更新的過程,並完成實際的功能。另外在使用過程中發現,登錄之後重啟app,會發現需要再次登錄,使用很不方便,我們也在第三部分解決這個問題。 二、fusion ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...