انتقال للمقال
وقت القراءة: ≈ 20 دقيقة (بمعدل فنجان واحد من القهوة 😊)

تشغيل Nginx داخل Docker

السلام عليكم ورحمة الله وبركاته


المقدمة

في المقالة السابقة تعرفنا على أساسيات التعامل مع الـ Docker
وتعلمنا كيفية تحميل الـ Images وإنشاء الـ Containers والتعامل معها
استخدمنا Alpine Linux كمثال بسيط للتعرف على الأوامر الأساسية

في هذه المقالة سنشرح على مثال عملي باستخدام Nginx
بمعنى أننا سنقوم بتشغيل Nginx داخل Docker Container
ونتعرف أمور جديدة متعلقة بالتعامل مع الـ Containers
وسنتعرف على مفهوم الـ Port Mapping الذي يسمح لنا بربط port من جهازنا بـ port داخل الـ Container

ما هو الـ Nginx ؟

عندما تدخل إلى الموقع الرسمي لـ Nginx ستجده يصف نفسه كالتالي:

nginx ("engine x") is an HTTP web server, reverse proxy, content cache, load balancer, TCP/UDP proxy server, and mail proxy server.

بالتالي نفهم أن الـ Nginx هو Server يمكنك من خلاله القيام بأمور كثيرة
يمكنك أن تستخدمه كـ Web Server ليستضيف Static Files مثل HTML و CSS و JavaScript عليه
أو يمكنك استخدامه كـ Load Balancer لتوزيع الحمل على أكثر من Server
أو كـ Content Cache بمعنى أنه Server وسيط يقوم بتخزين نسخ من المحتوى لتسريعه
أو كـ Reverse Proxy الذي يستقبل الطلبات ويوجهها إلى الـ Server
والعديد من الأمور الأخرى التي يمكنه القيام بها

وبسبب مميزاته ستجده يستخدم على نطاق واسع في استضافة المواقع والتطبيقات على الإنترنت
ونحن هنا سنقوم بتشغيل Nginx داخل Docker Container ليعمل كـ Web Server بسيط

تحميل الـ Nginx Image

أول خطوة هي تحميل الـ Image الخاصة بـ Nginx من الـ Docker Hub

> docker image pull nginx:latest
latest: Pulling from library/nginx
eaf8753feae0: Pull complete
10b68cfefee1: Pull complete
57f0dd1befe2: Pull complete
500799c30424: Pull complete
119d43eec815: Pull complete
700146c8ad64: Pull complete
d989100b8a84: Pull complete
Digest: sha256:c881927c4077710ac4b1da63b83aa163937fb47457950c267d92f7e4dedf4aec
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

لنتحقق من أن الـ Image تم تحميلها بنجاح:

> docker image list
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    c881927c4077   8 days ago    237MB
alpine       latest    865b95f46d98   4 weeks ago   13MB

الآن لدينا الـ Image الخاصة بـ Nginx على جهازنا وجاهزة للاستخدام
ولاحظ أن حجم الـ Image أكبر بكثير من حجم Alpine Linux الذي استخدمناه في المقالة السابقة
هذا لأن Nginx يحتوي على العديد من الملفات والأمور التي يحتاجها ليعمل

docker image inspect

يمكننا استخدام الأمر docker image inspect لعرض تفاصيل الـ Image الخاصة بـ Nginx

> docker image inspect nginx:latest
[
    {
        "Id": "sha256:c881927c4077710ac4b1da63b83aa163937fb47457950c267d92f7e4dedf4aec",
        "RepoTags": [
            "nginx:latest"
        ],
        ...
        "Config": {
          ...
            "ExposedPorts": {
                "80/tcp": {}
            },
            ...
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.29.5",
                "NJS_VERSION=0.9.5",
                "NJS_RELEASE=1~trixie",
                "ACME_VERSION=0.3.1",
                "PKG_RELEASE=1~trixie",
                "DYNPKG_RELEASE=1~trixie"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            ...
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            ...
        },
        ...
    }
]

