使用你喜歡的編程語言,將基礎(chǔ)設(shè)施作為代碼進(jìn)行配置
用 Node.js 或其他編程語言為你提供啟動(dòng)基礎(chǔ)設(shè)施所需的一切服務(wù)。
當(dāng)你在 IT 和技術(shù)的世界里遨游時(shí),你會(huì)反復(fù)遇到一些術(shù)語。其中有些術(shù)語很難量化,隨著時(shí)間的推移,可能會(huì)有不同的含義。“DevOps” 就是一個(gè)例子,這個(gè)詞似乎(在我看來)會(huì)根據(jù)使用它的人而改變;最初的 DevOps 先驅(qū)者可能甚至不認(rèn)識我們今天所說的 DevOps。
如果你是一個(gè)軟件開發(fā)者,“基礎(chǔ)架構(gòu)即代碼”(IaC)可能是其中一個(gè)術(shù)語。IaC 是使用與你編寫面向用戶的功能相同的軟件開發(fā)實(shí)踐來聲明應(yīng)用程序運(yùn)行的基礎(chǔ)設(shè)施。這通常意味著使用 Git 或 Mercurial 等工具進(jìn)行版本控制,使用 Puppet、Chef 或 Ansible 進(jìn)行配置管理。在基礎(chǔ)設(shè)施供應(yīng)層,最常見的技術(shù)是 CloudFormation(專用于 AWS),或開源替代品 Terraform,用來創(chuàng)建供你的應(yīng)用程序運(yùn)行的混合云資源。
在配置管理領(lǐng)域有很好產(chǎn)品可供選擇,可以將 IaC 寫成配置文件或首選的編程語言,但這種選擇在基礎(chǔ)設(shè)施供應(yīng)領(lǐng)域并不常見。
Pulumi 提供了一個(gè)使用標(biāo)準(zhǔn)編程語言來定義基礎(chǔ)設(shè)施的方式。它支持一系列語言,包括 JavaScript、TypeScript、Go、Python 和 C#。就像 Terraform 一樣,Pulumi 對許多熟悉的云提供商有一流的支持,比如 AWS、Azure、Google Cloud 和其他提供商。
在本文中,我將向你展示如何使用 Pulumi 以 Node.js 編寫基礎(chǔ)設(shè)施。
先決條件
首先,確保你已經(jīng)做好了使用 Pulumi 的準(zhǔn)備。Pulumi 支持所有主流的操作系統(tǒng),所以你安裝其先決條件的方法取決于你使用的操作系統(tǒng)。
首先,安裝你喜歡的編程語言的解釋器。我將使用 TypeScript,所以我需要安裝 node
二進(jìn)制。請查閱 Node 的安裝說明,了解你的操作系統(tǒng)的信息。你可以在 Mac 或 Linux 上使用 Homebrew 來安裝:
brew install node
在 Linux 上,你可以使用你常用的軟件包管理器,如 apt
或 dnf
。
$ sudo dnf install nodejs
無論哪種情況,結(jié)果都應(yīng)該是 node
二進(jìn)制文件在你的 $PATH
中可用。要確認(rèn)它是可訪問的,運(yùn)行:
node --version
接下來,安裝 Pulumi 命令行界面(CLI)。你可以在 Pulumi 的文檔中找到針對不同操作系統(tǒng)的安裝說明。在 Mac 或 Linux 上使用 brew
:
brew install pulumi
另外,你也可以使用安裝腳本。首先下載并審查它,然后執(zhí)行它:
$ curl -fsSL --output pulumi_installer.sh https://get.pulumi.com/
$ more pulumi_installer.sh
$ sh ./pulumi_installer.sh
同樣,我們所希望的結(jié)果是在你的路徑上有 pulumi
二進(jìn)制。檢查版本以確保你已經(jīng)準(zhǔn)備好了:
pulumi version
v2.5.0
配置 Pulumi
在你開始配置任何基礎(chǔ)設(shè)施之前,給 Pulumi 一個(gè)存儲(chǔ)其狀態(tài)的地方。
Pulumi 將其狀態(tài)存儲(chǔ)在后端。默認(rèn)的后端是 Pulumi 的軟件即服務(wù)(它有一個(gè)針對個(gè)人用戶的免費(fèi)計(jì)劃),但在這個(gè)例子中,我使用替代的文件后端。文件后端將在你的本地文件系統(tǒng)上創(chuàng)建一個(gè)文件來存儲(chǔ)狀態(tài):
pulumi login --local
如果你打算和別人分享這個(gè)項(xiàng)目,文件后臺可能不是一個(gè)好的起點(diǎn)。Pulumi 還可以將其狀態(tài)存儲(chǔ)在 AWS S3 等云對象存儲(chǔ)中。要使用它,請創(chuàng)建一個(gè) S3 bucket 并登錄:
pulumi login --cloud-url s3://my-pulumi-state-bucket
現(xiàn)在你已經(jīng)登錄到了狀態(tài)后端,你可以創(chuàng)建一個(gè)項(xiàng)目和一個(gè)堆棧了!
在你開始創(chuàng)建 Pulumi 項(xiàng)目之前,請先了解以下 Pulumi 術(shù)語,你將在本教程中看到這些術(shù)語。
項(xiàng)目
項(xiàng)目是一個(gè)包含 Pulumi.yaml
文件的目錄。這個(gè)文件包含了 Pulumi 需要知道的元數(shù)據(jù),以便進(jìn)行它的工作。在 Pulumi.yaml
文件中可以找到的示例字段有:
- 運(yùn)行時(shí)(例如,Python、Node、Go、.Net)
- 項(xiàng)目說明(如“我的第一個(gè) Pulumi 項(xiàng)目”)
- 項(xiàng)目名稱
項(xiàng)目是一個(gè)松散的概念,可以滿足你的需求。一般來說,一個(gè)項(xiàng)目包含了一系列的資源,這些資源是你想要提供和控制的東西。你可以選擇擁有資源很少的小型 Pulumi 項(xiàng)目,也可以選擇包含所有你需要的資源的大型項(xiàng)目。隨著你對 Pulumi 越來越熟悉,你想如何布局你的項(xiàng)目會(huì)變得更加清晰。
堆棧
Pulumi 堆棧允許你根據(jù)可配置的值來區(qū)分你的 Pulumi 項(xiàng)目。一個(gè)常見的用途是將一個(gè)項(xiàng)目部署到不同的環(huán)境,如開發(fā)或生產(chǎn)環(huán)境,或不同的地區(qū),如歐洲、中東和非洲以及美國。
在入門時(shí),你不大需要一個(gè)復(fù)雜的堆棧設(shè)置,所以本演練使用默認(rèn)的堆棧名稱 dev
。
在 IaC 中使用 TypeScript
你可以使用方便的 pulumi new
命令來初建一個(gè) Pulumi 項(xiàng)目。new
命令有一大堆標(biāo)志和選項(xiàng),可以幫助你入門 Pulumi,所以請繼續(xù)創(chuàng)建你的第一個(gè)項(xiàng)目:
$ pulumi new typescript
This command will walk you through creating a new Pulumi project.
Enter a value or leave blank to accept the (default), and press <ENTER>.
Press ^C at any time to quit.
project name: (pulumi) my-first-project
project description: (A minimal TypeScript Pulumi program) My very first Pulumi program
Created project 'my-first-project'
Please enter your desired stack name.
To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
stack name: (dev) dev
Created stack 'dev'
Installing dependencies...
> node scripts/postinstall
added 82 packages from 126 contributors and audited 82 packages in 2.84s
13 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Finished installing dependencies
Your new project is ready to go! ✨
To perform an initial deployment, run 'pulumi up'
這里發(fā)生了很多事情,我將其展開來說:
第一部分是為你的 Pulumi 項(xiàng)目確定一個(gè)模板。我選擇了通用的 typescript
選項(xiàng),但是有很多選項(xiàng)可供選擇。
這個(gè) new
命令從你的模板庫中抓取模板,并將這個(gè)文件復(fù)制到本地,包括運(yùn)行時(shí)的依賴關(guān)系(在本例中是 package.json
)。
new
命令通過在這個(gè)目錄下運(yùn)行 npm install
來安裝這些依賴關(guān)系。然后 npm install
下載并安裝運(yùn)行 Pulumi 程序所需的一切,在這種情況下就是:@pulumi/pulumi
NPM 包。
你已經(jīng)準(zhǔn)備好創(chuàng)建你的第一個(gè)資源了!
創(chuàng)建你的第一個(gè)云資源
資源是一個(gè)由你的基礎(chǔ)設(shè)施供應(yīng)軟件生命周期進(jìn)行管理的東西。資源一般是一個(gè)云提供商對象,比如 S3 桶。Pulumi 的提供商處理 Pulumi 資源,提供商是具體的云提供商。Pulumi 有大約 40 個(gè)提供商可供你使用,但對于你的第一個(gè)資源,使用一個(gè)最簡單的:隨機(jī)提供商。
隨機(jī)提供者顧名思義:它冪等地創(chuàng)建一個(gè)隨機(jī)資源(例如,可以是一個(gè)字符串),并將其存儲(chǔ)在 Pulumi 狀態(tài)中。
使用 npm
將其添加到你的 Pulumi 項(xiàng)目中作為依賴關(guān)系:
npm install @pulumi/random
npm 包管理器下載并安裝隨機(jī)提供者包,并為你安裝?,F(xiàn)在你已經(jīng)準(zhǔn)備好編寫你的 Pulumi 程序了。
當(dāng)你之前生成你的項(xiàng)目時(shí),Pulumi 的初建過程創(chuàng)建了一個(gè) index.ts
TypeScript 文件。在你喜歡的集成開發(fā)環(huán)境(IDE)中打開它,并添加你的第一個(gè)資源:
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";
const password = new random.RandomString(`password`, {
length: 10
})
如果你對 TypeScript 或 JavaScript 非常熟悉,這看起來會(huì)非常熟悉,因?yàn)樗怯媚闶煜さ木幊陶Z言編寫的。如果你使用的是 Pulumi 支持的其他語言之一,也是一樣的。這里是之前的那個(gè)隨機(jī)資源,但這次是用 Python 寫的:
import pulumi_random as random
password = random.RandomString("password", length=10)
一個(gè) Pulumi 項(xiàng)目目前只支持單一一種語言,但每個(gè)項(xiàng)目都可以引用其他語言編寫的項(xiàng)目,這對于多語言團(tuán)隊(duì)的成員來說是一個(gè)很有用的技巧。
你已經(jīng)編寫了第一個(gè) Pulumi 資源?,F(xiàn)在你需要部署它。
離開編輯器,回到命令行。在你的項(xiàng)目目錄下,運(yùn)行 pulumi up
,然后看著神奇的事情發(fā)生:
pulumi up
Previewing update (dev):
Type Name Plan
+ pulumi:pulumi:Stack my-first-project-dev create
+ └─ random:index:RandomString password create
Resources:
+ 2 to create
Do you want to perform this update? yes
Updating (dev):
Type Name Status
+ pulumi:pulumi:Stack my-first-project-dev created
+ └─ random:index:RandomString password created
Resources:
+ 2 created
Duration: 2s
Permalink: file:///Users/lbriggs/.pulumi/stacks/dev.json
太好了,你有了第一個(gè) Pulumi 資源! 雖然你可能很享受這種成就感,但不幸的是,這個(gè)隨機(jī)資源并沒有那么有用:它只是一個(gè)隨機(jī)的字符串,你甚至看不到它是什么。先解決這部分問題。修改你之前的程序,在你創(chuàng)建的常量中加入 export
:
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";
export const password = new random.RandomString(`password`, {
length: 10
})
重新運(yùn)行 pulumi up
,看看輸出:
pulumi up
Previewing update (dev):
Type Name Plan
pulumi:pulumi:Stack my-first-project-dev
Outputs:
+ password: {
+ id : "&+r?{}J$J7"
+ keepers : output<string>
+ length : 10
+ lower : true
+ minLower : 0
+ minNumeric : 0
+ minSpecial : 0
+ minUpper : 0
+ number : true
+ overrideSpecial: output<string>
+ result : "&+r?{}J$J7"
+ special : true
+ upper : true
+ urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
}
Resources:
2 unchanged
Do you want to perform this update? yes
Updating (dev):
Type Name Status
pulumi:pulumi:Stack my-first-project-dev
Outputs:
+ password: {
+ id : "&+r?{}J$J7"
+ length : 10
+ lower : true
+ minLower : 0
+ minNumeric: 0
+ minSpecial: 0
+ minUpper : 0
+ number : true
+ result : "&+r?{}J$J7"
+ special : true
+ upper : true
+ urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
}
Resources:
2 unchanged
Duration: 1s
Permalink: file:///Users/lbriggs/.pulumi/stacks/dev.json
現(xiàn)在你可以在 Outputs
的 result
部分下看到一個(gè)隨機(jī)生成的字符串。你現(xiàn)在可以看到你創(chuàng)建的資源有很多屬性。
這一切都很好,但如果你想享受 IaC,你得提供一些隨機(jī)字符串以外的東西。試試吧。
部署一個(gè)容器
到目前為止,你已經(jīng)通過安裝依賴關(guān)系和注冊一個(gè)簡單的隨機(jī)資源來 體驗(yàn)了初建你的 Pulumi。現(xiàn)在部署一些實(shí)際的基礎(chǔ)設(shè)施,盡管是在你的本地機(jī)器上。
首先,將 @pulumi/docker
提供者添加到你的堆棧中。使用你選擇的包管理器將其添加到項(xiàng)目中:
npm install @pulumi/docker
你已經(jīng)從 npm
下拉了 Pulumi Docker 提供商包,這意味著你現(xiàn)在可以在你的項(xiàng)目中創(chuàng)建 Docker 鏡像。
如果你的機(jī)器上還沒有安裝 Docker,現(xiàn)在是一個(gè)極好的時(shí)機(jī)去安裝它。說明將取決于你的操作系統(tǒng),所以看看 Docker 的安裝頁面了解信息。
再次打開你喜歡的 IDE,運(yùn)行一個(gè) Docker 容器。修改你之前的 index.ts
文件,讓它看起來像這樣:
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";
import * as docker from "@pulumi/docker";
const password = new random.RandomString(`password`, {
length: 10
})
const container = new docker.Container(`my-password`, {
image: 'hashicorp/http-echo',
command: [ pulumi.interpolate`-text=Your super secret password is: ${password.result}` ],
ports: [{
internal: 5678,
external: 5678,
}]
})
export const id = container.id
這將創(chuàng)建一個(gè)容器,創(chuàng)建一個(gè) Web 服務(wù)器。Web 服務(wù)器的輸出是你隨機(jī)生成的字符串,在本例中是一個(gè)密碼。運(yùn)行這個(gè),看看會(huì)發(fā)生什么:
pulumi up
Previewing update (dev):
Type Name Plan
pulumi:pulumi:Stack my-first-project-dev
+ └─ docker:index:Container my-password create
Outputs:
+ id : output<string>
~ password: {
id : "&+r?{}J$J7"
length : 10
lower : true
minLower : 0
minNumeric: 0
minSpecial: 0
minUpper : 0
number : true
result : "&+r?{}J$J7"
special : true
upper : true
urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
}
Resources:
+ 1 to create
2 unchanged
Do you want to perform this update? yes
Updating (dev):
Type Name Status
pulumi:pulumi:Stack my-first-project-dev
+ └─ docker:index:Container my-password created
Outputs:
+ id : "e73b34aeca34a64b72b61b0b9b8438637ce28853937bc359a1528ca99f49ddda"
password: {
id : "&+r?{}J$J7"
length : 10
lower : true
minLower : 0
minNumeric: 0
minSpecial: 0
minUpper : 0
number : true
result : "&+r?{}J$J7"
special : true
upper : true
urn : "urn:pulumi:dev::my-first-project::random:index/randomString:RandomString::password"
}
Resources:
+ 1 created
2 unchanged
Duration: 2s
Permalink: file:///Users/lbriggs/.pulumi/stacks/dev.json
你會(huì)注意到在 Outputs
部分,你輸出的值已經(jīng)改變了,它只是一個(gè) Docker 容器 ID。檢查你的非常簡單的密碼生成器是否工作:
curl http://localhost:5678
Your super secret password is: &+r?{}J$J7
就是這樣! 你剛剛用 TypeScript 配置了你的第一個(gè)基礎(chǔ)架構(gòu)。
關(guān)于 Pulumi 輸出的快速說明
你會(huì)注意到在創(chuàng)建 Docker 容器的代碼中,它使用了一個(gè)特殊的 pulumi.interpolate
調(diào)用。如果你熟悉 TypeScript,你可能會(huì)好奇為什么需要這樣做(因?yàn)樗?Pulumi 特有的)。這有一個(gè)有趣的原因。
當(dāng) Pulumi 創(chuàng)建一個(gè)資源時(shí),直到程序執(zhí)行時(shí)有一些值是 Pulumi 不知道的。在 Pulumi 中,這些值被稱為 Outputs
。這些 Outputs
可以在上面的代碼中看到,例如,在你的第一個(gè)隨機(jī)資源中,你使用 export
關(guān)鍵字來輸出隨機(jī)資源的屬性,你還輸出了你創(chuàng)建的容器的容器 ID。
因?yàn)?Pulumi 直到執(zhí)行時(shí)才知道這些 Outputs
的值,所以在操作字符串時(shí),它需要特殊的助手來使用它們。如果你想了解更多關(guān)于這個(gè)特殊的編程模型,請觀看這個(gè)短視頻。
總結(jié)
隨著混合云基礎(chǔ)架構(gòu)中出現(xiàn)的復(fù)雜性,IaC 在很多方面都有了發(fā)展。在基礎(chǔ)設(shè)施供應(yīng)領(lǐng)域,Pulumi 是一個(gè)很好的選擇,它可以使用你最喜歡的編程語言來供應(yīng)你所需要的一切基礎(chǔ)設(shè)施,然后你可以在你最喜歡的配置管理工具中進(jìn)行標(biāo)記,以采取下一步措施。