iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 16
1
DevOps

用 CDK 定義 AWS 架構系列 第 16

Day 16 - 要串接 API 除了 API Gateway 你還有另外的選擇 Application Load Balancer

不知道大家還記不記得在 Day 6 - AWS CDK 部署 Lambda 與 API Gateway 服務 (上) 的時候有說過要介紹 Lambda 串接 ALB,那時候因為還沒介紹 VPC,而我們已經介紹過 VPC 了,所以今天就來介紹它吧!

https://ithelp.ithome.com.tw/upload/images/20201002/20117701HtwmQ7qpm1.jpg

創建 Application Load Balancer 串接 Lambda

準備 Lambda

這次的 Lambda 與上次的大同小異,主要在於直接印出寫 API 的資訊

  • Method
  • Path
  • Query

大家可以直接用這個網頁做 Debug 或是開發

檔案:lambda/index.js

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><a href="https://ithelp.ithome.com.tw/users/20117701/ironman/3734" target="_blank">用 CDK 定義 AWS 架構 AWS Lambda!</a></h1>` +
      `<p><a href="https://blog.clarence.tw/" target="_blank">https://blog.clarence.tw/</a></p>` +
      `<p>Method: ${event.httpMethod}</p>` +
      `<p>Path: ${event.path}</p>` +
      `<p>Query: ${JSON.stringify(
        event.queryStringParameters,
        undefined,
        2
      )}</p>`,
  };
};

準備 VPC 與 Lambda Target

在這邊 VPC 建立方法與之前教大家 EC2 建立機器的 VPC 相同,主要不同的地方在於我們把 targets 放入 new targets.LambdaTarget(lambdaFunction)

const vpc = new ec2.Vpc(this, "VPC", {
  maxAzs: 3,
  natGateways: 0,
});

const lambdaFunction = new lambda.Function(this, "lambda", {
  runtime: lambda.Runtime.NODEJS_10_X,
  handler: "index.handler",
  code: lambda.Code.fromAsset("lambda"),
});

const lb = new elbv2.ApplicationLoadBalancer(this, "ALB", {
  vpc,
  internetFacing: true,
});
new cdk.CfnOutput(this, "ALBDomain", {
  value: lb.loadBalancerDnsName,
});

const listener = lb.addListener("Listener", { port: 80 });
listener.addTargets("LambdaTarget", {
  targets: [new targets.LambdaTarget(lambdaFunction)],

  healthCheck: {
    enabled: true,
  },
});

測試看看 API 吧!

我們這次拿到的 ALB Domain:http://cdklb-albae-1ixf52wqbsc7b-2018343058.us-west-2.elb.amazonaws.com/

拿到的資訊如下:

https://ithelp.ithome.com.tw/upload/images/20200930/20117701IU2ijBKA50.png

結合 Lambda API 與 EC2 API

使用了 Lambda 串接 ALB 大家有注意到可以玩什麼不一樣的變化嗎?

就是可以把前天教的 ALB 串接 EC2 加上 ALB 串接 Lambda 做一個組合技拉!
如此應該滿好玩的!因為大家就可以是情況幫它們拆負載或是把用 Lambda 比較好寫的服務用 Lambda 寫,想要用 EC2 組合的服務放機器,做很多種變化。

準備 CDK 腳本

話不多說現在就教大家怎麼做吧!
準備一下目標,我們希望目標 path 是 /api* 的全部導入 Lambda 而其他都給 EC2
如此我們會有兩個 Target 並且要切 path,而在 ALB 裡面如果設定 conditions 就需要給 priority

conditions

先來介紹一下 conditions

  • hostHeaders:用於設定 host 條件
  • httpHeader:用於設定 header 條件
  • httpRequestMethods:用於設定 method 條件
  • pathPatterns:用於設定 path 條件
  • queryStrings:用於設定 query 條件
  • sourceIps:用於設定 source ip 條件
const listener = lb.addListener("Listener", { port: 80 });
listener.addTargets("LambdaTarget", {
  priority: 1,
  conditions: [elbv2.ListenerCondition.pathPatterns(["/api*"])],

  targets: [new targets.LambdaTarget(lambdaFunction)],

  healthCheck: {
    enabled: true,
  },
});