سنحصل على العديد من التفاصيل عن الـ Image الخاصة بـ Nginx
بالطبع لم أعرض كل التفاصيل هنا، فقط عرضت بعض الأجزاء المهمة منها
والباقي استبدلته بـ ... وستجدني أقوم بذلك في كل مرة أريد أن أتجاهل جزء معين من التفاصيل

ستلاحظ تفاصيل مهمة مثل ExposedPorts التي تخبرنا أن الـ Nginx يعمل على port رقم 80 داخل الـ Container
وتعرف ما هى الـ Environment Variables الخاصة به

وما هو الأمر الافتراضي الذي يتم تنفيذه عند تشغيل Container منه وهو nginx -g 'daemon off;'
هل تتذكر حين قلنا أن كل Image لها أمر افتراضي يتم تنفيذه عند تشغيل Container منها ؟
هذا هو الأمر الافتراضي الخاص بـ Nginx الذي يتم تنفيذه عند تشغيل Container منه

وأيضًا الـ Entrypoint الخاص به هو /docker-entrypoint.sh الذي يتم تنفيذه قبل الأمر الافتراضي
وسنشرح الفرق بين الـ Entrypoint والـ Cmd في المقالات القادمة عندما نتحدث عن الـ Dockerfile وبناء الـ Images الخاصة بنا
كل ما يمكنني قوله أن الـ Entrypoint هو أمر يتم تنفيذه أولًا عند تشغيل الـ Container ثم بعد ذلك يتم تنفيذ الأمر الافتراضي المحدد في الـ Cmd
على أي حال ما يهمنا الآن هو أن نعرف أن الـ Nginx عند تشغيله داخل الـ Container يقوم بتنفيذ ملف /docker-entrypoint.sh أولًا ثم ينفذ الأمر الافتراضي nginx -g 'daemon off;'

تشغيل الـ Nginx Container

الآن دعنا نجرب تشغيل Container من هذه الـ Nginx Image:

> docker container run --name nginx-container nginx:latest
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
...
2026/01/21 16:07:23 [notice] 1#1: start worker process 30
2026/01/21 16:07:23 [notice] 1#1: start worker process 31
2026/01/21 16:07:23 [notice] 1#1: start worker process 32

هنا قمنا بإنشاء Container جديد من الـ Image الخاصة بـ Nginx وسميناه nginx-container
أول شيء ستلاحظه هو أن الـ Terminal أصبح مشغولًا بعرض الـ Logs الخاصة بـ Nginx

على أي حال، نلاحظ أن الـ Container لم ينتهي فورًا كما حدث مع Alpine Linux
بل هو مستمر في العمل ويطبع الـ Logs باستمرار

وقلنا أننا عندما ننشيء Container من أي Image فهو يقوم بتنفيذ الأمر الافتراضي المحدد في الـ Image
في حالة الـ Alpine Linux كان الأمر الافتراضي هو /bin/sh الذي ينتهي فورًا بعد تنفيذه لأننا لم نحدد -it
أما في حالة Nginx فكما عرفنا فهو يقوم بتنفيذ ملف /docker-entrypoint.sh أولًا ثم الأمر الافتراضي nginx -g 'daemon off;'
وهذا الملف هو الذي يقوم بتشغيل Nginx داخل الـ Container
وستلاحظ في الـ Logs وجود الملف /docker-entrypoint.sh في بداية الـ Logs والأمور التي يقوم بها وينفذها
وإذا أكمل قراءة الـ Logs ستجد في النهاية أنه قام بتشغيل Nginx وبدأ في طباعة الـ Logs الخاصة به

على أي حال، الآن بما أن الـ Container يعمل في الـ Terminal الحالية فلا يمكنك كتابة أوامر أخرى فيه
وهذا لأنه يعمل في الـ Foreground أي في الواجهة الحالية للـ Terminal
لذا دعنا نفتح نافذة Terminal جديدة لنتمكن من كتابة أوامر أخرى
ونبقى في النافذة الأولى كما هى

في النافذة الجديدة اكتب الأمر التالي للتحقق من أن الـ Container يعمل:

