Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Smalltalk
Antworten
Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Beitrag von paedubucher » 01.12.2023 06:26:44

Der DAMPF-Stack

Wer mit Linux unterwegs ist und sich schon etwas mit Web-Entwicklung befasst hat, dem dürfte der LAMP-Stack bestehend aus Linux, Apache, MySQL und PHP bereits begegnet sein. Wer mit Debian GNU/Linux arbeitet, kann das L mit einem D konkretisieren. Und wer PHP via FastCGI statt mit Apaches mod_php einbindet, dem dürfte PHP-FPM ein Begriff sein, wodurch das P zu PF ergänzt wird. So soll hier die Rede vom DAMPF-Stack sein: Debian, Apache, MariaDB (anstelle von MySQL) und PHP-FPM.

In diesem Beitrag wird erklärt, wie dieser Stack aufgesetzt und anhand einer minimalen Beispielanwendung in Betrieb genommen wird.

D wie Debian

Die Ausgangslage ist eine Grundinstallation von Debian 12 Bookworm. Grundlegende Kenntnisse von systemd, HTML, SQL und PHP sind dem Verständnis dienlich; die einzelnen Schritte sollten aber auch ohne dieses Vorwissen nachvollziehbar sein.

Als Konvention wird Befehlen, welche Superuser-Berechtigungen erfordern, das Rautezeichen # vorangestellt. (Diese Befehle lassen sich per sudo ausführen.) Befehlen, die man auch ohne Superuser-Berechtigungen ausführen kann, wird das Dollarzeichen $ vorangestellt.

A wie Apache

Zunächst soll der Apache-Webserver installiert werden:

Code: Alles auswählen

# apt install -y apache2
Dieser sollte nach der Installation bereits gestartet sein:

Code: Alles auswählen

$ systemctl is-active apache2.service
active
Unsere DAMPF-Webseite soll in einem neuen Verzeichnis zu liegen kommen:

Code: Alles auswählen

# mkdir /var/www/dampf
Zu Testzwecken soll eine statische HTML-Seite unter /var/www/dampf/index.html mit folgendem Inhalt angelegt werden:

Code: Alles auswählen

<h1>Hallo DAMPF!</h1>
Eine minimale Virtualhost-Konfiguration unter /etc/apache2/sites-available/dampf.conf mit folgendem Inhalt wird ebenfalls benötigt:

Code: Alles auswählen

<VirtualHost *:80>
    DocumentRoot /var/www/dampf
    ServerName localhost
</VirtualHost>
Die Seite wird aktiviert, indem man einen symbolischen Link innerhalb von /etc/apache2/sites-available zur jeweiligen Konfiguration unter /etc/apache2/sites-enabled erstellt. Dies lässt sich man manuell oder komfortabler mit dem Befehl a2ensite bewerkstelligen:

Code: Alles auswählen

# a2ensite dampf.conf
Die Standardseite von Debian 000-default.conf soll hingegen deaktiviert werden:

Code: Alles auswählen

# a2dissite 000-default.conf
Via systemd soll der Apache-Service zum Neuladen der Konfiguration veranlasst werden:

Code: Alles auswählen

# systemctl reload apache2.service
Anschliessend sollte die Seite unter localhost verfügbar sein.

M wie MariaDB

Weiter geht es mit der Installation von MariaDB, welches ein (für unsere Zwecke vollständig kompatibler) Fork von MySQL ist:

Code: Alles auswählen

# apt install -y mariadb-server
Für ein produktives Setup lohnt sich das Härten der Datenbankinstallation:

Code: Alles auswählen

# mariadb-secure-installation
Da je nach Umgebung und Bedürfnissen andere Optionen sinnvoll sind, soll hier nicht weiter auf diese eingegangen werden. Stattdessen sollen ein neuer Benutzer namens dampfer und eine neue Datenbank namens dampf angelegt werden:

Code: Alles auswählen

