Bengkel Beta RHEL 8: Membina Aplikasi Web Berfungsi

RHEL 8 Beta menawarkan pembangun banyak ciri baharu, penyenaraian yang boleh memuatkan halaman, walau bagaimanapun, mempelajari perkara baharu sentiasa lebih baik dalam amalan, jadi di bawah ini kami menawarkan amalan untuk benar-benar mencipta infrastruktur aplikasi berdasarkan Red Hat Enterprise Linux 8 Beta.

Bengkel Beta RHEL 8: Membina Aplikasi Web Berfungsi

Kami akan mengambil Python, bahasa pengaturcaraan yang popular di kalangan pembangun, sebagai asas, gabungan Django dan PostgreSQL, satu himpunan yang agak biasa untuk mencipta aplikasi, dan mengkonfigurasi RHEL 8 Beta untuk berfungsi dengan mereka. Kemudian kami akan menambah beberapa lagi bahan (tidak dikelaskan).

Persekitaran ujian akan berubah kerana menarik untuk meneroka kemungkinan automasi, bekerja dengan bekas dan mencuba persekitaran dengan berbilang pelayan. Untuk memulakan projek baharu, anda boleh mulakan dengan mencipta prototaip yang kecil dan ringkas dengan tangan supaya anda boleh melihat dengan tepat apa yang perlu berlaku dan cara interaksi dijalankan, dan kemudian beralih kepada automasi dan mencipta konfigurasi yang lebih kompleks. Hari ini adalah cerita tentang penciptaan prototaip sedemikian.

Mari mulakan dengan menggunakan imej RHEL 8 Beta VM. Anda boleh memasang mesin maya dari awal, atau menggunakan imej tetamu KVM yang tersedia dengan langganan Beta. Apabila menggunakan imej tetamu, anda perlu menyediakan CD maya yang akan mengandungi metadata dan data pengguna untuk peruntukan awan (cloud-init). Anda tidak perlu melakukan sesuatu yang istimewa dengan struktur cakera atau pakej yang tersedia, sebarang konfigurasi akan dilakukan.

Mari kita lihat keseluruhan proses dengan lebih terperinci.

Memasang Django

Dengan versi terkini Django, anda memerlukan persekitaran maya (virtualenv) dengan Python 3.5 atau lebih baru. Anda boleh melihat dalam nota Beta bahawa Python 3.6 tersedia, mari semak sama ada ini benar-benar berlaku:

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

Red Hat secara aktif menggunakan Python sebagai kit alat sistem dalam RHEL, jadi mengapa ini hasilnya?

Hakikatnya ialah ramai pembangun yang menggunakan Python masih berfikir tentang beralih daripada Python 2 kepada Python 2, manakala Python 3 sendiri sedang dalam pembangunan aktif, dan semakin banyak versi baharu sentiasa muncul. Oleh itu, untuk memenuhi keperluan alat sistem yang stabil, sambil turut menawarkan pengguna akses kepada pelbagai versi baharu Python, sistem Python telah dialihkan ke pakej baharu, dan kedua-dua Python 2.7 dan 3.6 boleh dipasang. Maklumat lanjut tentang perubahan dan sebab ini dilakukan boleh diperolehi daripada siaran dalam Blog Langdon White (Langdon White).

Jadi, untuk mendapatkan Python yang berfungsi, anda perlu memasang hanya dua pakej, manakala python3-pip akan ditarik ke atas sebagai kebergantungan.

sudo yum install python36 python3-virtualenv

Mengapa tidak menggunakan panggilan modul langsung seperti yang dicadangkan Langdon dan memasang pip3? Dengan mengingati automasi, kami tahu bahawa Ansible memerlukan pip untuk dipasang, kerana modul pip tidak menyokong persekitaran maya (virtualenvs) dengan pip tersuai boleh laku.

Dengan penterjemah python3 yang boleh digunakan, kami boleh meneruskan proses pemasangan Django dan mempunyai sistem yang berfungsi bersama-sama komponen kami yang lain. Terdapat banyak pilihan pelaksanaan di web. Ini adalah satu versi, tetapi pengguna boleh menggunakan proses mereka sendiri.

