Blog Name
  • Mittwoch, 16. August 2017 - Letztes Update: 24. August 2018

Nutzung von Oracle Datenbanken in Docker Containern

Die Oracle Datenbank ist traditionell auf vielen Plattformen verfügbar. Neben dem Betriebssystem als Plattform, gibt es auch verschiedene gängige Virtualisierungslösungen, zu der auch Docker gehört. Docker unterscheidet sich vom Konzept der virtuellen Maschinen dadurch, dass eine Container-Technologie zum Einsatz kommt, in der nicht immer ein eigenes Betriebssystem aufgebaut wird. Vielmehr basieren die Docker Container auf gemeinsam genutzten Kernels. Die Oracle Datenbank eignet sich auch bestens in einer Docker Umgebung und der Einsatz ist auch im Support, wie die MOS Note 2216342.1 beschreibt.

Natürlich muß auch bei der Verwendung der Oracle Datenbank Software auf Docker eine gültige Lizenz vorliegen.

Dieser Tipp geht davon aus, dass Sie mit Docker insofern vertraut sind, dass Sie wissen, wie typischerweise Docker Images oder Docker Container erstellt werden. Aufgrund der Architektur von Docker gibt es bzgl. des Betriebs von Oracle Datenbanken die folgenden Einschränkungen:

  • Das Feature "Automatic Memory Management" steht nicht zur Verfügung
  • Die Datenbank wird in einem Oracle Linux 7.3 Image betrieben

Sie können, wie bei der Verwendung von Docker im Allgemeinen üblich, vorgefertigte Docker Images verwenden, um eine Oracle Datenbank in einem Docker Container zu nutzen. Sie können aber auch eigene Docker Images erstellen, wobei Oracle dazu die erforderlichen Skripte zur Verfügung stellt. Dieser Tipp beschreibt beide Verfahren.

Dieser Tipp unterteilt sich in folgende Abschnitte:

 
Nutzung von vorgefertigten Images

Im Docker Store finden Sie mit dem Suchtext "Oracle Database Enterprise Edition" ein vorgefertigtes Image für die Datenbankversion 12.2.0.1 (nur Enterprise Edition / Single Instance) in zwei Varianten:

'store/oracle/database-enterprise:12.2.0.1'
Dieses Image beinhaltet die normale Enterprise Edition mit allen Funktionalitäten und umfaßt ca. 3.5GB.

'store/oracle/database-enterprise:12.2.0.1-slim'
Dieses Image beinhaltet eine abgespeckte Variante der Enterprise Edition. Dabei stehen Analytics, Oracle R, Oracle Label Security, Oracle Text, Oracle Application Express und Oracle DataVault nicht zur Verfügung. Der Download umfasst hier ca. 2.4GB.

Dieses Docker Image erstellt immer eine Containerdatenbank (CDB), die ihrerseits sogenannte Pluggable Datenbanken (PDB) betreibt. In diesem Image wird genau eine PDB erstellt und das ist durch die normale Datenbanklizenz auch abgedeckt. Wenn aber mehrere (mehr als eine) PDBs in einer CDB betrieben werden, benötigt man eine Lizenz für die Oracle Multitenant Option. Mehr zum Thema finden Sie im Dojo "Oracle 12c Multitenant Database Option".

Die Verwendung dieses vorgefertigen Docker Images ist vor allem für Entwickler geeignet, die während des Entwicklungsprozesses keinen Bedarf für eine Hochverfügbarkeit haben. Die Nutzung des vorgefertigten Docker Images ist recht einfach und wird in den Setup Instruktionen beschrieben.

Laden des Docker Images

Sie müssen sich bei Docker unbedingt mit Ihrer DockerID anmelden mit

$ docker login -u <ihre_dockerid> -p <ihr_passwort>

Ohne Anmeldung wird das vorgefertigte Image nicht gefunden. Sie können das vorgefertigte Docker Image zunächst herunterladen mit

$ docker pull store/oracle/database-enterprise:12.2.0.1

Sie geben also einfach einen der oben genannten zulässigen Imagenamen an. Das Docker Image wird aber auch automatisch geladen, wenn Sie einen neuen Docker Container erstellen. Dabei wird offiziell ein Minimum von 25GB Festplattenplatz und 4GB Memory angegeben.

Docker Container mit Defaults starten

Sie können Ihre Datenbank noch gezielt konfigurieren, wie es weiter unten beschrieben wird. Für einfache Anwendungen können Sie aber auch die Standardeinstellungen nutzen, mit

$ docker run -d -p <Listener_Port>:1521 -p <Http_Port>:5500 \ 
         -it --name <Container_Name> \
         store/oracle/database-enterprise:12.2.0.1

Dabei benötigt der Docker Container ca. 2GB Memory. Das Ergebnis ist eine Containerdatenbank mit dem Namen „ORCLCDB“ und eine Pluggable Datenbank mit dem Namen „ORCLPDB1“. Der Service für diese Pluggable Datenbank, die vom Listener akzeptiert wird, lautet „orclpdb1.localdomain“. Das Default Passwort für die Datenbankbenutzer „sys“ und „system“ lautet „Oradoc_db1“ und sollte möglichst sofort geändert werden.

Die Ports, die man angibt, dienen dem Zugriff von anderen Containern oder anderen Servern.

Soll die Datenbank im Rahmen eines Docker Compose Builds (siehe auch „Zusammenspiel mit anderen Docker Containern“) betrieben werden, sieht diese Datei wie folgt aus:

docker-compose.yml:
version: '2'

services:
  dbservice:
    image: store/oracle/database-enterprise:12.2.0.1
    ports:
      - 1521:1521
:

Docker Container mit eigener Konfiguration starten

Sie können Ihre Oracle Datenbank auch bzgl. einiger Parameter konfigurieren. So lassen sich die Namen der Container Datenbank und der Pluggable Datenbank festlegen, wie auch die Größe der SGA/PGA.

Diese Konfiguration wird mit einer Datei durch Parameter, wie zum Beispiel Name der Datenbankinstanz und Administrationspasswort erstellt.

db.env:
DB_SID=MYORCL
DB_PDB=MYPDB
DB_MEMORY=3GB
DB_PASSWD=welcome1
DB_DOMAIN=my.domain.com
y.domain.com
DB_BUNDLE=basic

Das Docker run Kommando sieht dann wie folgt aus:

$ docker run -d --env-file <pfad_zur_obigen_Datei> \
       -p <istener_Port>:1521 -p <Http_Port>:5500 \ 
       -it --name <Container_Name> \
       store/oracle/database-enterprise:12.2.0.1

Nach dem Download wird der Docker Container automatisch gestartet und die Datenbank ist verfügbar. Nach dem Download dauert das erstmalige Starten des Docker Containers ca. 5-8 Minuten. Sie können dieses beobachten mit

$ docker ps
… STATUS                           … NAMES
… Up 36 seconds (health: starting) … dbservice_1
:
… Up 3 minutes (unhealthy)         … dbservice_1
:
… Up 4 minutes (healthy)           … dbservice_1

Der Status des Datenbankservices ist zwischenzeitlich also auch mal „unhealthy“, was aber nicht beunruhigen soll. Sobald der Status „Healthy“ ist, kann die Datenbank benutzt werden.

Sobald der Docker Container läuft, können Sie sich dort anmelden mit

$ docker exec -it dbservice_1 /bin/bash 

Sie werden automatisch als oracle-Benutzer angemeldet.

Sie können jetzt prüfen, ob die Oracle Prozesse schon laufen mit

$ ps -ef | grep pmon
:
oracle     406     1  0 14:11 ?        00:00:00 ora_pmon_MYORCL

Prüfen Sie, ob die Umgebungsvariable ORACLE_SID gesetzt ist:

$ echo $ORACLE_SID
MYORCL 

und Sie können sich anmelden mit

$ sqlplus system/welcome1
SQL*Plus: Release 12.1.0.2.0 Production on Mon Aug 14 14:19:29 2017

Copyright (c) 1982, 2014, Oracle.  All rights reserved.

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, Oracle Label Security, OLAP, Advanced Analytics
and Real Application Testing options

SQL> 

Nutzung von Volumes

