RHEL 8 Beta Werkswinkel: Bou werkende webtoepassings

RHEL 8 Beta bied ontwikkelaars baie nuwe kenmerke, waarvan die lys bladsye kan neem, maar om nuwe dinge te leer is altyd beter in die praktyk, so hieronder bied ons 'n werkswinkel aan oor die werklike skep van 'n toepassingsinfrastruktuur gebaseer op Red Hat Enterprise Linux 8 Beta.

RHEL 8 Beta Werkswinkel: Bou werkende webtoepassings

Kom ons neem Python, 'n gewilde programmeertaal onder ontwikkelaars, as basis, 'n kombinasie van Django en PostgreSQL, 'n redelik algemene kombinasie vir die skep van toepassings, en stel RHEL 8 Beta op om daarmee te werk. Dan sal ons nog 'n paar (ongeklassifiseerde) bestanddele byvoeg.

Die toetsomgewing sal verander, want dit is interessant om die moontlikhede van outomatisering te verken, met houers te werk en omgewings met veelvuldige bedieners te probeer. Om met 'n nuwe projek te begin, kan jy begin deur 'n klein, eenvoudige prototipe met die hand te skep sodat jy presies kan sien wat moet gebeur en hoe dit in wisselwerking is, en dan voortgaan om te outomatiseer en meer komplekse konfigurasies te skep. Vandag praat ons oor die skepping van so 'n prototipe.

Kom ons begin deur die RHEL 8 Beta VM-beeld te ontplooi. Jy kan 'n virtuele masjien van nuuts af installeer, of die KVM-gasbeeld gebruik wat beskikbaar is met jou Beta-intekening. Wanneer u 'n gasprent gebruik, sal u 'n virtuele CD moet opstel wat metadata en gebruikersdata sal bevat vir wolkinisialisering (wolk-init). Jy hoef niks spesiaals te doen met die skyfstruktuur of beskikbare pakkette nie; enige konfigurasie sal doen.

Kom ons kyk na die hele proses van naderby.

Installeer Django

Met die nuutste weergawe van Django benodig u 'n virtuele omgewing (virtualenv) met Python 3.5 of later. In die Beta-aantekeninge kan jy sien dat Python 3.6 beskikbaar is, kom ons kyk of dit wel die geval is:

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

Red Hat gebruik Python aktief as 'n stelselgereedskapstel in RHEL, so hoekom lei dit tot gevolg?

Die feit is dat baie Python-ontwikkelaars steeds die oorgang van Python 2 na Python 2 oorweeg, terwyl Python 3 self onder aktiewe ontwikkeling is, en meer en meer nuwe weergawes verskyn voortdurend. Daarom, om aan die behoefte aan stabiele stelselnutsmiddels te voldoen, terwyl gebruikers toegang tot verskeie nuwe weergawes van Python bied, is stelsel Python na 'n nuwe pakket geskuif en het die vermoë verskaf om beide Python 2.7 en 3.6 te installeer. Meer inligting oor die veranderinge en hoekom dit gemaak is, kan gevind word in die publikasie in Langdon White se blog (Langdon White).

Dus, om Python te laat werk, hoef jy net twee pakkette te installeer, met python3-pip ingesluit as 'n afhanklikheid.

sudo yum install python36 python3-virtualenv

Hoekom nie direkte module-oproepe gebruik soos Langdon voorstel en pip3 installeer nie? Met die komende outomatisering in gedagte, is dit bekend dat Ansible pip geïnstalleer sal vereis om te loop, aangesien die pip-module nie virtualenvs met 'n pasgemaakte pip-uitvoerbare bestand ondersteun nie.

Met 'n werkende python3-tolk tot jou beskikking, kan jy voortgaan met die Django-installasieproses en 'n werkende stelsel hê saam met ons ander komponente. Daar is baie implementeringsopsies op die internet beskikbaar. Daar is een weergawe wat hier aangebied word, maar gebruikers kan hul eie prosesse gebruik.

Ons sal die PostgreSQL- en Nginx-weergawes wat in RHEL 8 beskikbaar is by verstek installeer met Yum.

