Workshop RHEL 8 Beta: Ishlaydigan veb-ilovalarni yaratish

RHEL 8 Beta ishlab chiquvchilarga ko'plab yangi xususiyatlarni taklif qiladi, ularning ro'yxati sahifalarni olishi mumkin, ammo yangi narsalarni o'rganish amalda har doim yaxshiroq, shuning uchun quyida biz Red Hat Enterprise Linux 8 Beta asosida amaliy dastur infratuzilmasini yaratish bo'yicha seminarni taklif qilamiz.

Workshop RHEL 8 Beta: Ishlaydigan veb-ilovalarni yaratish

Keling, dasturchilar orasida mashhur bo'lgan Python dasturlash tilini asos sifatida Django va PostgreSQL kombinatsiyasini olaylik, bu ilovalar yaratish uchun juda keng tarqalgan kombinatsiya va ular bilan ishlash uchun RHEL 8 Beta-ni sozlang. Keyin yana bir nechta (tasniflanmagan) ingredientlarni qo'shamiz.

Sinov muhiti o'zgaradi, chunki avtomatlashtirish imkoniyatlarini o'rganish, konteynerlar bilan ishlash va bir nechta serverlar bilan muhitlarni sinab ko'rish qiziq. Yangi loyihani boshlash uchun siz qo'lda kichik, oddiy prototip yaratishdan boshlashingiz mumkin, shunda siz aniq nima bo'lishi kerakligini va u qanday o'zaro ta'sir qilishini ko'rishingiz mumkin, keyin esa avtomatlashtirish va yanada murakkab konfiguratsiyalarni yaratishga o'ting. Bugun biz bunday prototipni yaratish haqida gapiramiz.

RHEL 8 Beta VM tasvirini joylashtirishdan boshlaylik. Siz virtual mashinani noldan o'rnatishingiz yoki Beta obunangiz bilan mavjud KVM mehmon tasviridan foydalanishingiz mumkin. Mehmon tasviridan foydalanganda, bulutni ishga tushirish uchun metadata va foydalanuvchi ma'lumotlarini o'z ichiga olgan virtual kompakt diskni sozlashingiz kerak bo'ladi (cloud-init). Disk tuzilishi yoki mavjud paketlar bilan maxsus biror narsa qilishingiz shart emas, har qanday konfiguratsiya yordam beradi.

Keling, butun jarayonni batafsil ko'rib chiqaylik.

Django o'rnatilmoqda

Django-ning eng yangi versiyasi bilan sizga Python 3.5 yoki undan keyingi versiyalari bilan virtual muhit (virtualenv) kerak bo'ladi. Beta eslatmalarida siz Python 3.6 mavjudligini ko'rishingiz mumkin, keling, bu haqiqatan ham shundaymi yoki yo'qligini tekshiramiz:

[cloud-user@8beta1 ~]$ python
-bash: python: command not found
[cloud-user@8beta1 ~]$ python3
-bash: python3: command not found

Red Hat Python-dan RHEL-da tizim asboblar to'plami sifatida faol foydalanadi, shuning uchun nima uchun bu natijaga olib keladi?

Gap shundaki, ko'plab Python dasturchilari hali ham Python 2 dan Python 2 ga o'tish haqida o'ylashmoqda, Python 3 esa faol ishlab chiqilmoqda va tobora ko'proq yangi versiyalar paydo bo'lmoqda. Shu sababli, barqaror tizim vositalariga bo'lgan ehtiyojni qondirish va foydalanuvchilarga Pythonning turli xil yangi versiyalariga kirishni taklif qilish uchun Python tizimi yangi paketga ko'chirildi va Python 2.7 va 3.6 ni o'rnatish imkoniyatini berdi. O'zgartirishlar va ular nima uchun kiritilganligi haqida ko'proq ma'lumotni nashrda topishingiz mumkin Langdon Whitening blogi (Langdon Uayt).

Shunday qilib, Python bilan ishlash uchun faqat ikkita paketni o'rnatishingiz kerak, python3-pip bog'liqlik sifatida kiritilgan.

sudo yum install python36 python3-virtualenv

