{"id":6897,"date":"2020-08-08T18:14:03","date_gmt":"2020-08-08T16:14:03","guid":{"rendered":"https:\/\/u-labs.de\/portal\/?p=6897"},"modified":"2022-12-11T16:46:07","modified_gmt":"2022-12-11T14:46:07","slug":"postgres-mit-docker-docker-compose-installieren-inkl-postgresql-grundlagen","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/postgres-mit-docker-docker-compose-installieren-inkl-postgresql-grundlagen\/","title":{"rendered":"Postgres mit Docker\/Docker-Compose installieren inkl. PostgreSQL Grundlagen"},"content":{"rendered":"<p>Die Datenbank Postgres bzw. PostgreSQL erfreut sich steigender Beliebtheit. Eben so verh\u00e4lt es sich mit Docker: Schlie\u00dflich kann man eine neue Datenbank damit sehr einfach installieren und testen. In diesem Artikel wird Schritt f\u00fcr Schritt gezeigt, wie man Postgres mithilfe von Docker zum Laufen bekommt.<\/p>\n<h2 class=\"wp-block-heading\">Warum Postgres mit Docker installieren?<\/h2>\n<p>PostgreSQL, auch als Postgres bezeichnet, ist ein objektrelationales Open-Source-Datenbankmanagementsystem. Entwickler entscheiden sich h\u00e4ufig f\u00fcr diese relationale Datenbank, da sie frei, stabil und flexibel ist. Tats\u00e4chlich sind PostgreSQL und MySQL die beliebtesten relationalen Datenbankverwaltungssysteme.<\/p>\n<p>Heute ist Postgres eines der am weitesten verbreiteten &#8220;Docker-Images&#8220;, die in Containern laufen. Die Beliebtheit von containerisierten Datenbanken wird der Einfachheit zugeschrieben, mit der sie eingesetzt werden k\u00f6nnen. Anstatt eine zentrale Datenbank f\u00fcr viele Anwendungen zu haben, k\u00f6nnen Entwickler auch einen PostgreSQL-Container f\u00fcr jede Anwendung verwenden.<\/p>\n<p>Container k\u00f6nnen je nach Bedarf flexibel erzeugt und auch wieder gel\u00f6scht werden. Dabei findet kein tiefer Eingriff in das Betriebssystem statt. Durch deren Isolation kommt es selbst bei der parallelen Verwendung mehrere Versionen nicht zu Konflikten. Daher sind Docker-Container ideal, um Erfahrung mit einer neuen Datenbank zu sammeln.<\/p>\n<h2 class=\"wp-block-heading\">Voraussetzungen<\/h2>\n<p>Ihr braucht ein Linux-System, auf dem Docker in einer m\u00f6glichst aktuellen Version installiert wurde. Docker-Compose ist ebenso zu empfehlen, aber nicht zwingend notwendig.<\/p>\n<h2 class=\"wp-block-heading\">Variante 1: Postgres mit Plain Docker installieren\/starten<\/h2>\n<p>Am einfachsten und schnellsten kann ein Container \u00fcber die Kommandozeile gestartet werden. Dies ist f\u00fcr die ersten Schritte sinnvoll. Sp\u00e4testens beim Arbeiten mit mehreren Containern bzw. komplexeren Konfigurationen wird das Arbeiten mit langen Kommandozeilenbefehlen un\u00fcbersichtlich und fehleranf\u00e4llig. Hier ist die Verwendung von Docker-Compose zu empfehlen (siehe Variante 2). <\/p>\n<p>In beiden F\u00e4llen verwenden wir das offizielle Postgres-Image vom Docker-Hub. Die erzeugten Container sind somit identisch. Nur die Art des Startens variiert.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">docker run --name my-postgres -e POSTGRES_PASSWORD=1234 -d postgres<\/code><\/pre>\n<p>Dieser Befehl startet einen neuen Container namens <strong>my-postgres<\/strong>. W\u00fcrden wir dies nicht angeben, erzeugt Docker einen zuf\u00e4llig generierten Namen. Funktionell ist er irrelevant, aber wichtig, um den Container sp\u00e4ter wieder zu finden.<\/p>\n<p>Mit dem Schalter <strong>-e<\/strong> \u00fcbergeben wir eine Umgebungsvariable. Die Doku im Docker-Hub zeigt, welche f\u00fcr das jeweilige Image zur Verf\u00fcgung stehen. Hier  legen wir das Passwort f\u00fcr den Postgres-Benutzer auf 1234 fest. <\/p>\n<p>Der Schalter <strong>-d<\/strong> steht f\u00fcr <strong>daemonize<\/strong>. Er startet den Container im Hintergrund. So kann unser Konsolenfenster weiter verwendet werden. Der Prozess l\u00e4uft im Hintergrund weiter und ist nicht an die Konsolensitzung gebunden.<\/p>\n<p>Schlussendlich ben\u00f6tigt Docker noch das Abbild. Da wir keinen Tag angegeben haben, wird latest (also die aktuellste Version) verwendet. Ein Blick in den Docker-Hub zeigt, welche Tags zur Verf\u00fcgung stehen. F\u00fcr die weitere Verwendung ist grunds\u00e4tzlich zu empfehlen, zumindest einen Tag f\u00fcr die Hauptversion (z.B. <strong>postgres:12<\/strong>) zu setzen. Sonst werden ggf. unkontrolliert Updates eingespielt, falls das Image gel\u00f6scht wird.<\/p>\n<h3 class=\"wp-block-heading\">Auf die Datenbank zugreifen<\/h3>\n<p>Mit <strong>docker ps<\/strong> pr\u00fcfen wir zun\u00e4chst, ob der Container erfolgreich gestartet wurde. Um ihn wieder zu finden, kommt der zuvor vergebene Name als Filter zum Einsatz:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ docker ps | grep my-postgres\n88c9e89f6b80        postgres                                              &quot;docker-entrypoint.s\u2026&quot;   About a minute ago   Up About a minute   5432\/tcp                                     my-postgres<\/code><\/pre>\n<p>Nun betreten wir den Container, um auf das Kommandozeilenwerkzeug von Postgres zuzugreifen. Dies geschieht durch <strong>docker exec<\/strong>. Auch an dieser Stelle wird der Containername verwendet:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ docker exec -it --user postgres my-postgres bash<\/code><\/pre>\n<p>Bei Postgres ist die Angabe des Benutzers notwendig, da die Datenbank im Kontext des Linux-Nutzers arbeitet. Nun erhalten wir eine Shell im Container und k\u00f6nnen den Client mit <strong>psql<\/strong> starten:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ docker exec -it --user postgres my-postgres bash\npostgres@88c9e89f6b80:\/$ psql \npsql (12.3 (Debian 12.3-1.pgdg100+1))\nType &quot;help&quot; for help.\n\npostgres=# <\/code><\/pre>\n<p>Ab hier k\u00f6nnen die Standardbefehle von Postgres genutzt werden. Wer diese noch nicht kennt, findet weiter unten einige Beispiele.<\/p>\n<h2 class=\"wp-block-heading\">Variante 2: Postgres mit Docker-Compose<\/h2>\n<p>Docker-Compose bietet den Vorteil, die Konfiguration in eine Yaml-Datei auszulagern. Damit entfallen lange CLI-Aufrufe von <strong>docker run<\/strong>. Au\u00dferdem k\u00f6nnen mehrere Container gestartet und in Abh\u00e4ngigkeit zueinander gesetzt werden. Docker-Compose startet dann beispielsweise zuerst die Datenbank, danach einen Anwendungsserver.<\/p>\n<p>Zun\u00e4chst legen wir einen Ordner an<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">mkdir postgres\ncd postgres<\/code><\/pre>\n<p>und erstellen darin eine Datei namens <strong>docker-compose.yml<\/strong> mit folgendem Inhalt:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">version: &#039;2.4&#039;\nservices:\n  my-postgres:\n    image: postgres\n    environment:\n      - POSTGRES_PASSWORD=1234\n<\/code><\/pre>\n<p>Dies definiert einen Container mit dem Postgres-Image, in dem die Umgebungsvariable f\u00fcr das Passwort gesetzt wird. Die Yaml-Datei entspricht dem obigen <strong>docker run<\/strong> Aufruf aus Variante 1. Da sich die gesamte Konfiguration darin befindet, gen\u00fcgt zum Starten folgender kurzer Befehl:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">docker-compose up -d<\/code><\/pre>\n<p>Eine \u00dcbersicht aller Container aus der Yaml-Datei mit ihrem Status liefert <strong>docker-compose ps<\/strong>. Um einen Befehl im Container auszuf\u00fchren, existiert <strong>docker-compose exec<\/strong> analog zu <strong>docker exec<\/strong>. Als Parameter ist der definierte Name (hier ebenfalls <strong>my-postgres<\/strong>) anzugeben:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ docker-compose exec --user postgres my-postgres bash\npostgres@878b80da23f7:\/$<\/code><\/pre>\n<p>Durch die Eingabe von <strong>psql<\/strong> wird eine Postgres-Shell gestartet. Alternativ k\u00f6nnen wir statt der Bash aber dies auch direkt als Befehl f\u00fcr <strong>docker-compose exec<\/strong> angeben. So entf\u00e4llt dieser Schritt, da die Postgres-Shell direkt gestartet wird:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">$ docker-compose exec --user postgres my-postgres psql\npsql (12.3 (Debian 12.3-1.pgdg100+1))\nType &quot;help&quot; for help.\n\npostgres=#<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Postgres f\u00fcr ander Anwendungen erreichbar machen (Portfreigabe)<\/h2>\n<p>Unabh\u00e4ngig davon, f\u00fcr welche der beiden Varianten man sich entschieden hat: Postgres ist nur innerhalb seines Containers erreichbar. Andere Anwendungen auf dem PC k\u00f6nnen sie nicht nutzen. Dies lie\u00dfe sich \u00e4ndern, in dem man bei Docker-Compose einen weiteren Container hinzuf\u00fcgt. Er kann \u00fcber den Hostname (hier <strong>my-postgres<\/strong>) auf die Datenbank zugreifen.<\/p>\n<p>Gerade beim Testen und Entwickeln m\u00f6chte man jedoch auch au\u00dferhalb des Containers eine Verbindung herstellen. Beispielsweise f\u00fcr einen Client wie DbWeaver. Oder eine lokal laufende Applikation, die noch nicht Containerisiert wurde. In diesem Falle helfen Portfreigaben.<\/p>\n<p><strong>Plain Docker (docker run)<\/strong><\/p>\n<p>Hier f\u00fcgen wir mit dem Schalter <strong>-p<\/strong> eine Portfreigabe hinzu. Standardm\u00e4\u00dfig ist dies Port 5432, sodass <strong>-p &#8222;5432:5432&#8220;<\/strong> an den obigen Befehl angehangen werden muss. Vorher den Container mit <strong>docker stop my-postgres<\/strong> beenden.<\/p>\n<p><strong>Docker-Compose<\/strong><\/p>\n<p>In der <strong>docker-compose.yml<\/strong> einfach ans Ende eine Liste <strong>ports<\/strong> anf\u00fcgen. Das gesamte Compose-File sieht danach so aus:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">version: &#039;2.4&#039;\nservices:\n  my-postgres:\n    image: postgres\n    environment:\n      - POSTGRES_PASSWORD=1234\n    ports:\n      - 5432:5432<\/code><\/pre>\n<p>Um die \u00c4nderungen anzuwenden, zun\u00e4chst die Container mit <strong>docker-compose down<\/strong> beenden. Anschlie\u00dfend wie gehabt <strong>docker-compose up -d<\/strong> zum Starten ausf\u00fchren.<\/p>\n<h2 class=\"wp-block-heading\">Einstieg in Postgres: Erste Gehversuche auf der Kommandozeile<\/h2>\n<p>Nun haben wir eine Postgres-Instanz. Doch wie arbeite ich nun damit? Diese Frage d\u00fcrfen sich vor allem jene stellen, die bisher noch nicht damit gearbeitet haben &#8211; unabh\u00e4ngig von Docker. Wer sich mit anderen gro\u00dfen Datenbanken wie MySQL auskennt, kann Teile seines Wissens auch hier nutzen. Doch gerade der Einstieg ist etwas ungewohnt: Bekannte Befehl wie <strong>SHOW DATABASES<\/strong> funktionieren hier nicht.<\/p>\n<p>Im Folgenden wird davon ausgegangen, dass ihr eine Postgres-Shell wie oben beschrieben ge\u00f6ffnet habt. Sie ist daran zu erkennen, dass links <strong>postgres=#<\/strong> steht.<\/p>\n<h3 class=\"wp-block-heading\">Aufbau von Postgres-Befehlen<\/h3>\n<p>Grunds\u00e4tzlich beginnen die meisten Befehle mit einem umgekehrten Schr\u00e4gstrich \\ der als Backslash bezeichnet wird. Im Anschluss folgt ein Befehl. Hier steht die Wahl zwischen der Kurz- und Langschreibweise. \u00c4hnliches kennt man bereits von CLI-Parametern, bei denen oft z.B. <strong>-u<\/strong> und <strong>&#8211;user<\/strong> angeboten wird.<\/p>\n<p>Bei Postgres gibt es analog <strong>\\h<\/strong> oder <strong>\\help<\/strong>, um die Hilfe aufzurufen. Dadurch erh\u00e4lt man eine Liste aller Befehle. Ben\u00f6tigt man die Doku zu einem konkreten Befehl, kann dieser optional angegeben werden. Durch Eingabe von <strong>\\h create table<\/strong> bzw. <strong>\\help create table<\/strong> k\u00f6nnen wir also nachschlagen, wie eine Tabelle angelegt wird. <\/p>\n<h3 class=\"wp-block-heading\">\\l &#8211; Datenbanken auflisten<\/h3>\n<p>Eine Datenbank ist eine Sammlung von Tabellen, Informationen \u00fcber diese Tabellen, Informationen \u00fcber Benutzer und ihre Berechtigungen und vieles mehr. Einige dieser Datenbanken (und die darin enthaltenen Tabellen) werden von PostgreSQL automatisch aktualisiert, wenn man sie benutzt.<\/p>\n<p>Der Befehl <strong>\\l<\/strong> liefert uns eine kompakte \u00dcbersicht aller Datenbanken. H\u00e4ngt man ein Plus an <strong>\\l+<\/strong> werden weitere Meta-Informationen wie z.B. die Gr\u00f6\u00dfe dargestellt. Auch in einer frischen Postgres-Instanz existieren bereits einige automatisch erstellte Tabellen:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">postgres=# \\l\n                                 List of databases\n   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   \n-----------+----------+----------+------------+------------+-----------------------\n postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 | \n template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c\/postgres          +\n           |          |          |            |            | postgres=CTc\/postgres\n template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c\/postgres          +\n           |          |          |            |            | postgres=CTc\/postgres\n(3 rows)<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Datenbank anlegen und \u00f6ffnen<\/h3>\n<p>In einer neuen Datenbankinstanz wird man zuerst eine Datenbank zur Speicherung der gew\u00fcnschten Daten anlegen. Dies funktioniert entweder per SQL<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-sql\" data-line=\"\">postgres=# CREATE DATABASE mydb;\nCREATE DATABASE<\/code><\/pre>\n<p>oder mit dem Kommandozeilenwerkzeug <strong>createdb &lt;name&gt;<\/strong>. Das CLI-Tool kann nur au\u00dferhalb der Postgres-Shell genutzt werden, weswegen es hier nicht zum Einsatz kommt.<\/p>\n<p>Um sie zu \u00f6ffnen, wird mittels <strong>\\c<\/strong> eine Verbindung hergestellt. Dies ist vergleichbar mit <strong>USE &lt;dbname&gt;<\/strong> von MySQL\/MariaDB:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-sql\" data-line=\"\">postgres=# \\c mydb\nYou are now connected to database &quot;mydb&quot; as user &quot;postgres&quot;.<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Tabelle anlegen<\/h3>\n<p>Das Anlegen einer Datenbank d\u00fcrfte Benutzern mit SQL-Erfahrung leicht fallen. Hier gibt es kaum einen Unterschied zwischen anderen DBMS wie MySQL. <\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-sql\" data-line=\"\">create table if not exists sensors(\n    id SERIAL PRIMARY KEY,\n    temp NUMERIC NOT NULL,\n    dateTime timestamp NOT NULL\n);<\/code><\/pre>\n<p>Wurde die Datenbank erfolgreich angelegt, reagiert die Konsole mit der Zechenfolge <strong>CREATE TABLE<\/strong>.<\/p>\n<h3 class=\"wp-block-heading\">\\dt &#8211; Tabellen auflisten<\/h3>\n<p>Analog zu <strong>\\l<\/strong> kann <strong>\\dt<\/strong> (display table) alle Tabellen in einer Datenbank auflisten. F\u00fcgt man ein Plus + an den Befehl an, erscheinen zus\u00e4tzliche Informationen wie Gr\u00f6\u00dfe oder Beschreibung.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-sql\" data-line=\"\">mydb=# \\dt\n          List of relations\n Schema |  Name   | Type  |  Owner   \n--------+---------+-------+----------\n public | sensors | table | postgres\n(1 row)\n<\/code><\/pre>\n<h3 class=\"wp-block-heading\">Datens\u00e4tze einf\u00fcgen<\/h3>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-sql\" data-line=\"\">mydb=# insert into sensors(temp, datetime) values(25, now());\nINSERT 0 1\nmydb=# select * from sensors;\n id | temp |          datetime          \n----+------+----------------------------\n  1 |   25 | 2020-07-30 17:11:08.555956\n(1 row)\n<\/code><\/pre>\n<p>Die SELECT-Anfragen sind wiederum identisch zu MySQL. Ein einfaches Beispiel:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-sql\" data-line=\"\">mydb=# select * from sensors;\n id | temp |          datetime          \n----+------+----------------------------\n  1 |   25 | 2020-07-30 17:11:08.555956\n(1 row)\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Die Datenbank Postgres bzw. PostgreSQL erfreut sich steigender Beliebtheit. Eben so verh\u00e4lt es sich mit Docker: Schlie\u00dflich kann man eine neue Datenbank damit sehr einfach installieren und testen. In diesem Artikel wird Schritt f\u00fcr Schritt gezeigt, wie man Postgres mithilfe von Docker zum Laufen bekommt. Warum Postgres mit Docker installieren? PostgreSQL, auch als Postgres bezeichnet, &#8230;<\/p>\n","protected":false},"author":5,"featured_media":6920,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[883],"tags":[59,497,771,823,824],"class_list":["post-6897","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-docker-containertechnologie","tag-datenbank","tag-docker","tag-docker-compose","tag-postgres","tag-postgresql"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/6897","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/comments?post=6897"}],"version-history":[{"count":7,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/6897\/revisions"}],"predecessor-version":[{"id":6904,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/6897\/revisions\/6904"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/6920"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=6897"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=6897"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=6897"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}