העברת אפליקציות קונטיינר לענן - חלק ב׳ (Lambda Web Adapter)

Published
העברת אפליקציות קונטיינר לענן - חלק ב׳ (Lambda Web Adapter)

בחלק א׳ של סדרת הפוסטים הזאת דנו בסיבות השונות שבהן נרצה לקחת אפליקציה מבוססת קונטינרים ולהעבירן לענן אחת הדרכים לעשות זאת היא באמצעות AppRunner, ובפוסט זה נדון בדרך נוספת, קצת פחות מוכרת והיא באמצעות למדה.

למדה + קונטיינר = 🩷

אחת הדרכים הנוחות לארוז קוד ללמדה היא באמצעות קונטיינר, למה נוחות, מכיוון שבמידה ויש לכם הגדרה קודמת של קונטיינר,שאורזת את הקוד שלכם, אין צורך להגדיר אריזה חדשה באמצעות זיפ, המשמעות היא שקל מאוד לקחת קוד קיים, עם כל התלויות שלו ולעלות אותו כפונקציית למדה. יתרון נוסף לאריזה באמצעות קונטיינר, היא הגודל המירבי של למדה שארוזה כקונטיינר - 10 ג׳יגהבייט מול 250 מגהבייט באמצעות זיפ.

ישנם שלושה סוגי קונטיינרים שניתן להשתמש בהם:

  • קונטיינר רשמי של AWS שמבוסס על סביבת ריצה קיימת שמיועדת ללמדה, כשסביבות הריצה הן הרשמיות שנתמכות ע״י למדה, לדוגמא NodeJS, Python וכדומה. היתרון בקונטיינר כזה שהוא מכיל עבורך את סביבת הריצה המלאה, והיא מנהלת את המצבים השונים שהקוד שלך יכול להמצא בו (אתחול, ריצה וסיום). המשמעות של שימוש בקונטיינר כזה היא שעליך לכתוב את הקוד באופן שסביבת הריצה של הלמדה מצפה, קרי - handler.
    כדי להשתמש בקונטיינר כזה הוא שיש לכם למדה קיימת שהקוד הארוז שלה גדול יותר מ-250 מגהבייט.

  • קונטיינר רשמי שלי AWS שמבוסס על סביבת ריצה שאינה קיימת שמיועדת ללמדה, מאוד מזכיר את הסוג הנ״ל, אך מיועד עבור סביבות ריצה שהן provided כגון Go, Rust או סביבת ריצה שפותחו על ידכם.

  • קונטיינר שאינו רשמי ואינו מכיל סביבת ריצה, כאן ניתן להשתמש בכל סוג קונטיינר (Bring your own container) ואין צורך לכתוב קוד בעל מבנה מותאם ללמדה, קרי handler, אך עליכם לספק סביבת ריצה שתדע לתרגם את מכונת המצבים של סביבת הלמדה לקוד שלכם. בבחירה הזאת יש הגמישות הרבה ביותר והיא מאפשרת לקחת אפליקציות לגאסי, ולהעבירן לסביבת למדה. אנו נשתמש בבחירה הזאת כדי להמיר את אפליקציית האקספרס שלנו לרוץ תחת למדה.

הגדרת קונטיינר ב-AWS SAM

הגדרת למדה באמצעות קונטיינר היא פשוטה מאוד, הדבר נתמך ע״י כלי ה-IAC של AWS כגון CDK ו- AWS SAM, בחלק זה נדגים את היצירה באמצעות AWS SAM.

1Resources:
2 GetLambdasLWA:
3 Type: AWS::Serverless::Function
4 Properties:
5 PackageType: Image
6 ImageConfig:
7 Command: ['node', 'index.mjs']
8 ...
9 Metadata:
10 Dockerfile: Dockerfile
11 DockerContext: .
12 DockerTag: latest

צירפתי דוגמא של הגדרת למדה עם קונטיינר, שימו לב לשורה 5, בה הגדרתי את הצורה שבה אני אורז את הקוד, לאחר מכן בשורות 6 עד 7 אני מגדיר מהי הפקודה שתרוץ עם עליית הקונטיינר. שימו לב שניתן בדרך זאת לדרוס את ההגדרה של קובץ ה-Docker. שורות 9-12 מגדירות את אופן בניית הקונטיינר, משמעות הדבר שברגע שנריץ sam build, ממש יבנה לנו קונטיינר מקומי על המכונה שיעלה לאחר מכן ל-AWS ECR שיכיל את הקונטיינר. בנקודה זאת מגיע יתרון משמעותי של AWS SAM והוא יצירת ה-ECR כחלק מתהליך הדפלוי.