Nega Langdon taklif qilganidek to'g'ridan-to'g'ri modul qo'ng'iroqlarini ishlatmaslik va pip3 ni o'rnatish kerak? Kelgusi avtomatlashtirishni yodda tutgan holda, ma'lumki, Ansible ishga tushirish uchun pip o'rnatilishini talab qiladi, chunki pip moduli maxsus pip bajariladigan virtualenvlarni qo'llab-quvvatlamaydi.

Sizning ixtiyoringizda ishlaydigan python3 tarjimoni bilan siz Django o'rnatish jarayonini davom ettirishingiz va boshqa komponentlarimiz bilan birga ishlaydigan tizimga ega bo'lishingiz mumkin. Internetda amalga oshirishning ko'plab variantlari mavjud. Bu erda bitta versiya mavjud, ammo foydalanuvchilar o'zlarining jarayonlaridan foydalanishlari mumkin.

RHEL 8 da mavjud bo'lgan PostgreSQL va Nginx versiyalarini Yum yordamida sukut bo'yicha o'rnatamiz.

sudo yum install nginx postgresql-server

PostgreSQL psycopg2 ni talab qiladi, lekin u faqat virtual muhitda mavjud bo'lishi kerak, shuning uchun biz uni Django va Gunicorn bilan birga pip3 yordamida o'rnatamiz. Lekin birinchi navbatda virtualenv ni o'rnatishimiz kerak.

Django loyihalarini o'rnatish uchun to'g'ri joyni tanlash mavzusida har doim juda ko'p bahs-munozaralar mavjud, ammo shubhangiz bo'lsa, har doim Linux fayl tizimi ierarxiyasi standartiga murojaat qilishingiz mumkin. Xususan, FHSda aytilishicha, /srv quyidagilar uchun ishlatiladi: "xost-maxsus ma'lumotlarni saqlash - tizim ishlab chiqaradigan ma'lumotlar, masalan, veb-server ma'lumotlari va skriptlar, FTP serverlarida saqlangan ma'lumotlar va tizim omborlarini boshqarish." versiyalari (FHSda paydo bo'ladi) 2.3 yilda -2004).

Bu aynan bizning holatimiz, shuning uchun biz kerak bo'lgan hamma narsani ilova foydalanuvchimizga (bulut foydalanuvchisi) tegishli bo'lgan /srv ichiga joylashtiramiz.

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 va Django-ni sozlash oson: ma'lumotlar bazasini yaratish, foydalanuvchi yaratish, ruxsatlarni sozlash. PostgreSQL-ni dastlab o'rnatishda yodda tutish kerak bo'lgan narsa postgresql-server paketi bilan o'rnatiladigan postgresql-setup skriptidir. Ushbu skript klasterni ishga tushirish yoki yangilash jarayoni kabi ma'lumotlar bazasi klasterini boshqarish bilan bog'liq asosiy vazifalarni bajarishga yordam beradi. RHEL tizimida yangi PostgreSQL namunasini sozlash uchun biz quyidagi buyruqni bajarishimiz kerak:

sudo /usr/bin/postgresql-setup -initdb

Keyin Systemd yordamida PostgreSQLni ishga tushirishingiz, ma'lumotlar bazasini yaratishingiz va Django'da loyihani o'rnatishingiz mumkin. Ilova foydalanuvchisi uchun parolni saqlashni sozlash uchun mijozning autentifikatsiya konfiguratsiya fayliga (odatda pg_hba.conf) oβ€˜zgartirish kiritgandan soβ€˜ng PostgreSQLni qayta ishga tushirishni unutmang. Agar boshqa qiyinchiliklarga duch kelsangiz, pg_hba.conf faylidagi IPv4 va IPv6 sozlamalarini o'zgartirganingizga ishonch hosil qiling.

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 faylida:

# 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 faylida:

# Database
DATABASES = {
   'default': {
       'ENGINE': 'django.db.backends.postgresql_psycopg2',
       'NAME': '{{ db_name }}',
       'USER': '{{ db_user }}',
       'PASSWORD': '{{ db_password }}',
       'HOST': '{{ db_host }}',
   }
}