sudo yum install nginx postgresql-server

PostgreSQL sal psycopg2 benodig, maar dit moet slegs in 'n virtuele omgewing beskikbaar wees, so ons sal dit installeer met pip3 saam met Django en Gunicorn. Maar eers moet ons virtualenv opstel.

Daar is altyd baie debat oor die onderwerp van die keuse van die regte plek om Django-projekte te installeer, maar as u twyfel, kan u altyd na die Linux-lêerstelselhiërargiestandaard wend. Spesifiek sê die FHS dat /srv gebruik word om: "gasheerspesifieke data te stoor - data wat die stelsel produseer, soos webbedienerdata en skrifte, data wat op FTP-bedieners gestoor is, en stelselbewaarplekke te beheer." weergawes (verskyn in FHS -2.3 in 2004)."

Dit is presies ons geval, so ons sit alles wat ons nodig het in /srv, wat deur ons toepassinggebruiker (wolkgebruiker) besit word.

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

Die opstel van PostgreSQL en Django is maklik: skep 'n databasis, skep 'n gebruiker, stel toestemmings in. Een ding om in gedagte te hou wanneer u PostgreSQL aanvanklik installeer, is die postgresql-opstellingskrip wat saam met die postgresql-bedienerpakket geïnstalleer word. Hierdie skrif help jou om basiese take wat met databasisklusteradministrasie geassosieer word, uit te voer, soos groepinitialisasie of die opgraderingsproses. Om 'n nuwe PostgreSQL-instansie op 'n RHEL-stelsel op te stel, moet ons die opdrag uitvoer:

sudo /usr/bin/postgresql-setup -initdb

U kan dan PostgreSQL met systemd begin, 'n databasis skep en 'n projek in Django opstel. Onthou om PostgreSQL te herbegin nadat veranderinge aan die kliëntverifikasie-konfigurasielêer (gewoonlik pg_hba.conf) gemaak is om wagwoordberging vir die toepassinggebruiker op te stel. As jy ander probleme ondervind, maak seker dat jy die IPv4- en IPv6-instellings in die pg_hba.conf-lêer verander.

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

In die lêer /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

In die lêer /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 }}',
   }
}

Nadat u die settings.py-lêer in die projek gekonfigureer het en die databasiskonfigurasie opgestel het, kan u die ontwikkelingsbediener begin om seker te maak dat alles werk. Nadat u die ontwikkelingsbediener begin het, is dit 'n goeie idee om 'n admin-gebruiker te skep om die verbinding met die databasis te toets.

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

WSGI? Wai?

Die ontwikkelingsbediener is nuttig om te toets, maar om die toepassing te laat loop, moet jy die toepaslike bediener en instaanbediener vir die Web Server Gateway Interface (WSGI) opstel. Daar is verskeie algemene kombinasies, byvoorbeeld Apache HTTPD met uWSGI of Nginx met Gunicorn.

Die taak van die Web Server Gateway Interface is om versoeke van die webbediener na die Python-webraamwerk aan te stuur. WSGI is 'n oorblyfsel van die verskriklike verlede toe CGI-enjins bestaan ​​het, en vandag is WSGI die de facto standaard, ongeag die webbediener of Python-raamwerk wat gebruik word. Maar ten spyte van die wydverspreide gebruik daarvan, is daar steeds baie nuanses wanneer daar met hierdie raamwerke gewerk word, en baie keuses. In hierdie geval sal ons probeer om interaksie tussen Gunicorn en Nginx via 'n sok te vestig.

Aangesien beide hierdie komponente op dieselfde bediener geïnstalleer is, kom ons probeer om 'n UNIX-sok te gebruik in plaas van 'n netwerksok. Aangesien kommunikasie in elk geval 'n sok vereis, kom ons probeer om nog een stap te neem en sokaktivering vir Gunicorn op te stel via systemd.

