Workshop RHEL 8 Beta: Çalışan web uygulamaları oluşturma

RHEL 8 Beta, geliştiricilere birçok yeni özellik sunuyor; bunların listesi sayfalar sürebilir, ancak pratikte yeni şeyler öğrenmek her zaman daha iyidir; bu nedenle aşağıda, Red Hat Enterprise Linux 8 Beta'yı temel alan bir uygulama altyapısı oluşturmaya yönelik bir atölye çalışması sunuyoruz.

Workshop RHEL 8 Beta: Çalışan web uygulamaları oluşturma

Geliştiriciler arasında popüler bir programlama dili olan Python'u temel olarak, uygulamalar oluşturmak için oldukça yaygın bir kombinasyon olan Django ve PostgreSQL'in bir kombinasyonunu alalım ve RHEL 8 Beta'yı bunlarla çalışacak şekilde yapılandıralım. Daha sonra birkaç (sınıflandırılmamış) malzeme daha ekleyeceğiz.

Test ortamı değişecek çünkü otomasyonun, konteynerlerle çalışmanın ve birden fazla sunucunun bulunduğu ortamları denemenin olanaklarını keşfetmek ilginç olacak. Yeni bir projeye başlamak için, elle küçük, basit bir prototip oluşturarak başlayabilir, böylece tam olarak ne olması gerektiğini ve nasıl etkileşime girdiğini görebilir ve ardından otomatikleştirmeye ve daha karmaşık konfigürasyonlar oluşturmaya geçebilirsiniz. Bugün böyle bir prototipin yaratılmasından bahsediyoruz.

RHEL 8 Beta VM görüntüsünü dağıtarak başlayalım. Sıfırdan bir sanal makine kurabilir veya Beta aboneliğinizle birlikte sunulan KVM misafir görüntüsünü kullanabilirsiniz. Konuk imajı kullanırken, bulut başlatma (cloud-init) için meta veriler ve kullanıcı verilerini içerecek bir sanal CD yapılandırmanız gerekecektir. Disk yapısı veya mevcut paketler ile özel bir şey yapmanıza gerek yoktur; herhangi bir konfigürasyon işe yarayacaktır.

Tüm sürece daha yakından bakalım.

Django'yu Yükleme

Django'nun en yeni sürümüyle birlikte Python 3.5 veya sonraki sürümlere sahip bir sanal ortama (virtualenv) ihtiyacınız olacak. Beta notlarında Python 3.6'nın mevcut olduğunu görebilirsiniz, durumun gerçekten böyle olup olmadığını kontrol edelim:

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

Red Hat, Python'u RHEL'de bir sistem araç seti olarak aktif olarak kullanıyor, peki bu neden ortaya çıkıyor?

Gerçek şu ki, birçok Python geliştiricisi hala Python 2'den Python 2'ye geçişi düşünüyor, Python 3'ün kendisi ise aktif geliştirme aşamasında ve sürekli olarak daha fazla yeni sürüm ortaya çıkıyor. Bu nedenle, kullanıcılara Python'un çeşitli yeni sürümlerine erişim sunarken kararlı sistem araçları ihtiyacını karşılamak için Python sistemi yeni bir pakete taşındı ve hem Python 2.7 hem de 3.6'yı kurma yeteneği sağlandı. Değişiklikler ve bunların neden yapıldığı hakkında daha fazla bilgiyi adresindeki yayında bulabilirsiniz. Langdon White'ın blogu (Langdon White).

Dolayısıyla, Python'u çalışmaya başlamak için bağımlılık olarak python3-pip içeren yalnızca iki paket yüklemeniz gerekir.

sudo yum install python36 python3-virtualenv

Neden Langdon'ın önerdiği gibi doğrudan modül çağrılarını kullanıp pip3'ü yüklemiyorsunuz? Yaklaşan otomasyonu akılda tutarak, pip modülü özel bir pip yürütülebilir dosyasına sahip virtualenv'leri desteklemediğinden Ansible'ın çalışması için pip'in kurulu olmasını gerektireceği bilinmektedir.

Çalışan bir python3 yorumlayıcısı hizmetinizdeyken Django kurulum işlemine devam edebilir ve diğer bileşenlerimizle birlikte çalışan bir sisteme sahip olabilirsiniz. İnternette birçok uygulama seçeneği mevcuttur. Burada sunulan bir sürüm var, ancak kullanıcılar kendi süreçlerini kullanabilirler.

Yum'u kullanarak varsayılan olarak RHEL 8'de bulunan PostgreSQL ve Nginx sürümlerini yükleyeceğiz.