Sobald ein Docker Container, wie er oben erstellt wurde, gelöscht wird, sind auch alle Daten, die in der Datenbank gespeichert wurden, gelöscht. Um die Datendateien der Oracle Datenbank unabhängig vom Status des Containers zu machen, können Sie Volumes verwenden. Dazu geben Sie im run-Kommando ein externes Verzeichnis an, welches im Container auf das Verzeichnis /ORCL gemappt wird. Diese Verzeichnis muß zuvor mit den passenden Rechten ausgestattet werden, zum Beispiel:

$ chmod o+w /oradata

Dann kann dieses Verzeichnis als Volume direkt verwendet werden:

$ docker run -d -it --name <Oracle-DB>\
 -v /oradata:/ORCL \
 store/oracle/database-enterprise:12.2.0.1

In der Datei „docker-compose.yml“ sieht dieses dann so aus (inklusive Angabe der optionalen, konfigurierenden Umgebungsvariablen):

Docker-compose.xml:
version: '2'
services:
  proddbservice:
    image: store/oracle/database-enterprise:12.2.0.1
    environment:
      - DB_SID=MYORCL
      - DB_PDB=MYPDB
      - DB_MEMORY=3GB
      - DB_PASSWD=welcome1
      - DB_DOMAIN=my.domain.com
    volumes:
      - /oradata:/ORCL
    ports:
      - 1531:1521

Weitere Aspekte

Weitere Hinweise zur Nutzung der Datenbank finden Sie unter "Anmelden an die Oracle Datenbank".

Die Verwendung des vorgefertigten Docker Images ist einfach und schnell. Gerade für Entwickler ist diese Option besonders interessant. Die dabei erzeugte Datenbank benutzt den universellen Zeichensatz AL32UTF8, was auch die allgemeine Empfehlung zum Betrieb einer Container Datenbank ist, da dadurch die Pluggable Datenbank später bei Bedarf sehr leicht in eine zentrale Container Datenbank überführt werden kann.

Es ist zu berücksichtigen, dass mit dem vorgefertigten Docker Image immer eine Oracle Datenbank in der Enterprise Edition erstellt wird. Dieses ist natürlich nur erlaubt, falls auch entsprechende Lizenzen vorliegen. Im Falle von existierenden Lizenzen für die Standard Edition oder Express Edition der Oracle Datenbank kann dieses vorgefertigte Docker Image nicht verwendet werden und auch in diesem Fall helfen Ihnen die folgenden Abschnitte, um das passende Docker Image ganz leicht selbst zu erstellen.

 
Erstellung von Docker Images und Container für die Oracle Datenbank

Oracle stellt alle notwendigen Dateien für eine Erstellung eigener Docker Images auf Github zur Verfügung, sowohl Single Instance als auch für RAC Installationen. Mit einem vorgefertigtem Skript namens "buildDockerImage.sh" erstellen Sie die Docker Images für Oracle Datenbanken. Im Falle einer Single Instance ist es nur ein Docker Image, im Falle von RAC (Real Application Cluster) sind es mehrere Images.

Es gibt auch Beschreibungen auf Github, wie die Images zu erstellen sind:


Dieser Tipp beschränkt sich auf die Beschreibung einer Single Instance Umgebung.

Vorbereitungen

Bevor Sie ein Docker Image für Oracle Datenbanken erstellen, benötigen Sie sowohl die Oracle Datenbank Software als auch zusätzliche Skripte. Diese Skripte laden Sie von Github herunter und die Oracle Datenbanksoftware vom Oracle Technology Network.

Die Skripte sind Bestandteil eines großen Skriptpakets, welches mit der Datei "docker-images-master.zip" heruntergeladen wird. Entpacken Sie diese Datei in ein vorbereitetes Verzeichnis, welches im Folgenden mit $DOCKER_FILES beschrieben wird, also zum Beispiel

$ export DOCKER_FILES=/.../.../mein_docker_base

Sie erhalten dann ein Unterverzeichnis

$DOCKER_FILES/docker-images-master

Für die verschiedenen Datenbankversionen, die sich für ein Dockerimage eignen, finden Sie die Verzeichnisse

$ ls -l $DOCKER_FILES/docker-images-master/docker-images-master/OracleDatabase/SingleInstance/dockerfiles
drwxrwxr-x 2 rdurben rdurben 4096 Jul 17 12:20 11.2.0.2 
drwxrwxr-x 2 rdurben rdurben 4096 Jul 17 12:20 12.1.0.2 
drwxrwxr-x 2 rdurben rdurben 4096 Jul 17 12:20 12.2.0.1 
:
-rwxr-xr-x 1 rdurben rdurben 4141 Jul 17 12:20 buildDockerImage.sh 

Laden Sie nun die Datenbanksoftware herunter. Im Falle der Version ab 12.2.0.1 bekommen Sie eine ZIP-Datei. Im Falle früherer Versionen sind es zwei ZIP-Dateien. Die ältesten Versionen, die sich für Docker Images eignen, sind

  • Enterprise Edition: 12.1.0.2
  • Standard Edition 2: 12.1.0.2
  • Express Edition: 11.2.0.2

Diese Zip-Dateien, die Sie nicht auspacken, kopieren Sie in die oben gelisteten Verzeichnisse, passend zur Datenbankversion.

Das Erstellen eines Docker Images beinhaltet die Installation der Oracle Software, so wie es auch auf jedem anderen Server durchgeführt werden würde. Entsprechend können Sie das Skript "db_inst.rsp" anpassen, falls Sie von einer Standardinstallation abweichen möchten. Da eine Standardinstallation in den Skripten perfekt vorbereitet ist, sind dazu keine weiteren Kenntnisse erforderlich.

Das spätere Erstellen eines Docker Containers beinhaltet das Erstellen einer Datenbank, so wie es bei einer bestehenden Installation auch gemacht werden würde. Auch hier kann über Anpassungen im Skript "dbca.rsp.tmpl" Einfluß genommen werden, oder einfach eine Standard-Datenbank erstellt werden.

Wichtig ist es, zu wissen, dass im Standard bei einer 12c Datenbank eine Oracle Container Datenbank (CDB) mit einer Pluggable Datenbank (PDB) erstellt wird. Mehr zu diesem Thema finden Sie im Dojo "Oracle 12c Multitenant Database Option" .

Falls Sie eine NON-CDB erstellen möchten, muß ein entsprechendes Image aufgebaut werden. Dazu modifizieren Sie das Skript "dbca.rsp.tmpl" und kommentieren die folgenden Parameter aus:

# createAsContainerDatabase
# numberOfPDBs=1
# pdbName=###ORACLE_PDB###
# pdbAdminPassword=###ORACLE_PWD###

Allerdings möchte ich an dieser Stelle darauf hinweisen, dass Oracle Patches immer nur auf Docker Image Ebene eingespielt werden müssen und damit bestehende NON-CDB Datenbanken in Docker Containern nicht gepatcht werden können. Mehr dazu unter “Patching”.

Jetzt prüfen Sie, ob das Skript "$DOCKER_FILES/docker-images-master/docker-images-master/OracleDatabase/dockerfiles/buildDockerImage.sh" ausführbar ist.

$ chmod +x buildDockerImage.sh
$ ls -l build*
-rwxrwxr-x 1 rdurben rdurben 4141 Jul 17 12:20 buildDockerImage.sh 

Das Skript zeigt Ihnen mit der Hilfe -h an, wie es zu nutzen ist:

$ ./buildDockerImage.sh -h 

Usage: buildDockerImage.sh -v [version] [-e | -s | -x] [-i] 
Builds a Docker Image for Oracle Database. 
  
Parameters: 
   -v: version to build 
       Choose one of: 11.2.0.2  12.1.0.2  12.2.0.1 18.3.0  
   -e: creates image based on 'Enterprise Edition' 
   -s: creates image based on 'Standard Edition 2' 
   -x: creates image based on 'Express Edition' 
   -i: ignores the MD5 checksums 

* select one edition only: -e, -s, or -x 

LICENSE CDDL 1.0 + GPL 2.0 

Copyright (c) 2014-2017 Oracle and/or its affiliates. All rights reserved.

