קטגוריה: שרתים

צעדים ראשונים ב wireguard

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

כלומר נגיד ואני רוצה לגשת ל 10.0.0.12 ב HTTP כאשר אני נמצא באינטרנט, והשרת נמצא מאחורי 10.0.0.12, אין לי סיכוי ללא יכולת לעשות Port forwarding, הנגשת השרת כלפי חוץ או reverse proxy כלשהו.

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

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

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

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

הרעיון של Wireguard הוא שכל חיבור בין אם "שרת" ובין אם "לקוח" הוא בעצם Peer.
כאשר אני רוצה לתהחבר ל"שרת", אני אשים את הכתובת להתחבר אליו, ובמידה ואני רוצה למצוא שכנים אני אגדיר אותם במפורש בקובץ ההגדרות עבור אותו Peer.

ברגע שהבנתי את העיקרון הזה, ולי לקח זמן להבין את הרעיון הזה, למעשה הבנתי לגמרי כיצד Wireguard מוגדר ועובד.

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

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

אחד הדברים המדהימים באמת של Wireguard זו הפשטות ליצור תעודות הצפנה.
פקודה קטנה ליצור מפתח פרטי ופקודה נוספת לקחת את המפתח הזה וליצור מפתח ציבורי.
בקובץ של המכשיר שמים את המפתח הפרטי, ובהגדרות של כל מי שצריך לדבר איתו שמים את המפתח הציבורי.
המפתחות שמורים כשורת base64 ואין התעסקות עם המון כלים כדוגמת easy-rsa של openvpn, ואין צורך להתעסק עם openssl.
קובץ ההגדרות יראה בצורה הזו ב"לקוח":

[Interface]
PrivateKey = 
Address = 10.1.0.2/24

[Peer]
PublicKey = 
PersistentKeepalive = 20
Endpoint = address:port
AllowedIPs = 0.0.0.0/0, ::/0

[Peer]
PublicKey = 
AllowedIPs = 10.1.0.3/32

[Peer]
PublicKey = 
AllowedIPs = 10.1.0.2/32

 

היצירה של ה QR התבצעה על ידי באמצעות לינוקס עם הפקודה qrencode בצורה הזו:

qrencode -t PNG -o qr_conf_for_phone.png --verbose < wg_conf_for_phone.conf

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

בשורה התחתונה, אני מאוד מרוצה מה vpn שלא רק קל להגדרה אלא נראה יציב יותר.

אופטימיזצית פרוייקט בזמן קורונה

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

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

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

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

התחלתי למדוד מה המקומות שלוקחים הכי הרבה זמן וגיליתי כי משהו שהוא מחוץ לשליטתי הוא הגורם לכך.

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

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

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

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

יצרתי סוג של טיימר הסופר עד כמות מסויימת של מילי שניות ובמידה והגיע אותו timeout לפני שהתוצר הסתיים, הייתי מדווח שגיאה חזרה.
במידה והסתיים, המידע המתאים נשלח כי הוא התקבל חזרה, ובטיימר לא היה באמת sleep כלשהו אלא תפיסה של "אירועים" על ידי שיחרור מיוטקסים או לחכות לmutex מסוים להשתחרר. הידע מתי לשחרר אותו התבצע על ידי שמירת ה payload שמגיע בstreaming pipe עד אשר תו מסויים מגיע, או אורך מסוים הגיע (הראשון מבניהם). במידה ועד שזה מתבצע הגיע הזמן לשחרר, אז mutex אחר שספר ticks פעל כאשר הבדיקה היתה על אחד משניהם.

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

לאחר השינוי הזה, המערכת התחילה לחזור אלי לרוב אחרי 10-200 מילי שניות, כאשר 500 מילי שניות היו לתוכן גדול בהרבה ממה שאותו משרד ממשלתי שולח אלי.

גרמתי למערכת לרדת לפעמים לפחות מ10 מילי שניות כאשר מקודם לכן הממוצע הנמוך עמד על 500 מילי שניות והגבוה על 700 מילי שניות.

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

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

סינטרה מודולרית

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

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

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

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

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

אנחנו משתמשים בRack בעצם, היות וכמעט וכל הframeworks עבור בניית מערכות web ברובי משתמשים בו, אנו זקוקים לקובץ קבוע בשם config.ru.

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

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

לאחר טעינת התלויות, אני טוען קובץ בודד בשם app.rb שהוא בעצם מה שמנהל את האפליקציה שלי. אך במקום להשתמש ב require "רגיל", אני משתמש בפונקציה בשם require_relative, אשר מאפשרת לטעון דברים מהמיקום הנוכחי של הקובץ המנסה לטעון אותה.

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