sudo yum install nginx postgresql-server

PostgreSQL psycopg2 gerektirecektir, ancak yalnızca sanalenv ortamında mevcut olması gerekir, bu yüzden onu Django ve Gunicorn ile birlikte pip3 kullanarak kuracağız. Ama önce virtualenv'i kurmamız gerekiyor.

Django projelerini yüklemek için doğru yeri seçme konusunda her zaman çok fazla tartışma vardır, ancak şüpheye düştüğünüzde her zaman Linux Dosya Sistemi Hiyerarşi Standardına başvurabilirsiniz. FHS özellikle /srv'nin şu amaçlarla kullanıldığını söylüyor: "ana makineye özgü verileri - web sunucusu verileri ve komut dosyaları, FTP sunucularında depolanan veriler ve kontrol sistemi depoları gibi sistemin ürettiği veriler." versiyonları (FHS'de görünür) 2.3'te -2004)."

Bizim durumumuz da tam olarak bu, bu yüzden ihtiyacımız olan her şeyi uygulama kullanıcımızın (bulut kullanıcısı) sahip olduğu /srv'ye koyuyoruz.

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 ve Django'yu kurmak kolaydır: bir veritabanı oluşturun, bir kullanıcı oluşturun, izinleri yapılandırın. PostgreSQL'i ilk kez kurarken akılda tutulması gereken bir şey, postgresql-server paketiyle birlikte yüklenen postgresql-setup betiğidir. Bu komut dosyası, küme başlatma veya yükseltme işlemi gibi veritabanı kümesi yönetimiyle ilişkili temel görevleri gerçekleştirmenize yardımcı olur. RHEL sisteminde yeni bir PostgreSQL örneğini yapılandırmak için şu komutu çalıştırmamız gerekir:

sudo /usr/bin/postgresql-setup -initdb

Daha sonra Systemd'yi kullanarak PostgreSQL'i başlatabilir, bir veritabanı oluşturabilir ve Django'da bir proje oluşturabilirsiniz. Uygulama kullanıcısı için parola depolamayı yapılandırmak üzere istemci kimlik doğrulama yapılandırma dosyasında (genellikle pg_hba.conf) değişiklik yaptıktan sonra PostgreSQL'i yeniden başlatmayı unutmayın. Başka zorluklarla karşılaşırsanız pg_hba.conf dosyasındaki IPv4 ve IPv6 ayarlarını değiştirdiğinizden emin olun.

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 dosyasında:

# 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 dosyasında:

# Database
DATABASES = {
   'default': {
       'ENGINE': 'django.db.backends.postgresql_psycopg2',
       'NAME': '{{ db_name }}',
       'USER': '{{ db_user }}',
       'PASSWORD': '{{ db_password }}',
       'HOST': '{{ db_host }}',
   }
}

Projede settings.py dosyasını yapılandırıp veritabanı yapılandırmasını ayarladıktan sonra her şeyin çalıştığından emin olmak için geliştirme sunucusunu başlatabilirsiniz. Geliştirme sunucusunu başlattıktan sonra veritabanı bağlantısını test etmek için bir yönetici kullanıcı oluşturmak iyi bir fikirdir.

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

WSGI'mi? Vay?

Geliştirme sunucusu test için kullanışlıdır, ancak uygulamayı çalıştırmak için Web Sunucusu Ağ Geçidi Arayüzü (WSGI) için uygun sunucuyu ve proxy'yi yapılandırmanız gerekir. Birkaç yaygın kombinasyon vardır; örneğin, uWSGI ile Apache HTTPD veya Gunicorn ile Nginx.

Web Sunucusu Ağ Geçidi Arayüzünün görevi, web sunucusundan gelen istekleri Python web çerçevesine iletmektir. WSGI, CGI motorlarının ortalıkta olduğu korkunç geçmişin bir kalıntısıdır ve bugün WSGI, kullanılan web sunucusu veya Python çerçevesinden bağımsız olarak fiili standarttır. Ancak yaygın kullanımına rağmen, bu çerçevelerle çalışırken hala birçok nüans ve birçok seçenek vardır. Bu durumda Gunicorn ile Nginx arasındaki etkileşimi bir soket üzerinden kurmaya çalışacağız.

Bu bileşenlerin her ikisi de aynı sunucuya kurulduğundan ağ soketi yerine UNIX soketi kullanmayı deneyelim. İletişim her durumda bir soket gerektirdiğinden, bir adım daha atıp Gunicorn için soket aktivasyonunu systemd aracılığıyla yapılandırmaya çalışalım.