# mariadb
> CREATE USER dampfer@localhost IDENTIFIED BY 'topsecret';
> CREATE DATABASE dampf CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
> GRANT ALL PRIVILEGES ON dampf.* TO dampfer@localhost;
> FLUSH PRIVILEGES;
> EXIT
Die Befehle machen folgendes:
  1. Es wird ein neuer Benutzer namens dampf mit dem Passwort topsecret erstellt. (Mit @localhost wird angegeben, dass der Benutzer nicht von einem anderen System aus auf die Datenbank zugreifen kann.)
  2. Eine neue Datenbank namens dampf mit UTF-8-Kodierung ‒ nein: UTF-8 ist kein character set sondern ein encoding; Unicode wäre ein character set ‒ und entsprechender Collation (zwecks Sortierung) wird erstellt.
  3. Der Benutzer dampfer erhält sämtliche Rechte für die Datenbank dampf.
  4. Die alten Berechtigunge werden “gespült” (und anschliessend neu geladen).
  5. Die MariaDB-Konsole wird verlassen.
Damit es etwas zum DAMPFen gibt, soll eine entsprechende Datenbank angelegt werden. Das Skript hierzu wird in der Datei dampf.sql angelegt:

Code: Alles auswählen

CREATE TABLE dampfware (
    id INTEGER AUTO_INCREMENT PRIMARY KEY,
    substanz VARCHAR(255) UNIQUE NOT NULL,
    geruch VARCHAR(255) NULL,
    stinkend TINYINT(1) NOT NULL DEFAULT 0,
    toxisch TINYINT(1) NOT NULL DEFAULT 0
);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
    VALUES ("faule Eier", "Schwefel", 1, 0);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
    VALUES ("Surströmming", "Verwesung", 1, 0);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
    VALUES ("Trifluormethylhypofluorit", NULL, 0, 1);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
    VALUES ("Limburger", "faules Gemüse", 1, 0);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
    VALUES ("Weihrauch", "Messdienergewand", 0, 0);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
    VALUES ("Buttersäure", "Mundgeruch", 1, 1);
Das Skript dampf.sql soll nun ausgeführt werden, wozu Datenbank, Benutzername und Passwort (letzteres interaktiv) eingegeben werden müssen. Das Skript wird via Standard Input eingelesen:

Code: Alles auswählen

$ mariadb --database=dampf --user=dampfer --password <dampf.sql
Enter password: *********
Zur Kontrolle sollen die Daten noch (tabellarisch: -t) ausgegeben werden; zwecks Platzwersparnis mit den kurzen Varianten der Flags:

Code: Alles auswählen

$ echo 'SELECT * FROM dampfware;' | mariadb -D dampf -u dampfer -p -t
Enter password: *********
+----+---------------------------+------------------+----------+---------+
| id | substanz                  | geruch           | stinkend | toxisch |
+----+---------------------------+------------------+----------+---------+
|  1 | faule Eier                | Schwefel         |        1 |       0 |
|  2 | Surströmming              | Verwesung        |        1 |       0 |
|  3 | Trifluormethylhypofluorit | NULL             |        0 |       1 |
|  4 | Limburger                 | faules Gemüse    |        1 |       0 |
|  5 | Weihrauch                 | Messdienergewand |        0 |       0 |
|  6 | Buttersäure               | Mundgeruch       |        1 |       1 |
+----+---------------------------+------------------+----------+---------+
P wie PHP

Um die Dampfwaren aus der Datenbank auf eine Webseite zu bringen wird PHP benötigt, welches in Version 8.2 installiert werden soll:

Code: Alles auswählen

# apt install -y php8.2
Der Interpeter soll sogleich mit einem Einzeiler getestet werden:

Code: Alles auswählen

$ php -r 'echo("PHP Version " . phpversion() . " läuft.\n");'
PHP Version 8.2.7 läuft
Da PHP offenbar funktionstüchtig ist, soll die statische HTML-Seite durch eine dynamische PHP-Seite mit folgendem Inhalt ersetzt werden (/var/www/dampf/index.php):

Code: Alles auswählen

<?php
    echo("<h1>Hallo DAMPF!</h1>");
    echo("<p>" . "PHP Version " . phpversion() . " läuft.</p>");
?>
Die alte HTML-Seite kann entfernt werden:

Code: Alles auswählen