> docker container list --all
CONTAINER ID   IMAGE           COMMAND                  CREATED         STATUS                    PORTS     NAMES
60a264c4daa9   nginx:latest    "/docker-entrypoint.…"   7 minutes ago   Up 7 minutes              80/tcp    nginx-container
16704b093612   alpine:latest   "/bin/sh"                41 hours ago    Exited (0) 39 hours ago             my-alpine-container

نلاحظ أن الـ Container الخاص بـ Nginx يعمل وحالته Up 7 minutes أي أنه يعمل منذ 7 دقائق منذ إنشائه
وبما أننا استخدمنا الأمر --all فإنه يعرض لنا كل الـ Containers حتى التي توقفت والتى كانت من المقالة السابقة وهى Alpine Linux
لكن تركيزنا سيكون على الـ Container الخاص بـ Nginx

ستلاحظ في العمود COMMAND أن الأمر الذي تم تنفيذه داخل الـ Container سترى انه مكتوب بهذا الشكل "/docker-entrypoint.…" لأن الـ docker يقوم باختصار كافة القيم في كل الأعمدة لجعل العرض أكثر وضوحًا
لكن بالطبع يمكننا رؤية القيم كاملة عن طريق وضع --no-trunc مع الأمر docker container list

وحين نفعل هذا الأمر ستجد أن الأمر الذي تم تنفيذه داخل الـ Container هو "/docker-entrypoint.sh nginx -g 'daemon off;'"
وهو الـ Entrypoint الخاص بـ Nginx متبوعًا بالأمر الافتراضي الخاص به

على أي حال، ستلاحظ أن الـ PORTS الخاصة بالـ Container تظهر كـ 80/tcp فقط، وهذا يعني أن الـ Nginx يعمل على الـ port رقم 80 داخل الـ Container
أنتبه إلى أن هذا الـ port رقم 80 هو داخل الـ Container وليس على جهازك
بمعنى أنه لا يعمل على الـ port رقم 80 الخاص بجهازك، بل يعمل على الـ port رقم 80 داخل الـ Container فقط
لأن كل Container يعمل في بيئة معزولة عن جهازك، كما قلنا ولها الـ networking الخاص بها

لذا فنحن لا يمكننا الوصول إلى هذا الـ port من خارج الـ Container حتى الآن
ولا نعرف كيف نقوم بإرسال أي Request داخل هذا الـ Container

ربط الـ Nginx بـ Port على جهازك

عندما يعمل Nginx داخل الـ Container فإنه يعمل على port رقم 80 داخل الـ Container
لكن مشكلتنا أن هذا الـ port معزول داخل الـ Container ولا يمكن الوصول إليه من خارج الـ Container

هنا الـ docker يوفر لنا ميزة مهمة جدًا وهي الـ Port Mapping أو Port Forwarding
وهى أنه في حالة أن الـ Image التي تستخدمها تعمل على port معين داخل الـ Container
يمكنك ربط هذا الـ port الداخلي بـ port على جهازك بحيث يمكنك الوصول إليه من خارج الـ Container

كأنك تقول للـ Docker أي Request يأتي على هذا الـ port على جهازي قم بتوجيهه إلى هذا الـ port داخل الـ Container
هذا يسمح لنا بالوصول للتطبيقات داخل الـ Container من المتصفح أو من أي تطبيق آخر

لكن ليس كل Images تدعم الـ Port فعلى سبيل المثال Alpine Linux لا يعمل على أي port لأنه مجرد نظام تشغيل بسيط
أما Nginx فهو Server يعمل على port رقم 80 داخل الـ Container
وهناك العديد من الـ Images الأخرى التي تعمل على Ports محددة مثل MySQL و PostgreSQL و Redis وغيرها


لعمل Port Mapping نستخدم flag يدعى -p أو --publish عند تشغيل الـ Container

> docker container run -p <host-port>:<container-port> <image-name>

لاحظ أن صيغة الـ -p تأخذ قيمتين مفصولتين بنقطتين :

  • host-port: الـ port الذي على جهازك الذي تريد استخدامه
  • container-port: الـ port الذي داخل الـ Container الذي يعمل عليه التطبيق

في حالة Nginx فإنه يعمل على الـ port رقم 80 داخل الـ Container
لذا سنربطه بالـ port رقم 8080 الخاص بجهازنا

