Workshop RHEL 8 Beta: Ndërtimi i aplikacioneve që punojnë në ueb

RHEL 8 Beta u ofron zhvilluesve shumë veçori të reja, renditja e të cilave mund të marrë faqe, megjithatë, mësimi i gjërave të reja është gjithmonë më i mirë në praktikë, kështu që më poshtë ofrojmë një seminar për krijimin e vërtetë të një infrastrukture aplikacioni bazuar në Red Hat Enterprise Linux 8 Beta.

Workshop RHEL 8 Beta: Ndërtimi i aplikacioneve që punojnë në ueb

Le të marrim Python, një gjuhë programimi popullore midis zhvilluesve, si bazë, një kombinim i Django dhe PostgreSQL, një kombinim mjaft i zakonshëm për krijimin e aplikacioneve dhe konfigurojmë RHEL 8 Beta për të punuar me to. Më pas do të shtojmë disa përbërës të tjerë (të paklasifikuar).

Mjedisi i provës do të ndryshojë, sepse është interesante të eksplorohen mundësitë e automatizimit, të punës me kontejnerë dhe të testimit të mjediseve me serverë të shumtë. Për të filluar me një projekt të ri, mund të filloni duke krijuar një prototip të vogël e të thjeshtë me dorë, në mënyrë që të shihni saktësisht se çfarë duhet të ndodhë dhe si ndërvepron, dhe më pas të kaloni te automatizimi dhe të krijoni konfigurime më komplekse. Sot po flasim për krijimin e një prototipi të tillë.

Le të fillojmë duke vendosur imazhin RHEL 8 Beta VM. Mund të instaloni një makinë virtuale nga e para, ose të përdorni imazhin e mysafirit KVM të disponueshëm me pajtimin tuaj Beta. Kur përdorni një imazh të ftuar, do t'ju duhet të konfiguroni një CD virtuale që do të përmbajë meta të dhëna dhe të dhëna të përdoruesit për inicializimin e cloud (cloud-init). Ju nuk keni nevojë të bëni ndonjë gjë të veçantë me strukturën e diskut ose paketat e disponueshme; çdo konfigurim do të funksionojë.

Le të hedhim një vështrim më të afërt në të gjithë procesin.

Instalimi i Django

Me versionin më të ri të Django, do t'ju duhet një mjedis virtual (virtualenv) me Python 3.5 ose më vonë. Në shënimet Beta mund të shihni se Python 3.6 është i disponueshëm, le të kontrollojmë nëse është me të vërtetë kështu:

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

Red Hat përdor në mënyrë aktive Python si një grup mjetesh sistemi në RHEL, kështu që pse rezulton kjo?

Fakti është se shumë zhvillues të Python janë ende duke menduar për kalimin nga Python 2 në Python 2, ndërsa vetë Python 3 është në zhvillim aktiv dhe gjithnjë e më shumë versione të reja shfaqen vazhdimisht. Prandaj, për të plotësuar nevojën për mjete të qëndrueshme të sistemit duke u ofruar përdoruesve akses në versione të ndryshme të reja të Python, sistemi Python u zhvendos në një paketë të re dhe ofroi mundësinë për të instaluar të dy Python 2.7 dhe 3.6. Më shumë informacion në lidhje me ndryshimet dhe pse ato janë bërë mund të gjenden në publikimin në Blogu i Langdon White (Langdon White).

Pra, për të funksionuar Python, ju duhet vetëm të instaloni dy paketa, me python3-pip të përfshirë si një varësi.

sudo yum install python36 python3-virtualenv

Pse të mos përdorni thirrje direkte të modulit siç sugjeron Langdon dhe të instaloni pip3? Duke pasur parasysh automatizimin e ardhshëm, dihet se Ansible do të kërkojë të instaluar pip për të ekzekutuar, pasi moduli pip nuk mbështet virtualenvs me një ekzekutues të personalizuar pip.

Me një përkthyes python3 në dispozicionin tuaj, ju mund të vazhdoni me procesin e instalimit të Django dhe të keni një sistem pune së bashku me komponentët tanë të tjerë. Ka shumë opsione zbatimi të disponueshme në internet. Ekziston një version i paraqitur këtu, por përdoruesit mund të përdorin proceset e tyre.

Ne do të instalojmë versionet PostgreSQL dhe Nginx të disponueshme në RHEL 8 si parazgjedhje duke përdorur Yum.