# rm /var/www/dampf/index.html
Unter localhost sollte nun die von PHP dynamisch gerenderte Seite aufgerufen werden.

Um mehr über die Umgebung zu erfahren, soll zusätzlich die Datei /var/www/dampf/phpinfo.php mit folgendem Inhalt angelegt werden:

Code: Alles auswählen

<?php
    phpinfo();
?>
Unter localhost/phpinfo.php erfährt man nun u.a. folgendes:

Code: Alles auswählen

Server API: Apache 2.0 Handler
Das bedeutet, dass PHP von Apache mit mod_php ausgeführt wird. Ein DAMPF-Stack ist das noch nicht, es fehlt das F wie FPM.

F wie FPM

FPM steht für FastCGI Process Manager und ist eine Methode um PHP-Code auszuführen, die gegenüber mod_php bzw. herkömmlichen CGI einige Vorteile bietet:
  • PHP und Apache müssen nicht mehr mit gleichen Berechtigungen ausgeführt werden.
  • Es muss nicht (wie bei CGI) für jede Anfrage ein neuer PHP-Prozess gestartet werden.
  • PHP-FPM kann eine Reihe von PHP-Prozessen vorhalten, auf welche die Anfragen dann nebenläufig verteilt werden. Dies führt zu einer höheren Performanz unter starker Last.
Um PHP-FPM verwenden zu können, müssen weitere Pakete installiert werden:

Code: Alles auswählen

# apt install -y php8.2-fpm libapache2-mod-fcgid
Das Paket php8.2-fpm ist der Dienst, welcher die PHP-Prozesse verwaltet. Das Apache-Modul libapache2-mod-fcgid delegiert die Anfragen, welche die Ausführung von PHP erfordern, an PHP-FPM weiter.

Das Apache-Modul mod_php muss deaktiviert; das Proxy-Modul für FastCGI muss aktiviert werden:

Code: Alles auswählen

# a2dismod php8.2
# a2enmod proxy_fcgi
Weiter muss die Konfiguration von PHP-FPM aktiviert werden:

Code: Alles auswählen

# a2enconf php8.2-fpm
Entsprechende symbolische Links werden in /etc/apache2/mods-enabled und in /etc/apache2/conf-enabled erstellt bzw. entfernt.

Damit die Änderungen wirksam werden, muss die Konfiguration von Apache neu geladen werden:

Code: Alles auswählen

# systemctl reload apache2
Beim nächsten Aufruf von localhost/phpinfo.php sollte nun folgende Angabe erscheinen:

Code: Alles auswählen

Server API: FPM/FastCGI
Damit wäre der DAMPF-Stack betriebsbereit!

Full Stack DAMPF

Da nun der ganze Stack lauffähig ist, sollen auch alle Komponenten davon eingesetzt werden.

Eine Datenbankverbindung lässt sich mit PHP Data Objects (PDO) erstellen. Die Verbindung soll dann sogleich verwendet werden um die ganzen DAMPF-Waren als HTML-Seite auszugeben (/var/www/dampf/dampfwaren.php):

Code: Alles auswählen

<ol>
    <p>DAMPF-Waren:</p>
    <?php
        try {
            $db = new PDO("mysql:host=localhost;dbname=dampf", "dampfer", "topsecret");
            foreach ($db->query("SELECT * FROM dampfware;") as $dw) {
                echo("<li value=\"{$dw['id']}\">");
                echo("{$dw['substanz']}: {$dw['geruch']}");
                echo(" (stinkend: {$dw['stinkend']}, toxisch: {$dw['toxisch']})");
                echo("</li>");
            }
        } catch (PDOException $e) {
            die($e);
        }
    ?>
</ol>
Der Datenbanktreiber für MySQL (bzw. für MariaDB) muss noch über das entsprechende Paket installiert werden:

Code: Alles auswählen

# apt install php-mysql
Anschliessend sollte ein Aufruf von localhost/dampfwaren.php nun folgende Ausgabe erzeugen:

Code: Alles auswählen

DAMPF-Waren:

1. faule Eier: Schwefel (stinkend: 1, toxisch: 0)
2. Surstömming: Verwesung (stinkend: 1, toxisch: 0)
3. Trifluormethylhypofluorit: (stinkend: 0, toxisch: 1)
4. Limburger: faules Gemüse (stinkend: 1, toxisch: 0)
5. Weihrauch: Messdienergewand (stinkend: 0, toxisch: 0)
6. Buttersäure: Mundgeruch (stinkend: 1, toxisch: 1)
Übungen

Wer den hier beschriebenen DAMPF-Stack mit dieser Anleitung zum Laufen gebracht hat, der hat schon einiges geleistet. Wer noch nicht genug geDAMPFt hat, kann sich an folgenden Übungen versuchen:
  1. Die Datenbank-Verbindungsdaten sind in dampfwaren.php hartkodiert. Dies ist einerseits unflexibel, andererseits sicherheitstechnisch nicht optimal, da Quellcode schnell unwiderruflich in einem Versionierungssystem mit Änderungshistorie landet. Besser wäre es beispielsweise, die Verbindungsdaten in Umgebungsvariablen auszulagern. Hierzu nur einige wenige Stichworte:
    • Die Datei /etc/php/8.2/fpm/pool.d/www.conf mit den Direktiven env (Array) und clear_env (yes/no).
    • Das assoziative Array $_SERVER von PHP.
  2. Die Ausgabe der DAMPF-Waren als Liste weist noch einige Mängel optischer Natur auf, die verbessert werden könnten:
    • Die Darstellung von geruchlosen Einträgen (Trifluormethylhypofluorit) ist nicht optimal, da auf den Doppelpunkt keine Geruchsbezeichnung folgt, sondern direkt die geklammerten Eigenschaften aufgelistet werden.
    • Die TINYINT(1)-Felder “stinkend” und “toxisch” könnten besser dargestellt werden.
    • Eine Tabelle mit Spaltennamen wäre wohl übersichtlicher als eine Aufzählung.
Ich bin gespannt auf eure Anpassungen und evtl. Screenshots!
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Benutzeravatar
whisper
Beiträge: 3193
Registriert: 23.09.2002 14:32:21
Lizenz eigener Beiträge: GNU Free Documentation License
Kontaktdaten:

Re: Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Beitrag von whisper » 01.12.2023 08:37:32

Sehr schön aufbereitet! Gefällt mir.
Ergänzung:
paedubucher hat geschrieben: ↑ zum Beitrag ↑
01.12.2023 06:26:44

Code: Alles auswählen

$ mariadb --database=dampf --user=dampfer --password <dampf.sql
Enter password: *********
und wenn man nicht immer das Passwort eingeben möchte, dann den Socket verwenden

Code: Alles auswählen

mariadb -S /var/run/mysqld/mysqld.sock --database=dampf --user=dampfer <dampf.sql 
Auf einer lokalen Umgebung macht das Sinn, da der Socket ohnehin rootrechte hat.

uname
Beiträge: 12075
Registriert: 03.06.2008 09:33:02

Re: Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Beitrag von uname » 01.12.2023 09:00:44

Ich finde den Beitrag auch sehr schön. Vielen Dank dafür.

Ich würde nun gerne wissen, wie viel schneller DAMPF im Gegensatz zu DAMP ist. Kann vielleicht jemand ein Script schreiben, wo über einen Webservice eine Vielzahl an Anfragen einmal "langsam" mit mod_php und einmal mit Dampf mit PHP-FPM durchgeführt wird?

Benutzeravatar
mn77de
Beiträge: 155
Registriert: 23.11.2003 16:53:53
Wohnort: Übersee
Kontaktdaten:

Re: Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Beitrag von mn77de » 01.12.2023 09:43:16

Sehr schöner Beitrag und vielen Dank fürs Eröffnen des Adventskalenders! :THX:
DAMPF :lol: :lol: :lol:
Aber gutes Thema, DAMP hab' ich bereits am laufen und regelmäßig im Einsatz. 8)
OpenSource! :THX:

Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Beitrag von paedubucher » 01.12.2023 09:50:58