listener.addTargets("EC2Target", {
  healthCheck: {
    enabled: true,
    path: "/phpinfo.php",
  },
  port: 80,
  targets: [new targets.InstanceTarget(ec2Instance)],
});

組合一下

拆散解釋大家可能會看不懂,所以我們還是把它整個整理一下吧!

const vpc = new ec2.Vpc(this, "VPC", {
  maxAzs: 3,
  natGateways: 0,
});

const lambdaFunction = new lambda.Function(this, "lambda", {
  runtime: lambda.Runtime.NODEJS_10_X,
  handler: "index.handler",
  code: lambda.Code.fromAsset("lambda"),
});

const asset = new assets.Asset(this, "Asset", {
  path: path.join(__dirname, "../", "ec2-config", "configure.sh"),
});

const ec2Instance = new ec2.Instance(this, "Instance", {
  vpc,
  instanceType: ec2.InstanceType.of(
    ec2.InstanceClass.T3,
    ec2.InstanceSize.NANO
  ),
  machineImage: ec2.MachineImage.latestAmazonLinux({
    generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
  }),
  vpcSubnets: {
    subnetType: ec2.SubnetType.PUBLIC,
  },
  keyName: "KeyPair",
});
const localPath = ec2Instance.userData.addS3DownloadCommand({
  bucket: asset.bucket,
  bucketKey: asset.s3ObjectKey,
});
ec2Instance.userData.addExecuteFileCommand({
  filePath: localPath,
  arguments: "--verbose -y",
});
asset.grantRead(ec2Instance.role);

const lb = new elbv2.ApplicationLoadBalancer(this, "ALB", {
  vpc,
  internetFacing: true,
});
new cdk.CfnOutput(this, "ALBDomain", {
  value: lb.loadBalancerDnsName,
});

const listener = lb.addListener("Listener", { port: 80 });
listener.addTargets("LambdaTarget", {
  priority: 1,
  conditions: [elbv2.ListenerCondition.pathPatterns(["/api*"])],

  targets: [new targets.LambdaTarget(lambdaFunction)],

  healthCheck: {
    enabled: true,
  },
});

listener.addTargets("EC2Target", {
  healthCheck: {
    enabled: true,
    path: "/phpinfo.php",
  },
  port: 80,
  targets: [new targets.InstanceTarget(ec2Instance)],
});
listener.connections.allowTo(ec2Instance, ec2.Port.tcp(80));

測試看看 API 與 EC2 的結合吧!

https://ithelp.ithome.com.tw/upload/images/20200930/20117701l2np9lHq8f.png

https://ithelp.ithome.com.tw/upload/images/20200930/20117701u6zVm9NtXF.png

https://ithelp.ithome.com.tw/upload/images/20200930/20117701qnRwYT1G64.png

參考資料


以上為今日的 Application Load Balancer 與 Lambda 整合介紹,希望有幫助到大家

想要看更多嗎?歡迎到我的部落格參觀

文章內容主要是網路或是程式開發類型的文章

本文同步刊載於 Clarence 部落格:Day 16 - 要串接 API 除了 API Gateway 你還有另外的選擇 Application Load Balancer


「AWS CDK 完全學習手冊:打造雲端基礎架構程式碼 IaC」
本書改編並延伸自第 12 屆 iT 邦幫忙鐵人賽獲得 DevOps 組冠軍的《用 CDK 定義 AWS 架構》系列文章,以簡單、好讀的行文風格詳述技術細節,並提供完整的程式碼範例與說明,一步一步帶領新手從零開始踏上 AWS CDK 技術達人之路。

有興趣的朋友歡迎至天瓏書局選購!

購書連結 https://bit.ly/2ZMAebE

https://ithelp.ithome.com.tw/upload/images/20211103/20117701W7l6fQnn2L.jpg


上一篇
Day 15 - 使用 CDK 控制 Elastic Load Balancing - Network Load Balancer
下一篇
Day 17 - 使用 CDK 控制 Auto Scaling groups - 我要製作一個容量無限大的服務!
系列文
用 CDK 定義 AWS 架構30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言