لكن أولًا يجب إيقاف الـ Container الحالي الذي يعمل بدون Port Mapping
ارجع إلى النافذة التي يعمل فيها الـ Container واضغط Ctrl + C لإيقافه

الآن لنرى قائمة الـ Containers مرة أخرى:

> docker container list --all
CONTAINER ID   IMAGE           COMMAND                  CREATED          STATUS                      PORTS     NAMES
60a264c4daa9   nginx:latest    "/docker-entrypoint.…"   22 minutes ago   Exited (0) 33 seconds ago             nginx-container
16704b093612   alpine:latest   "/bin/sh"                41 hours ago     Exited (0) 39 hours ago               my-alpine-container

الآن كلا الـ Containers متوقفان
لنقم بحذف كلاهما لأننا لا نحتاجهما الآن:

> docker container remove nginx-container my-alpine-container
nginx-container
my-alpine-container

الآن لنقم بتشغيل Nginx مرة أخرى مع استخدام الـ Port Mapping:

> docker container run --name nginx-container -p 8080:80 nginx:latest
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
...
2026/01/21 16:32:24 [notice] 1#1: start worker process 30
2026/01/21 16:32:24 [notice] 1#1: start worker process 31
2026/01/21 16:32:24 [notice] 1#1: start worker process 32

الآن Nginx يعمل في الـ Foreground الخاصة بالـ Terminal الحالية
والـ Port Mapping مفعل لذا أي Request يأتي على الـ port رقم 8080 من جهازك سيتم توجيهه للـ port رقم 80 داخل الـ Container

لنتحقق من ذلك في نافذة Terminal جديدة ونقم بعرض قائمة الـ Containers:

> docker container list --all
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS         PORTS                  NAMES
7d7313459cb3   nginx:latest   "/docker-entrypoint.…"   2 minutes ago    Up 2 minutes   0.0.0.0:8080->80/tcp   nginx-container

لاحظ قيمة العمود PORTS أصبحت 0.0.0.0:8080->80/tcp
بمعنى أنه أي Request يأتي على الـ port رقم 8080 من جهازك سيتم توجيهه إلى الـ port رقم 80 داخل الـ Container

+----------------------------------------------+
|     Your Device                              |
|                                              |
| localhost:8080 ---+                          |
|                   |                          |
|               Port Mapping                   |
|                   |                          |
|  +----------------|-----------------------+  |
|  |                |    Docker Engine      |  |
|  |                V                       |  |
|  |  +---------------------+               |  |
|  |  | nginx-container     |               |  |
|  |  | running on port 80  |               |  |
|  |  +----------------------+              |  |
|  |                                        |  |
|  +----------------------------------------+  |
|                                              |
|                                              |
+----------------------------------------------+

هذا شكل تخيلي لما يحدث، بحيث لدينا nginx يعمل داخل Container على port رقم 80 داخل Docker Engine
وفي نفس الوقت لدينا Port Mapping يربط هذا الـ port الداخلي رقم 80 بالـ port رقم 8080 على جهازك
وأي Request يأتي على localhost:8080 من جهازك سيتم توجيهه إلى nginx داخل الـ Container على port رقم 80


الآن افتح المتصفح واذهب إلى العنوان التالي:

http://localhost:8080

ستظهر لك صفحة الترحيب الخاصة بـ Nginx والتي تقول Welcome to nginx!
وستلاحظ أن الـ Container في الـ Terminal الحالي يقوم بطباعة الـ Logs الخاصة بالـ Request الذي أرسلته من المتصفح هذا يعني أن كل شيء يعمل بشكل صحيح

حسنًا، الآن دعنا نوقف الـ Container مرة أخرى بالضغط على Ctrl + C

لنرى قائمة الـ Containers مرة أخرى:

> docker container list --all
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS                     PORTS     NAMES
7d7313459cb3   nginx:latest   "/docker-entrypoint.…"   10 minutes ago   Exited (0) 2 minutes ago             nginx-container