Die proses om sok-geaktiveerde dienste te skep is redelik eenvoudig. Eerstens word 'n eenheidlêer geskep wat 'n ListenStream-aanwysing bevat wat wys na die punt waarop die UNIX-sok geskep sal word, dan 'n eenheidlêer vir die diens waarin die Requires-aanwysing na die sokeenheidlêer sal wys. Dan, in die dienseenheidlêer, is al wat oorbly om Gunicorn van die virtuele omgewing te bel en 'n WSGI-binding vir die UNIX-sok en die Django-toepassing te skep.

Hier is 'n paar voorbeelde van eenheidlêers wat jy as basis kan gebruik. Eers stel ons die sok op.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Nou moet jy die Gunicorn-demon opstel.

[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

Vir Nginx is dit 'n eenvoudige kwessie van die skep van proxy-konfigurasielêers en die opstel van 'n gids om statiese inhoud te stoor as jy een gebruik. In RHEL is Nginx-konfigurasielêers geleë in /etc/nginx/conf.d. U kan die volgende voorbeeld na die lêer /etc/nginx/conf.d/default.conf kopieer en die diens begin. Maak seker dat jy die bedienernaam instel om by jou gasheernaam te pas.

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

Begin die Gunicorn-sok en Nginx met behulp van systemd en jy is gereed om te begin toets.

Slegte Gateway-fout?

As jy die adres in jou blaaier invoer, sal jy heel waarskynlik 'n 502 Bad Gateway-fout ontvang. Dit kan veroorsaak word deur verkeerd gekonfigureerde UNIX-soktoestemmings, of dit kan wees as gevolg van meer komplekse kwessies wat verband hou met toegangsbeheer in SELinux.

In die nginx-foutlogboek kan u 'n reël soos hierdie sien:

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"

As ons Gunicorn direk toets, sal ons 'n leë antwoord kry.

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

Kom ons vind uit hoekom dit gebeur. As jy die log oopmaak, sal jy heel waarskynlik sien dat die probleem met SELinux verband hou. Aangesien ons 'n daemoon bestuur waarvoor geen beleid geskep is nie, word dit as init_t gemerk. Kom ons toets hierdie teorie in die praktyk.

sudo setenforce 0

Dit alles kan kritiek en bloedtrane veroorsaak, maar dit is net om die prototipe te ontfout. Kom ons deaktiveer die tjek net om seker te maak dat dit die probleem is, waarna ons alles op sy plek sal terugbring.

Deur die bladsy in die blaaier te verfris of ons krul-opdrag weer uit te voer, kan jy die Django-toetsbladsy sien.

Dus, nadat ons seker gemaak het dat alles werk en daar nie meer toestemmingsprobleme is nie, aktiveer ons SELinux weer.

sudo setenforce 1

Ek sal nie hier praat oor oudit2allow of die skep van waarskuwingsgebaseerde beleide met sepolgen nie, aangesien daar geen werklike Django-toepassing op die oomblik is nie, so daar is geen volledige kaart van waartoe Gunicorn dalk toegang wil hê en waartoe dit toegang moet weier nie. Daarom is dit nodig om SELinux aan die gang te hou om die stelsel te beskerm, terwyl die toepassing terselfdertyd toegelaat word om te loop en boodskappe in die ouditlog te laat sodat die werklike beleid dan daaruit geskep kan word.

Spesifikasie van permissiewe domeine

Nie almal het gehoor van toegelate domeine in SELinux nie, maar dit is niks nuuts nie. Baie het selfs saam met hulle gewerk sonder dat hulle dit eers besef het. Wanneer 'n beleid op grond van ouditboodskappe geskep word, verteenwoordig die geskepte beleid die afgehandelde domein. Kom ons probeer om 'n eenvoudige permitbeleid te skep.

Om 'n spesifieke toegelate domein vir Gunicorn te skep, benodig u 'n soort beleid, en u moet ook die toepaslike lêers merk. Daarbenewens is gereedskap nodig om nuwe beleide saam te stel.

sudo yum install selinux-policy-devel

Die toegelate domeine-meganisme is 'n wonderlike hulpmiddel om probleme te identifiseer, veral wanneer dit kom by 'n pasgemaakte toepassing of toepassings wat gestuur word sonder beleid wat reeds geskep is. In hierdie geval sal die toegelate domeinbeleid vir Gunicorn so eenvoudig as moontlik wees - verklaar 'n hooftipe (gunicorn_t), verklaar 'n tipe wat ons sal gebruik om veelvuldige uitvoerbares te merk (gunicorn_exec_t), en stel dan 'n oorgang op vir stelsel om korrek te merk lopende prosesse. Die laaste reël stel die beleid as by verstek geaktiveer wanneer dit gelaai word.

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;

Jy kan hierdie beleidlêer saamstel en dit by jou stelsel voeg.

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

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

Kom ons kyk of SELinux iets anders blokkeer behalwe waartoe ons onbekende daemoon toegang het.

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 verhoed dat Nginx data skryf na die UNIX-sok wat deur Gunicorn gebruik word. Tipies begin beleide in sulke gevalle verander, maar daar is ander uitdagings wat voorlê. U kan ook die domeininstellings van 'n beperkingsdomein na 'n toestemmingsdomein verander. Kom ons skuif nou httpd_t na die toestemmingsdomein. Dit sal Nginx die nodige toegang gee en ons kan voortgaan met verdere ontfoutingswerk.

sudo semanage permissive -a httpd_t

So, sodra jy daarin geslaag het om SELinux beskerm te hou (jy moet regtig nie 'n SELinux-projek in beperkte modus laat nie) en die toestemmingsdomeine is gelaai, moet jy uitvind wat presies as gunicorn_exec_t gemerk moet word om alles behoorlik te laat werk weer. Kom ons probeer om die webwerf te besoek om nuwe boodskappe oor toegangsbeperkings te sien.

sudo ausearch -m AVC -c gunicorn

Jy sal baie boodskappe sien wat 'comm="gunicorn"' bevat wat verskeie dinge op lêers in /srv/djangoapp doen, so dit is natuurlik een van die opdragte wat die moeite werd is om te vlag.

Maar boonop verskyn 'n boodskap soos hierdie:

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

As jy na die status van die gunicorn-diens kyk of die ps-opdrag uitvoer, sal jy geen lopende prosesse sien nie. Dit lyk asof gunicorn probeer om toegang tot die Python-tolk in ons virtualenv-omgewing te kry, moontlik om werkerskrifte uit te voer. Kom ons merk nou hierdie twee uitvoerbare lêers en kyk of ons ons Django-toetsbladsy kan oopmaak.

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

Die gunicorn-diens sal herbegin moet word voordat die nuwe merker gekies kan word. U kan dit onmiddellik herbegin of die diens stop en die sok laat begin wanneer u die webwerf in die blaaier oopmaak. Verifieer dat prosesse die korrekte etikette ontvang het deur ps.

ps -efZ | grep gunicorn

Moenie vergeet om later 'n normale SELinux-beleid te skep nie!

As jy nou na die AVC-boodskappe kyk, bevat die laaste boodskap permissive=1 vir alles wat met die toepassing verband hou, en permissive=0 vir die res van die stelsel. As jy verstaan ​​watter soort toegang 'n regte toepassing benodig, kan jy vinnig die beste manier vind om sulke probleme op te los. Maar tot dan is dit die beste om die stelsel veilig te hou en 'n duidelike, bruikbare oudit van die Django-projek te kry.

sudo ausearch -m AVC

Het gebeur!

'n Werkende Django-projek het verskyn met 'n frontend gebaseer op Nginx en Gunicorn WSGI. Ons het Python 3 en PostgreSQL 10 opgestel vanaf die RHEL 8 Beta-bewaarplekke. Nou kan jy vorentoe beweeg en Django-toepassings skep (of eenvoudig ontplooi) of ander beskikbare gereedskap in RHEL 8 Beta verken om die konfigurasieproses te outomatiseer, werkverrigting te verbeter, of selfs hierdie konfigurasie te houer.

Bron: will.com

Voeg 'n opmerking