« לעמוד הראשי

היכרות עם HashiCorp Consul

בסרטון הבא Armon Dadgar מציג את HashiCorp Consul וכיצד הוא פותר את האתגרים של גילוי שירות, ניהול תצורה ופילוח רשת ביישומים מבוזרים.


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

HashiCorp Consul הוא כלי קוד פתוח הפותר את המורכבויות החדשות הללו על ידי service discovery, health checks, איזון עומסים (load balancing), service graph, אכיפת זהות TLS הדדית ואחסון key-value. תכונות אלה הופכות את Consul לפתרון אידאלי ל- Service Mesh .

בסרטון זה, המייסד וה- CTO של החברה, Armon Dadgar, נותן סקירה על הנושאים הבאים:

  • מבוא לארכיטקטורה מונוליטית לעומת microservices
  • service discovery במונוליט
  • האתגרים של service discovery במערכת מבוזרת ובפתרון של Consul
  • ניהול תצורה במונוליט
  • אתגרי תצורה במערכת מבוזרת ובפתרון של Consul
  • הפרדת רשתות במונוליט
  • אתגרי הפרדת רשתות במערכת מבוזרת והפתרון של Consul
  • הגדרה של "Service Mesh"

תרגום:

היי. שמי ארמון, והיום רציתי לתת הקדמה ל- Consul .

כאשר אנו בוחנים ארכיטקטורות מסורתיות למסירת יישום, מה שיש לנו הוא סוג של מונוליט קלאסי. כשאנחנו מדברים על המונוליט, מדובר ביישום יחיד שאנו פורסים, אך לרוב יש בו רכיבי משנה מרובים, נפרדים. לדוגמה, נניח שאנו מספקים את יישום הבנקאות השולחנית, ייתכן שיש בו חלקי משנה מרובים כאשר תת מערכת A היא – נניח – הכניסה למערכת. תת מערכת ב 'עשויה להציג את יתרת חשבוננו. C עשוי להיות העברה בנקאית. D עשוי להיות מטבע חוץ. כעת, למרות שמדובר בפונקציות עצמאיות – כניסה לעומת הצגת שיווי המשקל שלנו – אנו מספקים אותה ואורזים את היישום שלנו כאפליקציה יחידה ומונוליטית. אז אנו פורסים אותה כיחידה אחת.

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

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

Service Discovery במונוליט

הראשון, המיידי ביותר, הוא הגילוי. מה שאני מתכוון בזה הוא: נניח ששירות א' רוצה להתקשר לשירות B. הדרך שבה היית עושה זאת באופן מסורתי (באפליקציה מונוליטית) היא שירות ב' יחשוף שיטה, יסמן אותה כציבורית ואז שירות א 'יכול פשוט להתקשר זה. הם נמצאים באותו יישום. זו רק שיחת פונקציה. לכן כאשר A קורא לפונקציה ב- B, זה לוקח ננו שניות. אנחנו מבצעים קפיצה בזיכרון, והכל בתהליך ולכן אנחנו לא דואגים: מה קרה לנתונים שלנו, איך הנתונים הגיעו לשם, האם הצפנו אותם? זו שיחת פונקציה בזיכרון.

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

האתגרים של Service Discovery במערכת מבוזרת

בעיה זו ברמה הראשונה היא מה שאנו מכנים גילוי. כיצד מגלים החלקים השונים הללו זה את זה? ישנן כמה גישות לכך. מבחינה היסטורית, מה שהיינו עושים הוא כנראה לחזות כל אחד משירותים אלה עם איזון עומסים. אז היינו שמים כאן איזון עומסים מול כל שירות ואז נקשה את כתובת ה- IP של איזון העומס בקשיחה קשה. אז A קשה מקודד את ה- IP של איזון העומס, ואז איזון העומס מתמודד עם העובדה שאולי יש מספר מקרים של B. זה מאפשר ל- A לדלג על גילוי על ידי קידוד קשה של כתובת זו, אך היא מציגה כמה בעיות שונות עבור לָנוּ.

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

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

האתגר הנוסף הוא: אנו מוסיפים חביון אמיתי. במקום ש- A ידבר ישירות ל- B, A מדבר עם איזון עומסים שמדבר עם B ואותו הנתיב בדרך חזרה. אז למעשה אנו מכפילים את חביון הרשת הכרוך בכל הופ.

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

פתרון: Registry מרכזי

