AIOps系列 | 基礎(chǔ)設(shè)施即代碼
概述
講 AIOps 的時(shí)候?yàn)槭裁匆v 基礎(chǔ)設(shè)施即代碼(Infrastructure as Code,簡稱IaC) 呢?
在企業(yè)中,不論是先進(jìn)的技術(shù)也好,還是優(yōu)秀的思想也罷,終究都是服務(wù)于業(yè)務(wù),這些業(yè)務(wù)都是部署在各種基礎(chǔ)設(shè)施之上,包括 AIOps 本身的應(yīng)用,所以可以理解 IaC 是 AIOps 實(shí)現(xiàn)自動(dòng)化的基礎(chǔ)平臺(tái)。
在 AIOps 的加持下,IaC 可以變得更聰明,比如:
- 自動(dòng)識(shí)別資源的浪費(fèi)或瓶頸
- 根據(jù)負(fù)載預(yù)測推薦最優(yōu)的實(shí)例類型
- 在部署失敗的時(shí)候提供根因分析和修復(fù)建議
那什么是 基礎(chǔ)設(shè)施即代碼(以下簡稱IaC) 呢?
顧名思義,基礎(chǔ)設(shè)施即代碼(Infrastructure as Code,簡稱 IaC) 就是一種通過 代碼 來定義、管理和部署 IT 基礎(chǔ)設(shè)施的技術(shù)方法。換句話說就是 把以前“手動(dòng)點(diǎn)擊配置服務(wù)器”的過程,變成像寫程序一樣用“代碼”來描述和部署基礎(chǔ)設(shè)施。
舉個(gè)例子,過去你可能這樣做:
- 登錄云平臺(tái)控制臺(tái)
- 手動(dòng)創(chuàng)建 VPC、子網(wǎng)、安全組
- 創(chuàng)建 EC2 實(shí)例并安裝軟件
- 配置負(fù)載均衡器和數(shù)據(jù)庫
現(xiàn)在你可以這樣寫一段代碼(比如用 Terraform):
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}
然后運(yùn)行:
terraform apply
系統(tǒng)就會(huì)自動(dòng)幫你創(chuàng)建一個(gè) AWS 實(shí)例。
通過 IaC 可以將重復(fù)簡單的工作簡單化,它主要有以下優(yōu)勢:
特性 | 描述 |
?? 可重復(fù) | 每次部署都是一樣的結(jié)果,避免“在我機(jī)器上能跑”的問題 |
?? 可版本化 | 使用 Git 管理基礎(chǔ)設(shè)施的變更歷史 |
?? 可自動(dòng)化 | 能與 CI/CD 流程集成,實(shí)現(xiàn)一鍵部署 |
?? 易于擴(kuò)展 | 快速復(fù)制環(huán)境(開發(fā)、測試、生產(chǎn)) |
??? 可維護(hù)性強(qiáng) | 修改配置只需改代碼,無需手動(dòng)操作 |
常見的一些 IaC 工具有: |
類型 | 工具 | 說明 |
聲明式(Declarative) | Terraform、Kubernetes(YAML)、AWS CloudFormation | 描述目標(biāo)狀態(tài),工具負(fù)責(zé)實(shí)現(xiàn) |
命令式(Imperative) | Ansible、SaltStack、Chef、Puppet | 編寫具體指令一步步執(zhí)行 |
容器編排 | Docker Compose、Helm Charts | 定義容器化應(yīng)用的部署結(jié)構(gòu) |
云廠商專用 | AWS CDK、Azure Bicep | 結(jié)合云平臺(tái)特性的 IaC 工具 |
我們知道了 IaC 的優(yōu)勢以及常用的工具集,那我們具體能用它做什么呢? |
我們可以:
- 通過聲明式方式定義和創(chuàng)建基礎(chǔ)設(shè)施,使基礎(chǔ)設(shè)施的管理類似于編寫代碼,實(shí)現(xiàn)創(chuàng)建和更新的自動(dòng)化。
- 統(tǒng)一管理所有資源,無論這些資源最初是否由IC工具創(chuàng)建或管理,都可以導(dǎo)入進(jìn)行統(tǒng)一的管理,提升整體的資源管控效率。
- 提供更安全的基礎(chǔ)設(shè)施更改流程,通過預(yù)先列出影響范圍并經(jīng)由工程師確認(rèn)后再執(zhí)行變更,確保更改的安全性和準(zhǔn)確性。
- 與CICD工具整合,形成基礎(chǔ)設(shè)施管理的自動(dòng)化工作流,例如在工作流中自動(dòng)開通開發(fā)環(huán)境所需的云基礎(chǔ)設(shè)施,實(shí)現(xiàn)環(huán)境快速搭建和標(biāo)準(zhǔn)化。
- 提供可復(fù)用的模塊,編寫的IC代碼可以作為模塊供其他團(tuán)隊(duì)復(fù)用,促進(jìn)團(tuán)隊(duì)間協(xié)作和代碼的標(biāo)準(zhǔn)化使用,實(shí)現(xiàn)基礎(chǔ)設(shè)施管理流程的標(biāo)準(zhǔn)化和高效性。
在眾多 IaC 工具中, Terraform 一直是優(yōu)選工具,所以下面會(huì)主要介紹 Terraform 。
什么是Terraform
Terraform 是 IaC 的一個(gè)開源工具,它由 HashiCorp 開發(fā),用于安全高效地 預(yù)配、管理和銷毀基礎(chǔ)設(shè)施資源 。它就像是一把“萬能鑰匙”,你可以用它來創(chuàng)建服務(wù)器、數(shù)據(jù)庫、網(wǎng)絡(luò)、容器、負(fù)載均衡器等資源,而無需手動(dòng)點(diǎn)擊云平臺(tái)界面或?qū)懩_本去一個(gè)個(gè)配置。
圖片
它的核心優(yōu)勢有:
Terraform 采用 HCL(HashiCorp Configuration Language) 語言來定義這些文檔,HCL 比較簡單易學(xué),它是一種DSL(即領(lǐng)域特定語言),用于簡化基礎(chǔ)設(shè)施參數(shù)配置的復(fù)雜性,它具有以下優(yōu)勢:
- 保留YAML和JSON的可讀性優(yōu)勢,同時(shí)引入動(dòng)態(tài)編程特性,使其在編寫時(shí)類似編程語言,但專注于配置
- 使用HCL描述和編寫JSON對象時(shí),代碼變得更清晰且簡潔
比如要在AWS上創(chuàng)建一臺(tái)EC2,只需要使用 HCL 編寫以下文檔:
# main.tf
# 指定 AWS 提供商
provider "aws" {
region = "us-west-2"
}
# 創(chuàng)建 EC2 實(shí)例
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0" # Amazon Linux 2 AMI ID
instance_type = "t2.micro"
}
運(yùn)行 terraform init
和 terraform apply
后,你的 AWS 控制臺(tái)中就會(huì)出現(xiàn)這臺(tái)新創(chuàng)建的 EC2 實(shí)例。
Terraform架構(gòu)
在 Terraform 的執(zhí)行過程中,主要包含以下幾個(gè)組件配置:
- Terraform Config:使用 HCL 編寫的聲明式配置,用于描述用戶希望的狀態(tài)
- Terraform Core:它是Terraform的核心編排引擎,負(fù)責(zé)處理基礎(chǔ)設(shè)施的變更,它會(huì)通過用戶編寫的HCL代碼轉(zhuǎn)換成期望的基礎(chǔ)設(shè)施最終狀態(tài)。
- Terraform Provider:Provider是Terraform和云廠商通信的插件,負(fù)責(zé)將 HCL 配置映射為云平臺(tái)的具體 API 請求。不同云廠商有不同的Provider,這些Provider一般由云廠商自己維護(hù)。
- Terraform State:State文件用于記錄當(dāng)前基礎(chǔ)設(shè)施的真實(shí)狀態(tài),由Terraform進(jìn)行管理,用于保持配置和實(shí)際狀態(tài)是一致的,當(dāng)有變更操作的時(shí)候,Terraform就會(huì)對比期望狀態(tài)和實(shí)際狀態(tài),然后生成對應(yīng)的變更計(jì)劃。
圖片
特別說明:
- 注意 Provider 版本兼容性
- 引入不同 Provider 時(shí),需關(guān)注其版本,避免因上游更新導(dǎo)致代碼異?;騾?shù)廢棄。
- 推薦固定版本以確保穩(wěn)定性
- 建議使用固定版本號(hào) ,防止因自動(dòng)更新帶來的不兼容問題。
- 使用“波浪號(hào)加大于號(hào)(~>)”進(jìn)行版本約束
- 這是一種悲觀約束符 ,用于限制 Provider 的版本范圍。
- 它允許小版本更新(如 bug 修復(fù)、功能增強(qiáng)) ,但禁止大版本升級(jí)(可能帶來破壞性變更) 。
比如,采用以下配置表示允許使用 5.0.0
到 5.999.999
之間的版本,但不會(huì)升級(jí)到 6.0
:
provider "aws" {
version = "~> 5.0"
}
Terraform的核心命令
Terraform 的命令可以使用 terraform -help 來查看,這里介紹一個(gè)常用的命令。
基礎(chǔ)命令
常用的基礎(chǔ)命令有:
- terraform init:初始化工作目錄,下載provider插件等依賴
- terraform plan:查看將要執(zhí)行的操作,不會(huì)實(shí)際執(zhí)行
- terraform apply:執(zhí)行配置,該命令執(zhí)行后會(huì)實(shí)際執(zhí)行
- terraform destroy:銷毀所有由terraform創(chuàng)建的資源
狀態(tài)管理命令
常用的狀態(tài)管理命令有:
- terraform state list:列出當(dāng)前狀態(tài)中的所有資源
- terraform state show
<resource>
:查看某資源的具體信息 - terraform state rm
<resource>
:從狀態(tài)中移除某個(gè)資源(不刪除真實(shí)資源) - terraform state pull:從遠(yuǎn)端拉取狀態(tài)到本地
- terraform state push:更新本地的狀態(tài)到遠(yuǎn)端
- terraform refresh:從基礎(chǔ)設(shè)施實(shí)際狀態(tài)更新 state 狀態(tài)
- terraform import
<resource> <id>
:將已有資源導(dǎo)入到terraform中
查詢與調(diào)試命令
常用的查詢與調(diào)試命令有:
- terraform show:顯示當(dāng)前狀態(tài)文件的內(nèi)容
- terraform output:顯示outputs中定義的輸出值
- terraform graph:生成資源配置的依賴圖
- terraform validate:檢查配置語法是否正確
其他命令
還有一些比較實(shí)用的命令:
- terraform fmt:格式化
.tf
文件,統(tǒng)一風(fēng)格 - terraform taint
<resource>
:標(biāo)記某個(gè)資源為“污染”,下次apply的時(shí)候重建 - terraform workspace:管理多個(gè)環(huán)境(dev / staging / prod)
Terraform State
這里著重把 Terraform State 拿出來講,是因?yàn)樗?nbsp;Terraform 生命周期中必不可少的元素,它保存了真實(shí)基礎(chǔ)設(shè)施的所有元數(shù)據(jù)。默認(rèn)情況下,這些信息保存在一個(gè)名為 "terraform.tfstate" 的文件中。
Terraform 使用狀態(tài)來創(chuàng)建執(zhí)行計(jì)劃并更改您的基礎(chǔ)設(shè)施。當(dāng) Terraform 通過配置文件創(chuàng)建或者更改了遠(yuǎn)端對象時(shí),它會(huì)將該遠(yuǎn)端對象的標(biāo)識(shí)記錄在與之對應(yīng)的資源實(shí)例中,并保存在狀態(tài)文件中,之后,Terraform 可能會(huì)根據(jù)未來的配置更改更新或刪除該對象。
圖片
每個(gè)在資源塊中創(chuàng)建的基礎(chǔ)設(shè)施資源都是通過其resource_name
在 Terraform 狀態(tài)中進(jìn)行標(biāo)識(shí)的,其對資源的管理流程大致如下:
- 當(dāng)?shù)谝淮瓮ㄟ^ terraform apply 應(yīng)用 Terraform 配置時(shí),會(huì)創(chuàng)建基礎(chǔ)設(shè)施資源,同時(shí)自動(dòng)生成一個(gè)狀態(tài)文件,該文件引用資源塊中聲明的名稱
- 如果一個(gè)資源已經(jīng)在 Terraform 狀態(tài)文件中有標(biāo)識(shí),那么 Terraform 會(huì)將配置文件與狀態(tài)文件和當(dāng)前的資源遠(yuǎn)端的實(shí)際狀態(tài)進(jìn)行比較,并根據(jù)比較結(jié)果,會(huì)生成一個(gè)執(zhí)行計(jì)劃
- 當(dāng)執(zhí)行該計(jì)劃時(shí),它會(huì)更新資源的狀態(tài)以匹配配置文件中的定義,如果由于遠(yuǎn)端 API 限制無法實(shí)現(xiàn)就地更新參數(shù),那么該執(zhí)行計(jì)劃將會(huì)先銷毀資源,然后再重新創(chuàng)建新的資源;如果是一個(gè)資源銷毀的計(jì)劃,將發(fā)起資源的銷毀操作
- 計(jì)劃執(zhí)行成功后,Terraform 狀態(tài)文件會(huì)更新以反映當(dāng)前的基礎(chǔ)設(shè)施狀態(tài)
- 如果某資源已從當(dāng)前 Terraform 配置中移除但在狀態(tài)文件中仍然存在,Terraform 則會(huì)比較配置文件并銷毀不再存在的資源
Terraform 默認(rèn)將本地狀態(tài)文件保存在當(dāng)前工作目錄中,擴(kuò)展名為 .tfstate,因此它們不需要額外的維護(hù)。本地狀態(tài)文件適用于只有一個(gè)開發(fā)人員工作的項(xiàng)目,當(dāng)多個(gè)開發(fā)人員同時(shí)運(yùn)行 Terraform 并且每臺(tái)機(jī)器都有對當(dāng)前基礎(chǔ)設(shè)施的理解和配置時(shí),默認(rèn)的本地狀態(tài)文件的配置方式就會(huì)變得棘手。
在團(tuán)隊(duì)協(xié)作開發(fā)場景中使用本地狀態(tài)時(shí)主要存在以下幾個(gè)問題:
- 本地狀態(tài)沒有共享訪問權(quán)限:當(dāng)使用 Terraform 更新你的基礎(chǔ)設(shè)施,團(tuán)隊(duì)中的每個(gè)成員都需要訪問相同的狀態(tài)文件,這意味著這些文件必須存儲(chǔ)在一個(gè)共享的位置,比如 ECS 實(shí)例特定的位置,而這無形增加了管理成本。
- 不能鎖定本地狀態(tài)文件:如果兩個(gè)團(tuán)隊(duì)成員同時(shí)運(yùn)行 Terraform,他們可能會(huì)遇到競爭條件,因?yàn)槎鄠€(gè) Terraform 進(jìn)程可能同時(shí)在更新狀態(tài)文件。在這種情況下,可能帶來導(dǎo)致沖突、數(shù)據(jù)丟失和狀態(tài)文件損壞等風(fēng)險(xiǎn)。
- 本地狀態(tài)文件不保密:當(dāng)信息以明文形式存儲(chǔ)在狀態(tài)文件中時(shí),敏感數(shù)據(jù)將存在被暴露的風(fēng)險(xiǎn),例如數(shù)據(jù)庫憑證,SSH 登錄密碼等。
因此,在團(tuán)隊(duì)協(xié)作開發(fā)的場景中,推薦使用遠(yuǎn)程替代本地存儲(chǔ),這種存儲(chǔ)模式下會(huì):
- 遠(yuǎn)端狀態(tài)文件會(huì)自動(dòng)更新:每次使用 plan 或者 apply 命令的時(shí)候會(huì)自動(dòng)從遠(yuǎn)端加載狀態(tài)文件,每次執(zhí)行apply之后也會(huì)把狀態(tài)文件自動(dòng)同步到遠(yuǎn)端存儲(chǔ)中。
- 遠(yuǎn)端狀態(tài)文件支持狀態(tài)鎖定:當(dāng)執(zhí)行 terraform 的時(shí)候,可以對遠(yuǎn)端狀態(tài)文件進(jìn)行加鎖,這樣在多個(gè)開發(fā)人員同時(shí)運(yùn)行 terraform apply 的時(shí)候不會(huì)因同時(shí)更新而損壞。
- 遠(yuǎn)端狀態(tài)文件存儲(chǔ)比本地存儲(chǔ)更安全:比如像 OSS 這類遠(yuǎn)端存儲(chǔ)不僅支持精細(xì)化控制訪問權(quán)限,還支持傳輸和遠(yuǎn)端加密功能。
比如采用 阿里云OSS 作為后端存儲(chǔ),其配置如下:
terraform {
backend "oss" {
bucket = "bucket-for-terraform-state"
prefix = "path/mystate"
key = "version-1.tfstate"
region = "cn-beijing"
tablestore_endpoint = "https://terraform-remote.cn-hangzhou.ots.aliyuncs.com"
tablestore_table = "statelock"
}
}
其中:
- bucket:為阿里云OSS Bucket的名稱
- prefix:在Bucket中存放狀態(tài)文件的路徑前綴
- key:狀態(tài)文件的名稱
- region:Bucket所在區(qū)域
- tablestore_endpoint:tablestore的訪問地址,用于狀態(tài)鎖
- tablestore_table:用于狀態(tài)鎖的tablestore表名
說明:當(dāng)你運(yùn)行
terraform apply
或destroy
時(shí),Terraform 會(huì)嘗試對狀態(tài)文件加鎖。如果已有其他人在操作,就會(huì)提示“l(fā)ock failed”,防止并發(fā)修改導(dǎo)致錯(cuò)誤。
Terraform項(xiàng)目布局
任何項(xiàng)目的開發(fā)都需要比較好的項(xiàng)目布局,Terraform 也不例外,在簡單的項(xiàng)目中推薦使用 Terraform Layout 的項(xiàng)目布局方式,將文件拆分成四個(gè)文件:
- main.tf:表示主要的業(yè)務(wù)邏輯
- outputs.tf:定義輸出的內(nèi)容
- variables.tf:定義變量參數(shù)
- version.tf:定義依賴和版本
其中, main.tf 是業(yè)務(wù)的主邏輯,比如這里要?jiǎng)?chuàng)建一個(gè)EC2,定義如下:
resource "aws_instance" "my-example" {
ami = "ami-xxxxxxx"
instance_type = var.instance_type
}
這里的 var.instance_type
是定義的變量,所以我們還要?jiǎng)?chuàng)建一個(gè) variables.tf
,內(nèi)容如下:
variable "instance_type" {
description = "EC2 實(shí)例類型"
default = "t2.micro"
}
然后,我們喜歡得到創(chuàng)建后的EC2實(shí)例的IP,所以我們還要定義 outputs.tf
,如下:
output "public_ip" {
value = aws_instance.my-example.public_ip
}
另外,還有一個(gè) version.tf
,這個(gè)文件主要是用來固定版本的,避免上游版本變化導(dǎo)致腳本出現(xiàn)不可預(yù)知的BUG。其定義大概如下:
# versions.tf
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.0"
}
# 示例:阿里云 Provider
alicloud = {
source = "aliyun/alicloud"
version = "~> 1.2.0"
}
}
}
如果項(xiàng)目比較復(fù)雜,可以將 main.tf 再進(jìn)行拆分,比如我們要使用 terraform 部署 vpc、rds,則可以將其按模塊進(jìn)行拆分,如下:
main.tf
variables.tf
outputs.tf
modules/
└── vpc/
├── main.tf
├── variables.tf
└── outputs.tf
└── rds/
├── main.tf
├── variables.tf
└── outputs.tf
然后在 main.tf 中去引用即可,如下:
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
tags = { Name = "my-vpc" }
}
如果你的項(xiàng)目涉及多個(gè)環(huán)境(dev/staging/prod),且要提高代碼的復(fù)用,我們可以將目錄結(jié)構(gòu)定義如下:
project-root/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── staging/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── prod/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── modules/ # 可選:用于復(fù)用的模塊
│ ├── vpc/
│ └── rds/
├── versions.tf # 固定版本號(hào)(推薦)
└── backend.tf # 遠(yuǎn)程后端配置(可選)
在具體使用的時(shí)候我們應(yīng)該先創(chuàng)建 workspace ,然后再執(zhí)行。比如要在 dev 環(huán)境執(zhí)行命令,則用:
$ terraform workspace new dev # 創(chuàng)建 dev 的workspace
$ cd environments/dev # 切換到dev的主入口
$ terrafotm apply --auto-apprve # 在dev workspace 中創(chuàng)建資源
# 如果不清楚目前有哪些 workspace,可以使用 terraform workspace list 查看
$ terraform workspace list
# 如果想切換到某個(gè) workspace,可以使用 terraform workspace select <workspace> 進(jìn)行切換
$ terraform workspace select dev
# 如果要?jiǎng)h除某個(gè) workspace 中的資源,可以使用 terraform destroy --auto-approve 命令
$ terraform destroy --auto-approve
Terraform實(shí)戰(zhàn)
下面我們將以 模塊化 + 多環(huán)境支持 的方式設(shè)計(jì)這個(gè) Terraform 項(xiàng)目,并以 阿里云(Alibaba Cloud) 平臺(tái)為例進(jìn)行說明。
Tips:代碼未經(jīng)調(diào)試,原因是沒錢
整體的項(xiàng)目需求是:
- 創(chuàng)建VPC
- 創(chuàng)建ECS
- 在ECS中部署K8S,版本是1.32.1
- 在K8S中部署Nginx,版本是latest
整體的項(xiàng)目目錄結(jié)構(gòu)規(guī)劃如下:
terraform-k8s-on-ecs/
├── environments/
│ └── dev/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── ecs/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── k8s-install/
│ │ ├── main.tf
│ │ ├── install-k8s.sh
│ │ └── variables.tf
│ └── k8s-deploy-nginx/
│ ├── main.tf
│ └── nginx-deployment.yaml
├── versions.tf
└── providers.tf
1、固定版本號(hào)
# versions.tf
terraform {
required_version = ">= 1.6.0"
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = "~> 1.2.0"
}
null = {
source = "hashicorp/null"
version = "~> 3.0"
}
template = {
source = "hashicorp/template"
version = "~> 2.0"
}
}
}
2、創(chuàng)建VPC模塊
(1)定義變量
# modules/vpc/variables.tf
variable "vpc_name" {
description = "VPC 名稱"
type = string
}
variable "cidr_block" {
description = "VPC CIDR"
type = string
default = "10.0.0.0/16"
}
variable "subnet_cidr" {
description = "子網(wǎng) CIDR"
type = string
default = "10.0.1.0/24"
}
variable "zone_id" {
description = "可用區(qū) ID"
type = string
}
(2)定義主入口
# modules/vpc/main.tf
resource "alicloud_vpc" "main" {
vpc_name = var.vpc_name
cidr_block = var.cidr_block
}
resource "alicloud_vswitch" "main" {
vswitch_name = "${var.vpc_name}-vsw"
cidr_block = var.subnet_cidr
vpc_id = alicloud_vpc.main.id
zone_id = var.zone_id
}
3、創(chuàng)建ECS模塊
(1)定義變量
# modules/ecs/variables.tf
variable "instance_name" {
description = "ECS 實(shí)例名稱"
type = string
}
variable "image_id" {
description = "鏡像 ID(如 centos_7_9_x64_20G_alibase_20220310.vhd)"
type = string
}
variable "instance_type" {
description = "實(shí)例類型(如 ecs.n4.small)"
type = string
}
variable "vpc_id" {
description = "VPC ID"
type = string
}
variable "vswitch_id" {
description = "VSwitch ID"
type = string
}
variable "zone_id" {
description = "可用區(qū) ID"
type = string
}
variable "root_password" {
description = "ECS root 密碼"
type = string
}
(2)定義主入口
# modules/ecs/main.tf
resource "alicloud_security_group" "k8s-node" {
name = "k8s-node-sg"
vpc_id = var.vpc_id
}
resource "alicloud_instance" "k8s-master" {
instance_name = var.instance_name
image_id = var.image_id
instance_type = var.instance_type
availability_zone = var.zone_id
system_disk_category = "cloud_efficiency"
system_disk_size = 40
vswitch_id = var.vswitch_id
security_groups = [alicloud_security_group.k8s-node.id]
internet_max_bandwidth_out = 100
password = var.root_password
}
4、創(chuàng)建Kubernetes集群(采用kubeadm)
(1)創(chuàng)建安裝K8S腳本
# modules/k8s-install/install-k8s.sh
#!/bin/bash
# 安裝 Docker
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
systemctl start docker
systemctl enable docker
# 安裝 kubelet kubeadm kubectl
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
EOF
yum install -y kubelet-1.32.1 kubeadm-1.32.1 kubectl-1.32.1
systemctl enable kubelet
systemctl start kubelet
# 初始化集群
kubeadm init --pod-network-cidr=10.244.0.0/16
# 配置 kubectl
mkdir -p $HOME/.kube
cp /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
# 安裝 CNI(Flannel)
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
(1)定義變量
# modules/k8s-install/variables.tf
variable "ecs_public_ip" {
description = "ECS 公網(wǎng) IP"
type = string
}
variable "root_password" {
description = "ECS root 密碼"
type = string
}
(2)定義主入口
# modules/k8s-install/main.tf
resource "null_resource" "install_k8s" {
connection {
type = "ssh"
user = "root"
password = var.root_password
host = var.ecs_public_ip
}
provisioner "file" {
source = "${path.module}/install-k8s.sh"
destination = "/root/install-k8s.sh"
}
provisioner "remote-exec" {
inline = [
"chmod +x /root/install-k8s.sh",
"/root/install-k8s.sh"
]
}
}
5、在K8S中部署Nginx
(1)創(chuàng)建NG的Deployment
# modules/k8s-deploy-nginx/nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: NodePort
(2)、定義變量
# modules/k8s-deploy-nginx/variables.tf
variable "ecs_public_ip" {
description = "ECS 公網(wǎng) IP"
type = string
}
variable "root_password" {
description = "ECS root 密碼"
type = string
}
(3)、定義主入口
# modules/k8s-deploy-nginx/main.tf
resource "null_resource" "deploy_nginx" {
depends_on = [module.k8s-install]
connection {
type = "ssh"
user = "root"
password = var.root_password
host = var.ecs_public_ip
}
provisioner "file" {
source = "${path.module}/nginx-deployment.yaml"
destination = "/root/nginx-deployment.yaml"
}
provisioner "remote-exec" {
inline = [
"kubectl apply -f /root/nginx-deployment.yaml"
]
}
}
6、配置開發(fā)環(huán)境的主業(yè)務(wù)邏輯
# environments/dev/main.tf
# 創(chuàng)建 VPC
module "vpc" {
source = "../../modules/vpc"
vpc_name = "dev-vpc"
cidr_block = "10.0.0.0/16"
subnet_cidr = "10.0.1.0/24"
zone_id = "cn-beijing-a"
}
# 創(chuàng)建 ECS,依賴 VPC
module "ecs" {
source = "../../modules/ecs"
instance_name = "k8s-master"
image_id = "centos_7_9_x64_20G_alibase_20220310.vhd"
instance_type = "ecs.n4.small"
vpc_id = module.vpc.vpc_id
vswitch_id = module.vpc.vswitch_id
zone_id = "cn-beijing-a"
root_password = "your-root-password-123"
}
# 安裝 Kubernetes,依賴 ECS
module "k8s-install" {
source = "../../modules/k8s-install"
ecs_public_ip = module.ecs.ecs_public_ip
root_password = "your-root-password-123"
depends_on = [module.ecs] # 等 ECS 創(chuàng)建完成后再安裝 K8s
}
# 部署 Nginx,依賴 Kubernetes 安裝完成
module "deploy-nginx" {
source = "../../modules/k8s-deploy-nginx"
ecs_public_ip = module.ecs.ecs_public_ip
root_password = "your-root-password-123"
depends_on = [module.k8s-install] # 等 K8s 安裝完成后再部署應(yīng)用
}
配置輸出:
# environments/dev/outputs.tf
output "vpc_id" {
value = module.vpc.vpc_id
}
output "ecs_public_ip" {
value = module.ecs.ecs_public_ip
}
output "k8s_config" {
value = "/root/.kube/config"
}
7、部署
當(dāng)所有腳本開發(fā)完成后,為了保證后續(xù)的可擴(kuò)展,整體的命令執(zhí)行流程是:
# 切換到 dev 目錄下
$ cd environments/dev
# 創(chuàng)建 dev workspace
$ terraform workspace new dev
# 初始化下載依賴
$ terraform init
# 預(yù)執(zhí)行
$ terraform plan
# 執(zhí)行部署
$ terraform apply
總結(jié)
綜上所述,文章系統(tǒng)闡述了基礎(chǔ)設(shè)施即代碼(IaC)的核心概念、與AIOps的關(guān)聯(lián)及顯著優(yōu)勢,并聚焦IaC工具Terraform,深入解析其定義、架構(gòu)、核心命令、狀態(tài)管理、項(xiàng)目布局等關(guān)鍵內(nèi)容,最后通過在阿里云平臺(tái)部署VPC、ECS、K8S及Nginx的實(shí)戰(zhàn)案例,完整呈現(xiàn)了Terraform在模塊化和多環(huán)境支持下的應(yīng)用流程。這不僅展現(xiàn)了IaC通過代碼化管理基礎(chǔ)設(shè)施的高效性與規(guī)范性,也為實(shí)際運(yùn)維中利用Terraform實(shí)現(xiàn)自動(dòng)化部署提供了清晰的思路與參考。
引用
[1] https://developer.hashicorp.com/terraform/docs
[2] https://help.aliyun.com/zh/terraform/what-is-terraform?spm=a2c4g.help-menu-95817.d_0_1.dee2c092b7ORVO