Семинари RHEL 8 Beta: Сохтани барномаҳои корӣ

RHEL 8 Beta ба таҳиягарон бисёр хусусиятҳои навро пешниҳод мекунад, ки номгӯи онҳо метавонад саҳифаҳоро дар бар гирад, аммо омӯхтани чизҳои нав дар амал ҳамеша беҳтар аст, аз ин рӯ дар зер мо семинарро оид ба воқеан сохтани инфрасохтори барномаҳо дар асоси Red Hat Enterprise Linux 8 Beta пешниҳод менамоем.

Семинари RHEL 8 Beta: Сохтани барномаҳои корӣ

Биёед Python, забони маъмули барномасозӣ дар байни таҳиягаронро ҳамчун як омезиши Django ва PostgreSQL, комбинатсияи хеле маъмул барои эҷоди барномаҳо гирем ва RHEL 8 Beta-ро барои кор бо онҳо танзим кунем. Сипас, мо якчанд компонентҳои дигар (таснифнашуда) илова мекунем.

Муҳити санҷиш тағир хоҳад ёфт, зеро омӯхтани имкониятҳои автоматикунонӣ, кор бо контейнерҳо ва озмоиши муҳитҳо бо серверҳои сершумор ҷолиб аст. Барои оғоз кардани лоиҳаи нав, шумо метавонед бо эҷоди як прототипи хурд ва оддии дастӣ оғоз кунед, то бидонед, ки чӣ рӯй додан лозим аст ва чӣ гуна он мутақобила мекунад ва сипас ба автоматизатсия ва сохтани конфигуратсияҳои мураккабтар гузаред. Имруз мо дар бораи офаридани чунин прототип сухан меронем.

Биёед бо ҷойгиркунии тасвири RHEL 8 Beta VM оғоз кунем. Шумо метавонед як мошини виртуалиро аз сифр насб кунед ё тасвири меҳмони KVM-ро, ки бо обунаи Beta-и шумо дастрас аст, истифода баред. Ҳангоми истифодаи тасвири меҳмон, шумо бояд CD-и виртуалиро танзим кунед, ки дорои метамаълумотҳо ва маълумоти корбар барои оғозкунии абр (cloud-init) бошад. Ба шумо лозим нест, ки бо сохтори диск ё бастаҳои дастрас ягон кори махсус анҷом диҳед; ҳама гуна конфигуратсия иҷро мешавад.

Биёед тамоми равандро муфассалтар дида бароем.

Насб кардани Django

Бо версияи навтарини 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 2 фикр мекунанд, дар ҳоле ки худи Python 3 дар ҳоли таҳияи фаъол аст ва версияҳои бештари нав пайваста пайдо мешаванд. Аз ин рӯ, барои қонеъ кардани ниёз ба абзорҳои устувори система ҳангоми пешниҳоди дастрасӣ ба корбарон ба версияҳои нави Python, системаи Python ба бастаи нав интиқол дода шуд ва имкон дод, ки ҳам Python 2.7 ва 3.6 насб кунад. Маълумоти бештарро дар бораи тағирот ва чаро онҳо дар ин нашрия пайдо кардан мумкин аст Блоги Лангдон Уайт (Лангдон Уайт).

Ҳамин тавр, барои кор кардани Python, шумо бояд танҳо ду бастаро насб кунед, ки python3-pip ҳамчун вобастагӣ дохил карда шудаанд.

sudo yum install python36 python3-virtualenv

Чаро зангҳои мустақими модулро тавре ки Лэнгдон пешниҳод мекунад, истифода набаред ва pip3-ро насб кунед? Бо дарназардошти автоматизатсияи дарпешистода, маълум аст, ки Ansible барои кор кардани pip насбшударо талаб мекунад, зеро модули pip virtualenvҳоро бо иҷрошавандаи фармоишии pip дастгирӣ намекунад.

Бо тарҷумони кории 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-server насб шудааст. Ин скрипт ба шумо кӯмак мекунад, ки вазифаҳои асосии марбут ба маъмурияти кластери пойгоҳи додаҳо, ба монанди оғозкунии кластер ё раванди навсозӣ. Барои танзим кардани мисоли нави PostgreSQL дар системаи RHEL, мо бояд фармонро иҷро кунем:

sudo /usr/bin/postgresql-setup -initdb

Пас шумо метавонед PostgreSQL-ро бо истифода аз systemd оғоз кунед, пойгоҳи додаҳо эҷод кунед ва лоиҳаро дар Django насб кунед. Пас аз ворид кардани тағирот ба файли конфигуратсияи аутентификатсияи муштарӣ (одатан pg_hba.conf) барои танзими нигаҳдории парол барои корбари барнома, PostgreSQL-ро бозоғоз намоед. Агар шумо бо дигар мушкилот рӯ ба рӯ шавед, боварӣ ҳосил кунед, ки танзимоти 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? Вой?

Сервери таҳия барои озмоиш муфид аст, аммо барои иҷро кардани барнома шумо бояд сервер ва проксии мувофиқро барои Web Server Gateway Interface (WSGI) танзим кунед. Якчанд комбинатсияи умумӣ мавҷуданд, масалан, Apache HTTPD бо uWSGI ё Nginx бо Gunicorn.

Вазифаи Web Server Gateway Interface ин фиристодани дархостҳо аз сервери веб ба чаҳорчӯбаи веб Python мебошад. WSGI як осори гузаштаи даҳшатборест, ки муҳаррикҳои CGI дар атрофи буданд ва имрӯз WSGI стандарти воқеист, новобаста аз веб-сервер ё чаҳорчӯбаи Python истифода мешавад. Аммо сарфи назар аз истифодаи васеъи он, ҳангоми кор бо ин чаҳорчӯба нозукиҳои зиёд ва интихоби зиёде мавҷуданд. Дар ин ҳолат, мо кӯшиш хоҳем кард, ки байни Gunicorn ва Nginx тавассути розетка ҳамкорӣ кунем.

Азбаски ҳардуи ин ҷузъҳо дар як сервер насб шудаанд, биёед кӯшиш кунем, ки ба ҷои васлаки шабакавӣ васлаки UNIX-ро истифода барем. Азбаски муошират дар ҳама ҳолат розеткаро талаб мекунад, биёед кӯшиш кунем, ки як қадами дигар гузорем ва фаъолсозии розеткаро барои Gunicorn тавассути systemd танзим кунем.

Раванди эҷоди хидматҳои фаъолшудаи розетка хеле содда аст. Аввалан, файли воҳид сохта мешавад, ки дорои директиваи ListenStream мебошад, ки ба нуқтае, ки дар он васлаки UNIX сохта мешавад, ишора мекунад ва баъд файли воҳиди хидмате, ки дар он дастури Requires ба файли воҳиди розетка ишора мекунад. Сипас, дар файли воҳиди хидматрасонӣ танҳо занг задан ба 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 оғоз кунед ва шумо омодаед, ки озмоишро оғоз кунед.

Хатогии Gateway бад?

Агар шумо суроғаро ба браузери худ ворид кунед, шумо эҳтимолан хатои 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 дар муҳити virtualenv мо дастрасӣ пайдо кунад ва эҳтимолан скриптҳои коргариро иҷро кунад. Акнун биёед ин ду файли иҷрошавандаро қайд кунем ва тафтиш кунем, ки оё мо метавонем саҳифаи санҷиши 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 барои автоматикунонии раванди конфигуратсия, беҳтар кардани кор ё ҳатто контейнер кардани ин конфигуратсия омӯхта метавонед.

Манбаъ: will.com

Илова Эзоҳ