מבוא למודל יישום ללא שרתים של AWS

1. סקירה כללית

במאמר הקודם, כבר יישמנו יישום ללא מחסני שרת בערימות ב- AWS, תוך שימוש ב- API Gateway לנקודות קצה של REST, AWS Lambda לוגיקה עסקית, כמו גם DynamoDB כמאגר נתונים.

עם זאת, הפריסה מורכבת משלבים ידניים רבים, העלולים להסתבך עם מורכבות הולכת וגדלה ועם מספר הסביבות.

במדריך זה נדון כיצד להשתמש ב- מודל יישום ללא שרת AWS (SAM), המאפשר תיאור מבוסס תבנית ופריסה אוטומטית של יישומים ללא שרת ב- AWS.

בפירוט, נבחן את הנושאים הבאים:

  • היסודות של מודל היישומים ללא שרת (SAM), כמו גם של CloudFormation הבסיסית
  • הגדרת יישום ללא שרת, באמצעות תחביר תבנית SAM
  • פריסה אוטומטית של היישום, באמצעות CloudFormation CLI

2. יסודות

כפי שפורט לעיל, AWS מאפשר לנו ליישם יישומים ללא שרת לחלוטין באמצעות API Gateway, פונקציות Lambda ו- DynamoDB. ללא ספק, זה כבר מציע יתרונות רבים לביצועים, עלות ומדרגיות.

עם זאת, החיסרון הוא שאנחנו זקוקים להרבה צעדים ידניים במסוף AWS כרגע, כמו יצירת כל פונקציה, העלאת קוד, יצירת טבלת DynamoDB, יצירת תפקידי IAM, יצירת מבנה API ו- API וכו '.

עבור יישומים מורכבים ועם מספר סביבות כמו בדיקה, בימוי וייצור, המאמץ הזה מתרבה במהירות.

זה המקום בו CloudFormation ליישומים ב- AWS באופן כללי, ו- Modelless Application Model (SAM) במיוחד עבור יישומים ללא שרת, נכנס לתמונה.

2.1. AWS CloudFormation

CloudFormation הוא שירות AWS להקצאה אוטומטית של משאבי תשתית AWS. משתמש מגדיר את כל המשאבים הנדרשים בתוכנית מתכונת (נקראת תבנית), ו- AWS דואג לאספקה ​​ולקביעת התצורה.

המונחים והמושגים הבאים חיוניים להבנת CloudFormation ו- SAM:

תבנית היא תיאור של יישום, איך זה צריך להיות בנוי בזמן הריצה. אנו יכולים להגדיר קבוצה של משאבים נדרשים, כמו גם כיצד מוגדרים משאבים אלה. CloudFormation מספק שפה נפוצה להגדרת תבניות, התומכת ב- JSON ו- YAML כפורמט.

המשאבים הם אבני הבניין ב- CloudFormation. משאב יכול להיות כל דבר, כמו RestApi, Stage of RestApi, Job Batch, טבלת DynamoDB, מופע EC2, ממשק רשת, תפקיד IAM ועוד רבים אחרים. התיעוד הרשמי מפרט כרגע כ -300 סוגי משאבים עבור CloudFormation.

ערימה היא המיידיות של תבנית. CloudFormation דואג לאספקה ​​ולקביעת תצורה של הערימה.

2.2. דגם יישומים ללא שרת (SAM)

כמו לעתים קרובות כל כך, השימוש בכלים רבי עוצמה יכול להיות מורכב מאוד ולא קליל, וזה המקרה גם עבור CloudFormation.

זו הסיבה שאמזון הציגה את מודל היישומים ללא שרת (SAM). SAM התחילה עם הטענה לספק תחביר נקי ופשוט להגדרת יישומים ללא שרת. נכון לעכשיו, יש לו רק שלושה סוגי משאבים, שהם פונקציות Lambda, טבלאות DynamoDB ו- APIs.

SAM מבוסס על התחביר של תבנית CloudFormation, כך שנוכל להגדיר את התבנית שלנו באמצעות התחביר הפשוט של SAM, ו- CloudFormation יעבד עוד את התבנית הזו.

פרטים נוספים זמינים במאגר הרשמי של GitHub וכן בתיעוד AWS.

3. תנאים מוקדמים

להדרכה הבאה נצטרך חשבון AWS. חשבון שכבה בחינם אמור להספיק.