כשאתם מריצים sam deploy —guided, נשאלות מספר שאלות לגבי האפליקציה, אחת השאלות היא האם לייצר ECR עבורכם שיכיל את הקונטיינר, במידה ואתם עונים שכן, יווצר לכם ה-ECR המתאים יחד עם ההרשאות המתאימות לשירות הלמדה להוריד את הקונטיינר כשהוא רץ. הדבר מפשט את כאב הראש, כי שירות הלמדה לא יכול לגשת כך סתם ל-ECR ולהשתמש בקונטיינר שהגדרתם עבורו.

הרשאות נדרשות לשירות למדה
הרשאות נדרשות לשירות הלמדה

האפליקציה שלנו מבוססת express, כלומר בניגוד לפונקציית למדה סטנדרטית, אין לה handler, ומכיוון שאנחנו משתמשים בקונטיינר שאינו רשמי, אנו צריכים גם לספק סביבת ריצה. אנו צריכים לגשר על הפער הזה, כאן בדיוק נכנסת לתמונה Lambda Web Adapter או LWA.

Lambda Web Adapter (LWA)

LWA היא Extension, כלומר תוספת שרצה מחוץ לקוד שלכם, כתהליך נפרד אשר מכילה שני פונקציונליות:

  1. היא מכילה מימוש של סביבת ריצה, היא יודעת לתקשר עם שירות הלמדה ומנהלת את המצבים השונים בתקשורת הזאת.

  2. היא יודעת לקחת את הקלטים שמתקבלים מבחוץ ולהמיר אותם לקריאות http פנימית מול השרת שרץ כחלק מ-express. מה שנחמד בתוספת הזאת שהיא אגנוסטית לחלוטים לסוג השרת שרץ, ולכן במידה ואתם משתמשים ב-Django או ב-Flask או בכל פתרון אחר שמרים שרת מקומי אז התוספת תדע לתקשר איתו.

lambda web adapter high level view
מבט על

כיצד משתמשים

1FROM lambda-list-app:latest
2
3COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.9.0 /lambda-adapter /opt/extensions/lambda-adapter
4
5ENV PORT=3000
6ENV READINESS_CHECK_PATH=/health-check
7

אני לא מעוניין לשנות את ההגדרה המקורית של האפליקציה שלנו, ולכן אני מייצר הגדרה חדשה של קונטיינר שמבוססת על האפליקציה הקודמת ומוסיף לה את התוספת בשורה 3, שימו לב שאני צריך להעתיק את התוכן של התוספת ל-/opt/extensions , זה מיקום הספריה שסביבת הריצה של למדה מצפה למצוא תוספות שונות על מנת להריצן.

לאחר מכן בשורה 5 אני מגדיר על איזה פורט אפליקציית האקספרס שלי מאזינה, זכרו מצד אחד התוספת מאזינה לארועי הטרגה של למדה ומצד שנה היא מבצעת קריאת http מול השרת המקומי.

כחלק מתהליך של health check, התוספת מבצעת קריאה לכתובת שמצוינת בשורה 6, במידה וחוזרת תשובה שאינה מסמנת שגיאה אז הלמדה עולה בהצלחה, אחרת, התוספת תכשיל את הקריאה.

Non-Http

לרוב אתם תחברו את הלמדה שבה אתם משתמשים ב-LWA לשירות מבוסס http כגון API Gateway, AWS ALB או Lambda URL, מכיוון שהקוד שרץ בלמדה הוא שרת מבוסס http שאתם מעבירים לענן. אבל LWA תומך גם ביכולת לבצע אינטגרציה עם שירותים נוספים, למעשה עם כל השירותים שלמדה תומכת בהם.

כל אינטגרציה עם למדה שאינה מבוססת http, תבצע קריאה לכתובת /events כשהבקשה שלכם תכיל את פרטי ה-event של השירות שהטריג את הלמדה.

לדוגמא -

1app.post('/events', (req, res) => {
2 console.log(`Received event: ${JSON.stringify(req.body)}`)
3
4 // printout the message Id and body
5 req.body.Records.forEach((record) => {
6 console.log(`processing message: ${record.messageId} with body: ${record.body}`)
7 })
8
9 // send a 200 response with json string 'success'
10 res.json('success')
11})