Dabei werden die Versionen angezeigt, die als Unterverzeichnis erstellt wurden.

 
Erstellen eines Docker Images für die Oracle Datenbank

In meinem Beispiel habe ich in meiner Docker Umgebung nur das Standard Image "Hello World":

$ docker image ls 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE 
hello-world         latest              1815c82652c0        3 weeks ago         1.84kB

Das Skript "buildDockerImage.sh" wird vom Root-User, oder einem Benutzer, der das sudo Recht hat (empfohlen) ausgeführt. Der Grund dafür ist, dass im Verlauf des Skripts auch Aktionen mit Root-Rechten ausgeführt werden müssen. Wer sich mit der Installation von Oracle Software auskennt weiß, dass damit zum Beispiel die Ausführung des Skripts "root.sh" gemeint ist. Das Erstellen des Oracle DB Image in Docker ist mit vielen Aufgaben verbunden, die man sich auch ansehen sollte. Daher empfehle ich die Nutzung des build-Skripts mit einer Ausgabe in einer Datei:

$ ./buildDockerImage.sh -v 12.2.0.1 -e > wdg1.txt

Sie verfolgen dann die Ausführung mit

$ tail -f wdg1.txt

Sie sehen im Schritt 1 (in der Ausgabe unten "Step 1" bezeichnet), dass die Datenbank später in einer Oracle Linux Umgebung betrieben wird, denn dazu wird ein entsprechendes Image heruntergeladen.

Step 1/16 : FROM oraclelinux:7-slim 
7-slim: Pulling from library/oraclelinux 
7bd9e1692b54: Already exists 
Digest: sha256:f1388709e1ce62dfa9cf9af9746bc0cca47b2e09975a1fb6ba01c66061b2b793 
Status: Downloaded newer image for oraclelinux:7-slim 
 ---> 08a01cc7be97 

In meiner Umgebung hatte ich dieses schon einmal gemacht, das vorhandene Image wird aber durch ein neueres ersetzt, falls ein solches existiert. Dieses Image von Oracle Linux 7 ist eine Basisvariante, der noch viele Pakete zum Betrieb einer Oracle Datenbank fehlen. Auf Basis dieses Linux-Images wird ein neues Image erstellt, in dem die fehlenden Pakete in den nächsten Schritten automatisch installiert werden.

Die Erstellung des neuen Images kann man auch beobachten:

$ docker image ls 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE 
<none>              <none>              1ecbd91c9e6f        10 minutes ago      7.19GB 
oraclelinux         7-slim              08a01cc7be97        2 weeks ago         114MB 
hello-world         latest              1815c82652c0        3 weeks ago         1.84kB 

Danach wird die Oracle Software automatisch aus der ZIP-Datei ausgepackt und in dem noch nicht benannten Image installiert. Diese Installation erfolgt automatisch und erfordert keine entsprechenden Kenntnisse oder Interaktion. Nach Abschluß der Installation gibt das Kommando folgendes Ergebnis:

$ docker image ls 
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE 
oracle/database     12.2.0.1-ee         ee12d513da0c        About a minute ago   14.8GB 
oraclelinux         7-slim              08a01cc7be97        2 weeks ago          114MB 
hello-world         latest              1815c82652c0        3 weeks ago          1.84kB 

Das neue Image hat den Namen "oracle/database:12.2.0.1-ee" bekommen, da dieses im Skript "buildDockerImage.sh" so festgelegt wird in der Zeile

# Oracle Database Image Name 
IMAGE_NAME="oracle/database:$VERSION-$EDITION"

Falls Sie zwei Docker Images zur gleichen Datenbankversion erstellen möchten, zum Beispiel eines für eine CDB und eines für eine NON-CDB, passen Sie den Namen an dieser Stelle im Skript an, zum Beispiel mit

# Oracle Database Image Name 
IMAGE_NAME="oracle/database:$VERSION-NONCDB-$EDITION"

 
Docker Container mit Oracle Datenbank erstellen

Das Image mit dem Namen "oracle/database:12.2.0.1-ee" (solange der Image Name nicht anders festgelegt wurde) steht nun bereit und enthält die Oracle Datenbank-Software, nicht jedoch die Datenbank selbst. Die Datenbank wird in jedem Docker Container automatisch erstellt, wenn dieser zum ersten Mal gestartet wird und keine lauffähige Datenbank enthält. Sie können pro Docker Container nur eine Datenbank verwenden. Sie starten den Docker Container mit

$ docker run --name <container name> \
-p <host port>:1521 -p <host port>:5500 \
-e ORACLE_SID=<your SID> \
-e ORACLE_PDB=<your PDB name> \
-e ORACLE_PWD=<your database passwords> \
-e ORACLE_CHARACTERSET=<your character set>  \
-v [<host mount point>:]/opt/oracle/oradata \
oracle/database:12.2.0.1-ee
Parameters:
   --name:        The name of the container (default: auto generated)
   -p:            The port mapping of the host port to the container port. 
                  Two ports are exposed: 1521 (Oracle Listener), 5500 (OEM Express)
   -e ORACLE_SID: The Oracle Database SID that should be used (default: ORCLCDB)
   -e ORACLE_PDB: The Oracle Database PDB name that should be used (default: ORCLPDB1)
   -e ORACLE_PWD: The Oracle Database SYS, SYSTEM and PDB_ADMIN password (default: auto generated)
   -e ORACLE_CHARACTERSET:
                  The character set to use when creating the database (default: AL32UTF8)
   -v             The data volume to use for the database.
                  Has to be owned by the Unix user "oracle" or set appropriately.
                  If omitted the database will not be persisted over container recreation.

Also zum Beispiel

$ docker run --name mein_db_container -p 1532:1521 -p 5532:5500 \
-e ORACLE_SID=MYCDB -e ORACLE_PDB=MYPDB \
-e ORACLE_PWD=dErfgH7dsjkdsjkksgh \
oracle/database:12.1.0.2-ee > wdg2.txt

In meinem Beispiel habe ich das Passwort für die Superuser der Datenbank direkt vergeben. Sie können das Passwort auch einfach weglassen und es wird automatisch ein Passwort generiert und sofort angezeigt. Dieses generierte Passwort sollten Sie sich notieren.

Wenn die Datenbank dauerhaft verwendet werden soll, ist es ratsam, die Datenbankdateien unabhängig vom Docker Container zu speichern und dafür ein Shared Volume zu verwenden. Dazu nutzen Sie die Option -v und geben ein Verzeichnis auf dem Host-System (hier wurde das Verzeichnis $DOCKER_DB_FILES vorbereitet) an.

$ docker run --name mein_db_container -p 1532:1521 -p 5532:5500 \
-e ORACLE_SID=MYCDB -e ORACLE_PDB=MYPDB \
-e ORACLE_PWD=dErfgH7dsjkdsjkksgh \
-v $DOCKER_DB_FILES/oradata:/opt/oracle/oradata \
oracle/database:12.1.0.2-ee > wdg2.txt

Wenn beim ersten Starten eines Docker Containers das mit der Option -v angegebene Verzeichnis schon Datenbankdateien, passend zu ORACLE_SID und ORACLE_PDB beinhaltet, wird keine neue Datenbank erstellt, sondern nur der Container selbst. Sie können sich dann direkt an den Container anmelden mit

$ docker exec -it mein_db_container /bin/bash

und die Datenbank starten mit

$ sqlplus / as sysdba
startup

Zur Erklärung des Kommandos: mit -it geben Sie an, dass ein interaktives Pseudo-Terminal erzeugt wird.

 
Docker Container erstellen mit und ohne Detached Mode

Mit dem obigen Kommando

$ docker run --name mein_db_container -p 1532:1521 -p 5532:5500 \
-e ORACLE_SID=MYCDB -e ORACLE_PDB=MYPDB \
-e ORACLE_PWD= dErfgH7dsjkdsjkksgh \
-v $DOCKER_DB_FILES/oradata:/opt/oracle/oradata \
oracle/database:12.1.0.2-ee > wdg2.txt

erstellen Sie einen Docker Container in einer Terminalsitzung im Vordergrund. Während der Ausführung des Kommandos erscheint die Ausgabe