Versi PostgreSQL dan Nginx yang tersedia dalam RHEL 8 akan dipasang secara lalai menggunakan Yum.

sudo yum install nginx postgresql-server

PostgreSQL memerlukan psycopg2, tetapi ia hanya perlu tersedia dalam persekitaran virtualenv, jadi kami akan memasangnya dengan pip3 bersama-sama dengan Django dan Gunicorn. Tetapi pertama-tama kita perlu menyediakan virtualenv.

Sentiasa terdapat banyak perdebatan tentang memilih tempat yang betul untuk memasang projek Django, tetapi apabila ragu-ragu, anda sentiasa boleh merujuk kepada Piawaian Hierarki Sistem Fail Linux. Secara khusus, FHS mengatakan bahawa /srv digunakan untuk: β€œmenyimpan data khusus hos - data yang dihasilkan oleh sistem, seperti data dan skrip pelayan web, data yang disimpan pada pelayan FTP dan versi repositori sistem kawalan (diperkenalkan dalam FHS-2.3 pada tahun 2004).

Ini hanya kes kami, jadi kami meletakkan semua yang kami perlukan dalam / srv, yang dimiliki oleh pengguna aplikasi kami (pengguna awan).

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

Menyediakan PostgreSQL dan Django adalah mudah: buat pangkalan data, buat pengguna, tetapkan kebenaran. Satu perkara yang perlu diingat semasa memasang PostgreSQL pada mulanya ialah skrip persediaan postgresql, yang dipasang dengan pakej pelayan postgresql. Skrip ini membantu anda melaksanakan tugas pentadbiran kluster pangkalan data asas, seperti pemulaan kluster atau proses naik taraf. Untuk menyediakan contoh PostgreSQL baharu pada sistem RHEL, kita perlu menjalankan arahan:

sudo /usr/bin/postgresql-setup -initdb

Selepas itu, anda boleh memulakan PostgreSQL menggunakan systemd, mencipta pangkalan data dan menyediakan projek dalam Django. Ingat untuk memulakan semula PostgreSQL selepas membuat perubahan pada fail konfigurasi pengesahan klien (biasanya pg_hba.conf) untuk mengkonfigurasi storan kata laluan untuk pengguna aplikasi. Jika anda menghadapi isu lain, pastikan anda menukar tetapan IPv4 dan IPv6 dalam fail 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

Dalam fail /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

Dalam fail /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 }}',
   }
}

Selepas mengkonfigurasi fail settings.py dalam projek dan menyediakan konfigurasi pangkalan data, anda boleh memulakan pelayan pembangunan untuk memastikan semuanya berfungsi. Setelah pelayan pembangunan siap dan berjalan, adalah idea yang baik untuk mencipta pengguna pentadbir untuk menguji sambungan pangkalan data.

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

WSGI? Wai?

Pelayan pembangunan berguna untuk ujian, tetapi anda mesti mengkonfigurasi pelayan dan proksi yang sesuai untuk Antara Muka Gerbang Pelayan Web (WSGI) untuk menjalankan aplikasi anda. Terdapat beberapa berkas biasa, seperti Apache HTTPD dengan uWSGI atau Nginx dengan Gunicorn.

Tugas Antara Muka Gerbang Pelayan Web adalah untuk memajukan permintaan daripada pelayan web kepada rangka kerja web Python. WSGI ialah warisan masa lalu yang mengerikan apabila mekanisme CGI digunakan, dan hari ini WSGI ialah standard de facto, tanpa mengira pelayan web atau rangka kerja Python yang digunakan. Tetapi walaupun pengedarannya meluas, masih terdapat banyak nuansa apabila bekerja dengan rangka kerja ini, dan banyak pilihan untuk dipilih. Dalam kes ini, kami akan cuba mewujudkan interaksi antara Gunicorn dan Nginx melalui soket.

Memandangkan kedua-dua komponen ini dipasang pada pelayan yang sama, mari cuba gunakan soket UNIX dan bukannya soket rangkaian. Oleh kerana komunikasi memerlukan soket pula, mari kita cuba melangkah lebih jauh dan sediakan pengaktifan soket untuk Gunicorn melalui systemd.

