Setting Up Oracle on Docker

Docker is one of the latest hot technologies out there right now.

Basically it's a lightweight virtualization utility. Docker is available on Windows, Linux, and Mac OSX. These can be used to setup "hosts" which can then be used to run almost ANY Linux and Windows "guest" applications.

However, unlike a true virtual machine which setups the ENTIRE OS, docker setups up "JUST ENOUGH" of an operating system to run a particular application. It will also not grab a large portion of the host machines resources (memory, disk ,etc) for exclusive use. As a result, docker apps are much less memory intensive and much more portable.

Once you get an application up and running on Docker, it can be exported and "plugged" into another system without any setup and configuration issues.

For more information, click here.

In this tutorial, let's go through setting up a docker container running Oracle. 

Please note that this is very technical article, and you will need to know a fair bit of Linux and Oracle commands.

Before we start, you will also need to the following:

  • Docker (sort of obvious). Download the installer at http://www.docker.com
  • Access to an existing 64 bit Oracle 11g or 12c RDBMS installation on Linux

This tutorial was setup on a 2009 MacBook Pro running Docker-Toolbar. However these steps should also work on Windows and Linux platforms as well.

Step 1: Create the docker machine:

After you install docker, you will need to create the docker virtual machine. In this step, you will also specify the size of the virtual disk. Be sure to create the disk with enough space to run hold $ORACLE_HOME AND your database data files.  Also note that in the current release of docker, you cannot resize your virtual disk so if you find out later that your disk isn't large enough, you will need to redo the whole thing. In the example below, we are creating a docker machine called "default" with a virtual disk of 100G

In a terminal or command prompt shell, type the following:

$ docker-machine create -d virtualbox --virtualbox-disk-size "100000" default

Step 2: Start the docker machine.

$ docker-machine start default

