RHEL 8 Beta Laborrenkontiĝo: Konstruado de Laborantaj Retaj Aplikaĵoj

RHEL 8 Beta ofertas al programistoj multajn novajn funkciojn, kies listigo povus preni paĝojn, tamen lerni novajn aferojn ĉiam estas pli bona en la praktiko, do ĉi-sube ni proponas laborrenkontiĝon pri efektive krei aplikan infrastrukturon bazitan sur Red Hat Enterprise Linux 8 Beta.

RHEL 8 Beta Laborrenkontiĝo: Konstruado de Laborantaj Retaj Aplikaĵoj

Ni prenu Python, popularan programlingvon inter programistoj, kiel bazon, kombinaĵon de Django kaj PostgreSQL, sufiĉe oftan kombinaĵon por krei aplikojn, kaj agordu RHEL 8 Beta por labori kun ili. Poste ni aldonos kelkajn pliajn (neklasifikitajn) ingrediencojn.

La prova medio ŝanĝiĝos, ĉar estas interese esplori la eblecojn de aŭtomatigo, labori kun ujoj kaj provi mediojn kun pluraj serviloj. Por komenci novan projekton, vi povas komenci kreante malgrandan simplan prototipon permane, por ke vi vidu precize kio devas okazi kaj kiel ĝi interagas, kaj poste pluaŭtomatigi kaj krei pli kompleksajn agordojn. Hodiaŭ ni parolas pri la kreado de tia prototipo.

Ni komencu deplojante la bildon de RHEL 8 Beta VM. Vi povas instali virtualan maŝinon de nulo aŭ uzi la KVM-gastan bildon disponeblan kun via Beta-abono. Kiam vi uzas gastan bildon, vi devos agordi virtualan KD, kiu enhavos metadatenojn kaj uzantajn datumojn por nuba inicialigo (cloud-init). Vi ne bezonas fari ion specialan kun la diska strukturo aŭ disponeblaj pakaĵoj; ajna agordo taŭgos.

Ni rigardu pli detale la tutan procezon.

Instalante Django

Kun la plej nova versio de Django, vi bezonos virtualan medion (virtualenv) kun Python 3.5 aŭ poste. En la Beta-notoj vi povas vidi, ke Python 3.6 estas disponebla, ni kontrolu ĉu ĉi tio efektive estas la kazo:

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

Red Hat aktive uzas Python kiel sisteman ilaron en RHEL, do kial tio rezultas?

Fakte, multaj programistoj de Python ankoraŭ pripensas la transiron de Python 2 al Python 2, dum Python 3 mem estas aktiva disvolviĝo, kaj pli kaj pli da novaj versioj konstante aperas. Tial, por renkonti la bezonon de stabilaj sistemaj iloj dum proponante al uzantoj aliron al diversaj novaj versioj de Python, la sistemo Python estis proponita en novan pakaĵon kaj disponigis la kapablon instali kaj Python 2.7 kaj 3.6. Pliaj informoj pri la ŝanĝoj kaj kial ili estis faritaj troveblas en la publikigo en la blogo de Langdon White (Langdon White).

Do, por funkcii Python, vi nur bezonas instali du pakaĵojn, kun python3-pip inkluzivita kiel dependeco.

sudo yum install python36 python3-virtualenv

Kial ne uzi rektajn modulvokojn kiel Langdon sugestas kaj instali pip3? Konsiderante la venontan aŭtomatigon, oni scias, ke Ansible postulos pip instalitan por funkcii, ĉar la pip-modulo ne subtenas virtualenv-ojn kun laŭmenda pip rulebla.

Kun funkcianta python3 interpretisto je via dispono, vi povas daŭrigi kun la instalado de Django kaj havi funkciantan sistemon kune kun niaj aliaj komponantoj. Estas multaj efektivigeblecoj haveblaj en la Interreto. Estas unu versio prezentita ĉi tie, sed uzantoj povas uzi siajn proprajn procezojn.

Ni instalos la versiojn PostgreSQL kaj Nginx disponeblajn en RHEL 8 defaŭlte uzante Yum.

