يقدم RHEL 8 Beta للمطورين العديد من الميزات الجديدة ، التي قد تأخذ قوائمها صفحات ، ومع ذلك ، من الأفضل دائمًا تعلم أشياء جديدة في الممارسة ، لذلك نقترح الدخول في ورشة عمل لإنشاء بنية تحتية للتطبيق فعليًا تستند إلى Red Hat Enterprise Linux 8 Beta.

لنأخذ Python ، وهي مزيج من Django و PostgreSQL ، وهي حزمة شائعة إلى حد ما لإنشاء التطبيقات ، وتكوين RHEL 8 Beta للعمل معهم. ثم أضف بضعة مكونات (غير مصنفة).
ستتغير بيئة الاختبار ، لأنه من المثير للاهتمام دراسة إمكانات الأتمتة ، العمل مع الحاويات وتجربة البيئات مع خوادم متعددة. لبدء العمل في مشروع جديد ، يمكنك البدء بإنشاء نموذج أولي بسيط صغير يدويًا - وبهذه الطريقة يمكنك معرفة ما يجب أن يحدث بالضبط وكيفية تنفيذ التفاعل ، ثم الانتقال إلى الأتمتة وإنشاء تكوينات أكثر تعقيدًا. اليوم هي قصة إنشاء مثل هذا النموذج الأولي.
لنبدأ بنشر صورة الجهاز الظاهري RHEL 8 Beta VM. يمكنك تثبيت الجهاز الظاهري من نقطة الصفر ، أو استخدام صورة ضيف KVM ، المتاحة مع الاشتراك التجريبي. عند استخدام صورة ضيف ، ستحتاج إلى تكوين قرص مضغوط ظاهري ، والذي سيحتوي على بيانات التعريف وبيانات المستخدم لتهيئة السحابة (cloud-init). لا تحتاج إلى القيام بأي شيء خاص بهيكل القرص أو الحزم المتوفرة ، فإن أي تكوين سيفعل.
دعنا ننظر إلى العملية برمتها بمزيد من التفصيل.
تثبيت جانغو
مع أحدث إصدار من Django ، ستحتاج إلى بيئة افتراضية (virtualenv) مع Python 3.5 أو إصدار أحدث. في ملاحظات الإصدار التجريبي ، يمكنك أن ترى أن Python 3.6 متاح ، دعنا نتحقق مما إذا كان هذا صحيحًا:
[cloud-user@8beta1 ~]$ python -bash: python: command not found [cloud-user@8beta1 ~]$ python3 -bash: python3: command not found
يستخدم Red Hat بنشاط Python كأداة نظام في RHEL ، فلماذا تحصل على هذه النتيجة؟
والحقيقة هي أن العديد من المطورين الذين يستخدمون Python لا يزالون يفكرون في التحول من Python 2 إلى Python 3 ، في حين أن Python 3 نفسها قيد التطوير النشط ، وتظهر المزيد والمزيد من الإصدارات الجديدة باستمرار. لذلك ، من أجل تلبية الحاجة إلى أدوات نظام مستقرة ، وفي الوقت نفسه تتيح للمستخدمين الوصول إلى الإصدارات الجديدة المختلفة من Python ، تم نقل نظام Python إلى حزمة جديدة وتوفير القدرة على تثبيت Python 2.7 و 3.6. يمكن العثور على مزيد من المعلومات حول التغييرات والسبب في ذلك في
منشور مدونة Langdon White .
لذلك ، من أجل الحصول على عمل Python ، تحتاج إلى تثبيت حزمتين فقط ، في حين أن python3-pip سينطلق كتبعية.
sudo yum install python36 python3-virtualenv
لماذا لا تستخدم مكالمات الوحدة النمطية المباشرة ، كما يقترح Langdon ، ولا تقم بتثبيت pip3؟ مع الأخذ في الاعتبار الأتمتة القادمة ، من المعروف أن Ansible ستحتاج إلى نقطة مثبتة ، لأن وحدة النقطة لا تدعم البيئات الافتراضية (virtualenvs) مع نقطة تنفيذ مخصصة.
من خلال مترجم python3 يعمل تحت تصرفك ، يمكنك متابعة عملية تثبيت Django والحصول على نظام عمل مع المكونات الأخرى لدينا. تقدم الشبكة العديد من الخيارات للتنفيذ. يتم تقديم إصدار واحد هنا ، ولكن يمكن للمستخدمين استخدام العمليات الخاصة بهم.
سيتم تثبيت إصدارات PostgreSQL و Nginx المتوفرة في RHEL 8 افتراضيًا باستخدام Yum.
sudo yum install nginx postgresql-server
سيتطلب PostgreSQL psycopg2 ، لكن يجب أن يكون متاحًا فقط في بيئة virtualenv ، لذلك سنقوم بتثبيته باستخدام pip3 مع Django و Gunicorn. لكن أولاً نحتاج إلى تكوين virtualenv.
هناك دائمًا جدال كبير حول اختيار المكان المناسب لتثبيت مشاريع Django ، لكن عندما تكون في شك ، يمكنك دائمًا الرجوع إلى نظام التسلسل الهرمي لنظام ملفات Linux. على وجه الخصوص ، يقول FHS أن / srv يُستخدم من أجل: "تخزين البيانات الخاصة بالمضيف - البيانات التي يوفرها النظام ، على سبيل المثال ، البيانات والبرامج النصية من خوادم الويب ، والبيانات المخزنة على خوادم FTP ، فضلاً عن مستودعات أنظمة التحكم الإصدارات (المقدمة في FHS-2.3 في 2004). "
هذه هي حالتنا فقط ، لذلك نضع كل ما نحتاجه في / srv ، والذي يملكه مستخدم التطبيق لدينا (مستخدم سحابي).
sudo mkdir /srv/djangoapp sudo chown cloud-user:cloud-user /srv/djangoapp cd /srv/djangoapp virtualenv django source django/bin/activate pip3 install django gunicorn psycopg2 ./django-admin startproject djangoapp /srv/djangoapp
إعداد PostgreSQL و Django سهل: إنشاء قاعدة بيانات ، وإنشاء مستخدم ، وتكوين أذونات. هناك نقطة واحدة يجب مراعاتها عند تثبيت PostgreSQL للمرة الأولى - البرنامج النصي postgresql-setup ، والذي تم تثبيته مع حزمة خادم postgresql. يساعدك هذا البرنامج النصي في أداء المهام الأساسية المتعلقة بإدارة كتلة قاعدة بيانات ، مثل تهيئة نظام أو تحديث عملية. لتكوين مثيل جديد من PostgreSQL على نظام RHEL ، نحتاج إلى تشغيل الأمر:
sudo /usr/bin/postgresql-setup -initdb
بعد ذلك ، يمكنك بدء تشغيل PostgreSQL باستخدام systemd ، وإنشاء قاعدة بيانات وتكوين المشروع في جانغو. تذكر إعادة تشغيل PostgreSQL بعد إجراء تغييرات على ملف تكوين مصادقة العميل (عادةً pg_hba.conf) لتكوين تخزين كلمة المرور لمستخدم التطبيق. إذا واجهت صعوبات أخرى ، فتأكد من تغيير إعدادات IPv4 و IPv6 في ملف pg_hba.conf.
systemctl enable -now postgresql sudo -u postgres psql postgres=# create database djangoapp; postgres=# create user djangouser with password 'qwer4321'; postgres=# alter role djangouser set client_encoding to 'utf8'; postgres=# alter role djangouser set default_transaction_isolation to 'read committed'; postgres=# alter role djangouser set timezone to 'utc'; postgres=# grant all on DATABASE djangoapp to djangouser; postgres=# \q
في الملف /var/lib/pgsql/data/pg_hba.conf:
# IPv4 local connections: host all all 0.0.0.0/0 md5 # IPv6 local connections: host all all ::1/128 md5
في الملف / srv/djangoapp/settings.py:
# Database DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': '{{ db_name }}', 'USER': '{{ db_user }}', 'PASSWORD': '{{ db_password }}', 'HOST': '{{ db_host }}', } }
بعد تكوين ملف settings.py في المشروع وتكوين تكوين قاعدة البيانات ، يمكنك بدء تشغيل خادم التطوير للتأكد من أن كل شيء يعمل. بعد بدء خادم التطوير ، من الجيد إنشاء مستخدم مسؤول لاختبار الاتصال بقاعدة البيانات.
./manage.py runserver 0.0.0.0:8000 ./manage.py createsuperuser
WSGI؟ واي؟
يعد خادم التطوير مفيدًا للاختبار ، ولكن لتشغيل التطبيق ، يجب عليك تكوين الخادم والوكيل المناسبين لواجهة خادم الويب (WSGI). هناك عدة حزم شائعة ، على سبيل المثال ، Apache HTTPD مع uWSGI أو Nginx مع Gunicorn.
الهدف من Web Server Gateway Interface هو إعادة توجيه الطلبات من خادم الويب إلى إطار عمل Python على الويب. WSGI هو نوع من تراث الماضي الرهيب عندما كانت آليات CGI قيد الاستخدام ، واليوم WSGI هو في الواقع المعيار ، بغض النظر عن خادم الويب أو إطار عمل Python المستخدم. ولكن على الرغم من توزيعها على نطاق واسع ، لا يزال هناك العديد من الفروق الدقيقة عند العمل مع هذه الأطر ، والعديد من الخيارات. في هذه الحالة ، سنحاول إقامة تفاعل بين Gunicorn و Nginx من خلال المقبس.
نظرًا لأن كلا المكونين مثبتان على نفس الخادم ، فسنحاول استخدام مقبس UNIX بدلاً من مقبس الشبكة. نظرًا لأن الاتصال يتطلب مأخذ توصيل على أي حال ، فلنجرب خطوة أخرى وقم بتكوين تنشيط المقبس لـ Gunicorn من خلال systemd.
عملية إنشاء خدمات تنشيط مأخذ التوصيل بسيطة بما فيه الكفاية. أولاً ، يتم إنشاء ملف وحدة يحتوي على توجيه ListenStream ، مشيرًا إلى النقطة التي سيتم عندها إنشاء مقبس UNIX ، ثم ملف وحدة للخدمة ، حيث يشير التوجيه المطلوب إلى ملف وحدة مأخذ التوصيل. بعد ذلك ، في ملف وحدة الخدمة ، يبقى فقط الاتصال بـ Gunicorn من البيئة الافتراضية وإنشاء رابط WSGI لمقبس UNIX وتطبيق Django.
فيما يلي بعض الأمثلة لملفات الوحدة التي يمكن اتخاذها كأساس. أولا ، تكوين المقبس.
[Unit] Description=Gunicorn WSGI socket [Socket] ListenStream=/run/gunicorn.sock [Install] WantedBy=sockets.target
الآن تحتاج إلى تكوين البرنامج الخفي Gunicorn.
[Unit] Description=Gunicorn daemon Requires=gunicorn.socket After=network.target [Service] User=cloud-user Group=cloud-user WorkingDirectory=/srv/djangoapp ExecStart=/srv/djangoapp/django/bin/gunicorn \ —access-logfile - \ —workers 3 \ —bind unix:gunicorn.sock djangoapp.wsgi [Install] WantedBy=multi-user.target
بالنسبة لـ Nginx ، قم فقط بإنشاء ملف تكوين وكيل وإعداد دليل لتخزين المحتوى الثابت إذا كنت تستخدمه. في RHEL ، ملفات تكوين Nginx هي /etc/nginx/conf.d. يمكنك نسخ المثال التالي هناك إلى الملف /etc/nginx/conf.d/default.conf ، وبدء الخدمة. تأكد من تحديد server_name وفقًا لاسم المضيف الخاص بك.
server { listen 80; server_name 8beta1.example.com; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /srv/djangoapp; } location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://unix:/run/gunicorn.sock; } }
قم بتشغيل مآخذ Gunicorn و Nginx باستخدام systemd ، ويمكنك البدء في الاختبار.
خطأ في بوابة سيئة؟
إذا أدخلت العنوان في المتصفح ، فمن المرجح أن تحصل على الخطأ 502 Bad Gateway. يمكن أن يكون سبب أذونات تكوين غير صحيح لمأخذ UNIX ، أو بسبب مشاكل أكثر تعقيدًا تتعلق بالتحكم في الوصول في SELinux.
في سجل أخطاء nginx ، يمكنك رؤية سطر مثل هذا:
2018/12/18 15:38:03 [crit] 12734#0: *3 connect() to unix:/run/gunicorn.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.122.1, server: 8beta1.example.com, request: "GET / HTTP/1.1", upstream: "http://unix:/run/gunicorn.sock:/", host: "8beta1.example.com"
إذا اختبرنا Gunicorn مباشرة ، فسوف نحصل على إجابة فارغة.
curl —unix-socket /run/gunicorn.sock 8beta1.example.com
دعونا نرى لماذا يحدث هذا. إذا قمت بفتح السجل ، فعلى الأرجح سنرى أن المشكلة تتعلق بـ SELinux. نظرًا لأننا ندير برنامج خفي لم ننشئ سياستنا الخاصة به ، فقد تم وضع علامة عليه كـ init_t. دعونا اختبار هذه النظرية في الممارسة العملية.
sudo setenforce 0
كل هذا يمكن أن يسبب النقد والدموع الدامية ، ولكن هذا هو مجرد تصحيح النموذج الأولي. نقوم بإيقاف تشغيل الشيك فقط للتأكد من أن هذه هي المشكلة ، وبعد ذلك سنعود بكل شيء إلى أماكنهم.
عن طريق تحديث الصفحة في المتصفح أو عن طريق إعادة تشغيل أمر curl الخاص بنا ، يمكنك رؤية صفحة اختبار Django.
لذلك ، مع التأكد من أن كل شيء يعمل ، ولم تعد هناك مشاكل في الأذونات ، فإننا نعيد تمكين SELinux.
sudo setenforce 1
لن يكون هناك أي حديث عن audit2allow وإنشاء سياسات تستند إلى التنبيهات باستخدام sepolgen ، حيث لا يوجد حاليًا تطبيق Django حقيقي ، ولا توجد خريطة كاملة لما قد يرغب Gunicorn في الوصول إليه وما يجب رفض الوصول إليه. لذلك ، من الضروري الحفاظ على عمل SELinux لحماية النظام ، وفي الوقت نفسه ، السماح للتطبيق ببدء الرسائل وتركها في سجل التدقيق حتى تتمكن من إنشاء سياسة حقيقية بناءً عليها.
تحديد المجالات المسموح بها
لم يسمع الجميع بالمجالات المسموح بها في SELinux ، لكن لا يوجد شيء جديد فيها. حتى أن الكثير منهم عمل معهم ، دون أن يدركوا ذلك بأنفسهم. عندما يتم إنشاء سياسة بناءً على رسائل التدقيق ، فإن السياسة التي يتم إنشاؤها هي مجال مسموح به. دعونا نحاول إنشاء أبسط سياسة متساهلة.
لإنشاء مجال معين مسموح به لـ Gunicorn ، ستحتاج إلى سياسة معينة ، وستحتاج أيضًا إلى وضع علامة على الملفات المناسبة. بالإضافة إلى ذلك ، هناك حاجة إلى أدوات لتجميع السياسات الجديدة.
sudo yum install selinux-policy-devel
تعد آلية المجال التي تم حلها أداة رائعة لتحديد المشكلات ، خاصة عندما يتعلق الأمر بتطبيق مخصص أو تطبيقات تأتي بدون سياسات تم إنشاؤها بالفعل. في هذه الحالة ، ستكون سياسة المجال المسموح بها لـ Gunicorn بسيطة قدر الإمكان - أعلن النوع الرئيسي (gunicorn_t) ، وأعلن النوع الذي سنستخدمه لتمييز العديد من الملفات القابلة للتنفيذ (gunicorn_exec_t) ، ثم قم بتكوين الانتقال للنظام ليشير إلى العمليات الجارية بشكل صحيح . يعين السطر الأخير السياسة كما تم تمكينها افتراضيًا في وقت التحميل.
gunicorn.te: policy_module(gunicorn, 1.0) type gunicorn_t; type gunicorn_exec_t; init_daemon_domain(gunicorn_t, gunicorn_exec_t) permissive gunicorn_t;
يمكنك ترجمة ملف السياسة هذا وإضافته إلى النظام.
make -f /usr/share/selinux/devel/Makefile sudo semodule -i gunicorn.pp sudo semanage permissive -a gunicorn_t sudo semodule -l | grep permissive
دعونا نتحقق مما إذا كان SELinux يحظر أي شيء آخر إلى جانب ما يقوم به برنامجنا الخفي المجهول.
sudo ausearch -m AVC type=AVC msg=audit(1545315977.237:1273): avc: denied { write } for pid=19400 comm="nginx" name="gunicorn.sock" dev="tmpfs" ino=52977 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:var_run_t:s0 tclass=sock_file permissive=0
SELinux يمنع Nginx من كتابة البيانات إلى مقبس UNIX المستخدم من قبل Gunicorn. عادة ، في مثل هذه الحالات ، يبدأ السياسيون في التغيير ، ولكن هناك مهام أخرى في المستقبل. يمكنك أيضًا تغيير إعدادات المجال عن طريق تحويلها من مجال تقييد إلى مجال إذن. الآن انتقل httpd_t إلى مجال الإذن. سيوفر ذلك لـ Nginx الوصول اللازم ، وسنكون قادرين على مواصلة العمل على تصحيح الأخطاء.
sudo semanage permissive -a httpd_t
لذلك ، عندما كان من الممكن الحفاظ على حماية SELinux (في الواقع ، يجب ألا تترك المشروع مع SELinux في وضع التقييد) ويتم تحميل مجالات الأذونات ، تحتاج إلى معرفة ما يجب وضع علامة بالضبط على أنه gunicorn_exec_t بحيث يعمل كل شيء مرة أخرى كما هو متوقع. دعونا نحاول الوصول إلى موقع الويب لرؤية رسائل جديدة حول قيود الوصول.
sudo ausearch -m AVC -c gunicorn
يمكنك رؤية الكثير من الرسائل التي تحتوي على "comm =" gunicorn "" التي تؤدي إجراءات مختلفة على الملفات الموجودة في / srv / djangoapp ، لذلك من الواضح أن هذا مجرد واحد من الأوامر التي يجب أن تحددها.
لكن بالإضافة إلى ذلك ، تظهر رسالة كهذه:
type=AVC msg=audit(1545320700.070:1542): avc: denied { execute } for pid=20704 comm="(gunicorn)" name="python3.6" dev="vda3" ino=8515706 scontext=system_u:system_r:init_t:s0 tcontext=unconfined_u:object_r:var_t:s0 tclass=file permissive=0
إذا نظرت إلى حالة الخدمة gunicorn أو قمت بتشغيل الأمر ps ، فلن تظهر أية عمليات قيد التشغيل. يبدو أن Gunicorn يحاول الوصول إلى مترجم Python في بيئة أعمالنا الافتراضية ، وربما لتشغيل نصوص عمل (عمال). فلنضع الآن علامة على هذين الملفين التنفيذيين ونرى ما إذا كان بإمكاننا فتح صفحة اختبار Django الخاصة بنا.
chcon -t gunicorn_exec_t /srv/djangoapp/django/bin/gunicorn /srv/djangoapp/django/bin/python3.6
ستحتاج إلى إعادة تشغيل خدمة gunicorn حتى تتمكن من تحديد تسمية جديدة. يمكنك إعادة تشغيله على الفور أو إيقاف الخدمة والسماح للمقبس ببدء تشغيله عند فتح الموقع في مستعرض. تأكد من حصول العمليات على الملصقات الصحيحة باستخدام ps.
ps -efZ | grep gunicorn
تذكر إنشاء سياسة SELinux طبيعية في وقت لاحق!
إذا نظرت الآن إلى رسائل AVC ، فستحتوي الرسالة الأخيرة على = 1 لكل ما يتعلق بالتطبيق ، و = 0 = بالنسبة لبقية النظام. إذا فهمت نوع الوصول الذي يحتاجه التطبيق الحقيقي ، فيمكنك العثور بسرعة على أفضل طريقة لحل هذه المشكلات. ولكن حتى ذلك الحين ، من الأفضل حماية النظام ، ومن أجل الحصول على مراجعة واضحة وقابلة للاستخدام من قبل مشروع Django.
sudo ausearch -m AVC
اتضح!
ظهر مشروع Django يعمل مع واجهة على Nginx و Gunicorn WSGI. لقد قمنا بتهيئة Python 3 و PostgreSQL 10 من مستودعات RHEL 8 Beta. يمكنك الآن تشغيل تطبيقات Django (أو مجرد نشرها) أو استكشاف الأدوات الأخرى المتاحة في RHEL 8 Beta لأتمتة عملية التوليف أو تحسين الأداء أو حتى تكوين هذا التكوين في حاويات.