######################### 
DATABASE IS READY TO USE! 
#########################

die anzeigt, dass die Datenbank erfolgreich erstellt wurde. Es kommt aber kein Kommando-Prompt zurück, denn das Kommando wurde nicht im Hintergrund ausgeführt und wenn dieses Terminalfenster geschlossen oder darin ein Ctrl-C ausgelöst wird, wird der Container gestoppt. In diesem Fall können Sie den Docker Container wieder starten mit

$ docker container start mein_db_container

Mit der Option -d im Kommando "docker run" wird ein Container im Hintergrund (Detached Mode) gestartet. Da jetzt aber kein Standard-Output zur Verfügung steht, müssen Sie bei der Mitverfolgung der Erstellung anders vorgehen. Der Docker Container ist recht schnell soweit erstellt, das man sich damit verbinden kann mit:

$ docker exec -it mein_db_container /bin/bash

Dann nutzen Sie das Kommando tail:

$ tail -f $ORACLE_HOME/cfgtoollogs/dbca/$ORACLE_SID/trace.log

Das Ende der Datenbankerstellung erkennen Sie an :

[Thread-3] [ 2017-07-11 15:05:47.141 UTC ] [DbcaCleanupHook.run:44]  Cleanup started 
[Thread-3] [ 2017-07-11 15:05:47.141 UTC ] [OracleHome.cleanupDBOptionsIntance:1671]  DB Options dummy instance sid=null 
[Thread-3] [ 2017-07-11 15:05:47.141 UTC ] [DbcaCleanupHook.run:49]  Cleanup ended 

 
Anmelden an die Oracle Datenbank

Sobald der Docker Container erfolgreich erstellt wurde, können Sie sich an die Datenbank anmelden mit

$ docker exec -it mein_db_container /bin/bash 
 $ sqlplus sys/<your password>@//localhost:1521/<your SID> as sysdba

Also in meinem Beispiel:

$ docker exec -it mein_db_container /bin/bash 
 $ sqlplus sys/dErfgH7dsjkdsjkksgh@//localhost:1521/MYCDB as sysdba

Sie können SQL*Plus aber auch aufrufen, ohne sich vorher mit dem Docker Container zu verbinden:

$ docker exec -it <container name> sqlplus <user>@<dbservice>

Also im vorliegenden Fall:

$ docker exec -it mein_db_container sqlplus sys/dErfgH7dsjkdsjkksgh@//localhost:1521/MYCDB as sysdba

 
Zusammenspiel mit anderen Docker Containern

Der Docker Container mit der Oracle Datenbank soll anderen Docker Containern als Datenquelle dienen. Docker baut ein internes Netzwerk auf, sodass eine Kommunikation zwischen den Docker Containern möglich ist. Eine zusammenhängende Gruppe von Docker Containern erstellt man am besten mit docker-compose. Dazu erstellen Sie eine Datei docker-compose.yml, die angibt, welche Docker Container zusammenarbeiten sollen. In einem Beispiel soll eine Webseite angezeigt werden, die auf Daten in der Oracle Datenbank zugreift und Produkte anzeigt.

In meinem Beispiel soll PHP zum Einsatz kommen, kombiniert mit dem Oracle Call Interface (OCI). Derartige Images gibt es vorgefertigt im Docker Hub. Im folgenden Beispiel wird die Datei "docker-compose.yml" verwendet, die im Verzeichnis $DOCKER_FILES/ liegt (bei mir ist das Projekt mit "oradb" benannt):

$DOCKER_FILES/oradb/docker-compose.yml:
version: '2' 
services: 
  database: 
    image: oracle/database:12.2.0.1-ee 
    volumes: 
      - /home/rdurben/DockerExamples/oradb/oradata:/opt/oracle/oradata # persistent oracle database data. 
      - /home/rdurben/DockerExamples/oradb/database_content:/opt/oracle/scripts 
      
    ports: 
      - 1531:1521 
      - 8080:8080 
      - 5531:5500 

  website: 
    image: davidgaya/apache-php-oci:latest 
    volumes: 
      - ./website:/var/www/html 
    ports: 
      - 5090:80 
    depends_on: 
      - database 

Die erste Sektion (unter "database: ") beschreibt die Nutzung des Docker Images für die Datenbank. Dabei wird neben dem Volume für die Datenbankdateien ein zweites für eigene Skripte angelegt. In dieses Verzeichnis können Sie zum Beispiel ein Skript zum Erstellen von Beispieldaten kopieren.

Die zweite Sektion beschreibt das Image für die Website, wobei auf das auf Github liegende Image "davidgaya/apache-php-oci:latest" zugegriffen wird.

Im Unterverzeichnis "$DOCKER_FILES/oradb/website", welches dem Image hinzugemounted wird, ist die Datei "index.php" gespeichert, die dann die Webseite anzeigt.

Die Datei index.php sieht dann zum Beispiel so aus:

index.php:
<html> 
 <head> 
  <title>My Shop</title> 
 <head> 

 <body> 
  <h1>Welcome to my shop</h1> 
 <br> 
  In my shop you can buy: 
  <ul> 
   <?php 
     // Create connection to Oracle 
     $conn = oci_connect("shop", "welcome1", "//oradb_database_1/mypdb"); 

     if (!$conn) { 
        echo "shop/welcome1//oradb_database_1/MYPDB"; 
        $m = oci_error(); 
        echo $m['message'], "\n"; 
        exit; 
     } 
     else { 
      //  print "Connected to Oracle!"; 
        $query = 'select * from shop.products'; 
        $stid = oci_parse($conn, $query); 
        $r = oci_execute($stid); 

        print '<table border="1">'; 
          print '<tr>'; 
          print '<td><b>Name</b></td>'; 
          print '<td><b>Description</b></td>'; 
          print '<td><b>Link</b></td>'; 
          print '</tr>'; 
        while (($row = oci_fetch_array($stid, OCI_BOTH )) != false) { 
          print '<tr><td>'; 
          echo $row[1]; 
          print '</td><td>';
          echo $row[2]; 
          print '</td><td>'; 
          echo '<a href="'.$row[3].'">'.$row[3].'</a>'; 
          print '</td></tr>'; 
          } 
        print '</table>'; 
    
     } 
     // Close the Oracle connection 
     oci_close($conn); 
   ?> 
  </ul> 

 </body> 
</html> 

