Search

Top 60 Oracle Blogs

Recent comments

Installing the Oracle database in docker

This blogpost is about how to install and run the Oracle database in docker. Please mind this is not an officially supported virtualisation platform for the Oracle database. This is a proof of concept setup.

Linux host setup.
In my setup, I used a linux host, freshly installed with Oracle Linux 6.7, which is going to be used as docker server. Please mind you need to leave diskspace (or a disk device) unused for the commonly documented docker setup with the btrfs driver. The root filesystem is using a ext4 filesystem by default. For the proof of concept setup, a 20G diskspace for the Operating system only is enough. I used the minimal linux installation.

The first step is to add a disk, or use a partition and format it with btrfs and mount it:

# lsblk
# yum install btrfs-progs
# mkfs.btrfs -L btrfs1 /dev/sdb
# vi /etc/fstab: LABEL=btrfs1 /var/lib/docker btrfs defaults 0 1
# mkdir /var/lib/docker
# mount -a

1- list blockdevices. this showed me my added block device for docker was /dev/sdb.
2- because of the minimal install, I need to add the btrfs userspace programs.
3- create a btrfs filesystem on /dev/sdb, and label it btrfs1.
4- edit /etc/fstab, make it mount the btrfs filesystem to /var/lib/docker.
5- create the mount point for the btrfs filesystem.
6- mount all the mounts listed in /etc/fstab.

The second step is to install and preliminary configure docker:

# vi /etc/yum.repos.d/public-yum-ol6.repo: enable public_ol6_addons
# yum install docker
# vi /etc/sysconfig/docker: add "-s btrfs" to other_args
# service docker start
# chkconfig docker on
# printf "limit memlock unlimited unlimited\n" > /etc/init/docker.conf

1- enable public_ol6_addons, in which the docker rpm sits.
2- install docker.
3- make docker use the btrfs driver.
4- start docker.
5- enable autostart for docker.
6- reset the memlock ulimit for the containers (needed for the Oracle database SGA later on).

Now we can go into the true docker part of it. Docker lives, as far as I can see at this point, in the /var/lib/docker directory. In order to build my oracle database image, I create a ‘dockerfiles’ directory, and in it a ‘build-oracle-12102’ directory:

mkdir -p /var/lib/docker/dockerfiles/build-oracle-12102

Next up, the dockerfile (aptly named Dockerfile by default) needs to be made in the build-oracle-12102 directory to build an image:

FROM	oraclelinux:6
MAINTAINER frits.hoogland@gmail.com
RUN	groupadd -g 54321 oinstall
RUN	groupadd -g 54322 dba
RUN	useradd -m -g oinstall -G oinstall,dba -u 54321 oracle
RUN	yum -y install oracle-rdbms-server-12cR1-preinstall perl wget unzip
RUN	mkdir /u01
RUN	chown oracle:oinstall /u01
USER	oracle
WORKDIR /home/oracle
ENV	mosUser=you@example.com mosPass=supersecret DownList=1,2
RUN	wget https://dl.dropboxusercontent.com/u/7787450/getMOSPatch.sh
RUN	wget https://dl.dropboxusercontent.com/u/7787450/responsefile_oracle12102.rsp
RUN	echo "226P;Linux x86-64" > /home/oracle/.getMOSPatch.sh.cfg
RUN	sh /home/oracle/getMOSPatch.sh patch=17694377
RUN	unzip p17694377_121020_Linux-x86-64_1of8.zip
RUN	unzip p17694377_121020_Linux-x86-64_2of8.zip
RUN	rm p17694377_121020_Linux-x86-64_1of8.zip p17694377_121020_Linux-x86-64_2of8.zip
RUN	/home/oracle/database/runInstaller -silent -force -waitforcompletion -responsefile /home/oracle/responsefile_oracle12102.rsp -ignoresysprereqs -ignoreprereq
USER	root
RUN	/u01/app/oraInventory/orainstRoot.sh
RUN	/u01/app/oracle/product/12.1.0.2/dbhome_1/root.sh -silent
RUN	rm -rf /home/oracle/responsefile_oracle12102.rsp /home/oracle/getMOSPatch.sh /home/oracle/database
USER	oracle
WORKDIR	/home/oracle
RUN     mkdir -p /u01/app/oracle/data
RUN     wget https://dl.dropboxusercontent.com/u/7787450/manage-oracle.sh
RUN     chmod 700 /home/oracle/manage-oracle.sh
RUN     wget https://dl.dropboxusercontent.com/u/7787450/db_install.dbt
EXPOSE  1521
CMD	/home/oracle/manage-oracle.sh

