Day 6 – AWS CDK 部署 Lambda 與 API Gateway 服務 (上)

今天我們來部署一個 API Gateway 串接 Lambda 的服務,讓我們直接來 serverless 一下!

https://ithelp.ithome.com.tw/upload/images/20201024/20117701QzNO37YYln.jpg

建立 Lambda

創建新的 CDK Project

我們這次的專案叫它 cdk-lambda,首先我們先創建資料夾然後 init 一下專案

$ mkdir cdk-lambda && cd cdk-lambda
$ cdk init --language typescript
Applying project template app for typescript
# Welcome to your CDK TypeScript project!

This is a blank project for TypeScript development with CDK.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

## Useful commands

 * `npm run build`   compile typescript to js
 * `npm run watch`   watch for changes and compile
 * `npm run test`    perform the jest unit tests
 * `cdk deploy`      deploy this stack to your default AWS account/region
 * `cdk diff`        compare deployed stack with current state
 * `cdk synth`       emits the synthesized CloudFormation template

Initializing a new git repository...
Executing npm install...
npm WARN deprecated [email protected]: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated [email protected]: request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142
npm WARN deprecated [email protected]: this library is no longer supported
npm WARN deprecated [email protected]: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated [email protected]: Please see https://github.com/lydell/urix#deprecated
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN [email protected] No repository field.
npm WARN [email protected] No license field.

✅ All done!

與之前的 CDK Project 創建方法做比較

可以看到這次沒有加入 template 指令,所以在 cdk-lambda.stack.ts 裡面沒有內容只有一行註解,移除註解就可以開始我們今天的主題了!

https://ithelp.ithome.com.tw/upload/images/20200919/20117701GbnkomaadV.png

創建 Lambda function 主程式

  • 接下來我們創建一個放 lambda function 的資料夾
$ mkdir lambda
  • 放入 lambda/index.js 測試檔案
exports.handler = async function (event) {
  console.log("request:", JSON.stringify(event, undefined, 2));
  return;
};
  • 加入 cdk-lambda.stack.ts 放入 lambda
import * as cdk from "@aws-cdk/core";
import * as lambda from "@aws-cdk/aws-lambda";

export class CdkLambdaStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const main = new lambda.Function(this, "lambda", {
      runtime: lambda.Runtime.NODEJS_10_X,
      handler: "index.handler",
      code: lambda.Code.fromAsset("lambda"),
    });
  }
}
  • 安裝套件
$ npm i @aws-cdk/aws-lambda
  • 執行 deploy
$ cdk deploy
  • 開啟 AWS Console 檢查一下看一下我們的 Lambda 是否有成功部署上去! https://ithelp.ithome.com.tw/upload/images/20200920/20117701o9dCUQzGvW.png

準備 API Gateway 要用的 Lambda Function

第一次使用 CDK 部署 Lambda 來測試看看改變我們的 Lambda Function 會不會同步幫我們修改吧! 此次的修改內容因應要串接 API Gateway 做了一點改變 如果想要進一步知道其他的串接參數可以直接閱讀官方文件在 API Gateway 中設定整合回應

exports.handler = async function (event) {
  console.log("request:", JSON.stringify(event, undefined, 2));
  return {
    statusCode: 200,
    headers: { "Content-Type": "text/html" },
    body: `<h1>第 12 屆 iT 邦幫忙鐵人賽 用 CDK 定義 AWS 架構 AWS Lambda!</h1>`,
  };
};

在部署之前先查看一下 cdk diff 可以發現我們更新了 index.js CDK 會幫我們重新上傳檔案到 S3 並且更新它 這段繁瑣的功能 CDK 完美的幫我們處理好了 ~~ 可以從 Parameters 與 Resources 看到有 S3 的新增檔案與移除

$ cdk diff

因為剛開始使用我們還是重新整理一下 AWS Console 看看吧! https://ithelp.ithome.com.tw/upload/images/20200920/201177010v7nnBdvdN.png

加入 API Gateway

修改 lib/cdk-lambda-stack.ts

