ใน Best Practices ของการทำ AWS Lambda Function มีอยู่ข้อหนึ่งที่บอกว่า “Control the dependencies in your function’s deployment package.” คือ แนะนำให้เราควบคุมและจัดการกับ Library ที่ Funtion ของเราต้องใช้งาน
เพราะเมื่อระบบเราใหญ่ขึ้น สมมติว่ามี 100 Functions และต้องเรียกใช้ Library คล้ายกัน ปัญหาคือ
- เราจะควบคุม Version ของ Library ให้เหมือนกันทุก Function ได้ไหม
- Filesize ของ Deployment Package เราจะใหญ่ เพราะ ทุก Function ต้องแพ็ค Library ที่เกี่ยวข้องติดไปด้วยทุกตัว
- เมื่อ Deployment Package เราใหญ่ จะทำให้ช่วงเวลา Cold Start ของ Lambda เรา ช้าขึ้นไปอีก
Amazon เลยมีฟีเจอร์หนึ่งให้ใช้คือ Lambda Layers เพื่อใช้เก็บ Libraries, Custom Runtime หรือพวก Dependencies ต่างๆ แยกออกจาก Function ของเรา เพื่อให้ Function เราเล็กลง และสามารถเรียกใช้ Layers ต่างๆที่ Function อื่นได้ด้วย
คำแนะนำ: บทความนี้จะอ่านเข้าใจ ถ้าคุณใช้ AWS Lambda เบื้องต้นเป็นแล้ว
ปัญหา Lambda Layers กับ Net Core
ในขณะที่ผมกำลังเขียนบล็อกนี้ (7 Feb 2019) ตัว AWS Lambda เอง รองรับการทำ Layers แค่ Node.js, Python, และ Ruby functions เท่านั้น
ส่วนภาษาอื่นๆ อาจจะลำบากหน่อย เพราะ Dependency อยู่ในโฟลเดอร์ข้างนอก project เช่น C# ของ MacOS จะอยู่ใน /usr/local/share/dotnet/ ซึ่งเราจะต้องสร้าง Runtime package store ของ project นั้น แล้วไปคัดเลือก Dependency เอง จากนั้น zip file ออกมานำไปใช้ใน Lambda Layer ส่วนโค้ดของเรา เมื่อทำคำสั่ง publish แล้ว เราต้อง zip เฉพาะโค้ดเราเท่านั้น และนำไปขึ้น AWS เอง และทำการลิงค์กัน… ฟังดูยุ่งยากเนอะ
แต่อย่าเพิ่งตกใจไป ที่เขียนบล็อกนี้เพราะ Amazon กำลังปรับปรุงเครื่องมือ AWS CLI ของตัวเอง เพื่อให้ชาว C# .Net Core ทำทำ Layers ได้ง่ายๆแล้ว ซึ่งขณะนี้อยู่ในช่วงของ Beta Version เพิ่งปล่อย Docs มาให้ได้อ่านกันเพียง 20 วันนี้เอง
Amazon Lambda Tools V.3.2.0-beta1 ที่มาพร้อมกับ คำสั่ง “ lambda publish-layers”
ถ้าอ่านถึงตรงนี้ ชาว C# น่าจะอยากใช้งาน Layer กันบ้างแล้ว แต่เราจะไม่สามารถใช้กับ AWS Lambda Tools เวอร์ชั่นปัจจุบันได้ (ตอนนี้คือ V.3.1.2) ดังนั้นต้องเอาตัว Beta มาใช้ ด้วยวิธีการ Build Package มันขึ้นมาเองเอง
สำหรับคนที่ไม่เคยใช้ AWS CLI จำเป็นต้องทำสองขั้นตอนนี้ก่อน คือ
แต่ถ้าเรามี AWS CLI พร้อมใช้อยู่แล้ว ให้เริ่มติดตั้ง Amazon Lambda Tools กันเลยได้ให้ทำการ clone repo https://github.com/aws/aws-extensions-for-dotnet-cli.git
1.ให้ทำการ clone repo https://github.com/aws/aws-extensions-for-dotnet-cli.git
git clone https://github.com/aws/aws-extensions-for-dotnet-cli.git
2. จากนั้นทำการ checkout branchไปที่ “lambda-layers”
git checkout lambda-layers
3.สร้าง NuGet Package ใหม่ของ amazon.lambda.tools
dotnet msbuild buildtools/build.proj /t:build-nuget-packages
4.ทำการ uninstall amazon.lambda.tools ตัวเก่าออก (หากใครยังไม่เคยใช้มาก่อน ก็ไม่ต้องทำบรรทัดนี้)
dotnet tool uninstall -g amazon.lambda.tools
5.ติดตั้ง package amazon.lambda.tools ใหม่
dotnet tool install -g --add-source ./Deployment/nuget-packages/ Amazon.Lambda.Tools --version 3.2.0-beta1
เมื่อติดตั้งเสร็จ ให้ลองพิมพ์ “dotnet lambda“ ดูครับ จะต้องได้เวอร์ชั่น 3.2.0-beta1 และมีคำสั่ง publish-layer เพิ่มเข้ามา (นอกจากมี publish-layer แล้ว ยังทำให้คำสั่ง deploy-function และ package รองรับการใช้งาน layers ด้วย)
มาลองสร้าง Lambda Layers ของภาษา C# .Net Core กัน
ก่อนอื่นเลย เราต้องมี S3 Bucket ก่อน เพราะว่าเมื่อทำคำสั่งนี้ มันจะเก็บ Package ต่างๆ ไว้ที่ S3 ซึ่งในที่นี้ผมตั้งชื่อว่า lambda-profile-dependency
จากนั้นเข้าไปที่โฟลเดอร์ C# Project ของเรา และเราจะใช้คำสั่ง dotnet lambda publish-layer ซึ่งมีรูปแบบการใช้งานดังนี้
dotnet lambda publish-layer layer-name --layer-type runtime-package-store --s3-bucket bucket-name
โดย
- layer-name คือ ชื่อของ Layer ที่เราต้องการ
- bucket-name คือ ชื่อของ S3 Bucket ที่เราจะใช้เก็บไฟล์
- runtime-package-store คือ type ของ layer ซึ่งคำสั่งนี้ถูกทำเผื่อไว้ในอนาคต ว่าจะมีประเภทของ package ให้เลือกได้ ตอนนี้มีให้ใช้อย่างเดียวคือ runtime package
ในที่นี้ ถ้าผมต้องการเก็บลง S3 Bucket ชื่อ lambda-profile-dependency และตั้งชื่อ Layer ว่า profile-lib จะได้คำสั่งประมาณนี้
dotnet lambda publish-layer profile-lib --layer-type runtime-package-store --s3-bucket lambda-profile-dependency
เมื่อรันคำสั่ง มันก็จะทำการแพ็คไฟล์นั่นนู่นนี่ไปเรื่อยๆ จนสุดท้าย ออกมาจะต้องได้ ARN ของ AWS Lambda Layer ที่เราจะใช้งาน ตามภาพด้านล่าง (บรรทัดสุดท้าย)
ให้เราคัดลอก ARN ไปใช้ในคำสั่ง deploy lambda ด้วยรูปแบบดังนี้
dotnet lambda deploy-function function-name --function-layers layer-arn
โดย
- function-name คือ ชื่อ Lambda Function ของเรา
- layer-arn คือ ARN ของ Lambda Layer ที่เราจะลิงค์ถึง (รูปแบบจะประมาณนี้ arn:aws:lambda:[region-name]:[aws-user-id]:layer:[layer-name]:[layer-version])
ดังนั้น ถ้าผมต้องการ Function ชื่อ list_profile และ ใช้ layer ที่เพิ่งสร้างขึ้นเมื่อสักครู่ จะใช้คำสั่งดังนี้
dotnet lambda deploy-function list_profile –-function-role MyRole --function-layers arn:aws:lambda:ap-southeast-1:819684245502:layer:profile-lib:1
เมื่อรันคำสั่ง มันก็จะทำการแพ็คไฟล์ เพื่อเตรียม deploy โดยมันจะแยกเอาเฉพาะไฟล์ Function ของเราเท่านั้น ไม่เอาพวก dependency library เข้าไปด้วย (ขั้นตอนนี้ ทำมือเองได้ แต่ใช้คำสั่งเถอะ เร็วกว่า)
เป็นอันว่าเสร็จเรียบร้อย Lambda Function ของเรา กับ Lambda Layer ถูกนำขึ้นไปไว้บน AWS และผูกมิตรกันให้ด้วย
สำรวจผลลัพธ์ Lambda Function และ Lambda Layer หลัง Deployment
ลองมาดูกันว่าผลลัพธ์หลังจากการใช้งาน Lambda Layer เป็นอย่างไร
เพิ่มเติม: อย่าลืมว่า การคิดเงินของ AWS Lambda มันคิดที่หน่วย 100ms นะ
อย่าง cold start จากที่โดนคิดเงิน 16000ms จะเหลือแค่ 15500ms หายไป 500ms
คำเตือน: ถ้าเราเคยมี Environment Variable เดิมอยู่ มันจะหายไป!!!
สรุป
ถ้าชาว C# .Net Core อยากใช้ Lambda Layer ก็ลองทำตามในบล็อกนี้ได้เลย หรือไม่ก็รอ AWS CLI เวอร์ชั่น 3.2.0 ออกตัวเต็ม ก็ได้ครับ แต่เท่าที่ลองใช้ ไม่มีปัญหาอะไรนะ สะดวกดี
และข้อจำกัดตอนนี้ คือ Lambda Layer มีให้ใช้กันที่ 5 Layers ดังนั้น ต้องมาคิดต่อว่าจะจัดสรร Dependency กันอย่างไร เพื่อให้ใช้ประโยชน์ร่วมกันเยอะที่สุด
อ้างอิง
- https://github.com/aws/aws-extensions-for-dotnet-cli/blob/lambda-layers/docs/Layers.md
- https://github.com/aws/aws-extensions-for-dotnet-cli/tree/lambda-layers
- https://github.com/aws/aws-extensions-for-dotnet-cli/issues/58