ستلاحظ أن الـ Container توقف وحالته أصبحت Exited
بمعنى أننا بمجرد الضغط على Ctrl + C فإن الـ Container يتوقف عن العمل
وستلاحظ أن الـ Port Mapping لم يعد يظهر في العمود PORTS لأن الـ Container توقف عن العمل

تشغيل الـ Container في الخلفية

لاحظ أننا كل مرة نقوم فيها بتشغيل الـ Container فإنه يعمل في الـ Foreground أي في النافذة الحالية للـ Terminal
وهذا يمنعنا من كتابة أي أوامر أخرى في نفس النافذة ونضطر لفتح نافذة جديدة في كل مرة
لحل هذه المشكلة يمكننا تشغيل الـ Container في الخلفية باستخدام الـ flag المسمى -d أو --detach عند تشغيل الـ Container

لكن لنقم أولًا بحذف الـ Container الحالي:

> docker container remove nginx-container
nginx-container

ولمن يتسائل لما نقوم بحذف الـ Container بدلًا من إعادة تشغيله
فهذا لأن الـ Docker لا يسمح لنا بإعادة تشغيل Container مع إعدادات مختلفة عن التي أنشئ بها في البداية
لذا علينا حذف الـ Container وإنشاء واحد جديد مع الإعدادات الجديدة
ولا يمكننا استخدام الأمر docker container start لأنه يعيد تشغيل الـ Container بنفس الإعدادات القديمة
ونحن نريد تغيير إعدادات التشغيل لذا نضطر لحذفه وإنشاء واحد جديد بالإعدادات الجديدة

الآن لنقم بتشغيل Nginx مرة أخرى مع استخدام الـ flag المسمى -d لتشغيله في الخلفية:

> docker container run --name nginx-container -d -p 8080:80 nginx:latest
a7df9086f3601c46fa80ecf395da8008d3f6eea2c58e4874b4d205282c6958dc

الآن الـ Container يعمل في الخلفية
والأمر أعاد لنا الـ Container ID الكامل للـ Container الذي أنشأناه، أما الـ Container ID الذي نراه في الـ docker container list فهو مختصر منه

ستلاحظ الآن أن الـ Terminal عاد لك وأن الـ Container لا يعمل في الـ Foreground بعد الآن
بل يعمل في الـ Background
بالتالي يمكننا كتابة أوامر أخرى في نفس الـ Terminal الحالية

لنتحقق من أن الـ Container يعمل بالفعل أم لا:

> docker container list
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                  NAMES
a7df9086f360   nginx:latest   "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp   nginx-container

الآن الـ Container يعمل في الخلفية وحالته Up About a minute
يمكنك الآن الذهاب إلى المتصفح وفتح http://localhost:8080 مرة أخرى وستراه يعمل ويعرض صفحة الترحيب الخاصة بـ Nginx

docker container logs

الآن بما أن الـ Container يعمل في الخلفية الآن، كيف يمكننا رؤية الـ Logs الخاصة به؟
في الحالة السابقة عندما كان يعمل في الـ Foreground كنا نراه مباشرة في الـ Terminal
لكن الآن بما أنه يعمل في الخلفية فلا يمكننا رؤيته مباشرةً

هنا لدينا أمر بسيط من Docker يقوم بعرض الـ Logs وهو docker container logs

> docker container logs nginx-container
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
...

الأمر أعاد لنا كل الـ Logs التي تم طباعتها منذ تشغيل الـ Container
لكن ماذا لو أردنا متابعة الـ Logs بشكل مباشر كما كنا نراه في الـ Foreground ؟
يمكننا فعل ذلك باستخدام الـ flag المسمى -f أو --follow مع الأمر logs

> docker container logs -f nginx-container
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
...
2026/01/21 16:45:12 [notice] 1#1: start worker process 30
2026/01/21 16:45:12 [notice] 1#1: start worker process 31
2026/01/21 16:45:12 [notice] 1#1: start worker process 32

الآن أي Logs جديدة ستظهر مباشرة في الـ Terminal الحالية كما لو أن الـ Container يعمل في الـ Foreground
يمكنك تجربة ذلك بفتح المتصفح وإعادة تحميل صفحة http://localhost:8080
سترى أن الـ Logs الجديدة تظهر في الـ Terminal الحالية