חוץ מזה, עלינו להתקין את ה- AWS CLI.

לבסוף, אנו זקוקים לדלי S3 באזורנו, אשר ניתן ליצור באמצעות AWS CLI עם הפקודה הבאה:

$> aws s3 mb s3: // baeldung-sam-bucket

בזמן שהמדריך משתמש baeldung-sam-bucket בהמשך הדברים, שים לב ששמות הדלי חייבים להיות ייחודיים, לכן עליך לבחור את שמך.

כיישום הדגמה נשתמש בקוד מ- AWS Lambda עם API Gateway.

4. יצירת התבנית

בחלק זה ניצור את תבנית ה- SAM שלנו.

ראשית נבחן את המבנה הכללי, לפני שנגדיר את המשאבים האישיים.

4.1. מבנה התבנית

ראשית, נסתכל על המבנה הכללי של התבנית שלנו:

AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS :: Serverless-2016-10-31' תיאור: Baeldung ללא שרת דוגמה למודל יישום משאבים: PersonTable: סוג: AWS :: Serverless :: מאפייני שולחן פשוט: # הגדר מאפייני טבלה כאן StorePersonFunction: סוג: AWS :: ללא שרת :: מאפייני פונקציה: # הגדר כאן מאפייני פונקציה GetPersonByHTTPParamFunction: סוג: AWS :: ללא שרת :: מאפייני פונקציה: # הגדר כאן מאפייני פונקציה MyApi: סוג: AWS :: ללא שרת :: מאפייני Api: # הגדר כאן מאפייני API

כפי שאנו רואים, התבנית מורכבת מכותרת וגוף:

הכותרת מציינת את הגרסה של תבנית CloudFormation (AWSTemplateFormatVersion) כמו גם הגרסה של תבנית ה- SAM שלנו (שינוי צורה). אנחנו יכולים גם לציין a תיאור.

הגוף מורכב ממכלול משאבים: לכל משאב יש שם, משאב סוּג, וסט של נכסים.

מפרט ה- SAM תומך כיום בשלושה סוגים: AWS :: ללא שרת :: Api, AWS :: ללא שרת :: פונקציה בנוסף ל AWS :: ללא שרת :: SimpleTable.

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

4.2. הגדרת טבלת DynamoDB

בואו נגדיר את טבלת DynamoDB שלנו כעת:

AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS :: Serverless-2016-10-31' תיאור: Baeldung שרת ללא דוגמה למודל יישום משאבים: PersonTable: סוג: AWS :: Serverless :: מאפייני שולחן פשוט: Key Key: שם: id סוג: טבלת מספרים שם: אדם

עלינו להגדיר רק שני מאפיינים עבורנו שולחן פשוט: שם הטבלה וכן מפתח ראשי הנקרא תְעוּדַת זֶהוּת ויש לו את הסוג מספר במקרה שלנו.

רשימה מלאה של נתמכים שולחן פשוט ניתן למצוא נכסים במפרט הרשמי.

הערה: מכיוון שאנחנו רוצים לגשת לטבלה רק באמצעות המקש הראשי, ה- AWS :: ללא שרת :: SimpleTable מספיק לנו. לקבלת דרישות מורכבות יותר, הסוג המקורי של CloudFormation AWS :: DynamoDB :: טבלה ניתן להשתמש במקום.

4.3. הגדרת פונקציות למבדה

לאחר מכן, בואו נגדיר את שתי הפונקציות שלנו:

AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS :: Serverless-2016-10-31' תיאור: Baeldung Serverless דוגמה למודל יישום משאבים: StorePersonFunction: סוג: AWS :: Serverless :: מאפייני פונקציה: מטפל: com.baeldung .lambda.apigateway.APIDemoHandler :: handleRequest זמן ריצה: java8 פסק זמן: 15 MemorySize: 512 CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar מדיניות: DynamoDBCrudPolicy סביבה: משתנים: TABLE_NAME:! StoreApi: סוג: מאפייני Api: נתיב: / אנשים שיטה: PUT RestApiId: Ref: MyApi GetPersonByHTTPParamFunction: סוג: AWS :: ללא שרת :: מאפייני פונקציה: מטפל: com.baeldung.lambda.apigateway.APIDemoHandler :: handleGetByParam זמן ריצה: זמן Javaout : 15 MemorySize: 512 CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar מדיניות: DynamoDBReadPolicy סביבה: משתנים: TABLE_NAME:! Ref PersonTable אירועים: GetByPathApi: סוג: מאפייני Api: נתיב: / אנשים / { id} שיטה: GET RestApiId: Ref: MyApi GetByQueryApi: סוג: Api Propertie s: נתיב: / אנשים שיטה: GET RestApiId: Ref: MyApi