ניתן לראות כאן שירות express שמאזין להודעות שמגיעות מ-SQS, מרשים. היתרון המרכזי של צורת עבודה כזאת היא היכרות עם הטכנולוגיה, במידה ואתם יודעים כיצד לעבוד עם express ויש ברשותכם אפליקציה קיימת ואתם מעוניינים להרחיב אותה עם שירותים נוספים, ״יותר מודרניים״ של הענן, צורת העבודה הזאת תאפשר לכם לעשות זאת בקלות. לא הייתי ממליץ על הדרך הזאת במידה ואתם כותבים אפליקציה מאפס.

דמו

ניתן למצוא את הדמו כאן, בניגוד לפעמים הקודמות, לא ניתן להשתמש ישירות בקישור ל-Cloudformation, אלא תצטרכו לשכפל את הקוד ולהריץ AWS SAM מקומית.

  1. וודאו שמכונת הפיתוח שלכם מוכנה.

  2. צרו את הקונטיינר של האפליקציה המקורית. זכרו הקונטיינר של הלמדה מבוסס על האפליקציה המקורית.

  3. לאחר מכן הריצו sam build ואז sam deploy —guided.

  4. בסיום הריצה תודפס הכתובת של השירות החדש.

CloudFormation outputs from deployed stack
-------------------------------------------------------------------------------------------------------------------------------
Outputs
-------------------------------------------------------------------------------------------------------------------------------
Key GetLambdasLWAFunctionUrl
Description Lambda Function URL
Value https://xxxx.lambda-url.us-east-1.on.aws/
-------------------------------------------------------------------------------------------------------------------------------

מדוע להשתמש ב-LWA

זו שאלה מאוד חשובה, מה היתרון של שימוש ב-LWA על מנת להעביר את אפליקציית קונטיינרים, למה לא להשתמש ב-AppRunner או כפי שנראה בהמשך ב-ECS? מספר יתרונות:

  1. עלויות - בתחילת הדרך, כשהשירות שלכם עדין לא נפוץ, למדה כנראה תהייה זולה יותר, מכיוון שהיא לא עולה שקל אחד במידה ולא משתמשים בשירות שלכם.

  2. אינטגרציה קלה עם השירותים השונים של AWS, כפי שראינו LWA תומך ב-Non Http ולכן ניתן להשתמש בשירותים נוספים עם הטכנולוגיה שאתם מכירים ואוהבים.

  3. היתרונות המוכרים של למדות כגון סקיילינג אוטומטי, פתרון observability מובנה.

מה שיפה בצורה שפתרונות שהוצג בפוסט הנוכחי, בפוסט הקודם ובפוסט הבא על ECS, שניתן די בקלות להחליף בין הפתרונות, לא נדרשים שינויי קוד באפליקציה המקורית, רק בעטיפה שלה. כך שניתן להתחיל עם LWA על מנת לחסוך בעלויות, לאחר מכן לעבור ל-AppRunner, במידה ונושא ה-Cold Start הוא כואב ורק בסיום לעבור לפתרון המורכב יותר שהוא ECS.

סיכום

הפוסט מציג את השימוש בלמדה עם קונטיינרים כפתרון להעברת אפליקציות מבוססות קונטיינרים לענן AWS. הוא מתמקד בשימוש ב-Lambda Web Adapter (LWA), שמאפשר להריץ אפליקציות ווב מלאות (כמו אפליקציות Express) כפונקציות למדה ללא צורך בשינוי קוד. הפוסט מסביר את יתרונות האריזה באמצעות קונטיינרים, מדגים כיצד להגדיר קונטיינר ב-AWS SAM, ומפרט את יכולות ה-LWA לתמוך גם באירועים שאינם HTTP. היתרונות העיקריים של הפתרון כוללים חיסכון בעלויות (תשלום רק עבור שימוש בפועל), אינטגרציה קלה עם שירותי AWS, וסקיילינג אוטומטי, עם אפשרות לעבור בקלות לפתרונות אחרים כמו AppRunner או ECS בהמשך.

ביבליאוגרפיה

  1. שימוש בקונטיינרים להגדרת למדה

  2. גודל חבילת הקוד המקסימלית בשימוש בקונטיינר

  3. הגדרות הקונטיינר ב-AWS SAM

  4. AWS Lambda Extensions intro

  5. דוגמא לשימוש ב-no http

ניוזלטר

תגובות