Angenommen wir haben eine App, die mit einer postgres Datenbank läuft. Die Datenbank ist als Docker Volume namens website_pgdata gemountet.
~/blogtutorials: apoehlmann $ docker volume ls
DRIVER VOLUME NAME
local website_pgdata
Wir möchten nun einen neuen postgres Service mittels neuer docker-compose.yml Datei aufsetzen. Der daraus resultierende Container soll nun aber keine eigene, sondern die selbe Datenbank wie unsere App verwenden.
Eine Möglichkeit, dies zu tun, ist folgende docker-compose.yml Datei:
version: '3.6'
services:
postgres:
container_name: testpg
environment:
POSTGRES_DB: web_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
image: postgres:latest
expose:
- 5432
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
external: true
name:
website_pgdata
Und das wars auch schon.
Wir benutzen als compose file version 3.6 und kreieren einen Service namens postgres, den daraus resultierenden Container nennen wir testpg.
Da wie anfänglich erwähnt die Datenbank von einer anderen App bereits benutzt wird und dort die Datenbank einen bestimmten Namen (web_db) trägt sowie einen bestimmten postgres User samt Passwort, müssen hier die dazugehörigen Informationen als environement Variablen angegeben werden (Achtung: dies hängt von der Konfiguration der bereits bestehenden Datenbank ab! In eurem Fall müsst ihr diese Variablen also dementsprechend anpassen).
Als image spezifizieren wir das aktuellste postgres image, und stellen den Port 5432 (postgres default port) der Außenwelt zur Verfügung.
Nun kommt der ausschlaggebende Teil: wir spezifizieren ein externes Volume pgdata, welches im Container ins Verzeichnis /var/lib/postgres/data gemountet werden soll. Wir wählen dieses Verzeichnis, da es sich hierbei um das default Verzeichnis handelt, in dem in Linux sämtliche postgres Daten gespeichert werden.
Wir müssen nun das pgdata Volume genauer spezifizieren, welches von unserem postgres Service benutzt wird: Dafür legen wir - auf selbe Höhe wie services: - einen neuen Block volumes: an. Hier spezifizieren wir den Namen, den unser externes Volume tragen soll: pgdata (dieser Name ist beliebig, muss jedoch mit dem unter volumes beim postgres service übereinstimmen!).
Würden wir jetzt schon die docker-compose.yml ausführen, würde Docker ein neues Volume namens pg_data erzeugen. Wir möchten jedoch ein bereits existierendes Volume verwenden, daher müssen wir die Option external: true setzen und den Namen des zu benutzenden Volumes spezifizieren: website_pgdata
Aus dem selben Verzeichnis, wo auch die docker-compose.yml Datei liegt (in meinem Fall das Verzeichnis ~/blogtutorials), führen wir folgenden Befehl aus, um unseren Service zu starten und damit den Container zu bauen (wir benutzen das -d Flag, um den Service im detached mode, also im Hintergrund, laufen zu lassen):
~/blogtutorials: apoehlmann $ docker-compose up -d
Creating testpg ... done
Der Container sollte nun laufen
~/blogtutorials: apoehlmann $ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dad8e90789df postgres:latest "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 5432/tcp testpg
Als nächstes inspizieren wir den Container: in der "Mounts" Sektion müsste das entsprechende Volume aufgelistet sein
~/blogtutorials: apoehlmann $ docker inspect testpg
"Mounts": [
{
"Type": "volume",
"Name": "website_pgdata",
"Source": "/var/lib/docker/volumes/website_pgdata/_data",
"Destination": "/var/lib/postgresql/data",
"Driver": "local",
"Mode": "rw",
"RW": true,
"Propagation": ""
}
],
Der Name des Volumes stimmt mit dem bereits existierenden Volume überein. Source gibt das Verzeichnis auf dem Host an, Destination das Verzeichnis im Container. Alles scheint also einwandfrei gelaufen zu sein.
Als letzten Check loggen wir uns in den Container ein, switchen zum postgres user, starten psql und sehen nach, ob die Datenbank web_db tatsächlich vorliegt:
~/blogtutorials: apoehlmann $ docker exec -it testpg bash
root@00e22268eedb:/#
Wir befinden uns nun in der interaktiven Bash des Containers testpg. Nun führen wir die gerade oben beschrieben Schritte aus
# Switche zum postgres user
root@00e22268eedb:/# su postgres
# starte nun psql
$ psql
psql (10.3 (Debian 10.3-1.pgdg90+1))
Type "help" for help.
# und lassen uns alle Datenbanken ausgeben
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+------------+------------+--------------------
---
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres
+
| | | | | postgres=CTc/postgr
es
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres
+
| | | | | postgres=CTc/postgr
es
web_db | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
(4 rows)
# Baue eine Verbindung mit web_db auf
postgres=# \c web_db
You are now connected to database "web_db" as user "postgres".
# Lasse alle vorhandenen Tables ausgeben
web_db=# \dt
public | auth_group | table | postgres
public | auth_group_permissions | table | postgres
public | auth_permission | table | postgres
public | auth_user | table | postgres
public | auth_user_groups | table | postgres
public | auth_user_user_permissions | table | postgres
public | base_footertext | table | postgres
public | base_homepage | table | postgres
public | base_standardpage | table | postgres
public | blog_blogindexpage | table | postgres
public | blog_blogpage | table | postgres
public | blog_blogpagerelatedlink | table | postgres
public | blog_blogpagetag | table | postgres
public | django_admin_log | table | postgres
public | django_content_type | table | postgres
public | django_migrations | table | postgres
public | django_session | table | postgres
public | django_site | table | postgres
public | taggit_tag | table | postgres
public | taggit_taggeditem | table | postgres
public | wagtailcore_collection | table | postgres
public | wagtailcore_collectionviewrestriction | table | postgres
public | wagtailcore_collectionviewrestriction_groups | table | postgres
--More--
Wie wir sehen, liegt die Datenbank web_db vor, in der bereits Daten durch unsere ursprüngliche App eingepflegt sind (in diesem Fall ein Wagtail Blog).
Wir wissen nun also, wie man eine neue docker-compose.yml Datei erstellt, die einen neuen Postgres Service startet und ein bereits vorhandenes Volume in ein bestimmtes Verzeichnis (/var/lib/postgresql/data) in den aus dem neuen Service resultierenden Container mountet.
In diesem Tutorial haben wir also einen Spezialfall betrachtet. Das hier gelernte Prinzip ist jedoch über diesen Spezialfall hinaus für beliebige Volumes und Services anwendbar (bspw. für Redis, Elasticsearch, etc. pp.).