Loyihada settings.py faylini sozlaganingizdan va ma'lumotlar bazasi konfiguratsiyasini o'rnatganingizdan so'ng, hamma narsa ishlayotganiga ishonch hosil qilish uchun ishlab chiqish serverini ishga tushirishingiz mumkin. Rivojlanish serverini ishga tushirgandan so'ng, ma'lumotlar bazasiga ulanishni sinab ko'rish uchun administrator foydalanuvchisini yaratish yaxshi fikrdir.

./manage.py runserver 0.0.0.0:8000
./manage.py createsuperuser

WSGI? Vay?

Rivojlanish serveri sinov uchun foydalidir, lekin dasturni ishga tushirish uchun veb-server shlyuz interfeysi (WSGI) uchun tegishli server va proksi-serverni sozlashingiz kerak. Bir nechta umumiy kombinatsiyalar mavjud, masalan, uWSGI bilan Apache HTTPD yoki Gunicorn bilan Nginx.

Veb-server shlyuzi interfeysining vazifasi veb-serverdan so'rovlarni Python veb-ramkalariga yo'naltirishdir. WSGI - bu CGI dvigatellari mavjud bo'lgan dahshatli o'tmishning yodgorligi va bugungi kunda WSGI ishlatiladigan veb-server yoki Python ramkasidan qat'i nazar, de-fakto standartdir. Ammo keng qo'llanilishiga qaramay, ushbu ramkalar bilan ishlashda hali ko'p nuanslar va ko'plab tanlovlar mavjud. Bunday holda, biz Gunicorn va Nginx o'rtasida rozetka orqali o'zaro aloqani o'rnatishga harakat qilamiz.

Ushbu komponentlarning ikkalasi ham bitta serverda o'rnatilganligi sababli, tarmoq rozetkasi o'rniga UNIX soketidan foydalanishga harakat qilaylik. Aloqa har qanday holatda ham rozetkani talab qilganligi sababli, keling, yana bir qadam tashlab, Gunicorn uchun rozetkani faollashtirishni systemd orqali sozlashga harakat qilaylik.

Soket faollashtirilgan xizmatlarni yaratish jarayoni juda oddiy. Birinchidan, UNIX rozetkasi yaratiladigan nuqtaga ishora qiluvchi ListenStream direktivasini o'z ichiga olgan birlik fayli yaratiladi, so'ngra Requires direktivasi rozetka birligi fayliga ishora qiladigan xizmat uchun birlik fayli. Keyin, xizmat ko'rsatish birligi faylida faqat virtual muhitdan Gunicorn-ga qo'ng'iroq qilish va UNIX soketi va Django ilovasi uchun WSGI ulanishini yaratish qoladi.

Bu erda siz asos sifatida foydalanishingiz mumkin bo'lgan birlik fayllariga ba'zi misollar keltirilgan. Avval biz rozetkani o'rnatamiz.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Endi siz Gunicorn demonini sozlashingiz kerak.

[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 uchun proksi-server konfiguratsiya fayllarini yaratish va agar foydalanayotgan bo'lsangiz, statik tarkibni saqlash uchun katalogni o'rnatish oddiy masala. RHEL da Nginx konfiguratsiya fayllari /etc/nginx/conf.d da joylashgan. Quyidagi misolni /etc/nginx/conf.d/default.conf fayliga nusxalashingiz va xizmatni ishga tushirishingiz mumkin. server_name ni xost nomiga mos keladigan qilib o'rnatganingizga ishonch hosil qiling.

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;
   }
}

Systemd-dan foydalanib Gunicorn rozetkasini va Nginx-ni ishga tushiring va siz sinovni boshlashga tayyormiz.

Yomon Gateway xatosi?

Agar siz manzilni brauzeringizga kiritsangiz, siz 502 Bad Gateway xatosini olasiz. Bunga noto'g'ri sozlangan UNIX soket ruxsatnomalari sabab bo'lishi mumkin yoki SELinux-da kirishni boshqarish bilan bog'liq murakkabroq muammolar sabab bo'lishi mumkin.

Nginx xato jurnalida siz shunday qatorni ko'rishingiz mumkin:

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"

