RHEL 8 Beta bietet Entwicklern viele neue Funktionen, deren Auflistung möglicherweise Seiten umfasst. Es ist jedoch immer besser, neue Dinge in der Praxis zu lernen. Daher empfehlen wir, einen Workshop zu absolvieren, um eine Anwendungsinfrastruktur auf der Basis von Red Hat Enterprise Linux 8 Beta zu erstellen.

Nehmen wir Python, eine Kombination aus Django und PostgreSQL, einem ziemlich verbreiteten Bundle zum Erstellen von Anwendungen, und konfigurieren Sie RHEL 8 Beta für die Arbeit mit ihnen. Fügen Sie dann ein paar weitere (nicht klassifizierte) Zutaten hinzu.
Die Testumgebung wird sich ändern, da es interessant ist, Automatisierungsfunktionen zu untersuchen, mit Containern zu arbeiten und Umgebungen mit mehreren Servern auszuprobieren. Um mit einem neuen Projekt zu arbeiten, können Sie zunächst manuell einen kleinen einfachen Prototyp erstellen. Auf diese Weise können Sie sehen, was genau geschehen muss und wie die Interaktion ausgeführt wird. Anschließend können Sie mit der Automatisierung fortfahren und komplexere Konfigurationen erstellen. Heute ist die Geschichte der Schaffung eines solchen Prototyps.
Beginnen wir mit der Bereitstellung des Images der virtuellen Maschine RHEL 8 Beta VM. Sie können die virtuelle Maschine von Grund auf neu installieren oder das KVM-Gastimage verwenden, das mit einem Beta-Abonnement erhältlich ist. Wenn Sie ein Gastimage verwenden, müssen Sie eine virtuelle CD konfigurieren, die Metadaten und Benutzerdaten für die Cloud-Initialisierung (Cloud-Init) enthält. Sie müssen nichts Besonderes mit der Festplattenstruktur oder den verfügbaren Paketen tun, jede Konfiguration reicht aus.
Schauen wir uns den gesamten Prozess genauer an.
Installieren Sie Django
Mit der neuesten Version von Django benötigen Sie eine virtuelle Umgebung (virtualenv) mit Python 3.5 oder höher. In den Hinweisen zur Beta sehen Sie, dass Python 3.6 verfügbar ist. Überprüfen Sie, ob dies zutrifft:
[cloud-user@8beta1 ~]$ python -bash: python: command not found [cloud-user@8beta1 ~]$ python3 -bash: python3: command not found
Red Hat verwendet Python aktiv als System-Toolkit in RHEL. Warum erhalten Sie dieses Ergebnis?
Tatsache ist, dass viele Entwickler, die Python verwenden, immer noch darüber nachdenken, von Python 2 auf Python 3 umzusteigen, während Python 3 selbst aktiv entwickelt wird und immer mehr neue Versionen erscheinen. Um den Bedarf an stabilen Systemtools zu decken und den Benutzern gleichzeitig Zugriff auf verschiedene neue Versionen von Python zu bieten, wurde System Python in ein neues Paket übertragen und bot die Möglichkeit, sowohl Python 2.7 als auch 3.6 zu installieren. Weitere Informationen zu den Änderungen und warum dies getan wurde, finden Sie im
Langdon White-Blogbeitrag .
Um Python zum Laufen zu bringen, müssen Sie nur zwei Pakete installieren, während python3-pip als Abhängigkeit aufgerufen wird.
sudo yum install python36 python3-virtualenv
Warum nicht direkte Modulaufrufe verwenden, wie Langdon vorschlägt, und pip3 nicht installieren? Unter Berücksichtigung der bevorstehenden Automatisierung ist bekannt, dass Ansible installierte Pip benötigt, da das Pip-Modul keine virtuellen Umgebungen (virtualenvs) mit einer benutzerdefinierten ausführbaren Pip-Datei unterstützt.
Mit einem funktionierenden Python3-Interpreter können Sie den Django-Installationsprozess fortsetzen und ein funktionierendes System zusammen mit unseren anderen Komponenten erhalten. Das Netzwerk bietet viele Optionen für die Implementierung. Hier wird eine Version vorgestellt, aber Benutzer können ihre eigenen Prozesse verwenden.
Die in RHEL 8 verfügbaren Versionen von PostgreSQL und Nginx werden standardmäßig mit Yum installiert.
sudo yum install nginx postgresql-server
PostgreSQL benötigt psycopg2, muss jedoch nur in der virtualenv-Umgebung verfügbar sein, daher werden wir es mit pip3 zusammen mit Django und Gunicorn installieren. Aber zuerst müssen wir virtualenv konfigurieren.
Es gibt immer viele Diskussionen über die Auswahl des richtigen Ortes für die Installation von Django-Projekten, aber im Zweifelsfall können Sie sich immer auf den Linux Filesystem Hierarchy Standard beziehen. Laut FHS wird / srv insbesondere verwendet, um: „hostspezifische Daten zu speichern - Daten, die das System bereitstellt, z. B. Daten und Skripte von Webservern, auf FTP-Servern gespeicherte Daten sowie Repositorys von Steuerungssystemen Versionen (2004 in FHS-2.3 eingeführt). “
Dies ist nur unser Fall, also legen wir alles, was wir brauchen, in / srv ab, das unserem Anwendungsbenutzer (Cloud-Benutzer) gehört.
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
Das Einrichten von PostgreSQL und Django ist unkompliziert: Erstellen Sie eine Datenbank, erstellen Sie einen Benutzer, konfigurieren Sie Berechtigungen. Bei der erstmaligen Installation von PostgreSQL ist ein Punkt zu beachten: das Postgresql-Setup-Skript, das mit dem Postgresql-Server-Paket installiert wird. Mit diesem Skript können Sie grundlegende Aufgaben im Zusammenhang mit der Verwaltung eines Datenbankclusters ausführen, z. B. das Initialisieren eines Clusters oder das Aktualisieren von Prozessen. Um eine neue Instanz von PostgreSQL auf dem RHEL-System zu konfigurieren, müssen Sie den folgenden Befehl ausführen:
sudo /usr/bin/postgresql-setup -initdb
Danach können Sie PostgreSQL mit systemd starten, eine Datenbank erstellen und das Projekt in Django konfigurieren. Denken Sie daran, PostgreSQL neu zu starten, nachdem Sie Änderungen an der Konfigurationsdatei für die Clientauthentifizierung (normalerweise pg_hba.conf) vorgenommen haben, um den Kennwortspeicher für den Anwendungsbenutzer zu konfigurieren. Wenn Sie auf andere Schwierigkeiten stoßen, müssen Sie die IPv4- und IPv6-Einstellungen in der Datei pg_hba.conf ändern.
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 der Datei /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 der Datei /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 }}', } }
Nachdem Sie die Datei settings.py im Projekt konfiguriert und die Datenbankkonfiguration konfiguriert haben, können Sie den Entwicklungsserver starten, um sicherzustellen, dass alles funktioniert. Nach dem Starten des Entwicklungsservers ist es hilfreich, einen Administrator zu erstellen, um die Verbindung zur Datenbank zu testen.
./manage.py runserver 0.0.0.0:8000 ./manage.py createsuperuser
WSGI? Wai
Der Entwicklungsserver ist zum Testen nützlich. Um die Anwendung auszuführen, müssen Sie jedoch den entsprechenden Server und Proxy für das Web Server Gateway Interface (WSGI) konfigurieren. Es gibt mehrere gängige Bundles, z. B. Apache HTTPD mit uWSGI oder Nginx mit Gunicorn.
Das Ziel der Webserver-Gateway-Schnittstelle besteht darin, Anforderungen vom Webserver an das Python-Webframework umzuleiten. WSGI ist eine Art Erbe der schrecklichen Vergangenheit, als CGI-Mechanismen verwendet wurden, und heute ist WSGI tatsächlich der Standard, unabhängig vom verwendeten Webserver oder Python-Framework. Trotz seiner breiten Verbreitung gibt es bei der Arbeit mit diesen Frameworks immer noch viele Nuancen und viele Möglichkeiten. In diesem Fall werden wir versuchen, eine Interaktion zwischen Gunicorn und Nginx über den Socket herzustellen.
Da diese beiden Komponenten auf demselben Server installiert sind, werden wir versuchen, einen UNIX-Socket anstelle eines Netzwerk-Sockets zu verwenden. Da für die Kommunikation ohnehin ein Socket erforderlich ist, versuchen wir noch einen Schritt und konfigurieren die Socket-Aktivierung für Gunicorn über systemd.
Das Erstellen von Socket-aktivierten Diensten ist einfach genug. Zuerst wird eine Einheitendatei erstellt, die die ListenStream-Direktive enthält und auf den Punkt verweist, an dem der UNIX-Socket erstellt wird, dann eine Einheitendatei für den Dienst, wobei die Requires-Direktive auf die Socket-Einheitendatei verweist. In der Unit-Datei des Dienstes muss Gunicorn dann nur noch aus der virtuellen Umgebung aufgerufen und eine WSGI-Bindung für den UNIX-Socket und die Django-Anwendung erstellt werden.
Hier sind einige Beispiele für Einheitendateien, die als Grundlage dienen können. Konfigurieren Sie zunächst den Socket.
[Unit] Description=Gunicorn WSGI socket [Socket] ListenStream=/run/gunicorn.sock [Install] WantedBy=sockets.target
Jetzt müssen Sie den Gunicorn-Daemon konfigurieren.
[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
Erstellen Sie für Nginx einfach eine Proxy-Konfigurationsdatei und richten Sie ein Verzeichnis zum Speichern statischer Inhalte ein, wenn Sie diese verwenden. In RHEL lauten die Nginx-Konfigurationsdateien /etc/nginx/conf.d. Dort können Sie das folgende Beispiel in die Datei /etc/nginx/conf.d/default.conf kopieren und den Dienst starten. Stellen Sie sicher, dass Sie den Servernamen entsprechend Ihrem Hostnamen angeben.
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; } }
Führen Sie die Gunicorn- und Nginx-Sockets mit systemd aus, und Sie können mit dem Testen beginnen.
Fehlerhafter Gateway-Fehler?
Wenn Sie die Adresse im Browser eingeben, wird höchstwahrscheinlich der Fehler 502 Bad Gateway angezeigt. Dies kann durch falsch konfigurierte Berechtigungen für den UNIX-Socket oder durch komplexere Probleme im Zusammenhang mit der Zugriffssteuerung in SELinux verursacht werden.
Im Nginx-Fehlerprotokoll sehen Sie eine Zeile wie die folgende:
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"
Wenn wir Gunicorn direkt testen, erhalten wir eine leere Antwort.
curl —unix-socket /run/gunicorn.sock 8beta1.example.com
Mal sehen, warum das passiert. Wenn Sie das Protokoll öffnen, werden wir höchstwahrscheinlich feststellen, dass das Problem mit SELinux zusammenhängt. Da wir einen Daemon ausführen, für den wir keine eigene Richtlinie erstellt haben, wird dieser als init_t markiert. Lassen Sie uns diese Theorie in der Praxis testen.
sudo setenforce 0
All dies kann Kritik und blutige Tränen verursachen, aber dies ist nur das Debuggen des Prototyps. Wir schalten den Scheck nur aus, um sicherzustellen, dass dies das Problem ist. Danach werden wir alles wieder an ihren Platz zurückbringen.
Durch Aktualisieren der Seite im Browser oder durch Neustarten unseres Befehls curl können Sie die Django-Testseite anzeigen.
Um sicherzustellen, dass alles funktioniert und keine Berechtigungsprobleme mehr auftreten, aktivieren wir SELinux erneut.
sudo setenforce 1
Es wird nicht über audit2allow und die Erstellung von Richtlinien basierend auf Warnungen mit sepolgen gesprochen, da es derzeit keine echte Django-Anwendung gibt, es keine vollständige Karte darüber gibt, auf was Gunicorn möglicherweise zugreifen möchte und welcher Zugriff verweigert werden sollte. Daher ist es erforderlich, SELinux beizubehalten, um das System zu schützen, und gleichzeitig der Anwendung zu ermöglichen, Nachrichten im Überwachungsprotokoll zu starten und zu hinterlassen, damit Sie darauf basierend eine echte Richtlinie erstellen können.
Zulässige Domänen angeben
Nicht jeder hat von erlaubten Domains in SELinux gehört, aber es gibt nichts Neues in ihnen. Viele arbeiteten sogar mit ihnen, ohne es selbst zu merken. Wenn eine Richtlinie basierend auf Überwachungsnachrichten erstellt wird, ist die erstellte Richtlinie eine zulässige Domäne. Versuchen wir, die einfachste zulässige Richtlinie zu erstellen.
Um eine bestimmte zulässige Domain für Gunicorn zu erstellen, benötigen Sie eine bestimmte Richtlinie und die entsprechenden Dateien. Darüber hinaus werden Tools benötigt, um neue Richtlinien zusammenzustellen.
sudo yum install selinux-policy-devel
Der gelöste Domänenmechanismus ist ein hervorragendes Tool zum Erkennen von Problemen, insbesondere bei benutzerdefinierten Anwendungen oder Anwendungen, für die keine Richtlinien erstellt wurden. In diesem Fall ist die zulässige Domänenrichtlinie für Gunicorn so einfach wie möglich. Deklarieren Sie den Haupttyp (gunicorn_t), deklarieren Sie den Typ, mit dem mehrere ausführbare Dateien markiert werden (gunicorn_exec_t), und konfigurieren Sie dann den Übergang für das System, um die ausgeführten Prozesse korrekt zu markieren . In der letzten Zeile wird die Richtlinie zum Zeitpunkt des Ladens standardmäßig aktiviert.
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;
Sie können diese Richtliniendatei kompilieren und dem System hinzufügen.
make -f /usr/share/selinux/devel/Makefile sudo semodule -i gunicorn.pp sudo semanage permissive -a gunicorn_t sudo semodule -l | grep permissive
Lassen Sie uns überprüfen, ob SELinux etwas anderes blockiert als das, worauf unser unbekannter Daemon zugreift.
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 verhindert, dass Nginx Daten in den von Gunicorn verwendeten UNIX-Socket schreibt. In solchen Fällen beginnen sich die Politiker normalerweise zu verändern, aber es stehen noch andere Aufgaben bevor. Sie können die Domäneneinstellungen auch ändern, indem Sie sie von einer Einschränkungsdomäne in eine Berechtigungsdomäne umwandeln. Verschieben Sie nun httpd_t in die Berechtigungsdomäne. Dadurch erhält Nginx den erforderlichen Zugriff, und wir können die weitere Arbeit am Debuggen fortsetzen.
sudo semanage permissive -a httpd_t
Wenn es also möglich war, den SELinux-Schutz beizubehalten (tatsächlich sollten Sie das Projekt nicht mit SELinux im Einschränkungsmodus belassen) und die Berechtigungsdomänen geladen sind, müssen Sie herausfinden, was genau als gunicorn_exec_t markiert werden muss, damit alles wieder wie erwartet funktioniert. Versuchen wir, auf die Website zuzugreifen, um neue Nachrichten zu Zugriffsbeschränkungen anzuzeigen.
sudo ausearch -m AVC -c gunicorn
Sie können viele Nachrichten sehen, die 'comm =' gunicorn '' enthalten und verschiedene Aktionen für Dateien in / srv / djangoapp ausführen. Dies ist also offensichtlich nur einer der Befehle, die Sie markieren sollten.
Darüber hinaus wird jedoch eine Meldung wie die folgende angezeigt:
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
Wenn Sie sich den Status des Gunicorn-Dienstes ansehen oder den Befehl ps ausführen, werden keine laufenden Prozesse angezeigt. Gunicorn scheint zu versuchen, auf den Python-Interpreter in unserer virtuellen Umgebung zuzugreifen, möglicherweise um Arbeitsskripte (Worker) auszuführen. Markieren wir nun diese beiden ausführbaren Dateien und prüfen, ob wir unsere Django-Testseite öffnen können.
chcon -t gunicorn_exec_t /srv/djangoapp/django/bin/gunicorn /srv/djangoapp/django/bin/python3.6
Sie müssen den Gunicorn-Dienst neu starten, damit Sie ein neues Etikett auswählen können. Sie können es sofort neu starten oder den Dienst beenden und den Socket starten lassen, wenn Sie die Site in einem Browser öffnen. Stellen Sie sicher, dass die Prozesse mit ps die richtigen Beschriftungen erhalten.
ps -efZ | grep gunicorn
Denken Sie daran, später eine normale SELinux-Richtlinie zu erstellen!
Wenn Sie sich jetzt die AVC-Nachrichten ansehen, enthält die letzte Nachricht permissive = 1 für alles, was mit der Anwendung zu tun hat, und permissive = 0 für den Rest des Systems. Wenn Sie wissen, welche Art von Zugriff eine echte Anwendung benötigt, können Sie schnell den besten Weg finden, um solche Probleme zu lösen. Bis dahin ist es jedoch besser, das System zu schützen und eine klare und benutzerfreundliche Prüfung durch das Django-Projekt zu erhalten.
sudo ausearch -m AVC
Es stellte sich heraus!
Ein funktionierendes Django-Projekt mit einem Frontend für Nginx und Gunicorn WSGI erschien. Wir haben Python 3 und PostgreSQL 10 über die RHEL 8 Beta-Repositorys konfiguriert. Jetzt können Sie fortfahren und Django-Anwendungen erstellen (oder einfach nur bereitstellen) oder andere verfügbare Tools in RHEL 8 Beta erkunden, um den Optimierungsprozess zu automatisieren, die Leistung zu verbessern oder diese Konfiguration sogar zu containerisieren.