Mit den passenden Daten sieht das Ergebnis im Browser (URL: http://dockermaschine:5090) so aus:

Die Daten können Sie, falls Sie das Beispiel nachvollziehen möchten, über das Skript "data.sql" erstellen, welches Sie in das zweite Volume laden und im Docker Container ausführen:

data.sql:
# Run this as sys! 

create user shop identified by welcome1; 
grant connect, resource, unlimited tablespace to shop; 

create sequence shop.seq_products; 
create table shop.products 
 (prod_nr number default shop.seq_products.nextval, 
  name    varchar2(100), 
  note    varchar2(200)); 

insert into shop.products (name,note) values ('Glen Spirit 10y','Standard'); 
insert into shop.products (name,note) values ('Glen Spirit 15y','Rare'); 
insert into shop.products (name,note) values ('Glen Spirit 12y Cask Strength','Rich flavor'); 
insert into shop.products (name,note) values ('Glen Spirit 18y Single Cask','Special Selected Casks'); 
commit; 

alter table shop.products add more_info_link varchar2(400); 
update shop.products set more_info_link='http://www.oracle.com'; 
commit; 

Starten Sie das Skript mit

$ docker exec -it mein_db_container /bin/bash
 $ sqlplus / as sysdba
  alter session set container=mypdb;
  start /opt/oracle/scripts/data.sql

um die Beispieldaten zu erzeugen.

 
Patching

Für die Oracle Software und -Datenbanken werden regelmäßig Sicherheitspatches zur Verfügung gestellt. Aber auch außerhalb dieser Intervalle gibt es Patches. In diesem Kapitel wird beschrieben, wie Oracle Datenbanken in Docker Containern mit Patches versorgt werden.

Es gibt eine einfache Formel: Eine laufende Datenbank kann in einem bestehenden Container so nicht direkt gepatcht werden, zumindest nicht so, dass es von Oracle freigegeben wäre.

Vielmehr muß der Patch auf der Ebene des Docker Images eingespielt werden. Dabei wird ein neues, nun gepatchtes Docker Image erstellt. Letztlich bedeutet dieses, dass die Software mit neuen Binaries und sonstigen Dateien versorgt wird.

Aufgrund dieser Tatsache kann das von Oracle vorgefertigte Image vom Docker Store auch nicht gepatcht werden. Wenn Sie Oracle Datenbanken in Docker Containern patchen möchten, müssen Sie die skriptbasierten Images verwenden.

Das alleinige Patchen der Software ist für Oracle Datenbanken in der Regel aber nicht ausreichend, da auch Inhalte der Datenbank angepasst werden müssen. Wenn aber ein neues, gepatchtes, Image erstellt wurde, wird beim ersten Starten eines Containers mit diesem Image immer eine neue Datenbank erstellt. Die ist dann gepatcht, enthält aber nicht die Inhalte der ungepatchten Datenbank.

Ein Weg zur Lösung wäre ein Export der Daten aus der ungepatchten Datenbank, und Import dieser Daten in die gepatchte Datenbank. Ein eher aufwändiger Weg, der durch die Verwendung von Shared Volumes vermieden werden kann. Wenn nämlich die Datenbankdateien in einem separaten Shared Volume liegen, läßt sich der neue Docker Container mit dem gepatchten Docker Image starten ohne dass eine neue Datenbank erstellt wird. Die bestehende Datenbank kann dann mittels Ausführung von SQL-Skripten final gepatcht werden.

Die Standard Architektur für 12c Datenbanken ist, dass eine Containerdatenbank (CDB) erstellt wird, die ihrerseits sogenannte Pluggable Datenbanken (PDB) betreibt. Solange eine CDB nur eine PDB betreibt spricht man von "Single Tenant", welches keine Mehrkosten bzgl. von Datenbankoptionen bedeutet. Wenn mehr als eine PDB in einer CDB betrieben werden, spricht man von "Multitenant" und dieses muß &umml;ber die gleichnamige Datenbankoption lizenziert werden. Mehr zu diesem Thema finden Sie im Dojo "Oracle 12c Multitenant Database Option" .

Wenn nun ein neues, gepatchtes Docker Image erstellt wurde und dann damit ein Container gestartet wird, dann kann die PDB aus dem alten, ungepatchten Container in den neuen, gepatchten Container, wieder unter Verwendung von Shared Volumes, verschoben werden (Unplug / Plug). Alternativ kann auch seit Oracle 12c Release 2 ein PDB Relocate vorgenommen werden. Es folgt dann noch ein Ausführen von SQL-Skripten, die im Patch beschrieben werden.

Falls Sie die Datenbankoption "Multitenant" nicht lizenziert haben, löschen Sie nach dem ersten Start des neuen und gepatchten Containers die automatisch erstellte PDB, damit nach dem Hinzufügen der zu patchenden PDB am Ende wieder nur eine PDB von der CDB betrieben wird und Sie immer noch im "Single Tenant" Modus verbleiben. Sie können aber auch beim Erstellen der CDB über ein Responefile (hier im Beispiel "dbca.rsp.tmpl") angeben, dass Sie nur eine CDB ohne PDB wünschen, in dem Sie folgende Parameter setzen:

dbca.rsp.tmpl:
:
createAsContainerDatabase=true
# numberOfPDBs=1
# pdbName=###ORACLE_PDB###
# pdbAdminPassword=###ORACLE_PWD###
:

Um nun das gepatchte Image zu erstellen, laden Sie die Patches herunter und kopieren diese in Unterverzeichnisse von $DOCKER_FILES/docker-images-master/OracleDatabase/samples/applypatch/<dbversion>/patches, zum Beispiel

12.2.0.1
   patches
      001 (Verzeichnis für Patches mit Ausführungsreihenfole 1)
         pNNNNNN_RRRRRR.zip  (Patch ZIP Datei)
      002 (Verzeichnis für Patches mit Ausführungsreihenfole 2)
       :
      00N (Verzeichnis für Patches mit Ausführungsreihenfole N)
      p6880880*.zip (OPatch zip Datei, falls eine neuere Version gebraucht wird)

Die Patchverzeichnisse werden in ihrer numerischen Reihenfolge abgearbeitet. Damit kann beim Einspielen mehrerer Patches die Reihenfolge bestimmt werden. Die Angabe der Opatch-Zipdatei ist nur erforderlich, falls für die einzuspielenden Patches eine neuere Version als die im Image befindliche benötigt wird. Um hier nicht auf Fehler zu stoßen empfehle ich, immer die neueste Opatch Datei an dieser Stelle zu speichern.

Um nun das gepatchte Image zu erstellen, starten das Skript $DOCKER_FILES/docker-images-master/OracleDatabase/samples/applypatch/buildPatchedDockerImage.sh. Sie müssen dabei dem neuen Image einen neuen Namen geben, indem am besten mit der Option "-p" die Patchnumerierung an den bestehenden Imagenamen angehängt wird. Mit der Option "-v" wird wieder die Datenbankversion angegeben und mit der Option "-e" wird im Beispiel die Enterprise Edition ausgewählt (alternativ zu "-s" oder "-x" wie oben beim Erstellen eines Images).

./buildPatchedDockerImage.sh -v 12.2.0.1 -e -p 180116

Wenn das Image erstellt ist, starten Sie einen neuen Container. Jetzt können Sie die PDB patchen, indem die PDB mit Unplug/Plug oder PDB Relocate (seit Oracle 12.2) verschoben wird.

Beide Verfahrensweisen werden nun an einem Beispiel verdeutlicht. Dabei gibt es die folgende Situation: Es existieren zwei Images

$ docker image ls
REPOSITORY                         TAG                   IMAGE ID            CREATED             SIZE
oracle/database                    12.2.0.1-se2-180116   830b6d67ed15        46 hours ago        16.3GB
oracle/database                    12.2.0.1-se2          a5c431ca4d14        2 days ago          13.3GB

Der Container mit der ungepatchten CDB und PDB (hier "1_db_container_unpatched") und der neue, gepatchte Container mit CDB, aber ohne PDB (hier "3_db_container_RUJAN180116") laufen:

$ docker ps
CONTAINER ID        IMAGE                                 COMMAND                  CREATED             STATUS                   PORTS                                            NAMES
0d7d3afd9665        oracle/database:12.2.0.1-se2-180116   "/bin/sh -c 'exec $O…"   About an hour ago   Up 3 minutes (healthy)   0.0.0.0:1534->1521/tcp, 0.0.0.0:5534->5500/tcp   3_db_container_RUJAN180116
708f7fc3e7a3        oracle/database:12.2.0.1-se2          "/bin/sh -c 'exec $O…"   About an hour ago   Up 3 minutes (healthy)   0.0.0.0:1532->1521/tcp, 0.0.0.0:5532->5500/tcp   1_db_container_unpatched

Vorgehensweise bei Unplug/Plug

Mit einem einzigen Skript wird die PDB aus der ungepatchten CDB ausgehängt (Unplug), die Dateien verschoben, dann die PDB in die neue CDB eingehängt und zum Schluß das notwendige Kommando "datapatch" ausgeführt. Dabei wird im jeweiligen Container das passende SQL-Skript erzeugt, und dann mit sqlplus gestartet:

docker exec -it 1_db_container_unpatched sh -c "echo set echo on linesize 2000 > unplug_mypdb.sql"
docker exec -it 1_db_container_unpatched sh -c "echo alter pluggable database mypdb close\; >> unplug_mypdb.sql"
docker exec -it 1_db_container_unpatched sh -c "echo alter pluggable database mypdb unplug into \'/opt/oracle/oradata/MYCDB/mypdb.xml\'\; >> unplug_mypdb.sql"
docker exec -it 1_db_container_unpatched sh -c "echo drop pluggable database mypdb\; >> unplug_mypdb.sql"
docker exec -it 1_db_container_unpatched sh -c "echo select name,open_mode from v\$\pdbs\; >> unplug_mypdb.sql"
docker exec -it 1_db_container_unpatched sh -c "echo exit >> unplug_mypdb.sql"
docker exec -it 1_db_container_unpatched sqlplus sys/dErfgH7dsjkdsjkksgh@//localhost:1521/MYCDB as sysdba @unplug_mypdb.sql

sudo mv /home/rdurben/Docker/Docker-Server-OracleDB-Skriptbasierte-Images/oradata/1_db_container_unpatched/MYCDB/MYPDB /home/rdurben/Docker/Docker-Server-OracleDB-Skriptbasierte-Images/oradata/3_db_container_RUJA
N180116/PCDB/MYPDB
sudo mv /home/rdurben/Docker/Docker-Server-OracleDB-Skriptbasierte-Images/oradata/1_db_container_unpatched/MYCDB/mypdb.xml /home/rdurben/Docker/Docker-Server-OracleDB-Skriptbasierte-Images/oradata/3_db_container_
RUJAN180116/PCDB/mypdb.xml

docker exec -it 3_db_container_RUJAN180116 sh -c "echo set serveroutput on echo on linesize 2000 > plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo declare >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo  compatible constant varchar2\(3\) :=  >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo      case dbms_pdb.check_plug_compatibility\( >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo          pdb_descr_file =\> \'/opt/oracle/oradata/PCDB/mypdb.xml\'\) >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo      when true then \'YES\' >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo      else \'NO\' >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo end\; >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo begin >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo  dbms_output.put\(\'New PDB is compatible\: \'\)\; >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo  dbms_output.put_line\(compatible\)\; >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo end\; >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo / >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo SELECT type\|\|\' \'\|\|message\|\|\' \'\|\|action FROM pdb_plug_in_violations WHERE name = \'MYPDB\'\; >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo create pluggable database MYPDB using \'/opt/oracle/oradata/PCDB/mypdb.xml\' nocopy  source_file_name_convert=\(\'/opt/oracle/oradata/MYCDB\',\'/opt/oracle/o
radata/PCDB\'\) tempfile reuse\; >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo select name,open_mode from v\$\pdbs\; >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo alter pluggable database mypdb open\; >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo select name,open_mode from v\$\pdbs\; >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo exit >> plug_mypdb.sql"
docker exec -it 3_db_container_RUJAN180116 sqlplus sys/dErfgH7dsjkdsjkksgh@//localhost:1521/PCDB as sysdba @plug_mypdb.sql

sleep 10
docker exec -it 3_db_container_RUJAN180116 sh -c "cd /opt/oracle/product/12.2.0.1/dbhome_1/OPatch ; ./datapatch -verbose"

Hier der Ablauf des Skripts (leicht formatiert):

./unplug_plug_1_3.sh 

SQL*Plus: Release 12.2.0.1.0 Production on Fri Jan 26 09:32:18 2018

Copyright (c) 1982, 2016, Oracle.  All rights reserved.


Connected to:
Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production

SQL> alter pluggable database mypdb close;

Pluggable database altered.

SQL> alter pluggable database mypdb unplug into '/opt/oracle/oradata/MYCDB/mypdb.xml';

Pluggable database altered.

SQL> drop pluggable database mypdb;

Pluggable database dropped.

SQL> select name,open_mode from v$pdbs;

NAME			OPEN_MODE
----------------------- ----------
PDB$SEED		READ ONLY

SQL> exit
Disconnected from Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production
[sudo] password for rdurben: 

SQL*Plus: Release 12.2.0.1.0 Production on Fri Jan 26 09:06:41 2018

Copyright (c) 1982, 2016, Oracle.  All rights reserved.


Connected to:
Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production

SQL> declare
  2  compatible constant varchar2(3) :=
  3  case dbms_pdb.check_plug_compatibility(
  4  pdb_descr_file => '/opt/oracle/oradata/PCDB/mypdb.xml')
  5  when true then 'YES'
  6  else 'NO'
  7  end;
  8  begin
  9  dbms_output.put('New PDB is compatible: ');
 10  dbms_output.put_line(compatible);
 11  end;
 12  /
New PDB is compatible: NO

PL/SQL procedure successfully completed.

SQL> SELECT type||' '||message||' '||action FROM pdb_plug_in_violations WHERE name = 'MYPDB';

TYPE||''||MESSAGE||''||ACTION
---------------------------------------------------------------------------------------------------------------------------------
ERROR DBRU bundle patch 180116 (DATABASE RELEASE UPDATE 12.2.0.1.180116): Installed in the CDB but not in the PDB. Call datapatch to install in the PDB or the CDB

SQL> create pluggable database MYPDB using '/opt/oracle/oradata/PCDB/mypdb.xml' nocopy source_file_name_convert=('/opt/oracle/oradata/MYCDB','/opt/oracle/oradata/PCDB') tempfile reuse;

Pluggable database created.

SQL> select name,open_mode from v$pdbs;

NAME			OPEN_MODE
----------------------- ----------
PDB$SEED		READ ONLY
WDGPDB			READ WRITE
MYPDB			MOUNTED

SQL> alter pluggable database mypdb open;

Warning: PDB altered with errors.

SQL> select name,open_mode from v$pdbs;

NAME			OPEN_MODE
----------------------- ----------
PDB$SEED		READ ONLY
WDGPDB			READ WRITE
MYPDB			READ WRITE

SQL> exit
Disconnected from Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production
SQL Patching tool version 12.2.0.1.0 Production on Fri Jan 26 09:06:59 2018
Copyright (c) 2012, 2017, Oracle.  All rights reserved.

Log file for this invocation: /opt/oracle/cfgtoollogs/sqlpatch/sqlpatch_2827_2018_01_26_09_06_59/sqlpatch_invocation.log

Connecting to database...OK
Note:  Datapatch will only apply or rollback SQL fixes for PDBs
       that are in an open state, no patches will be applied to closed PDBs.
       Please refer to Note: Datapatch: Database 12c Post Patch SQL Automation
       (Doc ID 1585822.1)
Bootstrapping registry and package to current versions...done
Determining current state...done

Current state of SQL patches:
Bundle series DBRU:
  ID 180116 in the binary registry and ID 180116 in PDB CDB$ROOT, ID 180116 in PDB PDB$SEED, ID 180116 in PDB WDGPDB

Adding patches to installation queue and performing prereq checks...
Installation queue:
  For the following PDBs: CDB$ROOT PDB$SEED WDGPDB
    Nothing to roll back
    Nothing to apply
  For the following PDBs: MYPDB
    Nothing to roll back
    The following patches will be applied:
      27105253 (DATABASE RELEASE UPDATE 12.2.0.1.180116)

Installing patches...
Patch installation complete.  Total patches installed: 1

Validating logfiles...
Patch 27105253 apply (pdb MYPDB): SUCCESS
  logfile: /opt/oracle/cfgtoollogs/sqlpatch/27105253/21862470/27105253_apply_PCDB_MYPDB_2018Jan26_11_07_22.log (no errors)
SQL Patching tool complete on Fri Jan 26 09:09:07 2018

Vorgehensweise bei PDB Relocate

Um ein PDB Relocate durchführen zu können, müssen einige Voraussetzungen gegeben sein. So muß in der Quell-PDB ein Common-User eingerichtet werden, der Zugriff auf alle PDBs hat. Dieser Datenbankbenutzer wird dazu verwendet, dass die Ziel-CDB, die sich bei PDB Relocate die PDB von der Quell-CDB "holt", dieses mit einem Datenbanklink durchführen kann.

Um diesen Datenbanklink korrekt zu erzeugen, ist es erforderlich, die Netzwerkadresse des Quell-Containers zu erfahren. Dieses ist mit dem Kommando "docker network inspect bridge" möglich:

$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "365d3afe226e752256f8931e94d667258b577730d618f57ad851251857ca837f",
        "Created": "2018-01-23T14:57:26.740970305+01:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "0d7d3afd966568446880fcf61fb5d120f8314eb9f36c19ee8c1ce9206d04fef7": {
                "Name": "3_db_container_RUJAN180116",
                "EndpointID": "53620b3d4fd422c66cb201b5c6bd93c91cd5604c34489ec2c89020d94dfde71b",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "708f7fc3e7a3d440e8db6f40a097807784b6596f533c29950d1f94474a0370e5": {
                "Name": "1_db_container_unpatched",
                "EndpointID": "a0d8dc4c88369f10c8799032e195a7a0673b4a29571ff495cabba96056ad0fed",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

In diesem Beispiel muß also die CDB im Container "3_db_container_RUJAN180116" einen Datenbanklink auf die CDB im Container "1_db_container_unpatched" erstellen und dabei die Netzwerkadresse "172.17.0.2" verwenden. Wieder wird hier ein Skript verwendet, welches alle Schritte ausführt:

docker exec -it 1_db_container_unpatched sh -c "echo PROMPT Preparing unpatched CDB ... > relocate.sql"
docker exec -it 1_db_container_unpatched sh -c "echo set echo on feedback on >> relocate.sql"
docker exec -it 1_db_container_unpatched sh -c "echo CREATE USER c\#\#admin IDENTIFIED BY skeruicvbsjfvhskjsjkwiou\; >> relocate.sql"
docker exec -it 1_db_container_unpatched sh -c "echo GRANT connect,resource,create pluggable database,sysoper TO c\#\#admin CONTAINER=ALL\; >> relocate.sql"
docker exec -it 1_db_container_unpatched sh -c "echo exit >> relocate.sql"
docker exec -it 1_db_container_unpatched sqlplus sys/dErfgH7dsjkdsjkksgh@//localhost:1521/MYCDB as sysdba @relocate.sql

docker exec -it 3_db_container_RUJAN180116 sh -c "echo PROMPT Preparing patched CDB... > relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo set echo on feedback on >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo CREATE USER c\#\#admin IDENTIFIED BY skeruicvbsjfvhskjsjkwiou\; >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo GRANT connect,resource,create pluggable database,sysoper TO c\#\#admin CONTAINER=ALL\; >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo CREATE PUBLIC DATABASE LINK db_link_to_mycdb CONNECT TO c\#\#admin IDENTIFIED BY skeruicvbsjfvhskjsjkwiou USING \'\(DESCRIPTION=\(CONNECT_DATA=\(SERVICE_NAME
=MYCDB\)\)\(ADDRESS=\(PROTOCOL=TCP\)\(HOST=172.17.0.2\)\(PORT=1521\)\)\)\'\; >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo PROMPT Relocating ... >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo CREATE PLUGGABLE DATABASE mypdb FROM mypdb@db_link_to_mycdb FILE_NAME_CONVERT = \(\'/opt/oracle/oradata/MYCDB\',\'/opt/oracle/oradata/PCDB\'\) RELOCATE AVAIL
ABILITY MAX\; >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo PROMPT Status ...>> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo SELECT pdb_name,status FROM cdb_pdbs\; >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo PROMPT Open PDB ...>> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo ALTER PLUGGABLE DATABASE mypdb OPEN\; >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo PROMPT Status ...>> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo SELECT pdb_name,status FROM cdb_pdbs\; >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo select name,open_mode from v\$\pdbs\; >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo exit >> relocate.sql"
docker exec -it 3_db_container_RUJAN180116 sqlplus sys/dErfgH7dsjkdsjkksgh@//localhost:1521/PCDB as sysdba @relocate.sql