我絕對不會說我本來是想要串 ALB 可是突然想到要先講 VPC 才可以創 ALB 因此決定還是先寫 API Gateway 要使用 API Gateway 串接 Lambda 可以直接使用 CDK 的 LambdaRestApi 來完成 是不是非常簡單又快速呢!這邊如果手動可是還要在 AWS Console 點個好幾下呢!

import * as cdk from "@aws-cdk/core";
import * as lambda from "@aws-cdk/aws-lambda";
import * as apigw from '@aws-cdk/aws-apigateway';

export class CdkLambdaStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const main = new lambda.Function(this, "lambda", {
      runtime: lambda.Runtime.NODEJS_10_X,
      handler: "index.handler",
      code: lambda.Code.fromAsset("lambda"),
    });
    new apigw.LambdaRestApi(this, 'Endpoint', {
      handler: main
    });
  }
}

檢查一下 diff 可以看到新增了 API Gateway 的 Resources

$ cdk diff

安裝套件

$ npm i @aws-cdk/aws-apigateway

使用部署指令完成後可以看到網頁了!

$ cdk deploy

部署完成後測試

網頁亂碼

我們來看一下網頁,哇!竟然是亂碼,其實是我們忘記指定它是 UTF-8 了來修正一下程式 https://ithelp.ithome.com.tw/upload/images/20200920/2011770168RYYmfbLl.png

修正網頁

其實這邊的問題主要是在 HTML 語法的部分跟 Lambda 比較沒有關係,不過還是介紹一下 XD

exports.handler = async function (event) {
  console.log("request:", JSON.stringify(event, undefined, 2));
  return {
    statusCode: 200,
    headers: { "Content-Type": "text/html" },
    body: `<meta charset="utf-8"><h1>第 12 屆 iT 邦幫忙鐵人賽 用 CDK 定義 AWS 架構 AWS Lambda!</h1>`,
  };
};

再部署一次就正常了 https://ithelp.ithome.com.tw/upload/images/20200920/201177018WFxePIQre.png

讓 API Gateway 支援 customer domain

目前使用的網址是 API Gateway 的 domain 覺得不太美觀來幫它換一下! 首先我們先在 LambdaRestApi 指定 domain name 如 21-24 行使用 api.cdk.clarence.tw 在 API Gateway 使用 Customer Domain 需要使用 HTTPS 因此還需要設定 ACM 來新增 ACM 使用 *.cdk.clarence.tw 如 15-18 行

import * as cdk from "@aws-cdk/core";
import * as lambda from "@aws-cdk/aws-lambda";
import * as apigw from "@aws-cdk/aws-apigateway";
import * as acm from "@aws-cdk/aws-certificatemanager";

export class CdkLambdaStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const main = new lambda.Function(this, "lambda", {
      runtime: lambda.Runtime.NODEJS_10_X,
      handler: "index.handler",
      code: lambda.Code.fromAsset("lambda"),
    });
    const cert = new acm.Certificate(this, "Certificate", {
      domainName: "*.cdk.clarence.tw",
      validation: acm.CertificateValidation.fromDns(),
    });
    new apigw.LambdaRestApi(this, "Endpoint", {
      handler: main,
      domainName: {
        domainName: "api.cdk.clarence.tw",
        certificate: cert,
      },
    });
  }
}

安裝套件

$ npm i @aws-cdk/aws-certificatemanager

修改完程式後我們來更新一下

$ cdk deploy

執行完成後到 AWS Console 看 API Gateway/Custom domain names 看一下是否設定完成 https://ithelp.ithome.com.tw/upload/images/20200920/20117701HnnsTzBIuz.png

確定完成後到我們的 DNS 設定一下 Domain 的 CNAME,接下來就可以使用新的網址打開網站拉! 是不是變得比較美觀 ~ https://ithelp.ithome.com.tw/upload/images/20200920/20117701cOXKj3bPP0.png

以上是今天的 CDK 使用 Lambda、API Gateway 與 ACM 解說,目前的排版可能有點亂我還在思考要怎麼做會比較好看請大家見諒 QQ