AWSx 是 Pulumi 官方根據 AWS 最佳實務與 well-architected 所提供的套件,主要是將 AWS Provider 再包裝,提供比較高階的 Component Resource。有點像是 Terraform 的 module
或是 AWS CDK 的 L3 Constrcut
的角色。
在之前的實戰練習中,練習自己包裝製作 Vpc Component Resource 來簡化建立 AWS Infrastructure 的流程。
其實建立 AWS Infrastructure 這功能是很常見的需求,AWS 也有最佳實務,所以在 AWSx 中也有提供建立整套 AWS Infrastructure 的 Component Resource —— awsx.ec2.Vpc
。
以下是使用 awsx.ec2.Vpc
的範例:
const vpc = new awsx.ec2.Vpc('vpc', {
cidrBlock: '10.120.0.0/16',
natGateways: {
strategy: 'Single'
},
numberOfAvailabilityZones: 2,
});
短短 7 行的程式碼,就可以建立 22 個資源,包含 2 個 Public Subnet、2 個 Private Subnet,並設定對應的路由表與路由。
Type Name Plan
pulumi:pulumi:Stack day29-awsx-dev
+ └─ awsx:ec2:Vpc vpc create
+ └─ aws:ec2:Vpc vpc create
+ ├─ aws:ec2:Subnet vpc-private-1 create
+ │ └─ aws:ec2:RouteTable vpc-private-1 create
+ │ ├─ aws:ec2:RouteTableAssociation vpc-private-1 create
+ │ └─ aws:ec2:Route vpc-private-1 create
+ ├─ aws:ec2:InternetGateway vpc create
+ ├─ aws:ec2:Subnet vpc-public-1 create
+ │ ├─ aws:ec2:Eip vpc-1 create
+ │ ├─ aws:ec2:RouteTable vpc-public-1 create
+ │ │ ├─ aws:ec2:RouteTableAssociation vpc-public-1 create
+ │ │ └─ aws:ec2:Route vpc-public-1 create
+ │ └─ aws:ec2:NatGateway vpc-1 create
+ ├─ aws:ec2:Subnet vpc-private-2 create
+ │ └─ aws:ec2:RouteTable vpc-private-2 create
+ │ ├─ aws:ec2:RouteTableAssociation vpc-private-2 create
+ │ └─ aws:ec2:Route vpc-private-2 create
+ └─ aws:ec2:Subnet vpc-public-2 create
+ └─ aws:ec2:RouteTable vpc-public-2 create
+ ├─ aws:ec2:RouteTableAssociation vpc-public-2 create
+ └─ aws:ec2:Route vpc-public-2 create
除了 Vpc 以外,AWSx 還有提供很多其他的 Component Resource,可以到以下這些 package 的文件中查詢。
今天的最後,要介紹一個 Pulumi 中滿特別的功能,可以將 Lambda 與 IaC 程式結合在一起。
如何結合呢?我們先來看一個範例:
const bucket = new aws.s3.Bucket('my-bucket');
bucket.onObjectCreated('log-object', new aws.lambda.CallbackFunction<aws.s3.BucketEvent, void>('onObjectCreated', {
callback: async (event) => {
console.log(event);
}
}));
這個程式碼除了建立了 S3 Bucket 以外,還設定了 s3 notificaiton,當物件被建立時,會執行一個 Lambda。而這個 Lambda 就是直接定義在 onObjectCreated
方法中所傳入的 Lambda 資源中。
這個資源特殊的地方就在於,是將 Lambda 的程式碼寫在 Pulumi IaC 程式中。方便的地方在於不需將 Lambda 放置於其他資料夾,也不需處理打包的問題。Pulumi runtime 在執行的時候,會自動分析 callback 中所使用到的程式碼相依性,並將相關的相依性打包、提取 Callback 的內容、打包成 zip,最後建立 Lambda 資源。
不過可惜的是,這個功能目前只能在 TypeScript 語言中使用。且支援 aws.lambda.CallbackFunction
的事件也很有限。官方文件中有列出支援的 11 種事件。
接著來做一個範例,是當有圖片上傳至 S3 時,可以自動使用 Lambda 產生縮圖。
一開始,先建立兩個 bucket,一個用來儲存原圖,一個儲存縮圖。
const bucket = new aws.s3.Bucket('image-bucket');
const processedBucket = new aws.s3.Bucket('processed-image-bucket');
接著,註冊 onObjectCreated
事件,設定要執行的 Lambda 函式。因為要在 Lambda 中讀寫 S3 Bucket 內的檔案,因此需要設定 Lambda 相關的 Policy。這邊為了方便就直接給 FullAccess,正常來說,應該要使用 IAM 資源,建立專屬的 Policy。
import {S3Client, GetObjectCommand, PutObjectCommand} from "@aws-sdk/client-s3";
import * as Jimp from 'jimp';
bucket.onObjectCreated('resize-image', new aws.lambda.CallbackFunction<aws.s3.BucketEvent, void>('onObjectCreated', {
policies: [
aws.iam.ManagedPolicy.AWSLambdaExecute,
aws.iam.ManagedPolicy.AmazonS3FullAccess
],
memorySize: 1024,
timeout: 300,
callback: async (event) => {
}
}, {parent: bucket}));
最後在 callback 內,就是使用 aws-js SDK 內的 S3Client 下載圖片,並利用 Jimp 套件製作圖片縮圖,最後將縮圖上傳至另一個 bucket 中。
await Promise.all(event.Records.map(async (record) => {
// S3 檔案的路徑
const file = record.s3.object.key;
// 下載圖片檔
const s3client = new S3Client();
const data = await s3client.send(new GetObjectCommand({
Bucket: bucket.id.get(),
Key: file
}));
const bytes = await data.Body.transformToByteArray();
// 使用 Jimp 轉檔
return Jimp.read(Buffer.from(bytes), async (err, image) => {
if (err) {
console.log(err);
return;
}
// 產生縮圖,最大的寬高為 200
return await image.resize(200, Jimp.AUTO)
.getBufferAsync(Jimp.MIME_JPEG)
.then(async (data) => {
// 上傳至另一個 S3 Bucket
return s3client.send(new PutObjectCommand({
Bucket: processedBucket.id.get(),
Key: file,
Body: data
}));
});
});
}));
設定完以後,執行 pulumi up
就能看到所建立的資源列表。雖然程式中只有建立 2 個 bucket 與一個 Lambda,但其實背後會建立這麼多資源!
$ pulumi up
Previewing update (dev)
Type Name Plan
+ pulumi:pulumi:Stack day29-awsx-dev create
+ ├─ aws:s3:Bucket processed-image-bucket create
+ └─ aws:s3:Bucket image-bucket create
+ ├─ aws:iam:Role resize-image create
+ ├─ aws:s3:BucketEventSubscription resize-image create
+ │ └─ aws:lambda:Permission resize-image create
+ ├─ aws:iam:RolePolicyAttachment resize-image-4aaabb8e create
+ ├─ aws:iam:RolePolicyAttachment resize-image-aadec3c3 create
+ ├─ aws:lambda:Function resize-image create
+ └─ aws:s3:BucketNotification resize-image create
不知道是不是因為 Pulumi 的創始團隊有 AWS 前員工的關係,Pulumi 與 AWS 的整合做的滿深入的,今天介紹的功能 Pulumi 就沒有做在其他 Provider 中。