sudo yum install nginx postgresql-server

PostgreSQL do të kërkojë psycopg2, por duhet të jetë i disponueshëm vetëm në një mjedis virtualenv, kështu që ne do ta instalojmë duke përdorur pip3 së bashku me Django dhe Gunicorn. Por së pari duhet të konfigurojmë virtualenv.

Gjithmonë ka shumë debate mbi temën e zgjedhjes së vendit të duhur për instalimin e projekteve Django, por kur dyshoni, gjithmonë mund t'i drejtoheni Standardit të Hierarkisë së Skedarëve Linux. Në mënyrë të veçantë, FHS thotë se /srv përdoret për të: "ruajtur të dhëna specifike të hostit - të dhëna që prodhon sistemi, të tilla si të dhënat dhe skriptet e serverit në ueb, të dhënat e ruajtura në serverët FTP dhe depot e sistemit të kontrollit." versionet (që shfaqen në FHS -2.3 në 2004).

Ky është pikërisht rasti ynë, kështu që ne vendosim gjithçka që na nevojitet në /srv, e cila është në pronësi të përdoruesit të aplikacionit tonë (cloud-user).

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

Vendosja e PostgreSQL dhe Django është e lehtë: krijoni një bazë të dhënash, krijoni një përdorues, konfiguroni lejet. Një gjë që duhet mbajtur parasysh kur instaloni fillimisht PostgreSQL është skripti postgresql-setup që instalohet me paketën postgresql-server. Ky skrip ju ndihmon të kryeni detyrat bazë që lidhen me administrimin e grupit të bazës së të dhënave, të tilla si inicializimi i grupit ose procesi i përmirësimit. Për të konfiguruar një shembull të ri PostgreSQL në një sistem RHEL, duhet të ekzekutojmë komandën:

sudo /usr/bin/postgresql-setup -initdb

Më pas mund të nisni PostgreSQL duke përdorur systemd, të krijoni një bazë të dhënash dhe të vendosni një projekt në Django. Mos harroni të rinisni PostgreSQL pasi të bëni ndryshime në skedarin e konfigurimit të vërtetimit të klientit (zakonisht pg_hba.conf) për të konfiguruar ruajtjen e fjalëkalimit për përdoruesin e aplikacionit. Nëse hasni vështirësi të tjera, sigurohuni që të ndryshoni cilësimet IPv4 dhe IPv6 në skedarin 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

Në skedarin /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

Në skedarin /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 }}',
   }
}

Pas konfigurimit të skedarit settings.py në projekt dhe konfigurimit të konfigurimit të bazës së të dhënave, mund të nisni serverin e zhvillimit për t'u siguruar që gjithçka funksionon. Pas fillimit të serverit të zhvillimit, është mirë të krijoni një përdorues admin për të testuar lidhjen me bazën e të dhënave.

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

WSGI? Uai?

Serveri i zhvillimit është i dobishëm për testim, por për të ekzekutuar aplikacionin duhet të konfiguroni serverin dhe përfaqësuesin e duhur për ndërfaqen e portës së serverit ueb (WSGI). Ka disa kombinime të zakonshme, për shembull, Apache HTTPD me uWSGI ose Nginx me Gunicorn.

Puna e Ndërfaqes së Portës së Serverit të Uebit është të përcjellë kërkesat nga serveri i uebit në kornizën e uebit të Python. WSGI është një relike e së kaluarës së tmerrshme kur motorët CGI ishin përreth, dhe sot WSGI është standardi de fakto, pavarësisht nga serveri në internet ose kuadri Python i përdorur. Por pavarësisht përdorimit të gjerë të tij, ka ende shumë nuanca kur punoni me këto korniza dhe shumë zgjedhje. Në këtë rast, ne do të përpiqemi të krijojmë ndërveprim midis Gunicorn dhe Nginx përmes një prize.

Meqenëse të dy këta komponentë janë instaluar në të njëjtin server, le të provojmë të përdorim një fole UNIX në vend të një prize rrjeti. Meqenëse komunikimi kërkon një prizë në çdo rast, le të përpiqemi të bëjmë një hap më shumë dhe të konfigurojmë aktivizimin e prizës për Gunicorn nëpërmjet systemd.