sudo yum install nginx postgresql-server

PostgreSQL postulos psycopg2, sed ĝi devas esti disponebla nur en virtualenv-medio, do ni instalos ĝin uzante pip3 kune kun Django kaj Gunicorn. Sed unue ni devas agordi virtualenv.

Ĉiam estas multe da debato pri la temo elekti la ĝustan lokon por instali Django-projektojn, sed kiam vi dubas, vi ĉiam povas turni sin al la Linuksa Dosiera Hierarkia Normo. Specife, la FHS diras, ke /srv estas uzata por: "stoki gastigantajn specifajn datumojn—datenojn, kiujn la sistemo produktas, kiel retservilaj datumoj kaj skriptoj, datumoj stokitaj sur FTP-serviloj, kaj kontrolaj sistemdeponejoj." versioj (aperantaj en FHS). —2.3 en 2004)."

Ĝuste ĉi tio estas nia kazo, do ni metas ĉion, kion ni bezonas en /srv, kiu estas posedata de nia aplikaĵuzanto (nubo-uzanto).

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

Agordi PostgreSQL kaj Django estas facila: krei datumbazon, krei uzanton, agordi permesojn. Unu afero, kiun oni devas memori, kiam oni komence instalas PostgreSQL, estas la postgresql-setup-skripto, kiu estas instalita kun la pako postgresql-servilo. Ĉi tiu skripto helpas vin plenumi bazajn taskojn asociitajn kun administrado de datumbazoj, kiel la inicialigo de la grapo aŭ la ĝisdatiga procezo. Por agordi novan PostgreSQL-instancon en RHEL-sistemo, ni devas ruli la komandon:

sudo /usr/bin/postgresql-setup -initdb

Vi tiam povas komenci PostgreSQL per systemd, krei datumbazon kaj starigi projekton en Django. Memoru rekomenci PostgreSQL post fari ŝanĝojn al la agorda dosiero de kliento-aŭtentikigo (kutime pg_hba.conf) por agordi pasvortan stokadon por la aplikaĵuzanto. Se vi renkontas aliajn malfacilaĵojn, nepre ŝanĝi la agordojn de IPv4 kaj IPv6 en la dosiero 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

En la dosiero /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

En la dosiero /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 }}',
   }
}

Post agordo de la dosiero settings.py en la projekto kaj agordo de la datumbaza agordo, vi povas komenci la evoluservilon por certigi, ke ĉio funkcias. Post lanĉo de la evoluservilo, estas bona ideo krei administran uzanton por testi la konekton al la datumbazo.

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

WSGI? Wai?

La disvolva servilo estas utila por testado, sed por ruli la aplikaĵon vi devas agordi la taŭgan servilon kaj prokurilon por la Interfaco de RetServilo-Enirejo (WSGI). Estas pluraj komunaj kombinaĵoj, ekzemple, Apache HTTPD kun uWSGI aŭ Nginx kun Gunicorn.

La tasko de la Reta Servila Enireja Interfaco estas plusendi petojn de la retservilo al la retkadro de Python. WSGI estas restaĵo de la terura pasinteco kiam CGI-motoroj estis ĉirkaŭe, kaj hodiaŭ WSGI estas la fakta normo, sendepende de la retservilo aŭ Python-kadro uzata. Sed malgraŭ ĝia disvastigita uzo, ankoraŭ estas multaj nuancoj kiam oni laboras kun ĉi tiuj kadroj, kaj multaj elektoj. En ĉi tiu kazo, ni provos establi interagadon inter Gunicorn kaj Nginx per ingo.

Ĉar ambaŭ ĉi tiuj komponantoj estas instalitaj sur la sama servilo, ni provu uzi UNIX-ingon anstataŭ retan ingon. Ĉar komunikado ĉiukaze postulas ingon, ni provu fari unu plian paŝon kaj agordi aktivigon de ingo por Gunicorn per systemd.