1- FROM; this is the (operating system) image which is used as a base image. If it is not available locally, it will be pulled from the central docker repository. oraclelinux:6 means Oracle Linux version 6. This serves as the base image on which all the other things are built.
2- MAINTAINER; the maintainer of the new image, obviously.
3/4/5- RUN; the groups and user for the oracle database (oinstall, dba, oracle) are created. This looks like an redundant step, as this is supposed to be done by the oracle-dbms-server-12cR1-preinstall rpm. However, this does not work. By manually creating them this way, the assignment is alright.
6- RUN; yum -y installs all the necessary packages. Oddly, it seems unzip is not in the preinstall package?
7- RUN; /u01 is the directory in which the database software is installed.
8- RUN; chown user:group is used to change the user and group permissions of /u01.
9- USER; this changes the current user for execution to ‘oracle’.
10- WORKDIR; this sets the work directory.
11- ENV; this sets a few environment variables needed by the getMOSPatch.sh script. Please mind you need to fill out your own My Oracle Support username (mosUser) and password (mosPass). Leave DownList as it is.
12- RUN; this downloads a modified version of the getMOSPatch.sh script by Maris Elsins (thank you Maris and John Piwowar). The only modification I made is to make the downloads pre-selectable by setting the DownList environment variable.
13- RUN; this downloads a response file for the installation.
14- RUN; this echoes the language for the patches to download.
15- RUN; sh /home/oracle/getMOSPatch.sh patch=17694377 runs getMOSPatch.sh and downloads file 1 and 2 of patch 17694377, which is the patch for the Oracle database version 12.1.0.2.
16/17- RUN; unzips the two files as the result of the patch download in step 15.
18- RUN; cleanup the zip files after they have been extracted.
19- RUN; runs the installer with the template downloaded, and a few extra switches.
20- USER; here we switch to root, because after installation there are two scripts which need to be run as root.
21/22- RUN; runs the two post-install root scripts.
23- RUN; cleans up the getMOSPatch.sh script, the template and the database directory, which contains the database installation media.
24/25- USER/WORKDIR; change back to the oracle user.
26- RUN; create a directory on which we hook the persistent storage of the database
27- RUN; download manage-oracle.sh, the main script that sets up the listener and the database.
28- RUN; sets the mode of the manage-oracle.sh script to 700 (read/write/execute for the oracle user).
29- RUN; download the database installation template.
30- EXPOSE; make port 1521 (the listener port) available externally.
31- CMD; make /home/oracle/manage-oracle.sh the main command (pid 1 in the container).

After creating the Dockerfile, we can build an image with the description in the Dockerfile:

# cd /var/lib/docker/dockerfiles/build-oracle-12102
# docker build -t "oracle-12102" .

(mind the trailing dot)

This will take some time, as it is downloading the operating system base image, the software and does the installation. If all goes well, you end up with two images:

# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
oracle-12102        latest              28c18b083371        42 seconds ago      12.25 GB
oraclelinux         6                   cfc75fa9f295        11 days ago         156.2 MB

Which are the image we started with (oraclelinux), and our fresh created image “oracle-12102”.

In order to start the container, we need to prepare a directory for the database files, which is mounted into the container, and is persistent (so we can actually store and save everything, which is one of the basic things a database is used for). For this I create a directory, and set the userid and group id of the Oracle user (inside the container!):

# mkdir -p /var/lib/docker/db/frits
# chown 54321:54321 /var/lib/docker/db/frits

Now that we made all preparations, we can start a container, in which the database will run. The way I created the script (manage-oracle.sh), the container will create or start a database with the hostname set for the container. At this point I don’t know if that is the best choice. It seems like a good way to automate currently. This is how a container is started based on the image we just created. The startup line looks rather long, because a couple of settings need to be made, which are saved by docker:

# docker run --ipc=host --volume=/var/lib/docker/db/frits:/u01/app/oracle/data --name frits --hostname frits --detach=true oracle-12102
25efb5d26aad31e7b06a8e2707af7c25943e2e42ec5c432dc9fa55f0da0bdaef

If you wonder what the long hexadecimal string is, this is the full image hash. Now the container is starting. There are a couple of important things to see in the docker run line:
–ipc=host This makes the host’s IPC available to the container. Otherwise my container only could see 32MB of shared memory.
–volume=/var/lib/docker/db/frits:/u01/app/oracle/data This maps the docker hosts directory /var/lib/docker/db/frits available in the container at /u01/app/oracle/data (–volume=host:container). This is persistent storage, unlike the container’s image.
–name=frits This gives the docker container the name frits.
–hostname=frits This makes the container set the hostname to frits.
–detach=true This makes the container not be connected to the starting shell, because otherwise the shell signals will be honoured by the container, meaning the CTRL-C will stop the container.
oracle-12102 This is the image on which the container is based.

If you want to see what is going on in the container, the first thing is to use the docker logs command. This will show the standard out of the main running process. The container will stop if the main running process terminates (CMD in our Dockerfile, which is starting manage-oracle.sh). In the manage-oracle.sh I put a tail on the alert.log of the database after starting the listener, so you can use ‘docker logs’ to look how the database is doing (-f means follow):

# docker logs -f frits

LSNRCTL for Linux: Version 12.1.0.2.0 - Production on 11-AUG-2015 15:33:30

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