uname hat geschrieben: ↑ zum Beitrag ↑
01.12.2023 09:00:44
Ich finde den Beitrag auch sehr schön. Vielen Dank dafür.

Ich würde nun gerne wissen, wie viel schneller DAMPF im Gegensatz zu DAMP ist. Kann vielleicht jemand ein Script schreiben, wo über einen Webservice eine Vielzahl an Anfragen einmal "langsam" mit mod_php und einmal mit Dampf mit PHP-FPM durchgeführt wird?
Danke schon einmal für die Rückmeldung!

Die Performance-Messung wäre eine schöne Übung. Ideal wäre, wenn man gleich die Anzahl der Clients und die Frequenz bestimmen könnte. Das schreit für mich geradezu nach einem kleinen Go-Tool. Der Feierabend ist gerettet! :D

Nachtrag: Ich hatte bereits Zeit ein kleines Kommandozeilentool dafür zu schreiben: request0r
Zuletzt geändert von paedubucher am 01.12.2023 13:34:29, insgesamt 1-mal geändert.
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

thoerb
Beiträge: 1677
Registriert: 01.08.2012 15:34:53
Lizenz eigener Beiträge: MIT Lizenz

Re: Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Beitrag von thoerb » 01.12.2023 10:46:34

Ich finde den Beitrag ebenfalls sehr schön und werde den Link dazu gleich im meinem DokuWiki ablegen, das hier auf DAMP läuft. (Eigentlich läuft es ja nur auf DAP)

Vielen Dank dafür. :THX:

Benutzeravatar
Livingston
Beiträge: 1454
Registriert: 04.02.2007 22:52:25
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: 127.0.0.1

Re: Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Beitrag von Livingston » 01.12.2023 13:23:13

Merci, ich hab mich jahrelang nicht mehr um Neuerungen gekümmert. Jetzt habe ich endlich mal 'nen Anlass, mich um das "F" in "DAMPF" zu kümmern.
Thumbs up :THX:
Der Hauptunterschied zwischen etwas, was möglicherweise kaputtgehen könnte und etwas, was unmöglich kaputtgehen kann, besteht darin, dass sich bei allem, was unmöglich kaputtgehen kann, falls es doch kaputtgeht, normalerweise herausstellt, dass es unmöglich zerlegt oder repariert werden kann.
Douglas Adams

inne
Beiträge: 3281
Registriert: 29.06.2013 17:32:10
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Beitrag von inne » 01.12.2023 14:29:52

paedubucher hat geschrieben: ↑ zum Beitrag ↑
01.12.2023 06:26:44
nein: UTF-8 ist kein character set sondern ein encoding; Unicode wäre ein character set
Danke für die Ausführung.

:THX: :THX: :THX:

Damit hast Du bei mir ein riesiges Verständnisproblem gelöst.

Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Beitrag von paedubucher » 01.12.2023 15:08:31

inne hat geschrieben: ↑ zum Beitrag ↑
01.12.2023 14:29:52
paedubucher hat geschrieben: ↑ zum Beitrag ↑
01.12.2023 06:26:44
nein: UTF-8 ist kein character set sondern ein encoding; Unicode wäre ein character set
Danke für die Ausführung.

:THX: :THX: :THX:

Damit hast Du bei mir ein riesiges Verständnisproblem gelöst.
Ich gebe den Dank gerne an meillo weiter, der das einmal in einem Chaos Seminar ausgeführt hatte. Seither sehe ich diesen Fehler überall, inkl. HTML (charset="utf-8" gehört zum Standard).
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

TuxPeter
Beiträge: 1966
Registriert: 19.11.2008 20:39:02
Lizenz eigener Beiträge: MIT Lizenz

Re: Adventskalender 1. Dezember 2023 - Der DAMPF-Stack

Beitrag von TuxPeter » 01.12.2023 21:27:30

Möchte auch für diesen schönen Beitrag danken!
Er betrifft Dinge, von denen ich nur wenig Ahnung habe, und hat meine Ahnungslosigkeit doch deutlich verringert und böte einen sehr guten Ansatz, den Nebel noch viel gründlicher zu tun vertreiben. ...

Antworten