Problemstellung

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.

Lösung

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.

Erklärung

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

Deployment

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.

Sanity Check: Datenbank im Container überprüfen

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.).

Getagged mit:
Docker Tutorial German
blog comments powered by Disqus