طبعًا، للخروج من متابعة الـ Logs نضغط على Ctrl + C

الدخول داخل الـ Container

هناك عدة طرق للدخول داخل الـ Container لاستكشاف الملفات أو تعديلها أو تنفيذ أوامر معينة داخله
من هذه الطرق للدخول إلى الـ Shell الخاص بالـ Container
هى استخدام الـ flag المسمى -it مع أمر run
لكن هكذا سننشئ Container جديد، ونحن نريد الدخول إلى Container موجود بالفعل
لذا الطريقة الثانية كانت تنفيذ الـ flags الـ -ai مع أمر start
لكن الـ container قيد التشغيل بالفعل ولا نريد إيقافه وتشغيله مرة أخرى
نحن نريد الدخول إليه مباشرةً وهو يعمل بالفعل

الحل النهائي والمناسب لهذه الحالة هو استخدام أمر exec
وهو الأمر الذي يتيح لنا تنفيذ أوامر داخل Container قيد التشغيل بالفعل
وقد استخدمناه في المقالة السابقة مع Alpine Linux

لذا سنستخدمه مرة أخرى لتنفيذ أوامر داخل الـ Container الخاص بـ Nginx
لكن نحن نريد الدخول إلى الـ Shell الخاص به، وأمر الـ exec يُستخدم لتنفيذ أوامر فقط من دون الدخول إلى الـ Shell

حسنًا معك حق، لكن اتبع الخطوات الآتية لترى كيف سنقوم بذلك أولًا لنقم بتنفيذ أمر ls داخل الـ Container الخاص بـ Nginx:

> docker container exec nginx-container ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home ...

الآن عرفنا كل الملفات والمجلدات داخل الـ Container
وهو أشبه بنية نظام تشغيل الـ Linux

الآن لنقم بتنفيذ أمر cat لعرض محتوى ملف etc/os-release الذي يحتوي على معلومات عن نظام التشغيل:

> docker container exec nginx-container cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
NAME="Debian GNU/Linux"
VERSION_ID="13"
VERSION="13 (trixie)"
VERSION_CODENAME=trixie
DEBIAN_VERSION_FULL=13.3
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

لاحظ أن الـ Nginx يعمل داخل نظام تشغيل Debian Linux
بمعنى أن الـ Image الخاصة بـ Nginx مبنية على Debian Linux كنظام تشغيل أساسي
بالطبع يمكنك تغير هذا واستخدام Nginx مبني على أي نظام تشغيل آخر مثل Alpine Linux أو Ubuntu أو غيرها
عن طريق تحديد الـ التوزيعة التي تريدها عند تحميل الـ Image من الـ Docker Hub
فبدلًا من تحميل nginx:latest يمكنك تحميل nginx:alpine أو nginx:ubuntu وهكذا
لكن دعنا لا نغير شيء الآن ونكمل مع Debian Linux

طالما نحن داخل توزيعة من توزيعات Linux فيمكننا استكشاف الملفات والأوامر الخاصة بها

الآن لننظر داخل مجلد bin:

> docker container exec nginx-container ls /bin
bash busybox cat chmod ...

داخل مجلد bin نجد العديد من الأوامر الخاصة بنظام التشغيل المستخدم داخل الـ Container الخاص بـ Nginx
والذي هى أوامر أساسية في أي نظام تشغيل Linux
ومن ضمن هذه الأوامر نجد bash وهو الـ Shell الذي نريد الدخول إليه

لذا لنقم بالدخول إلى الـ Shell الخاص بالـ Container الخاص بـ Nginx يمكننا فعل ذلك باستخدام الأمر docker container exec مع الـ -it للدخول إلى الـ Shell التفاعلي داخل الـ Container:

> docker container exec -it nginx-container /bin/bash
root@a7df9086f360:/#

لاحظ أن الـ Terminal تغير وأصبح يظهر لنا root@a7df9086f360:/#
هذا يعني أننا دخلنا إلى الـ Bash Shell داخل الـ Container الخاص بـ Nginx المبني على Debian Linux
والـ a7df9086f360 هو الـ Container ID الخاص بالـ Container الذي دخلنا إليه