כפי שאנו רואים, לכל פונקציה יש את אותם המאפיינים:

מטפל מגדיר את ההיגיון של הפונקציה. כשאנחנו משתמשים בג'אווה, זה שם המחלקה כולל החבילה, בקשר לשם השיטה.

זמן ריצה מגדיר את אופן הטמעת הפונקציה, שהוא Java 8 במקרה שלנו.

פסק זמן מגדיר כמה זמן ביצוע הקוד עשוי לכל היותר לפני ש- AWS תסיים את הביצוע.

גודל זיכרוןמגדיר את גודל הזיכרון שהוקצה ב- MB. חשוב לדעת כי AWS מקצה משאבי מעבד באופן יחסי גודל זיכרון. כך שבמקרה של פונקציה עתירת מעבד, ייתכן שיידרש להגדיל גודל זיכרון, גם אם הפונקציה לא צריכה כל כך הרבה זיכרון.

CodeUriמגדיר את המיקום של קוד הפונקציה. כעת הוא מתייחס לתיקיית היעד בסביבת העבודה המקומית שלנו. כאשר אנו מעלים את הפונקציה שלנו מאוחר יותר באמצעות CloudFormation, נקבל קובץ מעודכן עם התייחסות לאובייקט S3.

מדיניותיכול להחזיק קבוצה של מדיניות IAM בניהול AWS או תבניות מדיניות ספציפיות ל- SAM. אנו משתמשים במדיניות הספציפית ל- SAM מדיניות DynamoDBCrud בשביל ה StorePersonFunction ו DynamoDBReadPolicy ל GetPersonByPathParamFunction ו GetPersonByQueryParamFunction.

סביבהמגדיר מאפייני סביבה בזמן ריצה. אנו משתמשים במשתנה סביבה להחזקת שם הטבלה DynamoDB שלנו.

אירועיםיכול לקיים קבוצה של אירועי AWS, אשר יוכלו להפעיל את הפונקציה. במקרה שלנו אנו מגדירים מִקרֶה מהסוג Api. השילוב הייחודי של נָתִיב, HTTP שיטה, ו RestApiId מקשר את הפונקציה לשיטה של ​​ה- API שלנו, אותה נגדיר בסעיף הבא.

רשימה מלאה של נתמכים פוּנקצִיָה ניתן למצוא נכסים במפרט הרשמי.

4.4. הגדרת API כקובץ Swagger

לאחר הגדרת הטבלה והפונקציות של DynamoDB, כעת אנו יכולים להגדיר את ה- API.

האפשרות הראשונה היא להגדיר את ה- API שלנו באמצעות פורמט Swagger:

AWSTemplateFormatVersion: '2009-09-09' Transform: 'AWS :: Serverless-2016-10-31' תיאור: Baeldung Serverless דוגמה למודל יישום משאבים: MyApi: סוג: AWS :: Serverless :: מאפייני Api: StageName: test Endpoint תצורה: הגדרה אזורית גוף: swagger: "2.0" מידע: כותרת: "TestAPI" נתיבים: / אנשים: get: פרמטרים: - שם: "id" ב: "שאילתה" נדרש: סוג אמיתי: "מחרוזת" x-amazon-apigateway-request -validator: "אמת פרמטרים של מחרוזת שאילתה ו \ \ כותרות" x-amazon-apigateway-integration: uri: Fn :: Sub: arn: aws: apigateway: $ {AWS :: Region}: lambda: path / 2015-03- 31 / functions / $ {GetPersonByHTTPParamFunction.Arn} / תגובות הפעלות: {} httpMethod: "POST" סוג: "aws_proxy" put: x-amazon-apigateway-integration: uri: Fn :: Sub: arn: aws: apigateway: $ {AWS :: Region}: lambda: path / 2015-03-31 / functions / $ {StorePersonFunction.Arn} / תגובות הפעלות: {} httpMethod: "POST" סוג: "aws_proxy" / persons / {id}: get: פרמטרים: - שם: "id" ב: "נתיב" נדרש: סוג אמיתי: "מחרוזת" תגובות: {} xa mazon-apigateway-integration: uri: Fn :: Sub: arn: aws: apigateway: $ {AWS :: Region}: lambda: path / 2015-03-31 / functions / $ {GetPersonByHTTPParamFunction.Arn} / תגובות הפניות: { } httpMethod: סוג "POST": "aws_proxy" x-amazon-apigateway-request-validators: אמת פרמטרים וכותרות של מחרוזת שאילתה: validateRequestParameters: true validateRequestBody: false