docker exec -it 1_db_container_unpatched sh -c "echo PROMPT Status on unpatched CDB ... > relocate.sql"
docker exec -it 1_db_container_unpatched sh -c "echo set echo on feedback on >> relocate.sql"
docker exec -it 1_db_container_unpatched sh -c "echo SELECT pdb_name,status FROM cdb_pdbs\; >> relocate.sql"
docker exec -it 1_db_container_unpatched sh -c "echo select name,open_mode from v\$\pdbs\; >> relocate.sql"
docker exec -it 1_db_container_unpatched sh -c "echo exit >> relocate.sql"
docker exec -it 1_db_container_unpatched sqlplus sys/dErfgH7dsjkdsjkksgh@//localhost:1521/MYCDB as sysdba @relocate.sql

sleep 10
echo Run datapatch ...
docker exec -it 3_db_container_RUJAN180116 sh -c "cd /opt/oracle/product/12.2.0.1/dbhome_1/OPatch ; ./datapatch -verbose"

docker exec -it 3_db_container_RUJAN180116 sh -c "echo PROMPT Restart patched PDB... > restartPDB.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo set echo on feedback on >> restartPDB.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo ALTER PLUGGABLE DATABASE mypdb CLOSE\; >> restartPDB.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo ALTER PLUGGABLE DATABASE mypdb OPEN\; >> restartPDB.sql"
docker exec -it 3_db_container_RUJAN180116 sh -c "echo exit >> restartPDB.sql"
docker exec -it 3_db_container_RUJAN180116 sqlplus sys/dErfgH7dsjkdsjkksgh@//localhost:1521/PCDB as sysdba @restartPDB.sql

