2017-04-04 117 views
5

正如我們在評估Terraform更換(部分)我們Ansible配置過程中的多租戶SaaS的進步,我們意識到Terraform的便利性,性能和可靠性,我們可以處理基礎設施的變化(增加/刪除)順利,跟蹤基礎設施狀態(非常酷)。Terraform:狀態管理多租戶

我們的應用程序是一個多租戶SaaS的,我們提供單獨的實例爲我們的客戶 - 在Ansible我們有自己的動態庫存(不太一樣EC2動態庫存)。我們翻閱大量的書籍Terraform /教程和最佳實踐,其中許多建議多環境狀態,應在Terraform分別&遠程管理,但所有的人都像靜態ENV(如開發/分期/生產)。

是否有任何的最佳做法或管理狀態的動態庫存多租戶應用程序的實際例子嗎?我們希望跟蹤每個客戶實例集的狀態 - 輕鬆地爲其添加更改。

一種方法可能是我們創建內部每個客戶和地區* .tf腳本,它將調用託管某處全球我們的模塊的目錄。狀態文件可能被放到S3中,這樣我們可以根據需要爲每個單獨的客戶填充更改。

回答

2

你的建議的方法聽起來我的權利,但也有少數,你可以考慮做更多的事情。

保留原始Terraform模板(在下面的樹_template)作爲版本神器(混帳回購協議,爲EG),只是通過鍵值性能能夠重新創建你的基礎設施。通過這種方式,您將擁有非常少量的複製粘貼的Terraform配置代碼,並將其放置在目錄中。

這是它的外觀:需要

/tf-infra 
├── _global 
│   └── global 
│    ├── README.md 
│    ├── main.tf 
│    ├── outputs.tf 
│    ├── terraform.tfvars 
│    └── variables.tf 
└── staging 
    └── eu-west-1 
     ├── saas 
     │   ├── _template 
     │   │   └── dynamic.tf.tpl 
     │   ├── customer1 
     │   │   ├── auto-generated.tf 
     │   │   └── terraform.tfvars 
     │   ├── customer2 
     │   │   ├── auto-generated.tf 
     │   │   └── terraform.tfvars 
... 

兩個輔助腳本:

  1. 模板渲染。二者必選其一sed產生module's source attribute或使用更強大的工具(如例如它airbnb/streamalert完成)

  2. 包裝腳本。運行terraform -var-file=...通常就足夠了。

共用terraform狀態文件作爲這應該是很好的全球資源(目錄以上_global)可以存儲在S3,使其它層可以訪問它們。

PS:我很開放的建議方案的意見,因爲這是一個有趣的任務,以對工作:)

5

Terraform工作在一個文件夾級別,在所有.tf文件拉動(和默認爲terraform.tfvars文件)。

所以我們做了類似於Antonanswer的東西,但是放棄了使用sed模擬東西的一些複雜性。因此,作爲一個基本的例子,你的結構可能是這樣的:

$ tree -a --dirsfirst 
. 
├── components 
│   ├── application.tf 
│   ├── common.tf 
│   ├── global_component1.tf 
│   └── global_component2.tf 
├── modules 
│   ├── module1 
│   ├── module2 
│   └── module3 
├── production 
│   ├── customer1 
│   │   ├── application.tf -> ../../components/application.tf 
│   │   ├── common.tf -> ../../components/common.tf 
│   │   └── terraform.tfvars 
│   ├── customer2 
│   │   ├── application.tf -> ../../components/application.tf 
│   │   ├── common.tf -> ../../components/common.tf 
│   │   └── terraform.tfvars 
│   └── global 
│    ├── common.tf -> ../../components/common.tf 
│    ├── global_component1.tf -> ../../components/global_component1.tf 
│    ├── global_component2.tf -> ../../components/global_component2.tf 
│    └── terraform.tfvars 
├── staging 
│   ├── customer1 
│   │   ├── application.tf -> ../../components/application.tf 
│   │   ├── common.tf -> ../../components/common.tf 
│   │   └── terraform.tfvars 
│   ├── customer2 
│   │   ├── application.tf -> ../../components/application.tf 
│   │   ├── common.tf -> ../../components/common.tf 
│   │   └── terraform.tfvars 
│   └── global 
│    ├── common.tf -> ../../components/common.tf 
│    ├── global_component1.tf -> ../../components/global_component1.tf 
│    └── terraform.tfvars 
├── apply.sh 
├── destroy.sh 
├── plan.sh 
└── remote.sh 

在這裏,你運行你的計劃/應用/從根級破壞,其中包裝shell腳本處理類似cd'ing進入該目錄並運行terraform get -update=true的東西,但也爲該文件夾運行terraform init,以便爲S3獲取唯一的狀態文件密鑰,使您可以獨立跟蹤每個文件夾的狀態。

上面的解決方案具有通用模塊,它們打包資源以提供通用接口(例如,我們的EC2實例根據某些輸入變量以特定方式進行標記,並且還給出了私有Route53記錄),然後執行組件」。

這些組件包含一組模塊/資源,這些模塊/資源將由Terraform在同一文件夾中應用。因此,我們可以將一個ELB,一些應用程序服務器和一個數據庫放在application.tf下,然後將它們鏈接到一個位置,這樣我們就可以使用Terraform來控制一個位置。如果我們可能在某個位置的資源上存在某些差異,那麼它們將被分離出來。在上例中,您可以看到staging/globalglobal_component2.tf不存在於生產中。這可能僅適用於非生產環境,例如某些網絡控制,以防止互聯網訪問環境。

這裏真正的好處是,所有東西都可以直接在開發人員的源代碼控制中直接查看,而不需要使用生成所需Terraform代碼的模板步驟。

它還有助於遵循DRY,其中環境之間的唯一真正區別在於位置中的terraform.tfvars文件,並且使它們在生效之前更容易測試,因爲每個文件夾幾乎與其他文件夾相同。

+0

使用這種方法,您將在每個文件夾內或從根目錄運行terraform?我問,因爲根據這個,狀態文件可能存儲在根路徑或每個文件夾中。 –

+0

您無法從父文件夾運行Terraform。 Terraform僅適用於當前目錄中的內容。正如它發生的那樣,我們有一些幫助程序腳本,它們位於repo的根目錄,cd'到我們想要執行的位置,然後從那裏運行'terraform' CLI命令。 – ydaetskcoR

+0

是的,你可以,我一直這麼做......'terraform plan path/to/something' –