La procezo de kreado de socket aktivigitaj servoj estas sufiĉe simpla. Unue, unuodosiero estas kreita kiu enhavas ListenStream direktivon montranta al la punkto ĉe kiu la UNIX ingo estos kreita, tiam unuodosiero por la servo en kiu la Requires direktivo indikos al la ingo unuodosiero. Poste, en la serva unuodosiero, restas nur voki Gunicorn el la virtuala medio kaj krei WSGI-ligadon por la UNIX-socket kaj la aplikaĵo Django.

Jen kelkaj ekzemploj de unuopaj dosieroj, kiujn vi povas uzi kiel bazon. Unue ni starigis la ingon.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Nun vi devas agordi la Gunicorn-demonon.

[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

Por Nginx, estas simpla afero krei prokurajn agordajn dosierojn kaj agordi dosierujon por stoki senmovan enhavon se vi uzas tian. En RHEL, Nginx-agordaj dosieroj troviĝas en /etc/nginx/conf.d. Vi povas kopii la sekvan ekzemplon en la dosieron /etc/nginx/conf.d/default.conf kaj komenci la servon. Certiĝu agordi la server_name por kongrui kun via gastiga nomo.

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

Komencu la Gunicorn-ingon kaj Nginx uzante systemd kaj vi pretas komenci testi.

Malbona Enirejo-eraro?

Se vi enigas la adreson en vian retumilon, vi plej verŝajne ricevos eraron 502 Bad Gateway. Ĝi povas esti kaŭzita de malĝuste agorditaj UNIX-sokaj permesoj, aŭ ĝi povas esti pro pli kompleksaj problemoj ligitaj al alirkontrolo en SELinux.

En la erarprotokolo de nginx vi povas vidi linion kiel ĉi tion:

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"

Se ni testos Gunicorn rekte, ni ricevos malplenan respondon.

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

Ni eltrovu kial tio okazas. Se vi malfermas la protokolon, vi plej verŝajne vidos, ke la problemo rilatas al SELinux. Ĉar ni prizorgas demonon por kiu neniu politiko estis kreita, ĝi estas markita kiel init_t. Ni provu ĉi tiun teorion praktike.

sudo setenforce 0

Ĉio ĉi povas kaŭzi kritikojn kaj sangajn larmojn, sed ĉi tio nur elpurigas la prototipon. Ni malŝaltu la kontrolon nur por certigi, ke ĉi tio estas la problemo, post kio ni revenos ĉion al sia loko.

Refreŝigante la paĝon en la retumilo aŭ rerulante nian buklan komandon, vi povas vidi la testpaĝon de Django.

Do, certiginte, ke ĉio funkcias kaj ne plu ekzistas permesproblemoj, ni denove ebligas SELinux.

sudo setenforce 1

Mi ne parolos pri audit2allow aŭ kreado de atentig-bazitaj politikoj kun sepolgen ĉi tie, ĉar ne ekzistas reala Django-apliko nuntempe, do ne ekzistas kompleta mapo pri tio, kion Gunicorn povus aliri kaj kion ĝi devus nei aliron. Sekve, necesas pluigi SELinux funkcii por protekti la sistemon, samtempe permesante al la aplikaĵo ruliĝi kaj lasi mesaĝojn en la revizia protokolo por ke la reala politiko tiam estu kreita de ili.

Specifante permesajn domajnojn

Ne ĉiuj aŭdis pri permesitaj domajnoj en SELinux, sed ili estas nenio nova. Multaj eĉ laboris kun ili sen eĉ rimarki tion. Kiam politiko estas kreita surbaze de reviziaj mesaĝoj, la kreita politiko reprezentas la solvitan domajnon. Ni provu krei simplan permespolitikon.

Por krei specifan permesitan domajnon por Gunicorn, vi bezonas ian politikon, kaj vi ankaŭ devas marki la taŭgajn dosierojn. Krome necesas iloj por kunmeti novajn politikojn.

sudo yum install selinux-policy-devel

La permesita domajna mekanismo estas bonega ilo por identigi problemojn, precipe kiam temas pri kutima aplikaĵo aŭ aplikaĵoj, kiuj sendas sen politikoj jam kreitaj. En ĉi tiu kazo, la permesita domajna politiko por Gunicorn estos kiel eble plej simpla - deklaru ĉefan tipon (gunicorn_t), deklaru tipon, kiun ni uzos por marki plurajn ekzekuteblajn (gunicorn_exec_t), kaj poste starigu transiron por ke sistemo ĝuste marku. kurantaj procezoj. La lasta linio fiksas la politikon kiel ebligita defaŭlte kiam ĝi estas ŝarĝita.

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;

Vi povas kompili ĉi tiun politikan dosieron kaj aldoni ĝin al via sistemo.

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

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

Ni kontrolu ĉu SELinux blokas ion alian ol kion nia nekonata demono aliras.

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 malhelpas Nginx skribi datumojn al la UNIX-ingo uzata de Gunicorn. Tipe, en tiaj kazoj, politikoj komencas ŝanĝiĝi, sed estas aliaj defioj antaŭen. Vi ankaŭ povas ŝanĝi la domajnan agordojn de restrikta domajno al permesa domajno. Nun ni movu httpd_t al la permesa domajno. Ĉi tio donos al Nginx la necesan aliron kaj ni povas daŭrigi kun plia sencimiga laboro.

sudo semanage permissive -a httpd_t

Do, post kiam vi sukcesis konservi SELinux protektita (vi vere ne devus lasi SELinux-projekton en limigita reĝimo) kaj la permesaj domajnoj estas ŝarĝitaj, vi devas eltrovi, kio precize devas esti markita kiel gunicorn_exec_t por ke ĉio funkcias ĝuste. denove. Ni provu viziti la retejon por vidi novajn mesaĝojn pri alirlimigo.

sudo ausearch -m AVC -c gunicorn

Vi vidos multajn mesaĝojn enhavantajn 'comm="gunicorn"', kiuj faras diversajn aferojn en dosieroj en /srv/djangoapp, do ĉi tio evidente estas unu el la komandoj markindaj.

Sed krome aperas mesaĝo tia:

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

Se vi rigardas la staton de la gunicorn-servo aŭ rulas la ps-komandon, vi ne vidos iujn ajn funkciajn procezojn. Ŝajnas, ke gunicorn provas aliri la Python-interpretilon en nia virtualenv-medio, eble por ruli laboristajn skriptojn. Do nun ni marku ĉi tiujn du ruleblajn dosierojn kaj kontrolu ĉu ni povas malfermi nian Django-testpaĝon.

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

La gunikornservo devos esti rekomencita antaŭ ol la nova etikedo povas esti elektita. Vi povas rekomenci ĝin tuj aŭ ĉesigi la servon kaj lasi la ingon komenci ĝin kiam vi malfermas la retejon en la retumilo. Kontrolu, ke procezoj ricevis la ĝustajn etikedojn per ps.

ps -efZ | grep gunicorn

Ne forgesu krei normalan politikon de SELinux poste!

Se vi rigardas la AVC-mesaĝojn nun, la lasta mesaĝo enhavas permisive=1 por ĉio rilata al la aplikaĵo, kaj permissive=0 por la resto de la sistemo. Se vi komprenas kian aliron bezonas vera aplikaĵo, vi povas rapide trovi la plej bonan manieron solvi tiajn problemojn. Sed ĝis tiam, estas plej bone konservi la sistemon sekura kaj ricevi klaran, uzeblan revizion de la projekto Django.

sudo ausearch -m AVC

Okazis!

Laboranta Django-projekto aperis kun fasado bazita sur Nginx kaj Gunicorn WSGI. Ni agordis Python 3 kaj PostgreSQL 10 el la deponejoj de RHEL 8 Beta. Nun vi povas antaŭeniri kaj krei (aŭ simple disfaldi) Django-aplikojn aŭ esplori aliajn disponeblajn ilojn en RHEL 8 Beta por aŭtomatigi la agordan procezon, plibonigi rendimenton aŭ eĉ kontenigi ĉi tiun agordon.

fonto: www.habr.com

Aldoni komenton