Damit ist das Patchen einer PDB umfassend ausgeführt. PDB Relocate hat den Vorteil, dass während des Relocates die zu patchende PDB online, also vollständig verfügbar bleibt. Erst, wenn sie in der Ziel-CDB geöffnet wird, entsteht eine kurze Downtime, weil alle Datenänderungen, die während des Relocates in der Quell-PDB durchgeführt wurden, noch nachgezogen werden. Diese Downtime ist aber viel kürzer als bei er Unplug/Plug-Methode.

 
Backup und Recovery

Soll die Datenbank in einem Docker Container dauerhaft und gesichert betrieben werden, so müssen auch Backups erzeugt und im Fehlerfall ein Recovery durchgeführt werden. Da dabei auch der Ausfall des Containers in Betracht gezogen werden muß, ist die Nutzung von Shared Volumes für die Datenbankdateien erforderlich. Zur Erinnerung sieht das Kommando wie folgt aus:

$ docker run --name mein_db_container -p 1532:1521 -p 5532:5500 \
-e ORACLE_SID=MYCDB -e ORACLE_PDB=MYPDB \
-e ORACLE_PWD=dErfgH7dsjkdsjkksgh \
-v $DOCKER_DB_FILES/oradata:/opt/oracle/oradata oracle/database:12.1.0.2-ee

Das Verzeichnis wird innerhalb des Containers mit den Eigentümerrechten des Betriebssystembenutzers "oracle" verwendet. Dieses ist nach außen aber nur über die im Container für diesen Benutzer verwendeten User-ID sichtbar, sodaß auf der Host-Ebene folgendes Ergebnis zu beobachten ist:

$ ls -l $DOCKER_DB_FILES/oradata
drwxr-xr-x 3   54321   54321 4096 Jul 19 14:10 dbconfig/ 
drwxr-x--- 4   54321   54321 4096 Jul 19 13:58 ORCLCDB/ 
drwxr-xr-x 3   54321   54321 4096 Jul 31 10:05 recovery_area/ 

Ein Blick im Container zeigt

$ cat /etc/passwd 
:
oracle:x:54321:54321::/home/oracle:/bin/bash

Um nun auf der Hostebene normal mit dem Verzeichnis "$DOCKER_DB_FILES/oradata" arbeiten zu können, erstellen Sie einen Benutzer mit der passenden User-ID, also zum Beispiel

$ sudo groupadd dba 
$ sudo useradd -u 54321 -g dba -d /home/oracle -s /bin/bash oracle 
$ ls -l $DOCKER_DB_FILES/oradata
drwxr-xr-x 3 oracle    54321 4096 Jul 19 14:10 dbconfig/ 
drwxr-x--- 4 oracle    54321 4096 Jul 19 13:58 ORCLCDB/ 
drwxr-xr-x 3 oracle    54321 4096 Jul 31 10:05 recovery_area/ 

Als nächstes aktivieren Sie den Archivelog Modus der Datenbank und konfigurieren die sogenannte Recovery Area:

SQL> alter system set db_recovery_file_dest_size = 20G;
SQL> alter system set db_recovery_file_dest = '/opt/oracle/oradata/recovery_area' scope=spfile;

SQL> shutdown immediate 
Database closed. 
Database dismounted. 
ORACLE instance shut down. 
SQL> startup mount 
ORACLE instance started. 