Starting /u01/app/oracle/product/12.1.0.2/dbhome_1/bin/tnslsnr: please wait...

TNSLSNR for Linux: Version 12.1.0.2.0 - Production
System parameter file is /u01/app/oracle/product/12.1.0.2/dbhome_1/network/admin/listener.ora
Log messages written to /u01/app/oracle/diag/tnslsnr/frits/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=frits)(PORT=1521)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=frits)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 12.1.0.2.0 - Production
Start Date                11-AUG-2015 15:33:30
Uptime                    0 days 0 hr. 0 min. 5 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Listener Parameter File   /u01/app/oracle/product/12.1.0.2/dbhome_1/network/admin/listener.ora
Listener Log File         /u01/app/oracle/diag/tnslsnr/frits/listener/alert/log.xml
Listening Endpoints Summary...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=frits)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
The listener supports no services
The command completed successfully

SQL*Plus: Release 12.1.0.2.0 Production on Tue Aug 11 15:33:36 2015

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

Connected to an idle instance.

SQL> ORACLE instance started.

Total System Global Area 1048576000 bytes
Fixed Size		    2932336 bytes
Variable Size		  247464336 bytes
Database Buffers	  658505728 bytes
Redo Buffers		  139673600 bytes
Database mounted.
Database opened.
SQL> Disconnected from Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
Database Characterset is WE8MSWIN1252
No Resource Manager plan active
replication_dependency_tracking turned off (no async multimaster replication found)
Starting background process AQPC
Tue Aug 11 15:33:55 2015
AQPC started with pid=30, OS id=88
Starting background process CJQ0
Tue Aug 11 15:33:57 2015
CJQ0 started with pid=61, OS id=150
Completed: ALTER DATABASE OPEN
Tue Aug 11 15:34:10 2015
===========================================================
Dumping current patch information
===========================================================
No patches have been applied
===========================================================

If you followed the examples in the blogpost, this is not what you would see, because there isn’t a database. Instead, if you look with docker logs, you will see:

# docker logs -f frits

LSNRCTL for Linux: Version 12.1.0.2.0 - Production on 11-AUG-2015 15:44:51

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

Starting /u01/app/oracle/product/12.1.0.2/dbhome_1/bin/tnslsnr: please wait...

TNSLSNR for Linux: Version 12.1.0.2.0 - Production
System parameter file is /u01/app/oracle/product/12.1.0.2/dbhome_1/network/admin/listener.ora
Log messages written to /u01/app/oracle/diag/tnslsnr/frits/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=frits)(PORT=1521)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=frits)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 12.1.0.2.0 - Production
Start Date                11-AUG-2015 15:44:51
Uptime                    0 days 0 hr. 0 min. 5 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Listener Parameter File   /u01/app/oracle/product/12.1.0.2/dbhome_1/network/admin/listener.ora
Listener Log File         /u01/app/oracle/diag/tnslsnr/frits/listener/alert/log.xml
Listening Endpoints Summary...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=frits)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
The listener supports no services
The command completed successfully
Creating and starting Oracle instance
2% complete
3% complete
5% complete

Which is the dbca working to create a database for you.

If you wonder what is going on inside the container, you can create a shell in it using the ‘docker exec’ command. This can not be done if the container is stopped, only if the container is running:

# docker exec -ti frits bash
[oracle@frits ~]$

Unlike an attached start, a docker exec bash session can exit without interrupting the container.

In order to see running containers, use docker ps:

# docker ps
CONTAINER ID        IMAGE                 COMMAND                CREATED             STATUS              PORTS               NAMES
304d273d9424        oracle-12102:latest   "/bin/sh -c /home/or   2 minutes ago       Up 2 minutes        1521/tcp            frits

The container can be stopped:

# docker stop frits
frits

It is not visible anymore as running container with docker ps:

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

However, you can see stopped containers when you add ‘-a’ to ps:

# docker ps -a
CONTAINER ID        IMAGE                 COMMAND                CREATED             STATUS                     PORTS               NAMES
304d273d9424        oracle-12102:latest   "/bin/sh -c /home/or   25 minutes ago      Exited (0) 2 minutes ago                       frits

You can start a stopped container with docker start:

# docker start -a=false frits
frits

If you want containers to start on boot, you must automate the docker start command on the operating system.

Please mind the exposed port on the container (1521, the listener) is local to the container, and not visible outside of the docker host. If you want to make the port visible outside of the docker host, you must publish it from the container to the host. In order to do that, you must redefine the container. This requires you to drop it first:

# docker stop frits
frits
# docker rm frits
frits
# docker run --ipc=host --volume=/var/lib/docker/db/frits:/u01/app/oracle/data --name frits --hostname frits --detach=true --publish=1521:1521 oracle-12102
84421ae6ee344df7d78aba5f0f5314894137f120a05b94870fcc0f805287b632

Because the database is on persistent storage, it can just startup again.

Tagged: Oracle database