iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0

今天的主題是介紹如何參考其他專案中 Stack 的資料,假設我們有兩個 Pulumi 專案如下:專案 B 的 stack 會需要參考到專案 A 相同名稱 stack 所建立的 VPC 資料。

  • 專案 A:VPC Network
    • Stack:
      • dev
      • stage
      • production
  • 專案 B:EKS Cluster
    • Stack:
      • dev
      • stage
      • production

StackReference

跨 Pulumi 專案的 Output 使用這種需求,可以透過 StackReference 來達成。
StackReference 的使用方式很簡單,只要使用要參考的專案的 Organization name、Project Name、Stack Name 資訊,即可參考另一個專案的 Output 資訊。

例如以下程式碼,會參考 pulumi-infra 專案相同 Stack 名稱的資訊。這邊我使用 pulumi.getOrganization() 取得目前 Project 所使用的 Pulumi Cloud 的組織名稱、pulumi.getStack() 取得目前執行的 Stack 名稱。

Note: 這邊預設所使用的 Backend 都是 Pulumi Cloud,如果是使用 Object Storage 或是本地檔案系統的話,組織名稱需要固定填寫 org

TypeScript 範例

const currentOrg = pulumi.getOrganization();

const currentStack = pulumi.getStack();

const stackRef = new pulumi.StackReference(`${currentOrg}/pulumi-infra/${currentStack}`);

Python 範例

current_org = pulumi.get_organization()
current_stack = pulumi.get_stack()

infra_stack = pulumi.StackReference(f"{current_org}/pulumi-infra/{current_stack}")

如果想要使用其他名稱做為 StackReference 的名字的話,可以將要參考的專案路徑設定在參數中。例如以下程式碼可以達到同樣的效果:

const currentOrg = pulumi.getOrganization();

const currentStack = pulumi.getStack();

const stackRef = new pulumi.StackReference('infra_stack', {
  name: `${currentOrg}/pulumi-infra/${currentStack}`
});

其實 StackReference 也是一種 Pulumi 中的 Resource。在顯示所有 Resource 時,可以看到 StackReference 也是一個 Resource。

Current stack resources (16):
    TYPE                              NAME
    pulumi:pulumi:Stack               aws-vpc-ts-dev
    ├─ pulumi-practice:vpc:Vpc        project-vpc
    ├─ pulumi:pulumi:StackReference   xxx/pulumi-infra/dev
    ├─ pulumi:providers:pulumi        default
    └─ pulumi:providers:aws           default_5_42_0

那又為何我們在使用 StackReference 時不需要指定 args 的參數,只要在 name 上指定要參考的 stack 位置就可以了呢?這其實是建立 StackReference 資源時,如果沒有拿到 args.name 的話,就會預設使用 Resource name 做為要參考的 Stack 名稱。

constructor(name, args, opts) {
        args = args || {};
        const stackReferenceName = args.name || name;
        ...
}

Note: Pulumi 中不支援跨 Backend 參考。意思是所有專案都必須使用同一個 Backend。如果是使用 S3 等 Object Storage,也必須在同一個 Bucket 之中。

StackReference 提供了以下的 Method 可用來存取 Stack 中的 Output 值:

  • public getOutput(name: Input<string>): Output<any>;
  • public getOutputValue(name: string): Promise<any>;
  • public requireOutput(name: Input<string>): Output<any>;
  • public requireOutputValue(name: string): Promise<any>;

這四個 method 主要可以分為兩組:

  • getOutput 與 requireOutput 為一組,都是輸入 Input<string>,取得 Output 型別的資料。
  • getOutputValue 與 requireOutputValue 為一組,輸入 string,取得 Promise 型別的資料。

get 與 require 的差別就與 Config 的 get 與 require 相同,get 可能會拿不到資料,而回傳 undefined;require 會確保資料存在,不存在就會拋出 Exception。

Note: Python 只有 getOutput 與 requireOutput

如果沒有特別需求的話,可以直接使用 getOutput 的方法取得其他 Stack 的 Output。

但 Output 處理起來有時候會比較麻煩,且 Output 值不能做為 Resource 的 name,官方也不建議在 Output.apply 內建立 Resource。這時就可以用 getOutputValue 取得資料,因為 getOutputValue 會回傳 Promise,可以直接使用 await 的方式取得 Promise 的值。這個方法就類似使用 aws.getAvailabilityZones 取得可用區一樣,一樣是回傳 Promise。

以下為使用兩種不同方式取得 pulumi-infra 專案 dev Stack 中的 VpcId 的方法:

TypeScript 範例

// 取得另一個 Stack 中的 vpcId,型別為 Output<string>
const vpcIdOutput: pulumi.Output<string> = stackRef.getOutput("vpcId") as pulumi.Output<string>;

// 取得另一個 Stack 中的 vpcId,型別為 string
const vpcIdValue: string = await stackRef.getOutputValue("vpcId") as string;

Python 範例

// 取得另一個 Stack 中的 vpcId,型別為 Output[str]
vpc_id: pulumi.Output[str] = infra_stack.get_output('vpcId')

小結

在 Pulumi 中,參考其他專案中的 Stack 應該是很常見的需求。不過目前的限制還是比較多。

因為 Pulumi 一開始開發就只支援 Pulumi Cloud,後期才開始支援不同的 Storage 做為 Backend。雖然個人使用 Pulumi Cloud 是完全免費的,但如果是企業使用就可能需要付費了。

Reference


上一篇
[Day 19] Pulumi 的 Backend 與 migration
下一篇
[Day 21] 參考其他 IaC 工具的狀態/輸出
系列文
30 天學習 Pulumi:用各種程式語言控制雲端資源30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言