Step 3: Start docker container for CentOS Linux and map port 1521 for the Oracle Listener (change this if you want to run listener on a different port. The first time you type this command, the system will download the image so be patient.

$ docker run -d -it -p 1521:1521 centos:latest

Step 4: Find your container ID. In our example, our ID is 69f76b125f64

Outworld2:~ jchung$ docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
69f76b125f64        centos:latest       "/bin/bash"         3 hours ago         Up 3 hours          0.0.0.0:1521->1521/tcp   agitated_mayer
Outworld2:~ jchung$

Step 5: Start up a bash shell.. This starts a root shell in your CentOS container. As we mentioned earlier, this is a BARE-BONES install of Linux; it's just enough to get a bash shell up with networking. Afterward, we will customize it by setting up everything we need in order to run Oracle.

$ docker exec -it 69f76b125f64 /bin/bash
Outworld2:~ jchung$ docker exec -it 69f76b125f64 /bin/bash
[root@69f76b125f64 /]#

Step 6: Create the dba group and oracle user. Locate the GID and UID of the dba group and oracle software owner, respectively,  on your existing oracle installation and re-create this in your container. In our example, the dba is GID 500 and UID 1000.

[root@69f76b125f64 /]# groupadd -g 500 dba
[root@69f76b125f64 /]# useradd -g dba -u 1000 oracle

Step 7: Install some required packages. You actually don't need all these patches, but they will make your life SO MUCH easier!

[root@69f76b125f64 /] yum install -y libaio-0.3.109-13.el7
[root@69f76b125f64 /] yum install -y openssh-clients-7.4p1-13.el7_4
[root@69f76b125f64 /] yum install -y openssh-server-7.4p1-13.el7_4
[root@69f76b125f64 /] yum install -y net-tools-2.0-0.22.20131004git.el7

Step 8: Create top level directories for the $ORACLE_HOME and Oracle Datafile directories, then change ownerships to "oracle:dba". In our example, these are /d01/oracle/product/11.2.0 and /oradata, respectively.

[root@69f76b125f64 /] mkdir -p /d01/oracle/product/11.2.0 ; chown oracle:dba /d01/oracle/product/11.2.0
[root@69f76b125f64 /] mkdir -p /oradata ; chown oracle:dba /oradata

Step 9: Create the /etc/sysctl.conf file. In the container, create the file /etc/sysctl.conf, then add the following lines. After you are done, type "sysctl -a" to load the parameters.

# System default settings live in /usr/lib/sysctl.d/00-system.conf.
# To override those settings, enter new settings here, or in an /etc/sysctl.d/.conf file
#
# For more information, see sysctl.conf(5) and sysctl.d(5).
fs.file-max = 6815744
## ORACLE PARAMETERS
kernel.shmall = 2097152
kernel.shmall = 4194304
kernel.shmmax = 2147483648

###########################
## Changed shmmax to 16gb ##
###########################
kernel.shmmax = 17179869184
kernel.shmmni = 4096
kernel.sem = 250 32000 100 128
fs.file-max = 6815744
net.ipv4.ip_local_port_range = 1024 65000
net.core.rmem_default = 4194304
net.core.wmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_max = 1048536

Step 10: Copy the $ORACLE_HOME and ORACLE data files from your existing home to the docker container.

Change to the oracle user, then use scp (which we installed earlier), and copy the files into the container. In this example our 11g files are on a host called "raven.nyquest.com".
Please note that you need to keep the same path for the $ORACLE_HOME and oradata directories in the container as you have in the original, preexisting installation. Otherwise you run into issues with relinking and/or recreating the control files.

[root@69f76b125f64 /]  su - oracle
Last login: Mon Nov  6 01:40:00 UTC 2017 on pts/1
[oracle@69f76b125f64 oradata]$ cd /oradata
[oracle@69f76b125f64 oradata]$ scp -r oracle@raven.nyquest.com:/oradata/SEED .
The authenticity of host 'raven.nyquest.com (xx.xx.xx.xx)' can't be established.
ECDSA key fingerprint is SHA256:NUew/8tPKeoVAEX7tXJaPTsxjxL3EJtyKD/B2w8HN9U.
ECDSA key fingerprint is xxxxx.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'xx.xx.xx.xx' (ECDSA) to the list of known hosts.
oracle@xx.xx.xx.xx's password: 
users01.dbf                                                                                                                                                                                                                     100% 5128KB  14.8MB/s   00:00    
redo02.log                                                                                                                                                                                                                      100%   50MB  20.6MB/s   00:02    
undotbs01.dbf                                                                                                                                                                                                                   100%  820MB  20.1MB/s   00:40    

[oracle@69f76b125f64 oradata]$ cd /d01/oracle/product/11.2.0
[oracle@69f76b125f64 oradata]$ scp -r oracle@raven.nyquest.com:/d01/oracle/product/11.2.0 .

Step 11: Exit back the root shell and then rerun the $ORACLE_HOME/root.sh script.

[oracle@69f76b125f64 ~]$ exit
logout
[root@69f76b125f64 /]# cd /d01/oracle/product/11.2.0/dbhome_1
[root@69f76b125f64 dbhome_1]# ./root.sh
Performing root user operation for Oracle 11g

The following environment variables are set as:
    ORACLE_OWNER= oracle
    ORACLE_HOME=  /d01/oracle/product/11.2.0/dbhome_1

Enter the full pathname of the local bin directory: [/usr/local/bin]:

Step 12: Start up oracle in the container. After you run the root.sh script. Change back to the oracle user and start the instance.

[root@69f76b125f64 dbhome_1]# su - oracle
Last login: Mon Nov  6 04:34:17 UTC 2017 on pts/1
[oracle@69f76b125f64 ~]$ . oraenv
ORACLE_SID = [oracle] ? SEED
The Oracle base for ORACLE_HOME=/d01/oracle/product/11.2.0/dbhome_1 is /d01/oracle
[oracle@69f76b125f64 ~]$ sqlplus / as sysdba 

SQL*Plus: Release 11.2.0.4.0 Production on Mon Nov 6 04:36:55 2017

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

Connected to an idle instance.

SQL> startup 
ORACLE instance started.

Total System Global Area  350736384 bytes
Fixed Size		    2253184 bytes
Variable Size		  222301824 bytes
Database Buffers	  121634816 bytes
Redo Buffers		    4546560 bytes
Database mounted.
Database opened.
SQL> exit
Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
[oracle@69f76b125f64 ~]$ 

Step 13: Start up the Oracle listener. If order to do this, we first need to determine the internal IP address of the container. Exit back to the root shell and type "ifconfig -a". Note the IP address of eth0, which in this case is 172.17.0.2. Add this address into the $ORACLE_HOME/network/admin/listener.ora file

[root@69f76b125f64 dbhome_1]# ifconfig -a 
eth0: flags=4163  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 0.0.0.0
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 1413868  bytes 14946101292 (13.9 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 849805  bytes 53659192 (51.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1  (Local Loopback)
        RX packets 321  bytes 43944 (42.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 321  bytes 43944 (42.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@69f76b125f64 dbhome_1]# cat /d01/oracle/product/11.2.0/dbhome_1/network/admin/listener.ora 
LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS_LIST =
        (ADDRESS = (PROTOCOL = TCP)(HOST = 172.17.0.2)(PORT = 1521))
      )
    )
  )
SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (ORACLE_HOME = /d01/oracle/product/11.2.0/dbhome_1)
      (SID_NAME = SEED)
    )
  )