Procesi i krijimit të shërbimeve të aktivizuara nga priza është mjaft i thjeshtë. Së pari, krijohet një skedar njësi që përmban një direktivë ListenStream që tregon pikën në të cilën do të krijohet foleja UNIX, më pas një skedar njësi për shërbimin në të cilin direktiva Requires do të tregojë në skedarin e njësisë së folesë. Më pas, në skedarin e njësisë së shërbimit, gjithçka që mbetet është të telefononi Gunicorn nga mjedisi virtual dhe të krijoni një lidhje WSGI për folenë UNIX dhe aplikacionin Django.

Këtu janë disa shembuj të skedarëve të njësive që mund t'i përdorni si bazë. Së pari vendosim prizën.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Tani ju duhet të konfiguroni demonin 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

Për Nginx, është një çështje e thjeshtë krijimi i skedarëve të konfigurimit të proxy dhe vendosja e një drejtorie për të ruajtur përmbajtje statike nëse jeni duke përdorur një të tillë. Në RHEL, skedarët e konfigurimit Nginx ndodhen në /etc/nginx/conf.d. Mund të kopjoni shembullin e mëposhtëm në skedarin /etc/nginx/conf.d/default.conf dhe të nisni shërbimin. Sigurohuni që të vendosni emrin e serverit që të përputhet me emrin tuaj të hostit.

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

Nisni prizën Gunicorn dhe Nginx duke përdorur systemd dhe jeni gati për të filluar testimin.

Gabim i keq i portës?

Nëse futni adresën në shfletuesin tuaj, me shumë mundësi do të merrni një gabim 502 Bad Gateway. Mund të shkaktohet nga lejet e foleve UNIX të konfiguruara gabimisht, ose mund të jetë për shkak të çështjeve më komplekse që lidhen me kontrollin e aksesit në SELinux.

Në regjistrin e gabimeve nginx mund të shihni një linjë si kjo:

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"

Nëse e testojmë drejtpërdrejt Gunicorn, do të marrim një përgjigje boshe.

curl —unix-socket /run/gunicorn.sock 8beta1.example.com

Le të kuptojmë pse ndodh kjo. Nëse hapni regjistrin, me shumë mundësi do të shihni se problemi lidhet me SELinux. Meqenëse po ekzekutojmë një demon për të cilin nuk është krijuar asnjë politikë, ai është shënuar si init_t. Le ta testojmë këtë teori në praktikë.

sudo setenforce 0

E gjithë kjo mund të shkaktojë kritika dhe lot gjaku, por kjo është vetëm debugim i prototipit. Le të çaktivizojmë kontrollin vetëm për t'u siguruar që ky është problemi, pas së cilës do të kthejmë gjithçka në vendin e vet.

Duke rifreskuar faqen në shfletues ose duke ri ekzekutuar komandën tonë curl, mund të shihni faqen e testimit të Django.

Pra, duke u siguruar që gjithçka funksionon dhe nuk ka më probleme me lejet, ne aktivizojmë përsëri SELinux.

sudo setenforce 1

Nuk do të flas për audit2allow ose krijimin e politikave të bazuara në alarm me sepolgen këtu, pasi nuk ka asnjë aplikacion aktual Django për momentin, kështu që nuk ka një hartë të plotë të asaj që Gunicorn mund të dëshirojë të ketë akses dhe në çfarë duhet të refuzojë aksesin. Prandaj, është e nevojshme që SELinux të vazhdojë të funksionojë për të mbrojtur sistemin, ndërsa në të njëjtën kohë lejohet që aplikacioni të ekzekutohet dhe të lërë mesazhe në regjistrin e auditimit, në mënyrë që të krijohet politika aktuale prej tyre.

Specifikimi i domeneve lejuese

Jo të gjithë kanë dëgjuar për domenet e lejuara në SELinux, por ato nuk janë asgjë e re. Shumë madje kanë punuar me ta pa e kuptuar. Kur një politikë krijohet bazuar në mesazhet e auditimit, politika e krijuar përfaqëson domenin e zgjidhur. Le të përpiqemi të krijojmë një politikë të thjeshtë lejeje.

Për të krijuar një domen specifik të lejuar për Gunicorn, ju nevojitet një lloj politike dhe gjithashtu duhet të shënoni skedarët e duhur. Përveç kësaj, nevojiten mjete për të mbledhur politika të reja.

sudo yum install selinux-policy-devel