שֶׁלָנוּ Api בעל שלושה מאפיינים: שם במהמגדיר את שלב ה- API, תצורת קצהמגדיר אם ה- API הוא אזורי או מותאם לקצה, וכן הגדרת גוף מכיל את המבנה בפועל של ה- API.

בתוך ה הגדרת גוףאנו מגדירים שלושה פרמטרים: יְהִירוּת גרסה כ “2.0”, ה מידע: כותרת: כפי ש "TestAPI", כמו גם סט של שבילים.

כפי שאנו רואים, שבילים מייצגים את מבנה ה- API, אותו היינו צריכים להגדיר ידנית קודם. ה שבילים ב- Swagger שוות ערך למשאבים במסוף AWS. בדיוק ככה, כל אחד נָתִיב יכולות להיות פעלים מסוג HTTP אחד או יותר, המקבילים לשיטות במסוף AWS.

לכל שיטה יכול להיות פרמטר אחד או יותר וכן מאמת בקשה.

החלק הכי מרגש הוא התכונה x-amazon-apigateway-integration, המהווה סיומת ספציפית ל- AWS ל- Swagger:

אורי מציין איזו פונקציה למבדה תופעל.

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

סוּג מגדיר שאנחנו רוצים להשתמש בשילוב Lambda Proxy, ועל ידי זה עלינו להגדיר httpMethod ל "הודעה", מכיוון שזה מה שמצפים פונקציות למבדה.

רשימה מלאה של נתמכים Api ניתן למצוא נכסים במפרט הרשמי.

4.5. הגדרת API מרומזת

אפשרות שנייה היא להגדיר את ה- API באופן משתמע במשאבי הפונקציה:

AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS :: Serverless-2016-10-31' תיאור: דוגמת מודל יישום ללא שרת Baeldung עם הגדרת ממשק API מרומז: Api: Endpoint תצורה: שם אזורי: "TestAPI" משאבים: StorePersonFunction: סוג: AWS :: ללא שרת :: מאפייני פונקציה: מטפל: com.baeldung.lambda.apigateway.APIDemoHandler :: handleRequest זמן ריצה: java8 פסק זמן: 15 זיכרון גודל: 512 CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT מדיניות .jar: - DynamoDBCrudPolicy: TableName:! Ref PersonTable סביבה: משתנים: TABLE_NAME:! Ref PersonTable אירועים: StoreApi: סוג: מאפייני Api: נתיב: / persons שיטה: PUT GetPersonByHTTPParamFunction: סוג: AWS :: ללא שרת :: מאפייני פונקציה: מטפל: com.baeldung.lambda.apigateway.APIDemoHandler :: handleGetByParam זמן ריצה: java8 זמן קצוב: 15 גודל זיכרון: 512 CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar מדיניות: - DynamoDBReadPolicy: טבלה שם:! Ref סביבת PersonTable: משתנים: TABLE_NAME:! Ref. PersonTable E פתחי אוורור: GetByPathApi: סוג: מאפייני Api: נתיב: / persons / {id} שיטה: GET GetByQueryApi: סוג: מאפייני Api: נתיב: / persons שיטה: GET

כפי שאנו רואים, התבנית שלנו שונה מעט כעת: אין AWS :: ללא שרת :: Api משאב יותר.

עם זאת, CloudFormation לוקח את אירועים תכונות מהסוג Api כהגדרה מרומזת ויוצרת ממילא API. ברגע שנבדוק את היישום שלנו, נראה שהוא מתנהג כמו בהגדרת ה- API במפורש באמצעות Swagger.

חוץ מזה יש גלובאלס קטע, שבו אנו יכולים להגדיר את שם ה- API שלנו, כמו גם שנקודת הסיום שלנו תהיה אזורית.

