<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: webdevmentor</title>
    <description>The latest articles on DEV Community by webdevmentor (@webdevmentor).</description>
    <link>https://dev.to/webdevmentor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4027763%2Fbbbb37a2-e7a0-47c6-96a0-c5397745ade2.png</url>
      <title>DEV Community: webdevmentor</title>
      <link>https://dev.to/webdevmentor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/webdevmentor"/>
    <language>en</language>
    <item>
      <title>Docker für PHP, Apache und MariaDB – aus einem Container wird eine Entwicklungsumgebung</title>
      <dc:creator>webdevmentor</dc:creator>
      <pubDate>Mon, 13 Jul 2026 19:40:56 +0000</pubDate>
      <link>https://dev.to/webdevmentor/docker-fur-php-apache-und-mariadb-aus-einem-container-wird-eine-entwicklungsumgebung-4oic</link>
      <guid>https://dev.to/webdevmentor/docker-fur-php-apache-und-mariadb-aus-einem-container-wird-eine-entwicklungsumgebung-4oic</guid>
      <description>&lt;p&gt;Im &lt;a href="https://www.webdevmentor.info/posts/php-apache-docker/" rel="noopener noreferrer"&gt;letzten Beitrag&lt;/a&gt; unserer Docker-Serie haben wir eine einfache PHP-Entwicklungsumgebung mit Docker erstellt. Für kleine Projekte oder erste Experimente ist das bereits völlig ausreichend und hat den großen Vorteil, dass keine lokale PHP-Installation mehr notwendig ist.&lt;/p&gt;

&lt;p&gt;Sobald eine Anwendung Daten speichern soll, stößt dieses einfache Setup allerdings an seine Grenzen. Neben dem Webserver benötigen wir nun auch eine Datenbank. Außerdem muss PHP die passenden Erweiterungen mitbringen, damit später überhaupt eine Verbindung zur Datenbank aufgebaut werden kann.&lt;/p&gt;

&lt;p&gt;In diesem Beitrag erweitern wir deshalb unsere bestehende Docker-Umgebung um einen MariaDB-Container und passen unseren Webcontainer entsprechend an.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unsere compose.yml erweitern
&lt;/h2&gt;

&lt;p&gt;Im letzten Beitrag bestand unsere &lt;code&gt;compose.yml&lt;/code&gt; lediglich aus einem Webcontainer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php:8.5-apache&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/var/www/html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Für unsere Datenbank ergänzen wir nun einen zweiten Service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/var/www/html&lt;/span&gt;

  &lt;span class="na"&gt;mariadb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb:10.11&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secret&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mariadb_data:/var/lib/mysql&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mariadb_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aus einem einzelnen Container ist damit eine kleine Entwicklungsumgebung geworden. Der Webcontainer kümmert sich um PHP und Apache, während MariaDB unsere Daten speichert.&lt;/p&gt;

&lt;h2&gt;
  
  
  Warum braucht die Datenbank ein eigenes Volume?
&lt;/h2&gt;

&lt;p&gt;Vielleicht ist dir der neue Abschnitt am Ende der Datei bereits aufgefallen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mariadb_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ein Docker-Container ist grundsätzlich austauschbar. Wird ein Container gelöscht, gehen auch alle darin gespeicherten Daten verloren.&lt;/p&gt;

&lt;p&gt;Damit uns das mit unserer Datenbank nicht passiert, verwenden wir ein &lt;strong&gt;Docker Volume&lt;/strong&gt;. Man kann es sich zunächst wie einen Speicherort vorstellen, den Docker unabhängig vom eigentlichen Container verwaltet.&lt;/p&gt;

&lt;p&gt;Der MariaDB-Container speichert seine Daten nicht im Container selbst, sondern im Volume &lt;code&gt;mariadb_data&lt;/code&gt;. Selbst wenn der Container später gelöscht oder neu erstellt wird, bleiben unsere Tabellen und Daten erhalten.&lt;/p&gt;

&lt;h2&gt;
  
  
  Den Webcontainer anpassen
&lt;/h2&gt;

&lt;p&gt;Vielleicht ist dir noch eine weitere Änderung aufgefallen.&lt;/p&gt;