הדרך בה אנו חושבים על כך בקונסול היא: כיצד נפתור זאת באמצעות מתן רישום שירות חיוני? במקום להשתמש במאזני עומסים, כאשר מקרים אלה מתחילים, הם נרשמים כחלק מהרישום המרכזי, כך שהוא מאוכלס כאן (ברישום). אז אנו יוצרים רישום, וכעת כאשר A רוצה לגלות ולתקשר עם B, הוא שואל את הרישום ואומר: "איפה כל המקרים במעלה הזרם של השירות הזה?" ועכשיו, במקום לעבור על איזון עומסים, שירות A יכול לתקשר ישירות עם מופע של B.

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

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

Configuration Management in a Monolith

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

Configuration Challenges in a Distributed System

עכשיו, כשאנחנו בעולם הזה (האפליקציה מוכוונת השירות), הפצנו בערך את בעיית התצורה שלנו. לכל אחד מהיישומים הללו יש תצוגה מעט שונה של התצורה שלנו. אז עכשיו יש לנו אתגר: איך אנחנו חושבים על תצורה בסביבה המבוזרת שלנו?

פתרון: חנות מרכזית עם ערך מפתח

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

Network segmentation in a monolith

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

  • היה לנו אזור אחד, שהיה האזור הפרוע והמפורז שלנו: תנועה שנכנסת מהאינטרנט הציבורי.
  • אז יש לנו את אזור היישומים שלנו, שקיבל במידה רבה תנועה מ- DMZ דרך קבוצה של מאזני עומסים.
  • אז כנראה היה לנו אזור נתונים מאחורינו או אזור פרטי.

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

Network segmentation challenges in a distributed system

כשאנחנו מסתכלים על העולם הזה (של האפליקציה מוכוונת השירות), דפוס זה השתנה באופן דרמטי. כעת אין עוד יישום מונוליטי אחד באזור שלנו, אלא מאות או אלפי שירותים ייחודיים באזור יישומים זה. האתגר הוא – דפוס התנועה שלהם הרבה יותר מורכב כעת. לשירותיה הרבים זרימת תנועה מורכבת ממזרח-מערב. זה כבר לא ברצף מאיזון עומסים ליישום למסד נתונים. תנועה עשויה להיכנס לאפליקציה הבנקאית למחשבים שולחניים, ליישום הבנקאות הנייד או לממשקי ה- API שלנו – נניח יכולות להיות מספר דלתות כניסה תלויות בדפוס הגישה, ושירותים אלה מתקשרים זה עם זה בתנועה מורכבת מזרח-מערב. אתגר זה ברמה השלישית הופך כעת: כיצד אנו חושבים על פילוח רשת זו? כיצד אנו מחלקים אילו שירותים מורשים לדבר עם אילו שירותים אחרים?

פתרון: Service graph

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

ראשית, אנו מתחילים במה שאנו מכנים גרף שירות. בעזרת גרף השירות אנו מגדירים – ברמת שירות – מי יכול לתקשר. אז אנו עשויים לומר, "" A "מסוגל לדבר עם B." אנו עשויים לומר "מותר ל- C לדבר עם 'ד'. ומה שתבחין בכך שאנחנו לא מדברים על IP ל- IP. אנחנו לא אומרים ש- IP 1 יכול לדבר עם IP 2. אנחנו מדברים על "שירות A יכול לדבר עם שירות B."

הדבר היפה בביטוי בשכבה זו הוא שהכלל אינו תלוי בקנה מידה. הכוונה שלי היא – אם יש לי כלל שאומר שניתן לאפשר לשרת האינטרנט שלי לדבר עם מסד הנתונים שלי, זה יכול לבוא לידי ביטוי בפשטות. אני יכול לומר, "שיחות אינטרנט למסד נתונים." אבל אם אני רוצה לתרגם את זה לכללי חומת האש המקבילים, ובכן, אם יש לי 50 שרתי אינטרנט ויש לי חמישה בסיסי נתונים, זה מתורגם ל -250 כללי חומת אש שונים. אז לזה אני מתכוון. כלל זה אינו תלוי בקנה מידה, לא משנה אם יש לי שרתי אינטרנט אחד, 10, 50 או 1000, זה אותו הכלל. כללי חומת האש הפוכים. הם מאוד תלויי קנה מידה וקשורים ליחידת הניהול שהיא IP. אז בואו ונעלה את הניהול הזה לרמה הגיונית זו שבה אנחנו לא באמת צריכים להיות קשורים לסולם האמיתי.

פתרון: TLS הדדי