Mekanizmi i domeneve të lejuara është një mjet i shkëlqyeshëm për identifikimin e problemeve, veçanërisht kur bëhet fjalë për një aplikacion të personalizuar ose aplikacione që dërgohen pa politika të krijuara tashmë. Në këtë rast, politika e lejuar e domenit për Gunicorn do të jetë sa më e thjeshtë që të jetë e mundur - deklaroni një lloj kryesor (gunicorn_t), deklaroni një lloj që do të përdorim për të shënuar ekzekutues të shumtë (gunicorn_exec_t) dhe më pas vendosni një tranzicion që sistemi të shënojë saktë proceset e ekzekutimit. Rreshti i fundit e vendos politikën si të aktivizuar si parazgjedhje në momentin që ngarkohet.

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;

Ju mund ta përpiloni këtë skedar politikash dhe ta shtoni në sistemin tuaj.

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

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

Le të kontrollojmë për të parë nëse SELinux po bllokon diçka tjetër përveç asaj që ka qasje demoni ynë i panjohur.

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 parandalon që Nginx të shkruajë të dhëna në folenë UNIX të përdorur nga Gunicorn. Në mënyrë tipike, në raste të tilla, politikat fillojnë të ndryshojnë, por ka sfida të tjera përpara. Ju gjithashtu mund të ndryshoni cilësimet e domenit nga një domen kufizimi në një domen leje. Tani le të zhvendosim httpd_t në domenin e lejeve. Kjo do t'i japë Nginx qasjen e nevojshme dhe ne mund të vazhdojmë me punën e mëtejshme të korrigjimit.

sudo semanage permissive -a httpd_t

Pra, pasi të keni arritur të mbani SELinux të mbrojtur (nuk duhet të lini një projekt SELinux në modalitetin e kufizuar) dhe domenet e lejeve janë ngarkuar, duhet të kuptoni se çfarë saktësisht duhet të shënohet si gunicorn_exec_t që gjithçka të funksionojë siç duhet. përsëri. Le të përpiqemi të vizitojmë faqen e internetit për të parë mesazhe të reja rreth kufizimeve të aksesit.

sudo ausearch -m AVC -c gunicorn

Do të shihni shumë mesazhe që përmbajnë 'comm="gunicorn"' që bëjnë gjëra të ndryshme në skedarë në /srv/djangoapp, kështu që kjo është padyshim një nga komandat që ia vlen të raportohet.

Por përveç kësaj, shfaqet një mesazh si ky:

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

Nëse shikoni statusin e shërbimit gunicorn ose ekzekutoni komandën ps, nuk do të shihni asnjë proces të ekzekutimit. Duket sikur gunicorn po përpiqet të hyjë në interpretuesin Python në mjedisin tonë virtualenv, ndoshta për të ekzekutuar skriptet e punëtorëve. Pra, tani le t'i shënojmë këto dy skedarë të ekzekutueshëm dhe të kontrollojmë nëse mund të hapim faqen tonë të testit Django.

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

Shërbimi Gunicorn do të duhet të riniset përpara se të zgjidhet etiketa e re. Mund ta rinisni menjëherë ose të ndaloni shërbimin dhe ta lini prizën ta fillojë kur hapni sajtin në shfletues. Verifikoni që proceset të kenë marrë etiketat e sakta duke përdorur ps.

ps -efZ | grep gunicorn

Mos harroni të krijoni një politikë normale SELinux më vonë!

Nëse shikoni mesazhet AVC tani, mesazhi i fundit përmban lejues=1 për gjithçka që lidhet me aplikacionin dhe lejues=0 për pjesën tjetër të sistemit. Nëse e kuptoni se çfarë lloj aksesi ka nevojë për një aplikacion të vërtetë, mund të gjeni shpejt mënyrën më të mirë për të zgjidhur probleme të tilla. Por deri atëherë, është më mirë ta mbani sistemin të sigurt dhe të merrni një auditim të qartë dhe të përdorshëm të projektit Django.

sudo ausearch -m AVC

Ndodhi!

Një projekt funksional Django është shfaqur me një frontend të bazuar në Nginx dhe Gunicorn WSGI. Ne konfiguruam Python 3 dhe PostgreSQL 10 nga magazinat RHEL 8 Beta. Tani mund të ecësh përpara dhe të krijosh (ose thjesht të vendosësh) aplikacione Django ose të eksplorosh mjete të tjera të disponueshme në RHEL 8 Beta për të automatizuar procesin e konfigurimit, për të përmirësuar performancën ose edhe për të kontejneruar këtë konfigurim.

Burimi: www.habr.com

Shto një koment