■ はじめに
Pulumi の Component (コンポーネント)って概念を勉強する
目次
【1】Component (コンポーネント) 【2】利点 1)階層化で表示され、見やすくなる 2)作成・削除の指定が楽になる 【3】使用例 【4】作成に当たって 1)ComponentResourceクラス 【5】サンプル 例1:Hello World 例2:AWS 例3:Outputとして登録する 例4:Kubernetes
【1】Component (コンポーネント)
https://www.pulumi.com/docs/intro/concepts/resources/components/
A component resource is a logical grouping of resources. [訳] コンポーネント リソース は、リソースの論理的なグルーピングです => 複数スタックにまたがる設定をまとめる
【2】利点
* 一言でいえば、「管理しやすいから」 => どう管理しやすいかっていうと、、、 ~~~~~ 1)階層化で表示され、見やすくなる 2)作成・削除の指定が楽になる ~~~~~
Pulumi ~ 基本編 / CLI ~
https://dk521123.hatenablog.com/entry/2021/10/25/215508
1)階層化で表示され、見やすくなる
* pulumi preview/up などで階層化で表示され、見やすくなる
例
$ pulumi stack --show-urns TYPE NAME pulumi:pulumi:Stack quickstart-dev │ URN: urn:pulumi:dev::quickstart::pulumi:pulumi:Stack::quickstart-dev ├─ demo:DemoComponent hello-world │ │ URN: urn:pulumi:dev::quickstart::yyyyy │ ├─ kubernetes:apps/v1:Deployment nginx │ │ URN: urn:pulumi:dev::quickstart::xxxxx │ └─ kubernetes:core/v1:Service nginx │ URN: urn:pulumi:dev::quickstart::demo:zzzzzzz └─ pulumi:providers:kubernetes default_3_17_0 URN: urn:pulumi:dev::quickstart::xxxxxxx
2)作成・削除の指定が楽になる
* pulumi up/destroy --target で作成・削除の指定が楽になる * 以下の関連記事の「pulumi up」「pulumi destroy」を参照のこと
https://dk521123.hatenablog.com/entry/2021/10/25/215508
例
# コマンド例「pulumi up --target {URN}」 pulumi up --target urn:pulumi:dev::quickstart::yyyyy
【3】使用例
例1:Glue workflow に必要な 以下をデプロイ処理を纏める
[1] スクリプトをS3にあげる [2] Glue workflow作成 [3] Glue Job作成 [4] 紐づく Glue trigger作成
【4】作成に当たって
* pulumi.ComponentResource を継承して使う
https://www.pulumi.com/docs/reference/pkg/nodejs/pulumi/pulumi/#ComponentResource
* 親子関係を設定しておくといい => 「例4:Kubernetes」の「{ parent: this }」を参考に、、、
1)ComponentResourceクラス
https://www.pulumi.com/docs/reference/pkg/nodejs/pulumi/pulumi/#ComponentResource
new ComponentResource( // type : the fully qualified type token type: string, // name : The unique name of the resource name: string, // args : Information passed to [initialize] method. args: Inputs, // opts : A bag of options that control this resource's behavior. opts: ComponentResourceOptions, // remote : True if this is a remote component resource. remote: boolean )
【5】サンプル
例1:Hello World
./components/demoComponent.ts
import * as pulumi from "@pulumi/pulumi"; // Inherit pulumi.ComponentResource export class DemoComponent extends pulumi.ComponentResource { readonly arg1: string; // Register this component with name demo:DemoComponent constructor( name: string, { arg1, }: DemoArgs, opts?: pulumi.ComponentResourceOptions ) { super("demo:DemoComponent", name, {}, opts); // 以降に処理を書く this.arg1 = arg1; pulumi.log.info(`arg1 = ${arg1}`) // Register that we are done constructing the component this.registerOutputs(); } } export type DemoArgs = { readonly arg1: string; }
index.ts
import * as pulumi from "@pulumi/pulumi"; // 作成したComponent クラスを import import { DemoComponent } from "./components/demoComponent"; const demoComponent = new DemoComponent( "hello-world", { arg1: "Hello, World!!", }, );
出力結果例:pulumi review
$ pulumi preview Previewing update (dev) View Live: https://app.pulumi.com/user/Hello/dev/previews/xxxxx Type Name Plan Info + pulumi:pulumi:Stack Hello-dev create 1 message + └─ demo:DemoComponent hello-world create Diagnostics: pulumi:pulumi:Stack (Hello-dev): arg1 = Hello, World!!
例2:AWS
demoComponent.ts
import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws"; // Inherit pulumi.ComponentResource export class DemoComponent extends pulumi.ComponentResource { readonly bucketName: string; // Register this component with name demo:DemoComponent constructor( name: string, { bucketName, }: DemoArgs, opts?: pulumi.ComponentResourceOptions ) { super("demo:DemoComponent", name, {}, opts); // 以降に処理を書く this.bucketName = bucketName; // Create a bucket const demoBucket = new aws.s3.Bucket(bucketName, {}, { parent: this } ); // specify resource parent ★重要★ // Create a property for the bucket name that was created this.bucketName = demoBucket.bucket, // Register that we are done constructing the component this.registerOutputs(); } } export type DemoArgs = { readonly bucketName: string; }
index.ts
import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws"; // 作成したComponent クラスを import import { DemoComponent } from "./demoComponent"; const demoComponent = new DemoComponent( "hello-world", { bucketName: "your-s3-bucket", }, );
例3:Outputとして登録する
* registerOutputs() の引数に登録すればいい * 「例1:Hello World」を修正する * 以下の Github が参考になる
https://github.com/pulumi/examples/tree/master/twilio-ts-component
./components/demoComponent.ts
import * as pulumi from "@pulumi/pulumi"; // Inherit pulumi.ComponentResource export class DemoComponent extends pulumi.ComponentResource { readonly arg1: string; // ★注目★ public readonly result: pulumi.Output<string>; // Register this component with name demo:DemoComponent constructor( name: string, { arg1, }: DemoArgs, opts?: pulumi.ComponentResourceOptions ) { super("demo:DemoComponent", name, {}, opts); // 以降に処理を書く this.arg1 = arg1; pulumi.log.info(`arg1 = ${arg1}`) // ★注目★ // Register the result as an output of the component itself. this.result = pulumi.interpolate `Result is ${arg1}...`; this.registerOutputs({ result: this.result, }); } } export type DemoArgs = { readonly arg1: string; }
index.ts
import * as pulumi from "@pulumi/pulumi"; // 作成したComponent クラスを import import { DemoComponent } from "./components/demoComponent"; const demoComponent = new DemoComponent( "hello-world", { arg1: "Hello, World!!", }, ); // ★注目★ export const result = demoComponent.result;
出力結果
$ pulumi preview Outputs: result: "Result is Hello, World!!..."
例4:Kubernetes
https://dk521123.hatenablog.com/entry/2022/03/07/233752
でやった例を Component で作成してみる
./components/demoComponent.ts
import * as pulumi from "@pulumi/pulumi"; import * as k8s from "@pulumi/kubernetes"; // Inherit pulumi.ComponentResource export class DemoComponent extends pulumi.ComponentResource { public readonly ip: pulumi.Output<string>; // Register this component with name demo:DemoComponent constructor( name: string, { arg1, }: DemoArgs, opts?: pulumi.ComponentResourceOptions ) { super("demo:DemoComponent", name, {}, opts); // Minikube does not implement services of type `LoadBalancer`; require the user to specify if we're // running on minikube, and if so, create only services of type ClusterIP. const config = new pulumi.Config(); const isMinikube = config.requireBoolean("isMinikube"); const appName = "nginx"; const appLabels = { app: appName }; const deployment = new k8s.apps.v1.Deployment(appName, { spec: { selector: { matchLabels: appLabels }, replicas: 1, template: { metadata: { labels: appLabels }, spec: { containers: [{ name: appName, image: "nginx" }] } } } }, { parent: this }); // ★親子関係を指定 // Allocate an IP to the Deployment. const frontend = new k8s.core.v1.Service(appName, { metadata: { labels: deployment.spec.template.metadata.labels }, spec: { type: isMinikube ? "ClusterIP" : "LoadBalancer", ports: [{ port: 80, targetPort: 80, protocol: "TCP" }], selector: appLabels } }, { parent: this }); // ★親子関係を指定 // When "done", this will print the public IP. this.ip = isMinikube ? pulumi.output(frontend.spec.clusterIP) : pulumi.output(frontend.status.loadBalancer.apply( (lb) => lb.ingress[0].ip || lb.ingress[0].hostname )); // Register the result as an output of the component itself. this.registerOutputs({ ip: this.ip, }); } } export type DemoArgs = { readonly arg1: string; }
index.ts
import * as pulumi from "@pulumi/pulumi"; // 作成したComponent クラスを import import { DemoComponent } from "./components/demoComponent"; const demoComponent = new DemoComponent( "hello-world", { arg1: "Hello, World!!", }, ); export const ip = demoComponent.ip;
出力結果
Updating (dev): Type Name Status pulumi:pulumi:Stack quickstart-dev ├─ demo:DemoComponent hello-world created << 親 │ ├─ kubernetes:apps/v1:Deployment nginx created << 子 │ └─ kubernetes:core/v1:Service nginx created << 子
参考文献
https://tech.guitarrapc.com/entry/2019/12/02/011359
https://qiita.com/suin/items/4cf7e97ae902b2d16417
https://tech.guitarrapc.com/entry/2019/12/05/000000
公式サイト
https://www.pulumi.com/registry/packages/aws/how-to-guides/s3-folder-component/#s3-folder-pulumi-component
https://www.pulumi.com/blog/resource-methods-for-pulumi-packages/#component-implementation
https://www.pulumi.com/docs/intro/concepts/resources/components/
関連記事
Pulumi ~ 基礎知識編 ~
https://dk521123.hatenablog.com/entry/2021/10/23/025230
Pulumi ~ 基本編 / Logging ~
https://dk521123.hatenablog.com/entry/2022/03/04/111618
Pulumi ~ AWS S3 / KMS のデプロイ ~
https://dk521123.hatenablog.com/entry/2022/03/03/095415
Pulumi ~ AWS Glue のデプロイ ~
https://dk521123.hatenablog.com/entry/2022/03/02/122037
Pulumi ~ 入門編 / Hello World in Local/k8s ~
https://dk521123.hatenablog.com/entry/2022/03/07/233752
Pulumi ~ 入門編 / Hello World in AWS ~
https://dk521123.hatenablog.com/entry/2022/03/11/184041
Pulumi ~ 基本編 / CLI ~
https://dk521123.hatenablog.com/entry/2021/10/25/215508