Proses mencipta perkhidmatan diaktifkan soket agak mudah. Mula-mula, fail unit dicipta yang mengandungi arahan ListenStream yang menunjuk ke titik di mana soket UNIX akan dibuat, kemudian fail unit untuk perkhidmatan, di mana arahan Memerlukan akan menghala ke fail unit soket. Kemudian, dalam fail unit perkhidmatan, yang tinggal hanyalah memanggil Gunicorn dari persekitaran maya dan mencipta pengikatan WSGI untuk soket UNIX dan aplikasi Django.

Berikut adalah beberapa contoh fail unit yang boleh diambil sebagai asas. Mula-mula kita sediakan soket.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Sekarang kita perlu mengkonfigurasi daemon 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

Untuk Nginx, ia semudah membuat fail konfigurasi proksi dan menyediakan direktori kandungan statik jika anda menggunakannya. Pada RHEL, fail konfigurasi Nginx ialah /etc/nginx/conf.d. Anda boleh menyalin contoh berikut di sana ke fail /etc/nginx/conf.d/default.conf dan mulakan perkhidmatan. Pastikan anda menetapkan nama_server agar sepadan dengan nama hos anda.

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

Mulakan soket Gunicorn dan Nginx dengan systemd dan anda boleh pergi.

Ralat Gerbang Buruk?

Jika anda memasukkan alamat ke dalam penyemak imbas, kemungkinan besar anda akan mendapat ralat 502 Bad Gateway. Ia boleh disebabkan oleh kebenaran soket UNIX yang salah konfigurasi, atau isu kawalan akses yang lebih kompleks dalam SELinux.

Dalam log ralat nginx, anda boleh mencari baris seperti ini:

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"

Jika kami menguji Gunicorn secara langsung, kami mendapat jawapan kosong.

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

Mari lihat mengapa ini berlaku. Jika anda membuka log, maka kemungkinan besar kita akan melihat bahawa masalah itu berkaitan dengan SELinux. Memandangkan kita mempunyai daemon yang sedang berjalan yang tidak ada dasar yang dibuat, ia ditandakan sebagai init_t. Mari kita uji teori ini secara praktikal.

sudo setenforce 0

Semua ini boleh menyebabkan kritikan dan air mata berdarah, tetapi ini hanya menyahpepijat prototaip. Mari matikan cek hanya untuk memastikan bahawa ini adalah masalahnya, selepas itu kami akan mengembalikan semuanya ke tempatnya.

Dengan menyegarkan halaman dalam penyemak imbas atau dengan menjalankan semula arahan curl kami, kami boleh melihat halaman ujian Django.

Jadi, selepas memastikan semuanya berfungsi dan tiada lagi isu kebenaran, kami mendayakan semula SELinux.

sudo setenforce 1

Saya tidak akan bercakap tentang audit2allow dan mencipta dasar berasaskan amaran dengan sepolgen di sini, memandangkan tiada aplikasi Django sebenar pada masa ini, tiada juga peta lengkap tentang perkara yang Gunicorn mungkin ingin akses dan nafikan. Oleh itu, adalah perlu untuk memastikan SELinux berjalan untuk melindungi sistem, sementara pada masa yang sama membenarkan aplikasi berjalan dan meninggalkan mesej dalam log audit supaya dasar sebenar boleh dibuat daripadanya.

Menentukan Domain Permisif

Tidak semua orang pernah mendengar tentang domain yang dibenarkan dalam SELinux, tetapi ia bukanlah sesuatu yang baharu. Ramai juga yang bekerja dengan mereka tanpa disedari. Apabila dasar dibuat berdasarkan mesej audit, dasar yang dijana mewakili domain yang dibenarkan. Mari cuba buat dasar permisif yang mudah.

Untuk mencipta domain khusus yang dibenarkan untuk Gunicorn, anda memerlukan beberapa jenis dasar, dan anda juga perlu menandakan fail yang sesuai. Di samping itu, alat diperlukan untuk menyusun dasar baharu.

sudo yum install selinux-policy-devel

