שילוב מספר מיכלים

27/04/2019

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

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

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

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

ב Docker מיכל שאמור לרוץ בסביבת ייצור כחלק ממערכת גדולה יותר נקרא Service. כמו שהקובץ Dockerfile הגדיר מה יש לנו בתוך מיכל, כך יש קובץ מקביל בשם docker-compose.yml שאחראי על הגדרת הסרביסים במערכת. לכל סרביס נרצה להגדיר על איזה מכונות מותר לו לרוץ, מהם מיפויי הפורטים שלו ואילוצים שונים של הסרביס (למשל שסרביס מסוים חייב לרוץ על מכונה מסוימת, או לא יכול לתפוס יותר מכמות מסוימת של זיכרון).

1. בואו נבנה קובץ docker-compose לדוגמא

הקלידו את התוכן הבא לקובץ docker-compose.yml. זה לא משנה באיזה תיקיה תשמרו אותו:

version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: ynonp/get-started:part2
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "4000:80"
    networks:
      - webnet

  redis:
    image: redis
    ports:
      - "6379:6379"
    volumes:
      - "/Users/ynonperek/tmp/data:/data"
    command: redis-server --appendonly yes
    deploy:
      replicas: 1
    networks:
      - webnet

networks:
  webnet:

שימו לב לשנות את התיקיה /Users/ynonperek/tmp/data לאיזושהי תיקיה ריקה על המחשב שלכם.

נראה מה כתבנו כאן:

  1. הקובץ מתחיל בציון מספר גירסא - לתחביר הקובץ docker-compose היו מספר גלגולים והגירסא העדכנית היא מספר 3.

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

  3. אנחנו מגדירים image שהסרביס יריץ במפתח image.

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

  5. אני מגדיר מיפוי פורטים לאותו סרביס כך שפורט 80 של כל אחד מהמיכלים יופיע ברשת החיצונית בפורט 4000.

  6. אני מגדיר שהמיכלים ישתמשו בהגדרות רשת שנקראת webnet. הגדרה זאת שמופיעה ללא פרטים אומרת שכל המיכלים ישבו מאחורי Load Balancer.

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

  8. אחרי סיום הגדרת הסרביסים אני יכול לבנות הגדרות ספציפיות ל Load Balancer. בינתיים אני משאיר את זה ריק.

2. הפעלת שני הסרביסים שבנינו

אנחנו כמעט מוכנים להפעיל את הסרביסים שלנו. בשביל להפעיל מיכלים מתואמים אנחנו צריכים להשתמש במנגנון נוסף של דוקר שנקרא Docker Swarm. אפשר לחשוב על מנגנון זה כמו מערכת לניהול Service-ים. ה Swarm לוקח את הקובץ docker-compose.yml, מייצר ממנו את כל הסרביסים המתאימים ומחלק את הסרביסים למכונות השונות ברשת.

אני עובד כרגע רק עם מכונת הפיתוח שלי, כלומר מכונה יחידה ברשת, ולכן אסתפק בפקודה הבאה כדי לאתחל את ה swarm עם מכונה בודדת (ובפוסטים הבאים בסידרה נוכל לדבר על הרחבה של המנגנון ושילוב מכונות נוספות):

$ docker swarm init

Swarm initialized: current node (mllwpdgsr5fk7ah037z7hstk4) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-0a7rsj9ryuj40n7csof11097lzdz8okj0m724bdisqvdo52aje-9iypcjhadd3d2ifsglu6oxle7 192.168.65.3:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

עכשיו שיש לנו מכונה נוכל להריץ את docker-compose על המכונה עם:

$ docker stack deploy -c docker-compose.yml helloworld
Creating network helloworld_webnet
Creating service helloworld_redis
Creating service helloworld_web

השם helloworld הוא בחירה שלי. עכשיו בואו נראה את הסרביסים שלנו בפעולה:

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                     PORTS
gjzmfimb4srr        helloworld_redis    replicated          1/1                 redis:latest              *:6379->6379/tcp
o8vqg6pejono        helloworld_web      replicated          3/3                 ynonp/get-started:part2   *:4000->80/tcp

ובשביל לראות את פרטי המיכלים עצמם נוכל להפעיל:

$ docker container ls
ID                  NAME                MODE                REPLICAS            IMAGE                     PORTS
gjzmfimb4srr        helloworld_redis    replicated          1/1                 redis:latest              *:6379->6379/tcp
o8vqg6pejono        helloworld_web      replicated          3/3                 ynonp/get-started:part2   *:4000->80/tcp
localhost:docker ynonperek$ docker container ls
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS               NAMES
3b1de797b0dd        ynonp/get-started:part2   "python app.py"          25 seconds ago      Up 22 seconds       80/tcp              helloworld_web.1.n5bnb9apc4bq7nco7hmk8me1d
8871f5dbd186        ynonp/get-started:part2   "python app.py"          25 seconds ago      Up 22 seconds       80/tcp              helloworld_web.2.6xglx5gixsthryfz72bon70iq
59012179c4fa        ynonp/get-started:part2   "python app.py"          25 seconds ago      Up 22 seconds       80/tcp              helloworld_web.3.fzjrphh7fdwx15pl8vzqmpzng
ec546297bbf5        redis:latest              "docker-entrypoint.s…"   28 seconds ago      Up 27 seconds       6379/tcp            helloworld_redis.1.7kqywtqr5jyrydbvjfo3c5sny

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

3. הוספת משאבים

ומה אם רוצים להוסיף עוד שני קונטיינרים שיריצו את הפייתון שלנו? אין בעיה. פשוט מעדכנים את הקובץ docker-compose.yml ומפעילים שוב:

docker stack deploy -c docker-compose.yml helloworld

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

בשביל למחוק את האפליקציה שיצרתם תוכלו להשתמש בפקודה:

$ docker stack rm helloworld

ובשביל לבטל את כל ה Swarm תוכלו להפעיל:

$ docker swarm leave --force

הדוגמא כאן בפוסט מבוססת על המדריך של דוקר בקישור הזה:

https://docs.docker.com/get-started/part3/