Agar biz Gunicorn-ni to'g'ridan-to'g'ri sinab ko'rsak, biz bo'sh javob olamiz.

curl β€”unix-socket /run/gunicorn.sock 8beta1.example.com

Keling, nima uchun bu sodir bo'lishini aniqlaylik. Agar siz jurnalni ochsangiz, muammo SELinux bilan bog'liqligini ko'rasiz. Biz hech qanday siyosat yaratilmagan demonni ishga tushirganimiz uchun u init_t sifatida belgilangan. Keling, ushbu nazariyani amalda sinab ko'ramiz.

sudo setenforce 0

Bularning barchasi tanqid va qon ko'z yoshlariga olib kelishi mumkin, ammo bu prototipni tuzatishdir. Muammo shu ekanligiga ishonch hosil qilish uchun chekni o'chirib qo'yamiz, shundan so'ng biz hamma narsani o'z joyiga qaytaramiz.

Brauzerda sahifani yangilash yoki curl buyrug'imizni qayta ishga tushirish orqali siz Django test sahifasini ko'rishingiz mumkin.

Shunday qilib, hamma narsa ishlayotganiga va ruxsat berish bilan bog'liq muammolar yo'qligiga ishonch hosil qilib, biz SELinux-ni qayta yoqamiz.

sudo setenforce 1

Bu yerda men audit2allow yoki sepolgen bilan ogohlantirishga asoslangan siyosatlar yaratish haqida gapirmayman, chunki hozirda Django ilovasi mavjud emas, shuning uchun Gunicorn nimaga kirishni xohlashi va nimalarga kirishni rad etishi kerakligi haqida toΚ»liq xarita yoΚ»q. Shu sababli, tizimni himoya qilish uchun SELinux-ning ishlashini davom ettirish kerak, shu bilan birga dasturni ishga tushirishga va audit jurnalida xabarlar qoldirishga ruxsat berish kerak, shunda ulardan haqiqiy siyosat yaratilishi mumkin.

Ruxsat berilgan domenlarni belgilash

SELinux-da ruxsat etilgan domenlar haqida hamma ham eshitmagan, ammo ular yangilik emas. Ko'pchilik hatto o'zlari ham sezmasdan ular bilan ishladilar. Audit xabarlari asosida siyosat yaratilganda, yaratilgan siyosat hal qilingan domenni ifodalaydi. Keling, oddiy ruxsat berish siyosatini yaratishga harakat qilaylik.

Gunicorn uchun ma'lum ruxsat etilgan domenni yaratish uchun sizga qandaydir siyosat kerak, shuningdek, tegishli fayllarni belgilashingiz kerak. Bundan tashqari, yangi siyosatlarni yig'ish uchun vositalar kerak.

sudo yum install selinux-policy-devel

Ruxsat etilgan domenlar mexanizmi muammolarni aniqlash uchun ajoyib vositadir, ayniqsa maxsus dastur yoki allaqachon yaratilgan siyosatlarsiz yuboriladigan ilovalar haqida gap ketganda. Bunday holda, Gunicorn uchun ruxsat etilgan domen siyosati iloji boricha sodda bo'ladi - asosiy turni e'lon qiling (gunicorn_t), biz bir nechta bajariladigan fayllarni belgilash uchun foydalanadigan turni e'lon qiling (gunicorn_exec_t) va tizimni to'g'ri belgilash uchun o'tishni o'rnating. ishlaydigan jarayonlar. Oxirgi satr siyosatni yuklangan paytda sukut bo'yicha yoqilgandek o'rnatadi.

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;

Siz ushbu siyosat faylini kompilyatsiya qilishingiz va uni tizimingizga qo'shishingiz mumkin.

make -f /usr/share/selinux/devel/Makefile
sudo semodule -i gunicorn.pp

sudo semanage permissive -a gunicorn_t
sudo semodule -l | grep permissive

