הפעלת nginx בתוך קונטיינר

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

1. מה אפשר ללמוד מדף האימג' ב Docker Hub

דף האימג' של nginx נמצא בקישור: https://hub.docker.com/_/nginx.

הדבר הראשון שאנחנו רואים הוא הכיתוב Docker Official Images שאומר שמדובר באימג' רשמי ולכן יש פחות סיכוי לבעיות אבטחה או בעיות אחרות איתו. ברשימת התגיות אנחנו רואים שהגירסה המרכזית להתקנה נקראת mainline שזו באמת הגירסה היציבה של nginx, ושהאימג' זמין בגירסת דביאן מלאה או בגירסת alpine מצומצמת.

בחלק How to use this image אני יכול למצוא כמה דוגמאות להפעלה של האימג' כדי להגיש תוכן סטטי כלומר קבצי HTML, CSS ו JavaScript. הדוגמה הראשונה המעניינת היא:

$ docker run --name some-nginx -v /some/content:/usr/share/nginx/html:ro -d nginx

והיא מראה לנו ש nginx מגיש את הקבצים מתיקיית /var/share/nginx/html של הקונטיינר. בשביל להגיש קבצים מהמחשב המקומי אני צריך למפות תיקיה שיש בה את הקבצים כדי שתהיה זמינה בתוך הקונטיינר. הסיומת :ro אומרת שהקונטיינר לא יוכל לשנות קבצים אלה, והמתג -d גורם לקונטיינר לא להשתלט על המסוף ומאפשר לי להמשיך להריץ פקודות נוספות. בהמשך השיעור נכתוב בעצמנו דוגמה דוגמה כדי להגיש קובץ HTML שנכתוב לדפדפן.

2. מיפוי פורטים

דוגמא מעניינת נוספת ממחישה את מיפוי הפורטים:

$ docker run -d -p 8080:80 nginx

בתוך הקונטיינר שרת הווב nginx יקשיב על פורט 80. זה נתון, כך עובד האימג'. אם יש לי את כתובת ה IP של הקונטיינר שמריץ nginx, אני אוכל להתחבר לפורט 80 שלו כדי לקבל את עמוד ה HTML.

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

3. מיפוי Volumes

בחלק Complex Configuration אני רואה שאם יש לי קובץ הגדרות nginx.conf שאני רוצה להעביר לקונטיינר אני יכול לעשות את זה באמצעות מיפוי Volumes.

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

$ docker run --name my-custom-nginx-container -v /host/path/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx

השורה מחברת את הקובץ שנמצא על המחשב המקומי שלי בנתיב /host/path/nginx.conf לתוך הקונטיינר ושם נותנת לו את השם /etc/nginx/nginx.conf. בתוך הקונטיינר זה שם שמור ש nginx יודע לחפש שם את קובץ ההגדרות שלו. הסיומת :ro אומרת שהקונטיינר לא יוכל לשנות את הקובץ הזה.

דוגמה נוספת לשימוש במיפוי תהיה למפות תיקיה עם קבצי HTML למקום שהקונטיינר מכיר ואז nginx שבתוך הקונטיינר יוכל לשלוח ממנה את הקבצים. תחילה אכין קובץ index.html שאותו ארצה להגיש עם nginx ובו אכתוב את התוכן הבא:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title></title>
  </head>
  <body>
    <h1>Hello From Docker</h1>
  </body>
</html>

אני שומר את הקובץ בתיקיית html בתוך תיקיית הפרויקט שלי. אצלי הנתיב המלא לקובץ הוא /home/ynonp/work/courses/docker-microservices/demos/06-nginx-container/after/html, אבל אצלכם הוא כמובן יכול להיות אחר. עכשיו אני כותב:

$ docker run -v /home/ynonp/work/courses/docker-microservices/demos/06-nginx-container/after/html:/usr/share/nginx/html:ro -p 8080:80 nginx

כדי להפעיל קונטיינר nginx שיגיש את הקובץ מתוך תיקיית html. טריק פשוט לקצר את השורה הוא להשתמש במשתנה הסביבה PWD שמכיל את הנתיב המלא לתיקיה הנוכחית. אם אני עכשיו בתוך תיקיית html שמכילה את הקובץ index.html שיצרתי אני יכול לכתוב:

$ docker run -v $PWD:/usr/share/nginx/html:ro -p 8080:80 nginx

אחרי הפעלת הקונטיינר אני יכול להיכנס לדפדפן ולגלוש ל localhost:8080 כדי לקבל את דף הפתיחה של nginx.

4. הפעלת פקודות בתוך הקונטיינר

הקונטיינר מתנהג כמו מכונת לינוקס לכל דבר, ולמרות שהוא מריץ פקודה מסוימת (התוכנית nginx), אפשר להריץ עליו פקודות נוספות ואפילו לתקשר איתן. הפקודה הבאה מאפשרת להריץ shell בתוך הקונטיינר כדי לקבל ממשק עבודה אינטרקטיבי שם:

$ docker exec -it 503919e7eacc /bin/bash

אתם תצטרכו להחליף את 503919e7eacc במזהה הקונטיינר שלכם. בתוך הקונטיינר אפשר להציץ על קובץ הקונפיגורציה של nginx:

root@503919e7eacc:/# cat /etc/nginx/nginx.conf 

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;

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

5. סגירה ומחיקה

הפקודה exit יוצאת מהמסוף של הקונטיינר ועכשיו אני יכול לסגור ולמחוק אותו עם:

$ docker rm -f 503919e7eacc

6. תקציר הפקודות שראינו בפרק

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

# Create a new container and run it on the background
$ docker run -d nginx

# List all active containers
$ docker ps

# Stop and delete a container
$ docker rm -f <container_id>

# Execute a shell inside a container
$ docker exec -it <container_id> /bin/bash

# Or if bash is not installed (for example in alpine)
$ docker exec -it <container_id> /bin/sh

# See the logs from a container
$ docker logs <container_id>

כמו כן ראינו איך למפות תיקיה מהמחשב המקומי לתוך הקונטיינר:

$ docker run -v <local_path>:<path_inside_container> ...


קישור לדף האימג' בדוקרהאב: https://hub.docker.com/_/nginx

קובץ ה HTML שכתבתי בוידאו:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Index</title>
  </head>
  <body>
    <h1>Hello From Nginx Container</h1>
    <h2>Welcome to Docker Course</h2>
    <p>I can change the code haha</p>
  </body>
</html>

פקודות מרכזיות שראינו בוידאו:

# Run nginx container as daemon with mapped ports
$ dokcer run -p 8080:80 -v $PWD/html:/usr/share/nginx/html:ro -d nginx:1.21

# See all running containers
$ docker ps

# Close and delete a container
$ docker rm -f containerid