למערכת שיצרתי ישנם שני מצבים – מערכת לדיבוג REST, ומערכת "בדיקות" אשר עליה אפשר לבדוק שדברים עובדים, והיא בעיקר על תקן "echo" כלשהו.

את המערכת של יצירת המסכים, ושליחת ה REST, יצרתי בקובץ rest.rb, והכל מאוגד שם.
יש שם משהו שהולך לעבור למקום אחר בקרוב, וזה מספר מתודות לסיוע בפעולות.

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

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

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

במקרה הזה, הגדרתי כי במצב של ‎:development משתמשים ב Sinatra::Reloader, אשר מגיע עם Sinatra-Contrib – תת פרוייקט המספק הרבה כלי עזר לדברים שונים.
הסיבה לשימוש ב Reloader הוא לא לאתחל את השרת בכל שינוי שעושים למחלקה של סינטרה, כאשר Reloader מגלה כי התוכן של הקובץ השתנה, הוא גורם ל rack לטעון אותו שוב, וככה אנחנו לא זקוקים לטעינה מחודשת של השרת עצמו.

המערכת שכתבתי, משתמשת ב template בשם haml, למעשה פעם ראשונה אשר אני משתמש בה מרצון. תוכלו למצוא את ה layout.haml שהוא המסגרת הרגילה וכן כרגע קובץ בשם index.haml תחת ספריית view.
ועבור העיצוב, אני משתמש ב Foundation 5, אשר אני אוהב אותה יותר מאשר bootstrap.
עבור Javascript יש גם את jQuery וגם את knockout.js, כאשר אני נעזר גם ב lodash.js למספר דברים פשוטים, והיא מספקת בעצם גרסה שעברה אופטימיזציה ל underscore.

את הקבצים של Foundation, וכל ה Javascript ניתן למצוא תחת public.

דבר אחרון שנשאר לספר עליו הוא שאני משתמש במשהו אשר נקרא puma.
מה זה ?
puma הוא משהו שלוקח את rack וגורם לו להיות שרת לכל דבר ועניין, אשר ניתן לבצע עליו חיבור לשרתי HTTP שונים, כדוגמץ apache או nginx.
החיבור נעשה על ידי הגדרת proxy בשרתים.

ההגדרות של puma, נמצאות תחת config, וכפי שניתן לראות את הקובץ הראשי והחשוב, הוא גם יודע לבנות לעצמו מבנה ספריות במידה והן לא קיימות, דבר שהוספתי לקוד עצמו. הוא כרגע מכוון למצב של development, ולכן יש לשנות קצת הגדרות בשביל שזה יעבור למצב production.

אתם מוזמנים לבצע fork, לשחק עם הקוד וגם להחזיק לי תיקונים ותוספות.

מזלגות נעוצים

בתקופה האחרונה, נעשו מספר פעולות fork לפרויקטים מוכרים, בהם node.js ודביאן.
בנוסף, פרויקט docker מקבל מתחרה, לאחר שחברת CoreOS הודיעה כי לא מקובל עליה הכיון של docker.

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

אתחיל בדביאן
יש המון טינה על systemd, ובעקבות כל הנושא, עם כל הזעם, הוחלט ליצור fork בשם devuan, אשר ימשיך לספק יכולות של sysv init במקום systemd ה"נורא".

החשיבה כאילו systemd גוזל משהו, בכך שהוא בא לסדר בלאגן ובעיות שיש במערכת הקיימת כיום, מקבלת תירוצים של "נוצרת תלות במערכת", והתשובה שלי היא: "כי עד עכשיו התלות ב sysv לא היתה קיימת ?"

המאבקים המפגרים האלו, האם להשתמש בsystemd או לא, פוגעים בלינוקס, ולא האם systemd טוב או לא.

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

הרעיון הוא לא להיות תלוי בהחלטות של חברה מסחרית בפרויקט, ובכך להשאיר אותו פתוח בתפיסה, אם כי זה לא אומר שהתפיסה של המפתחים תהיה מוסכמת על שאר השוק …

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

Rocket
במידה ולא שמעתם על docker, אתם כנראה ישנים איפשהו, או שרחוקים מעולם ה IT. זה השם החם ביותר מאז שסייבר ומחשוב ענן נכנס לעולם, או אולי זה היה 42 ?

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

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

החברה של CoreOS, רוצים container ומשהו שזו כל ההתמחות שלו, אבל docker מתחיל להיות stack שלם של דברים, והם ממש לא אוהבים את זה, כי בסופו של דבר,זו סוג של תחרות, לא ?

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

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