Soketle etkinleştirilen hizmetler oluşturma süreci oldukça basittir. Öncelikle, UNIX soketinin oluşturulacağı noktaya işaret eden ListenStream direktifini içeren bir birim dosyası oluşturulur, ardından Requires direktifinin soket birim dosyasına işaret edeceği hizmet için bir birim dosyası oluşturulur. Daha sonra hizmet birimi dosyasında geriye kalan tek şey sanal ortamdan Gunicorn'u çağırmak ve UNIX soketi ve Django uygulaması için bir WSGI bağlaması oluşturmaktır.

Burada temel olarak kullanabileceğiniz bazı birim dosyaları örnekleri verilmiştir. İlk önce soketi kuruyoruz.

[Unit]
Description=Gunicorn WSGI socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Şimdi Gunicorn arka plan programını yapılandırmanız gerekiyor.

[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 için bu, proxy yapılandırma dosyaları oluşturmak ve kullanıyorsanız statik içeriği depolamak için bir dizin ayarlamak basit bir meseledir. RHEL'de Nginx yapılandırma dosyaları /etc/nginx/conf.d konumunda bulunur. Aşağıdaki örneği /etc/nginx/conf.d/default.conf dosyasına kopyalayıp servisi başlatabilirsiniz. Sunucu_adı'nı ana bilgisayar adınızla eşleşecek şekilde ayarladığınızdan emin olun.

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 soketini ve Nginx'i systemd kullanarak başlatın; teste başlamaya hazırsınız.

Kötü Ağ Geçidi hatası mı?

Adresi tarayıcınıza girerseniz büyük ihtimalle 502 Bad Gateway hatası alırsınız. Yanlış yapılandırılmış UNIX soket izinlerinden kaynaklanabilir veya SELinux'taki erişim kontrolüyle ilgili daha karmaşık sorunlardan kaynaklanabilir.

Nginx hata günlüğünde şöyle bir satır görebilirsiniz:

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'u doğrudan test edersek boş bir cevap alırız.

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

Bunun neden olduğunu anlayalım. Günlüğü açtığınızda büyük ihtimalle sorunun SELinux ile ilgili olduğunu göreceksiniz. Kendisi için hiçbir politika oluşturulmamış bir arka plan programı çalıştırdığımız için, bu init_t olarak işaretlendi. Bu teoriyi pratikte test edelim.

sudo setenforce 0

Bütün bunlar eleştirilere ve kanlı gözyaşlarına neden olabilir, ancak bu yalnızca prototipte hata ayıklamadır. Sorunun bu olduğundan emin olmak için kontrolü devre dışı bırakalım, ardından her şeyi yerine geri koyacağız.

Tarayıcıda sayfayı yenileyerek veya curl komutumuzu tekrar çalıştırarak Django test sayfasını görebilirsiniz.

Böylece her şeyin çalıştığından ve artık izin sorunu olmadığından emin olduktan sonra SELinux'u tekrar etkinleştiriyoruz.

sudo setenforce 1

Şu anda gerçek bir Django uygulaması olmadığından, burada denetim2allow veya sepolgen ile uyarı tabanlı politikalar oluşturma hakkında konuşmayacağım, dolayısıyla Gunicorn'un neye erişmek isteyebileceği ve neye erişimi reddetmesi gerektiğine dair tam bir harita yok. Bu nedenle, sistemi korumak için SELinux'u çalışır durumda tutmak gerekir, aynı zamanda uygulamanın çalışmasına ve denetim günlüğünde mesajlar bırakmasına izin vererek gerçek politikanın onlardan oluşturulabilmesini sağlamak gerekir.

İzin verilen alanları belirtme

Herkes SELinux'ta izin verilen alan adlarını duymamıştır, ancak bunlar yeni bir şey değildir. Hatta birçoğu farkına bile varmadan onlarla çalıştı. Denetim mesajlarına dayalı olarak bir politika oluşturulduğunda, oluşturulan politika çözümlenen etki alanını temsil eder. Basit bir izin politikası oluşturmaya çalışalım.

Gunicorn için izin verilen belirli bir alan adı oluşturmak için bir tür politikaya ihtiyacınız var ve ayrıca uygun dosyaları işaretlemeniz gerekiyor. Ayrıca yeni politikaların oluşturulması için araçlara ihtiyaç vardır.

sudo yum install selinux-policy-devel

İzin verilen etki alanları mekanizması, özellikle özel bir uygulama veya önceden oluşturulmuş politikalar olmadan gönderilen uygulamalar söz konusu olduğunda sorunları tanımlamak için harika bir araçtır. Bu durumda, Gunicorn için izin verilen etki alanı politikası mümkün olduğu kadar basit olacaktır - bir ana tür (gunicorn_t) bildirin, birden fazla yürütülebilir dosyayı işaretlemek için kullanacağımız bir tür bildirin (gunicorn_exec_t) ve ardından sistemin doğru şekilde işaretlemesi için bir geçiş ayarlayın süreçleri çalıştırıyor. Son satır, politikayı yüklendiği anda varsayılan olarak etkin olarak ayarlar.

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;

Bu politika dosyasını derleyip sisteminize ekleyebilirsiniz.

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

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

SELinux'un bilinmeyen arka plan programımızın eriştiğinden başka bir şeyi engelleyip engellemediğini kontrol edelim.

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'in Gunicorn tarafından kullanılan UNIX soketine veri yazmasını engeller. Tipik olarak bu gibi durumlarda politikalar değişmeye başlar ancak ileride başka zorluklar da vardır. Ayrıca etki alanı ayarlarını kısıtlama etki alanından izin etki alanına değiştirebilirsiniz. Şimdi httpd_t'yi izinler alanına taşıyalım. Bu, Nginx'e gerekli erişimi sağlayacaktır ve daha fazla hata ayıklama çalışmasına devam edebiliriz.

sudo semanage permissive -a httpd_t

Dolayısıyla, SELinux'u korumayı başardıktan sonra (bir SELinux projesini kısıtlı modda bırakmamalısınız) ve izin alanları yüklendikten sonra, her şeyin düzgün çalışmasını sağlamak için tam olarak neyin gunicorn_exec_t olarak işaretlenmesi gerektiğini bulmanız gerekir. Tekrar. Erişim kısıtlamalarıyla ilgili yeni mesajları görmek için web sitesini ziyaret etmeyi deneyelim.

sudo ausearch -m AVC -c gunicorn

/srv/djangoapp içindeki dosyalarda çeşitli şeyler yapan 'comm='gunicorn'' içeren çok sayıda mesaj göreceksiniz, dolayısıyla bu açıkça işaretlemeye değer komutlardan biridir.

Ancak buna ek olarak şöyle bir mesaj belirir:

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 hizmetinin durumuna baktığınızda veya ps komutunu çalıştırdığınızda çalışan herhangi bir işlem görmezsiniz. Gunicorn'un, muhtemelen çalışan komut dosyalarını çalıştırmak için virtualenv ortamımızdaki Python yorumlayıcısına erişmeye çalıştığı anlaşılıyor. Şimdi bu iki yürütülebilir dosyayı işaretleyelim ve Django test sayfamızı açıp açamayacağımızı kontrol edelim.

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

Yeni etiketin seçilebilmesi için gunicorn hizmetinin yeniden başlatılması gerekecektir. Siteyi tarayıcıda açtığınızda hemen yeniden başlatabilir veya hizmeti durdurup soketin başlatmasını sağlayabilirsiniz. İşlemlerin doğru etiketleri aldığını ps kullanarak doğrulayın.

ps -efZ | grep gunicorn

Daha sonra normal bir SELinux politikası oluşturmayı unutmayın!

Şimdi AVC mesajlarına bakarsanız, son mesajda uygulamayla ilgili her şey için permissive=1 ve sistemin geri kalanı için permissive=0 ifadesi yer alıyor. Gerçek bir uygulamanın ne tür bir erişime ihtiyaç duyduğunu anlarsanız bu tür sorunları çözmenin en iyi yolunu hızlı bir şekilde bulabilirsiniz. Ancak o zamana kadar sistemi güvende tutmak ve Django projesinin net, kullanılabilir bir denetimini elde etmek en iyisidir.

sudo ausearch -m AVC

Çıktı!

Nginx ve Gunicorn WSGI tabanlı bir ön yüze sahip, çalışan bir Django projesi ortaya çıktı. Python 3 ve PostgreSQL 10'u RHEL 8 Beta depolarından yapılandırdık. Artık ilerleyebilir ve Django uygulamaları oluşturabilir (veya yalnızca dağıtabilir) veya yapılandırma sürecini otomatikleştirmek, performansı artırmak ve hatta bu yapılandırmayı kapsayıcı hale getirmek için RHEL 8 Beta'daki diğer mevcut araçları keşfedebilirsiniz.

Kaynak: habr.com

Yorum ekle