Mekanisme Domain Dibenarkan ialah alat yang hebat untuk mengenal pasti masalah, terutamanya apabila ia berkaitan dengan aplikasi tersuai atau aplikasi yang datang tanpa dasar yang telah dibuat. Dalam kes ini, dasar domain yang dibenarkan untuk Gunicorn adalah semudah mungkin - kami akan mengisytiharkan jenis utama (gunicorn_t), kami akan mengisytiharkan jenis yang akan kami gunakan untuk menandakan berbilang fail boleh laku (gunicorn_exec_t), dan kemudian kami akan mengkonfigurasi peralihan (peralihan) untuk sistem menandakan dengan betul proses yang sedang berjalan . Baris terakhir menetapkan dasar sebagai didayakan secara lalai apabila ia dimuatkan.

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;

Anda boleh menyusun fail dasar ini dan menambahkannya pada sistem anda.

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

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

Mari lihat sama ada SELinux menyekat sesuatu yang lain selain apa yang diakses oleh daemon kami yang tidak diketahui.

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 menghalang Nginx daripada menulis data ke soket UNIX yang digunakan oleh Gunicorn. Biasanya dalam kes sedemikian, mereka mula menukar dasar, tetapi ada tugas lain di hadapan. Anda juga boleh menukar tetapan domain daripada domain sekatan kepada domain benarkan. Sekarang mari kita alihkan httpd_t ke domain kebenaran. Ini akan memberi Nginx akses yang diperlukan supaya kami boleh meneruskan kerja penyahpepijatan selanjutnya.

sudo semanage permissive -a httpd_t

Jadi, sebaik sahaja anda berjaya memastikan SELinux dilindungi (sebenarnya, anda tidak sepatutnya meninggalkan projek SELinux anda dalam mod terhad) dan domain kebenaran dimuatkan, anda perlu memikirkan apa sebenarnya yang perlu ditanda sebagai gunicorn_exec_t untuk mendapatkan segala-galanya berfungsi semula dengan baik. Mari cuba mengakses tapak web untuk melihat mesej baharu tentang sekatan akses.

sudo ausearch -m AVC -c gunicorn

Anda boleh melihat banyak mesej yang mengandungi 'comm="gunicorn"' yang melakukan pelbagai tindakan pada fail dalam /srv/djangoapp, jadi ini jelas merupakan salah satu arahan yang patut dibenderakan.

Tetapi sebagai tambahan, mesej seperti ini muncul:

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

Jika anda melihat status perkhidmatan gunicorn atau menjalankan arahan ps, tidak akan ada sebarang proses berjalan. Nampaknya gunicorn cuba mengakses penterjemah Python dalam virtualenv kami, mungkin untuk menjalankan skrip pekerja. Jadi sekarang mari tandakan kedua-dua boleh laku ini dan lihat sama ada halaman ujian Django kami boleh dibuka.

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

Perkhidmatan gunicorn perlu dimulakan semula sebelum label baharu boleh dipilih. Anda boleh memulakan semula dengan segera atau menghentikan perkhidmatan dan biarkan soket memulakannya apabila anda membuka tapak dalam penyemak imbas. Sahkan bahawa proses telah menerima label yang betul menggunakan ps.

ps -efZ | grep gunicorn

Jangan lupa buat dasar SELinux biasa selepas itu!

Melihat kepada mesej AVC sekarang, mesej terakhir mengandungi permisif=1 untuk semua yang berkaitan dengan aplikasi dan permisif=0 untuk seluruh sistem. Jika anda memahami dengan tepat jenis akses yang diperlukan oleh aplikasi sebenar, anda boleh mencari cara terbaik untuk menyelesaikan masalah sedemikian dengan cepat. Tetapi sehingga itu, adalah lebih baik untuk memastikan sistem selamat dan mendapatkan audit yang jelas dan boleh digunakan bagi projek Django.

sudo ausearch -m AVC

Terjadi!

Projek Django yang berfungsi muncul dengan bahagian hadapan pada Nginx dan Gunicorn WSGI. Kami telah mengkonfigurasi Python 3 dan PostgreSQL 10 daripada repositori RHEL 8 Beta. Anda kini boleh meneruskan dan mencipta (atau hanya menggunakan) aplikasi Django atau meneroka alat lain yang tersedia dalam RHEL 8 Beta untuk mengautomasikan proses menyesuaikan, meningkatkan prestasi, atau bahkan menyimpan konfigurasi itu.

Sumber: www.habr.com

Tambah komen