[root@69f76b125f64 dbhome_1]# su - oracle
Last login: Mon Nov  6 04:36:51 UTC 2017 on pts/1
[oracle@69f76b125f64 ~]$ . oraenv
ORACLE_SID = [oracle] ? SEED
The Oracle base for ORACLE_HOME=/d01/oracle/product/11.2.0/dbhome_1 is /d01/oracle
[oracle@69f76b125f64 ~]$ lsnrctl start

LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 06-NOV-2017 05:02:01

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

Starting /d01/oracle/product/11.2.0/dbhome_1/bin/tnslsnr: please wait...

TNSLSNR for Linux: Version 11.2.0.4.0 - Production
System parameter file is /d01/oracle/product/11.2.0/dbhome_1/network/admin/listener.ora
Log messages written to /d01/oracle/diag/tnslsnr/69f76b125f64/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=172.17.0.2)(PORT=1521)))

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.17.0.2)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date                06-NOV-2017 05:02:01
Uptime                    0 days 0 hr. 0 min. 0 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Listener Parameter File   /d01/oracle/product/11.2.0/dbhome_1/network/admin/listener.ora
Listener Log File         /d01/oracle/diag/tnslsnr/69f76b125f64/listener/alert/log.xml
Listening Endpoints Summary...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=172.17.0.2)(PORT=1521)))
Services Summary...
Service "SEED" has 1 instance(s).
  Instance "SEED", status UNKNOWN, has 1 handler(s) for this service...
The command completed successfully
[oracle@69f76b125f64 ~]$ 

Step 14: Connect to the container from the host. Once you've gotten Oracle running in the container, the final step is to connect to this database externally. But in order to do this, we will need to find the external IP address. From the host, type the following command. In this example, the container's external address is 192.168.99.100.

[oracle@69f76b125f64 ~]$ exit
logout
[root@69f76b125f64 dbhome_1]# exit
#
# At this point we are back in the host OS
#
Outworld2:~ jchung$ docker-machine ip default 
192.168.99.100
Outworld2:~ jchung$ 

Remember, that when we started the container, we mapped port 1521, so externally the TNS extry should be the following:

DOCKER=
 (DESCRIPTION =
      (ADDRESS =
        (PROTOCOL = TCP)
        (HOST = 192.168.99.100)
        (PORT = 1521)
      )
      (CONNECT_DATA =
        (SERVER = DEDICATED)
        (SERVICE_NAME = SEED)
      )
  )

Step 15: Finally, commit your changes. Docker containers, by default, do not record changes. In order to do so, we need to commit to another image:

From the host system, type the following:

# get container ID
Outworld2:~ jchung$ docker container ls 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
69f76b125f64        centos:latest       "/bin/bash"         5 hours ago         Up 4 hours          0.0.0.0:1521->1521/tcp   agitated_mayer
# commit changes to a new image centos-oracle
Outworld2:~ jchung$ docker container commit 69f76b125f64  centos-oracle
# you should be able to see a new image now 
Outworld2:~ jchung$ docker image ls 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos-oracle       latest              6d359b2657fb        4 hours ago         15.1GB
centos              latest              d123f4e55e12        2 days ago          197MB

Ok, so at this point, you've setup a docker container running Oracle. So what? Well, for starters, anytime you need a copy of this database to be running, you can simply deploy the container. No need to go thru the whole cloning process each time.

To move your image to another machine, simply save the image to a tar file.

# we can get the image id from the command above. 
# this will save the contents of the image in a tgz file called /tmp/centos-oracle.tgz
Outworld2:~ jchung$  docker image save 6d359b2657fb -o /tmp/centos-oracle.tgz

You can then take this tar file to another server, and import it into a new image which you can then run in another container.

# in this command we will load the centos-oracle.tgz file into a new docker image
# presumably you will be doing this on a different machine
# once the load is done it will create a new image on your system
InnerWorld:~ jchung$  docker load -i /tmp/centos-oracle.tgz

Setting up a database on a new server becomes trivial; instead of downloading Oracle, running the installer, and doing all that configuration (you DBA's know what I mean, /etc/sysctl.conf, tnsnames.ora, root,sh, listener.ora, etc), you can just deploy the container and have a working database environment running in minutes!

Finally, one thing that Banner® Users always want is a clean training environment. Well with docker setting up a clean training PPRD, TRNG, DEVL database also becomes trivial. Each time you need this, simply deploy the container. Also note that changes within the container are NOT saved when the container is restarted, so each time you need to refresh, simply restart everything.

For people that want to go further, you can also setup Docker environments for other Banner® components such as Weblogic, Tomcat, Oracle Forms.


Contact us if you have any questions or if you require any help with setting up docker in your environment(s).