החלק הבא בכך הוא כיצד אנו טוענים זהות? זה בא מרשות אישורים, אז כשאנחנו אומרים ששירות א 'יכול לדבר עם שירות ב', איך נדע מהו שירות א' ומהו שירות ב'? הגישה שלקונסול קונקט נוקטת היא לקשור זאת לפרוטוקול מאוד ידוע, TLS. אנו מנפיקים אישורי TLS המזהים שירותים אלה באופן ייחודי. אז אנו יכולים לומר באופן ייחודי "זה שירות A וזה שירות B". שלא כמו לומר," יש IP ואנחנו לא באמת יודעים מה פועל באותה IP עם שום אחריות חזקה. "

כיצד אנו למעשה אוכפים זאת? זה מתורגם למכלול פרוקסי. הדרך שבה אנו מיישמים את בקרת הגישה היא באמצעות פרוקסי הדדי. אז בתיבה אולי יש לנו שירות A ובאותה תיבה, אנחנו מריצים פרוקסי לצידו. זהו סוג של פרוקסי לרכב צדדי. ואז באופן דומה לשירות B, הוא פועל על מכונה משלו או על מיכל משלו, ויש לו גם proxy לרכב צדדי. עכשיו כאשר A רוצה לתקשר עם B זה מדבר בשקיפות עם ה- proxy הזה שמבסס תקשורת בצד השני ל- proxy אחר. צד זה מסיים את הקשר ומעביר אותו לידי ב'.

למעשה יש לכך כמה יתרונות שונים. ראשית, אנו לא משנים את הקוד של A ו- B. שניהם מבריחים לא מודעים לכך שמשהו השתנה. הם פשוט מתקשרים בדרך הרגילה. אנשי הכוח, לעומת זאת, משתמשים ברשויות האישור הללו. אז ה- proxy בצד A ישתמש בתעודה זו כדי לומר, "אני A ואאמת את זהות ה- B ולהיפך." ה- proxy בצד B יאמת שהוא מדבר עם A. אז עכשיו, אנו מקבלים את תחושת הזהות החזקה הזו בין שני הצדדים. וזה נעשה עם TLS הדדי.

היתרון השני של שימוש ב- TLS הדדי הוא כעת אנו מקימים ערוץ מוצפן ביניהם. זה נהיה חשוב יותר ויותר ככל שאנו מדברים על תקנות כמו GDPR. יותר ויותר ההתמקדות שלנו היא לומר, "אתה יודע מה? אנחנו בעצם לא סומכים על הרשת שלנו במרכז הנתונים שלנו. אנחנו לא יכולים רק להניח שמכוח היותנו ברשת, הדברים מהימנים." לכן כחלק מהשינוי הזה אנו רואים יותר ויותר מנדט להצפין את הנתונים שלנו במנוחה – דברים שאנחנו כותבים למאגרי המידע שלנו או כותבים לחנויות האובייקטים שלנו – אך גם נתונים במעבר. אז כאשר נתונים עוברים בין יישום האינטרנט שלנו למסד הנתונים שלנו, האם הוא מוצפן? מכיוון שהוא זורם בין שירותים שונים במרכז הנתונים שלנו, האם אנו מצפינים את התנועה הזו?

האתגר הוא – כנראה שיש לנו מאות או אלפי יישומים רבים שקיימים ואינם מודעים ל- TLS. אז היתרון בהטלתו על שכבת ה- proxy הוא שנוכל לקבל את ההבטחה לכך שהנתונים שלנו יוצפנו במעבר מבלי שנצטרך ליישם מחדש את כל היישומים הללו.

החלק השלישי של זה הוא – רק מכיוון ש- A יכול להוכיח שהוא מדבר עם B, ו- B יכול להוכיח שהוא מדבר עם A, זה לא מספיק מכיוון שלא ברור שאפשר אפילו לאפשר ל- A לדבר עם B. כאן המקום שמגיע גרף השירות פנימה ה- proxy נקרא חזרה לגרף השירות ומחפש קשת כזו – האם יש כלל המאפשר לשירות A לדבר עם שירות 'B?' אם כן, אז הפרוקסים מאפשרים לתנועה להתקיים, א 'רשאי לדבר ישירות עם ב', והם לא חכמים יותר שפרוקסי ביניים אלה מתקיימים.

Consul and the Service Mesh

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

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

אני מקווה שזה היה מבוא מועיל ל- Consul. יש הרבה יותר פרטים באתר שלנו. תודה!

 

חברת ALM-Toolbox מייצגת בישראל את חברת HashiCorp וחברות נוספות המציעות פתרונות ליישום microservices (כגון GitLab, Sysdig, Azul ועוד). לפרטים נוספים: hashicorp@almtoolbox.com או טלפונית 072-240-5222