Keling, SELinux bizning noma'lum daemonimiz kirayotgan narsadan boshqa narsani bloklayaptimi yoki yo'qligini tekshirib ko'raylik.

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-ni Gunicorn tomonidan ishlatiladigan UNIX soketiga ma'lumotlarni yozishni oldini oladi. Odatda, bunday hollarda siyosat o'zgara boshlaydi, ammo oldinda boshqa muammolar ham bor. Shuningdek, siz domen sozlamalarini cheklash domenidan ruxsat domeniga o'zgartirishingiz mumkin. Endi httpd_t ni ruxsatlar domeniga o'tkazamiz. Bu Nginx-ga kerakli ruxsatni beradi va biz keyingi disk raskadrovka ishlarini davom ettirishimiz mumkin.

sudo semanage permissive -a httpd_t

Shunday qilib, siz SELinux-ni himoyalangan saqlashga muvaffaq bo'lganingizdan so'ng (siz SELinux loyihasini cheklangan rejimda qoldirmasligingiz kerak) va ruxsat domenlari yuklangandan so'ng, hamma narsa to'g'ri ishlashi uchun gunicorn_exec_t sifatida aniq nima belgilanishi kerakligini aniqlashingiz kerak. yana. Keling, kirish cheklovlari haqida yangi xabarlarni ko'rish uchun veb-saytga tashrif buyurishga harakat qilaylik.

sudo ausearch -m AVC -c gunicorn

Siz /srv/djangoapp-dagi fayllarda turli xil ishlarni bajaradigan 'comm="gunicorn"' ni o'z ichiga olgan juda ko'p xabarlarni ko'rasiz, shuning uchun bu belgilanishi kerak bo'lgan buyruqlardan biri ekanligi aniq.

Ammo qo'shimcha ravishda, shunga o'xshash xabar paydo bo'ladi:

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

Agar siz gunicorn xizmatining holatiga qarasangiz yoki ps buyrug'ini ishga tushirsangiz, ishlaydigan jarayonlarni ko'rmaysiz. Gunicorn virtual muhitimizdagi Python tarjimoniga kirishga, ehtimol ishchi skriptlarni ishga tushirishga harakat qilayotganga o'xshaydi. Endi keling, ushbu ikkita bajariladigan faylni belgilaymiz va Django test sahifamizni ochishimiz mumkinligini tekshiramiz.

chcon -t gunicorn_exec_t /srv/djangoapp/django/bin/gunicorn /srv/djangoapp/django/bin/python3.6

Yangi tegni tanlashdan oldin gunicorn xizmatini qayta ishga tushirish kerak bo'ladi. Siz uni darhol qayta ishga tushirishingiz yoki xizmatni to'xtatishingiz va saytni brauzerda ochganingizda rozetkaga uni ishga tushirishga ruxsat berishingiz mumkin. ps yordamida jarayonlar to'g'ri teglarni olganligini tekshiring.

ps -efZ | grep gunicorn

Keyinchalik oddiy SELinux siyosatini yaratishni unutmang!

Agar siz hozir AVC xabarlarini ko'rsangiz, oxirgi xabarda ilova bilan bog'liq bo'lgan barcha narsalar uchun ruxsat beruvchi = 1 va tizimning qolgan qismi uchun ruxsat beruvchi = 0 mavjud. Haqiqiy dasturga qanday kirish kerakligini tushunsangiz, bunday muammolarni hal qilishning eng yaxshi usulini tezda topishingiz mumkin. Ammo shu vaqtgacha tizimni xavfsiz saqlash va Django loyihasining aniq, foydali auditini olish yaxshiroqdir.

sudo ausearch -m AVC

Bo'ldi!

Nginx va Gunicorn WSGI-ga asoslangan frontend bilan ishlaydigan Django loyihasi paydo bo'ldi. Biz RHEL 3 Beta repozitariylaridan Python 10 va PostgreSQL 8 ni sozladik. Endi siz oldinga siljishingiz va Django ilovalarini yaratishingiz (yoki oddiygina joylashtirishingiz) yoki konfiguratsiya jarayonini avtomatlashtirish, unumdorlikni oshirish yoki hatto ushbu konfiguratsiyani konteynerga joylashtirish uchun RHEL 8 Beta-dagi boshqa mavjud vositalarni o'rganishingiz mumkin.

Manba: www.habr.com

a Izoh qo'shish