רק מגבלה אחת מתרחשת: כאשר אנו מגדירים את ה- API באופן מרומז, איננו יכולים להגדיר שם במה. זו הסיבה ש- AWS תיצור במה שנקראת לְדַרבֵּן בכל מקרה.

5. פריסה ובדיקה

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

לשם כך, נעלה את קוד הפונקציה שלנו ל- S3 לפני שנפעיל את הפריסה בפועל.

בסופו של דבר אנו יכולים לבדוק את היישום שלנו באמצעות כל לקוח HTTP.

5.1. העלאת קוד ל- S3

בשלב ראשון עלינו להעלות את קוד הפונקציה ל- S3.

אנו יכולים לעשות זאת על ידי התקשרות ל- CloudFormation דרך AWS CLI:

$> חבילת aws cloudformation --template-file ./sam-templates/template.yml --s3-bucket baeldung-sam-bucket - output-template-file ./sam-templates/packaged-template.yml

עם פקודה זו, אנו מפעילים את CloudFormation לקחת את קוד הפונקציה שצוין ב קוד אורי: ולהעלות אותו ל- S3. CloudFormation תיצור packaged-template.yml קובץ, המכיל את אותו התוכן, למעט זה קוד אורי: מצביע כעת על אובייקט S3.

בואו נסתכל על פלט ה- CLI:

העלאה ל 4b445c195c24d05d8a9eee4cd07f34d0 92702076 / 92702076.0 (100.00%) חפצים ארוזים בהצלחה וכתב תבנית פלט לקובץ packaged-template.yml. בצע את הפקודה הבאה לפריסת התבנית הארוזית aws cloudformation deploy - תבנית-קובץ c: \ zz_workspace \ tutorials \ aws-lambda \ sam-templates \ packaged-template.yml - stack-name 

5.2. פְּרִיסָה

כעת אנו יכולים להפעיל את הפריסה בפועל:

$> aws cloudformation deploy --template-file ./sam-templates/packaged-template.yml - stack-name baeldung-sam-stack --capabilities CAPABILITY_IAM

מכיוון שהערימה שלנו זקוקה גם לתפקידי IAM (כמו תפקידי הפונקציות לגישה לטבלת DynamoDB שלנו), עלינו להכיר במפורש בכך על ידי ציון פרמטר יכולות.

ופלט ה- CLI אמור להיראות כך:

ממתין ליצירת ערכת שינויים .. ממתין ליצירת מחסנית / עדכון להשלמת המחסנית שנוצרה / עודכנה בהצלחה - baeldung-sam-stack

5.3. סקירת פריסה

לאחר הפריסה נוכל לבדוק את התוצאה:

$> aws cloudformation לתאר-stack-resources - stack-name baeldung-sam-stack

CloudFormation יפרט את כל המשאבים שהם חלק מהערימה שלנו.

5.4. מִבְחָן

לבסוף, אנו יכולים לבדוק את היישום שלנו באמצעות כל לקוח HTTP.

בואו נראה דוגמה כלשהי סִלְסוּל פקודות שאנו יכולים להשתמש בהן לבדיקות אלה.

StorePersonFunction:

$> תלתל -X PUT '//0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons' \ -H 'סוג תוכן: יישום / json' \ -d '{"id": 1, "name": "John Doe"} '

GetPersonByPathParamFunction:

$> תלתל -X GET '//0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons/1' \ -H 'סוג תוכן: יישום / json'

GetPersonByQueryParamFunction:

$> curl -X GET '//0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons?id=1' \ -H 'סוג תוכן: יישום / json'

5.5. לנקות

בסופו של דבר נוכל לנקות על ידי הסרת הערימה וכל המשאבים הכלולים:

aws cloudformation delete-stack - stack-name baeldung-sam-stack

6. מסקנה

במאמר זה, הסתכלנו על מודל היישום ללא שרת AWS (SAM) המאפשר תיאור מבוסס תבנית ופריסה אוטומטית של יישומים ללא שרת ב- AWS.

בפירוט דנו בנושאים הבאים:

  • היסודות של מודל היישומים ללא שרת (SAM), כמו גם את CloudFormation הבסיסית
  • הגדרת יישום ללא שרת, באמצעות תחביר תבנית SAM
  • פריסה אוטומטית של היישום, באמצעות CloudFormation CLI

כרגיל, כל הקוד עבור מאמר זה זמין ב- GitHub.