الآن نستطيع تنفيذ أي أوامر داخل هذا الـ Shell كما لو أننا داخل نظام تشغيل Linux عادي
لاحظ أننا مع exec كنا ننفذ أوامر من خارج الـ Container
أما الآن مع الدخول إلى الـ Shell داخل الـ Container فنحن ننفذ الأوامر من داخل الـ Container نفسه


الآن قلنا أن الـ Nginx هو Web Server ويستخدم لاستضافة Static Files مثل صفحات HTML وملفات CSS و JavaScript
وعندما ذهبنا إلى http://localhost:8080 في المتصفح رأينا صفحة الترحيب الخاصة بـ Nginx
هذه الصفحة هى ملف HTML مخزن داخل الـ Container الخاص بـ Nginx ويقوم الـ Nginx باستضافة هذا الملف وعرضه كصفحة افتراضية له

السؤال الآن هو أين المكان الذي يخزن فيه Nginx هذه الملفات داخل الـ Container ؟
الاجابة ببساطة هى في مجلد /usr/share/nginx/html داخل الـ Container
أي ملف HTML نضعه في هذا المجلد سيتم استضافته بواسطة Nginx وسيكون متاحًا في المتصفح على http://localhost:8080

لنذهب إلى هذا المجلد:

root@a7df9086f360:/# cd /usr/share/nginx/html
root@a7df9086f360:/usr/share/nginx/html#

نحن الآن داخل المجلد /usr/share/nginx/html لنقم بعرض محتوياته عن طريق أمر ls:

root@a7df9086f360:/usr/share/nginx/html# ls
50x.html  index.html

الملف index.html هو صفحة الترحيب التي رأيناها في المتصفح
ويشترط Nginx أن يكون اسم الملف الرئيسي هو index.html ليتم عرضه افتراضيًا عند الدخول إلى الـ Server
بمعنى إذا قمت بتغير اسم الملف من index.html إلى أي اسم آخر فلن يتم عرضه افتراضيًا عند الدخول إلى http://localhost:8080
يمكنك تعديل هذا السلوك في إعدادات Nginx لكن هذا موضوع متقدم وليس هدفنا هنا

لاحظ وجود ملف آخر اسمه 50x.html وهو صفحة خطأ يتم عرضها في حالة حدوث أخطاء في الـ Server الخاص بـ Nginx

لنقم بعرض محتوى ملف index.html عن طريق أمر cat

root@a7df9086f360:/usr/share/nginx/html# cat index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</head>
<body>
<h1>Welcome to nginx!</h1>
...
</body>
</html>

ستلاحظ أن محتوى الملف هو صفحة HTML هى نفس الصفحة التي رأيناها في المتصفح
يمكنك بالطبع تعديل هذا الملف أو حذفه بشكل نهائي ووضع موقع الويب الخاص بك هنا في هذا المجلد ليتم استضافته بواسطة Nginx
وتراه في المتصفح عند الدخول إلى http://localhost:8080

تعديل محتوى داخل الـ Nginx

دعنا نجرب تعديل صفحة الترحيب الخاصة بـ Nginx
سندخل إلى الـ Container ونعدل الملف index.html

root@a7df9086f360:/usr/share/nginx/html# echo "<h1>Visit eltabarani.com</h1>" > index.html

الآن قمنا بتعديل الملف index.html ليحتوي على السطر <h1>Visit eltabarani.com</h1> بدلاً من المحتوى السابق

الآن لنذهب إلى http://localhost:8080 في المتصفح ونعيد تحميل الصفحة
ستلاحظ أن الصفحة تغيرت وتعرض Visit eltabarani.com

هكذا يمكنك تعديل أي ملف داخل الـ Container الخاص بـ Nginx

ملحوظة: أي تعديل تقوم به داخل الـ Container سيضيع عند حذف الـ Container
وستضطر إلى إعادة التعديلات مرة أخرى مع كل مرة تنشئ فيها Container جديد من نفس الـ Image
لكن في المقالات القادمة سنتعرف على كيفية حفظ التعديلات التي نقوم بها داخل الـ Container عن طريق الـ Volumes