Total System Global Area 1610612736 bytes 
Fixed Size		    2924928 bytes 
Variable Size		  520097408 bytes 
Database Buffers	 1073741824 bytes 
Redo Buffers		   13848576 bytes 
Database mounted. 
SQL> alter database archivelog; 

Database altered. 

SQL> alter database open; 

Database altered.

Nun können Sie im Container Datenbank-Backups ganz normal mit RMAN erstellen, auf Host-Ebene auch auf andere Devices kopieren und bei Bedarf wieder zurückspielen.

 
Komplett-Images erstellen

Bislang habe ich beschrieben, wie eigene Docker Images zum Betreiben von Oracle Datenbanken erstellt werden. Dieses müssen Sie nicht auf jedem Host-System durchführen, sondern Sie können bereits erstellte Images auch speichern, übertragen und in bestehende Docker Installationen laden. Dazu gehen Sie wie folgt vor.

Zunächst erstellen Sie ein neues Docker Image, basierend auf dem aktuellen Zustand eines Docker Containers mit

$ docker commit [Optionen] CONTAINER_ID [REPOSITORY[:TAG]]

also zum Beispiel mit

$ docker commit -a "Ralf Durben ralf.durben@oracle.com" bbb9b41e7532 oracle/database:12.2.0.1-se2-myimage

Dann speichern Sie das Docker Image mit

$ docker save -o <save image to path> <image name>

also beispielsweise

$ docker save -o myimage.tar oracle/database:12.2.0.1-se2-myimage

Diese Tar-Datei übertragen Sie auf den Zielrechner mit einer bestehenden Docker-Installation. Soll eine Datenbank auch übertragen werden, kopieren Sie auch die Datenbankdateien, die in einem Shared Volume liegen. Auf dem Zielrechner laden Sie das Image nun mit

$ docker load -i <path to image tar file>

beispielsweise:

$ docker load -i  myimage.tar

und Sie können dieses Image sofort nutzen. Wenn Sie jetzt einen neuen Container so erstellen, dass das Shared Volume zu "oradata" auf gültige Datenbankdateien verweist, wird diese Datenbank beim Starten des neuen Containers verwendet. Gibt es keine gültigen Datenbankdateien, wird wieder eine neue Datenbank angelegt.

Wenn Sie die Datenbankdateien mitliefern möchten, müssen Sie auf die korrekten Dateiberechtigungen achten. Damit die Rechte beim Zugriff auf das Shared Volume korrekt sind, erstellen Sie auf dem Zielsystem zunächst einen Benutzer "oracle":

$ sudo groupadd dba 
$ sudo useradd -u 54321 -g dba -d /home/oracle -s /bin/bash oracle 
$ sudo mkdir /home/oracle
$ sudo chown oracle:dba /home/oracle
$ sudo passwd oracle

Dann erstellen Sie mit diesem Benutzer ein Verzeichnis

$ su – oracle
$ mkdir oradata 

und kopieren die Datenbankdateien jetzt in dieses Verzeichnis. Jetzt starten Sie einfach einen neuen Docker Container.

$ docker run --name mein_db_container -p 1532:1521 -p 5532:5500 \
  -e ORACLE_SID=MYCDB -e ORACLE_PDB=MYPDB \
  -e ORACLE_PWD=dErfgH7dsjkdsjkksgh \
  -v $DOCKER_DB_FILES/oradata:/opt/oracle/oradata \
  oracle/database:12.2.0.1-se2-myimage

Der Oracle Listener wird gestartet und die Sitzung landet im Tool SQL*Plus. Hier sind Sie schon korrekt angemeldet und Sie müssen nur die Oracle Datenbank starten mit

SQL> startup 

Die Oracle Datenbank steht danach inklusive Daten zur Verfügung. Der gesamte Output der "docker run" Kommandos sollte wie folgt aussehen:

$ docker run --name mein_db_container -p 1532:1521 -p 5532:5500 \ 
  -e ORACLE_SID=MYCDB -e ORACLE_PDB=MYPDB \
  -v $DOCKER_DB_FILES/oradata:/opt/oracle/oradata \
  oracle/database:12.2.0.1-se2-myimage 

LSNRCTL for Linux: Version 12.2.0.1.0 - Production on 31-JUL-2017 14:34:43 

Copyright (c) 1991, 2016, Oracle.  All rights reserved. 

Starting /opt/oracle/product/12.2.0.1/dbhome_1/bin/tnslsnr: please wait... 

TNSLSNR for Linux: Version 12.2.0.1.0 - Production 
System parameter file is /opt/oracle/product/12.2.0.1/dbhome_1/network/admin/listener.ora 
Log messages written to /opt/oracle/diag/tnslsnr/db523fb74a63/listener/alert/log.xml 
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1))) 
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521))) 

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1))) 
STATUS of the LISTENER 
------------------------ 
Alias                     LISTENER 
Version                   TNSLSNR for Linux: Version 12.2.0.1.0 - Production 
Start Date                31-JUL-2017 14:34:48 
Uptime                    0 days 0 hr. 0 min. 4 sec 
Trace Level               off 
Security                  ON: Local OS Authentication 
SNMP                      OFF 
Listener Parameter File   /opt/oracle/product/12.2.0.1/dbhome_1/network/admin/listener.ora 
Listener Log File         /opt/oracle/diag/tnslsnr/db523fb74a63/listener/alert/log.xml 
Listening Endpoints Summary... 
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1))) 
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521))) 
The listener supports no services 
The command completed successfully 

SQL*Plus: Release 12.2.0.1.0 Production on Mon Jul 31 14:34:50 2017 

Copyright (c) 1982, 2016, Oracle.  All rights reserved. 

Connected to an idle instance. 

SQL> startup 
ORACLE instance started. 

Total System Global Area 1610612736 bytes 
Fixed Size		    8793304 bytes 
Variable Size		  520094504 bytes 
Database Buffers	 1073741824 bytes 
Redo Buffers		    7983104 bytes 
Database mounted. 
Database opened. 
SQL> Disconnected from Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production 
######################### 
DATABASE IS READY TO USE! 
######################### 
The following output is now a tail of the alert.log: 
:
:

Die Datenbank ist geöffnet und kann jetzt verwendet werden.

 
Docker Container bei Reboot automatisch starten

Sollte der Server, auf dem die Docker Umgebung läuft einmal ausfallen und damit auch alle dort laufenden Container, kann man dafür sorgen, dass bei einem Neustart des Servers wichtige Docker Container (also auch diejenigen, in denen die Oracle Datenbank läuft) automatisch gestartet werden. Dieses erreichen Sie im Rahmen des Kommandos "docker run" mit der Option "--restart", also zum Beispiel

$ docker run --restart on-failure --name mein_db_container -p 1532:1521 -p 5532:5500 \
-e ORACLE_SID=MYCDB -e ORACLE_PDB=MYPDB \
-e ORACLE_PWD=Welcome1 \
-v $DOCKER_DB_FILES/oradata:/opt/oracle/oradata oracle/database:12.2.0.1-se2-myimage 

Das Docker Image ist schon so gestaltet, dass bei automatischen Starten des Docker Containers auch die Oracle Datenbank gestartet wird.

 
Fazit

Oracle Datenbanken lassen sich auch sehr gut auf der Docker Plattform im Rahmen von Microservices Landschaften betreiben. Da die Docker Images dabei wesentlich größer sind, als für Entwicklungsumgebungen üblich, werden diese nicht "schlüsselfertig" von Github heruntergeladen, sondern in einer eigenen Docker Umgebung fertiggestellt. Dieses ist dank der von Oracle bereitgestellten Skripte einfach möglich, ohne dass tiefgreifende Kenntnisse bzgl. der Installation und Erstellung von Oracle Datenbanken notwendig sind. Auch das Übertragen von Docker Images sogar inklusive kompletten Datenbanken ist leicht möglich.

Hinweis zur Lizenzierung

Die Oracle Datenbank Software unterliegt auch auf Docker Umgebungen den normalen Lizenzierungsbedingungen.

Weitere Informationen


 

Zurück zum Anfang des Artikels

Zurück zur Community-Seite
 

Visit the Oracle Blog

 

Contact Us

Oracle

Integrated Cloud Applications & Platform Services