&lt;p&gt;Im letzten Beitrag haben wir den Webcontainer direkt über das &lt;code&gt;image&lt;/code&gt;-Attribut gestartet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php:8.5-apache&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jetzt verwenden wir stattdessen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Der Grund ist einfach: Unser PHP-Container benötigt jetzt zusätzlich die Erweiterungen für die Kommunikation mit MySQL-kompatiblen Datenbanken. Dafür erstellen wir erstmals ein eigenes Dockerfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; php:8.5-apache&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;docker-php-ext-install mysqli pdo pdo_mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mehr ist an dieser Stelle zunächst gar nicht notwendig.&lt;/p&gt;

&lt;p&gt;Während der Entwicklung möchten wir unseren Quellcode möglichst komfortabel bearbeiten. Deshalb kopieren wir ihn nicht in das Image, sondern binden ihn direkt in den Container ein. Änderungen an den PHP-Dateien stehen dadurch sofort zur Verfügung und wir müssen das Image nicht nach jeder kleinen Anpassung neu erstellen.&lt;/p&gt;

&lt;p&gt;Dafür verwenden wir dieses Volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/var/www/html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Diese Art der Einbindung bezeichnet Docker als &lt;strong&gt;Bind Mount&lt;/strong&gt;. Dabei wird unser Projektverzeichnis direkt mit dem Verzeichnis &lt;code&gt;/var/www/html&lt;/code&gt; im Container verbunden.&lt;/p&gt;

&lt;h2&gt;
  
  
  Die Container starten
&lt;/h2&gt;

&lt;p&gt;Sind beide Dateien vorbereitet, genügt wie gewohnt ein einziger Befehl.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker erstellt zunächst unser PHP-Image aus dem Dockerfile, lädt anschließend das MariaDB-Image herunter, legt das Docker Volume an und startet beide Container.&lt;/p&gt;

&lt;p&gt;Mit&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;lässt sich anschließend überprüfen, ob beide Dienste erfolgreich laufen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wie findet PHP die Datenbank?
&lt;/h2&gt;

&lt;p&gt;Obwohl Webserver und Datenbank in unterschiedlichen Containern laufen, können sie problemlos miteinander kommunizieren.&lt;/p&gt;

&lt;p&gt;Docker Compose erstellt dafür automatisch ein gemeinsames Netzwerk. Jeder Service ist innerhalb dieses Netzwerks über seinen Servicenamen erreichbar. Unsere Datenbank ist deshalb nicht unter &lt;code&gt;localhost&lt;/code&gt;, sondern unter &lt;code&gt;mariadb&lt;/code&gt; erreichbar.&lt;/p&gt;

&lt;p&gt;Eine Verbindung mit PDO könnte beispielsweise so aussehen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$dsn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'mysql:host=mariadb;dbname=app;charset=utf8mb4'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'app'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'secret'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$pdo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PDO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dsn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Den Hostnamen müssen wir dabei nicht selbst konfigurieren. Docker übernimmt die interne Namensauflösung automatisch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Warum MariaDB?
&lt;/h2&gt;

&lt;p&gt;In diesem Beitrag verwenden wir bewusst MariaDB. Die Datenbank ist vollständig Open Source, weit verbreitet und für die meisten PHP-Anwendungen ein direkter Ersatz für MySQL.&lt;/p&gt;

&lt;p&gt;Soll stattdessen MySQL verwendet werden, genügt in den meisten Fällen bereits eine kleine Änderung.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:8.4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Außerdem müssen die Umgebungsvariablen von &lt;code&gt;MARIADB_&lt;/code&gt; auf &lt;code&gt;MYSQL_&lt;/code&gt; angepasst werden.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dateien aus dem Artikel
&lt;/h2&gt;

&lt;p&gt;Du möchtest die Entwicklungsumgebung direkt ausprobieren? Alle benötigten Dateien aus diesem Artikel findest du als Gist:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/webdevmentor/b77d394f064f1ecc7c1ebaa5d9c6cb63" rel="noopener noreferrer"&gt;PHP Apache MariaDB Development Environment with Docker Compose auf GitHub.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fazit
&lt;/h2&gt;

&lt;p&gt;Mit wenigen zusätzlichen Zeilen ist aus unserem einzelnen PHP-Container eine vollständige Entwicklungsumgebung geworden. Docker Compose startet Webserver und Datenbank gemeinsam, Docker Volumes sorgen dafür, dass unsere Daten dauerhaft erhalten bleiben, und über das Dockerfile können wir unser PHP-Image an die Anforderungen unseres Projekts anpassen.&lt;/p&gt;

&lt;p&gt;Damit steht eine solide Grundlage für die weitere Entwicklung bereit – und das alles mit einem einzigen Befehl.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>mariadb</category>
      <category>php</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