الخروج من الـ Nginx

بعد الانتهاء من التعديلات التي تريدها داخل الـ Container الخاص بـ Nginx
يمكنك الخروج من الـ Shell داخل الـ Container عن طريق كتابة الأمر exit أو الضغط على Ctrl + D

root@a7df9086f360:/usr/share/nginx/html# exit

وعند الخروج ستعود إلى الـ Terminal الأصلية التي كنت تعمل فيها
وأيضًا الـ Container الخاص بـ Nginx سيظل يعمل في الخلفية ولن يتوقف

> docker container list --all
CONTAINER ID   IMAGE          COMMAND                  CREATED        STATUS          PORTS                  NAMES
a7df9086f360   nginx:latest   "/docker-entrypoint.…"   28 hours ago   Up 37 minutes   0.0.0.0:8080->80/tcp   nginx-container

تذكر أننا في المقالة السابقة عندما كنا نستخدم -it مع أمر run أو -ai مع أمر start
فإننا عندما نخرج من الـ Shell داخل الـ Container فإن الـ Container يتوقف عن العمل

أما هنا مع استخدام exec -it <container-id> /bin/bash
فإننا عندما نخرج من الـ Shell داخل الـ Container فإن الـ Container يظل يعمل في الخلفية
هذا لأننا لم نقم بإنشاء الـ Container مع -it أو -ai بل استخدمنا exec لتنفيذ أمر /bin/bash داخل Container
كأننا فتحنا برنامج الـ Bash داخل الـ Container فقط ثم خرجنا منه
فنحن لم نخرج من الـ Container نفسه بل خرجنا من برنامج الـ Bash الذي فتحناه داخل الـ Container


بعد الانتهاء من التجربة دعنا ننظف الـ Containers التي أنشأناها

أولًا نوقف الـ Container:

> docker container stop nginx-container
nginx-container

ثم نحذفه:

> docker container remove nginx-container
nginx-container

يمكننا أيضًا حذف الـ Container مباشرة حتى لو كان يعمل باستخدام الـ flag المسمى -f دون الحاجة لإيقافه أولًا:

> docker container remove -f nginx-container
nginx-container

هذا الأمر سيوقف الـ Container ويحذفه في خطوة واحدة


إذا أردت حذف الـ Container تلقائيًا بعد إيقافه
يمكنك استخدام الـ flag المسمى --rm عند إنشاء الـ Container:

> docker container run -d -p 8080:80 --rm --name nginx-container nginx:latest

هكذا عندما تقوم بإيقاف هذا الـ Container باستخدام docker container stop nginx-container
سيقوم الـ Docker بحذفه تلقائيًا دون الحاجة لاستخدام أمر docker container remove nginx-container

ملخص الأوامر

في هذه المقالة تعلمنا كيفية تشغيل Nginx داخل Docker Container
وتعرفنا على مفهوم الـ Port Mapping الذي يتيح لنا الوصول للتطبيقات داخل الـ Containers
وتعلمنا كيفية تشغيل الـ Containers في الخلفية والدخول إليها وعرض الـ Logs وبعض الأوامر المهمة الأخرى

ولأنني أعرف أنك من محبي الجداول والملخصات
فإليك ملخص سريع لأهم الأمور التي تعلمناها في هذه المقالة:

الأمر الوظيفة
docker container run -p 8080:80 nginx:latest تشغيل Container مع ربط المنافذ
docker container run -d nginx:latest تشغيل Container في الخلفية
docker container run --rm nginx:latest حذف الـ Container تلقائيًا عند الإيقاف
docker container logs <container> عرض سجلات الـ Container
docker container logs -f <container> متابعة سجلات الـ Container بشكل مباشر
docker container exec -it <container> /bin/bash الدخول إلى الـ Shell داخل Container قيد التشغيل
docker container remove -f <container> حذف الـ Container بالقوة حتى لو كان قيد التشغيل

في المقالة القادمة سنتعرف على الـ Dockerfile الذي يتيح لنا إنشاء Images مخصصة تناسب احتياجاتنا
وأيضًا يختصر علينا الكثير من الأمور عند إنشاء الـ Containers المتكررة