Pythian Blog: Technical Track

How to use Oracle Instant Client Docker images

There are two available, both Version 12.2. One is found on Docker Hub and the other on the Oracle Container Registry. The following are instructions on obtaining both images, followed by a narrative of making one of them work in my environment. It is assumed that you already have a Docker environment configured. If not you may wish to visit this site: Docker - Get Started

Docker Hub

Oracle Instant Client It is necessary to first 'Proceed to Checkout' and accept the terms and conditions. Once that is done you will be shown the docker pull command to be used.
$ docker login
 Authenticating with existing credentials...
 WARNING! Your password will be stored unencrypted in /home/jkstill/.docker/config.json.
 Configure a credential helper to remove this warning. See
 https://docs.docker.com/engine/reference/commandline/login/#credentials-store
 
 Login Succeeded
 
 $ docker pull store/oracle/database-instantclient:12.2.0.1
 

Oracle Container Registry

Follow the instructions here: Using the Oracle Container Registry
  • Log in to Oracle Container Registry with your Oracle Account (free if you don't already have one).
  • Navigate to the image you wish to install.
  • Accept the Terms and Conditions.
At this time you will be shown the Docker pull command used to obtain the Docker image. It is necessary to first log in to Oracle Container Registry in a browser or else the Docker pull command will fail. The instant client was located here at the time of writing: Oracle Instant Client The image was downloaded:
$ docker login container-registry.oracle.com
 Username: jkstill@gmail.com
 Password:
 WARNING! Your password will be stored unencrypted in /home/jkstill/.docker/config.json.
 Configure a credential helper to remove this warning. See
 https://docs.docker.com/engine/reference/commandline/login/#credentials-store
 
 Login Succeeded
 
 docker pull container-registry.oracle.com/database/instantclient:12.2.0.1
 
Now there are 2 rather large images installed
$ docker image ls | head -1 ; docker image ls | grep oracle
 REPOSITORY TAG IMAGE ID CREATED SIZE
 container-registry.oracle.com/database/instantclient 12.2.0.1 fda46de41de3 16 months ago 407MB
 store/oracle/database-instantclient 12.2.0.1 916033cf06bf 19 months ago 404MB
 

Run the images

The example command line as seen at Oracle Instant Client.
docker run -ti --rm container-registry.oracle.com/database/instantclient sqlplus hr/welcome@example.com/pdborcl
 
First I will log in to a database to make sure it is up
$ sqlplus jkstill/XXX@p1
 
 SQL*Plus: Release 12.1.0.2.0 Production on Fri Dec 28 07:21:56 2018
 
 Copyright (c) 1982, 2014, Oracle. All rights reserved.
 
 Last Successful login time: Fri Dec 28 2018 07:20:10 -08:00
 
 Connected to:
 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
 
 JKSTILL@p1 $
 
Now try with docker
$ docker run -ti --rm container-registry.oracle.com/database/instantclient:latest sqlplus -L jkstill/XXX@p1
 
 SQL*Plus: Release 12.2.0.1.0 Production on Fri Dec 28 15:23:06 2018
 
 Copyright (c) 1982, 2016, Oracle. All rights reserved.
 
 ERROR:
 ORA-12154: TNS:could not resolve the connect identifier specified
 
 SP2-0751: Unable to connect to Oracle. Exiting SQL*Plus
 
The problem here is that the environment in the Docker image does not know how to connect to my local environment. The instance 'p1' is actually defined in an LDAP database:
$ tnsping p1
 
 TNS Ping Utility for Linux: Version 12.1.0.2.0 - Production on 28-DEC-2018 07:24:29
 
 Copyright (c) 1997, 2014, Oracle. All rights reserved.
 
 Used parameter files:
 /u01/app/oracle/product/12.1.0/c12/network/admin/sqlnet.ora
 
 Used LDAP adapter to resolve the alias
 Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = ora122rac-scan.jks.com)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = js1.jks.com)))
 OK (0 msec)
 
What needs to be done now is create the ldap.ora file.
docker run -ti --rm container-registry.oracle.com/database/instantclient:latest /bin/bash
 
 bash-4.2# pwd
 /usr/lib/oracle/12.2/client64
 bash-4.2# mkdir -p network/admin
 
 bash-4.2# cat > network/admin/ldap.ora
 DIRECTORY_SERVERS=(192.168.1.2:389:636)
 DEFAULT_ADMIN_CONTEXT = "dc=jks,dc=com"
 DIRECTORY_SERVER_TYPE = OID
 
 bash-4.2# mkdir -p /opt/sql
 bash-4.2# mkdir -p /opt/sql-lib
 
 
From another session, commit the container to a new image:
$ docker container ls
 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
 be77ff794f70 container-registry.oracle.com/database/instantclient:latest "/bin/bash" 6 minutes ago Up 6 minutes loving_shaw
 
 $ docker commit -m 'added ldap.ora' be77ff794f70 jkstill/oracle-12.2-instantclient:latest
 sha256:45674fcb5eb82d80d86ede86e5b9789f4ee56bada32457ddbf3172bf53982be1
 
 
Connections are still failing.
docker run -ti --rm jkstill/oracle-12.2-instantclient sqlplus -L jkstill/XXX@p1
 
Now create a new commit of the image with TNS_ADMIN set. The location of the ldap.ora file should work in this location, but setting TNS_ADMIN will ensure that ldap.ora will be found
# docker commit -c 'ENV TNS_ADMIN=/usr/lib/oracle/12.2/client64/network/admin' -m 'added ldap.ora' 50ac8602f430 jkstill/oracle-12.2-instantclient:latest
 
Running the test again, there is still no connection being made. At this point, I suspect the issue is that this image cannot resolve names.
bash-4.2# cat resolv.conf
 # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
 # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
 search jks.com
 
 nameserver 8.8.8.8
 nameserver 8.8.4.4
 
Replace the file and make it immutable. The chattr program is not installed, so the e2fsprogs.x86_64 package was first installed.
bash-4.2# yum install e2fsprogs.x86_64
 ...
 
 bash-4.2# cat > resolv.conf
 domain jks.com
 search jks.com
 nameserver 192.168.1.2
 
 bash-4.2# chattr +i resolv.conf
 chattr: Operation not permitted while setting flags on resolv.conf
 
 bash-4.2# chmod -w resolv.conf
 
So chattr + operations are not allowed. I did not look into why, but set resolv.conf to read only (we will find out a little later why this didn't work). So that ping would be available...
bash-4.2# yum install iputils
 
Now connections to the RAC server are working.
bash-4.2# ping -c 1 ora122rac02
 PING ora122rac02.jks.com (192.168.1.222) 56(84) bytes of data.
 64 bytes from ora122rac02.jks.com (192.168.1.222): icmp_seq=1 ttl=63 time=0.472 ms
 
 --- ora122rac02.jks.com ping statistics ---
 1 packets transmitted, 1 received, 0% packet loss, time 0ms
 rtt min/avg/max/mdev = 0.472/0.472/0.472/0.000 ms
 
Re-commit the new image and check the size.
$ docker commit -c 'ENV TNS_ADMIN=/usr/lib/oracle/12.2/client64/network/admin' -m 'added ldap.ora and ping utilities' 50ac8602f430 jkstill/oracle-12.2-instantclient:latest
 
 $ docker image ls | head -1; docker image ls | grep instant
 REPOSITORY TAG IMAGE ID CREATED SIZE
 jkstill/oracle-12.2-instantclient latest f65f1b6a72c7 52 seconds ago 688MB
 container-registry.oracle.com/database/instantclient 12.2.0.1 fda46de41de3 16 months ago 407MB
 container-registry.oracle.com/database/instantclient latest fda46de41de3 16 months ago 407MB
 store/oracle/database-instantclient 12.2.0.1 916033cf06bf 19 months ago 404MB
 
The size has ballooned a bit at 688MB. Changing the /etc/resolv.conf file and committing to the new image did not help, as the same contents are again seen in /etc/resolv.conf.
$ docker run -ti --rm jkstill/oracle-12.2-instantclient /bin/bash
 bash-4.2# echo $TNS_ADMIN
 /usr/lib/oracle/12.2/client64/network/admin
 bash-4.2# ping ora122rac-scan.jks.com
 ping: ora122rac-scan.jks.com: Name or service not known
 bash-4.2# cat /etc/resolv.conf
 # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
 # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
 search jks.com
 
 nameserver 8.8.8.8
 nameserver 8.8.4.4
 bash-4.2# exit
 
Now it is time to take a look at the documentation. Configure Container DNS Docker uses some special files to manage the /etc/hosts, /etc/hostnames and /etc/resolv.conf files - read about it the previously shown documentation link (this is why earlier attempts to use chattr failed). The documentation also shows how to override these from the command line.
$ docker run --dns=192.168.1.2 --dns-search=jks.com -ti --rm jkstill/oracle-12.2-instantclient /bin/bash
 bash-4.2# cat /etc/resolv.conf
 search jks.com
 nameserver 192.168.1.2
 
Now the container can connect to the network properly.
$ docker run --dns=192.168.1.2 --dns-search=jks.com -ti --rm jkstill/oracle-12.2-instantclient sqlplus -L jkstill/XXX@p1
 
 SQL*Plus: Release 12.2.0.1.0 Production on Fri Dec 28 16:39:55 2018
 
 Copyright (c) 1982, 2016, Oracle. All rights reserved.
 
 Last Successful login time: Fri Dec 28 2018 15:21:56 +00:00
 
 Connected to:
 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
 
 SQL$ @who
 SP2-0310: unable to open file "who.sql"
 SQL$ Disconnected from Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
 
 SQL$
 
Success! Well, at least as far as connecting to the database. The container does not know about my $SQLPATH settings. Before dealing with that, however, I will see if the size of the image can be made somewhat smaller. Now that I know what to do to get the Docker image to work in my environment, I will remove the newly committed image and start over without installing extra packages.
$ docker image rm jkstill/oracle-12.2-instantclient
 Untagged: jkstill/oracle-12.2-instantclient:latest
 Deleted: sha256:f65f1b6a72c7cdaf19e279f2e8f8a6643fa966a5071eacbb0d3b3da2c0127469
 Deleted: sha256:19b964c8150b24b79925a7b5ad24efe409fc2394399edeff2affd0ceab95a04d
 
Restart the Oracle-provided image and re-apply the changes for TNS_ADMIN and ldap.ora to the new image.
$ docker run -ti --rm container-registry.oracle.com/database/instantclient /bin/bash
 bash-4.2# cd /usr/lib/oracle/12.2/client64
 
 bash-4.2# mkdir -p network/admin
 
 bash-4.2# cat > network/admin/ldap.ora
 DIRECTORY_SERVERS=(192.168.1.2:389:636)
 DEFAULT_ADMIN_CONTEXT = "dc=jks,dc=com"
 DIRECTORY_SERVER_TYPE = OID
 
 bash-4.2# mkdir -p /opt/sql
 bash-4.2# mkdir -p /opt/sql-lib
 
 
From another session:
$ docker ps
 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
 57263fa776e3 container-registry.oracle.com/database/instantclient "/bin/bash" 2 minutes ago Up 2 minutes condescending_pasteur
 
 $ docker commit -c 'ENV TNS_ADMIN=/usr/lib/oracle/12.2/client64/network/admin' -m 'added ldap.ora' 57263fa776e3 jkstill/oracle-12.2-instantclient:latest
 sha256:94ac5d2b864102388c951e9210fa5ef241aee5584a9999013ad6d34fe8ff11ba
 
Now the image is the same size as the original:
$ docker image ls | head -1; docker image ls | grep instant
 REPOSITORY TAG IMAGE ID CREATED SIZE
 jkstill/oracle-12.2-instantclient latest 94ac5d2b8641 42 seconds ago 407MB
 container-registry.oracle.com/database/instantclient 12.2.0.1 fda46de41de3 16 months ago 407MB
 container-registry.oracle.com/database/instantclient latest fda46de41de3 16 months ago 407MB
 store/oracle/database-instantclient 12.2.0.1 916033cf06bf 19 months ago 404MB
 
By using the --dns and --dns-search options, the connection to the database is now working.
$ docker run --dns=192.168.1.2 --dns-search=jks.com -ti --rm jkstill/oracle-12.2-instantclient sqlplus -L jkstill/XXX@p1
 
 SQL*Plus: Release 12.2.0.1.0 Production on Fri Dec 28 16:51:34 2018
 
 Copyright (c) 1982, 2016, Oracle. All rights reserved.
 
 Last Successful login time: Fri Dec 28 2018 16:49:21 +00:00
 
 Connected to:
 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
 
 SQL$ Disconnected from Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
 
Now to fix the SQLPATH issue. My SQLPATH at this time: /home/jkstill/oracle/oracle-script-lib/sql:/home/jkstill/oracle/admin/sql. There is no user 'jkstill' in the Docker image, and there is no need to create one. The Docker-mount option can be used to make these scripts available at runtime to the sqlplus client in the container. The following options will do it: --mount type=bind,source=/home/jkstill/oracle/oracle-script-lib/sql,target=/opt/sql-lib --mount type=bind,source=/home/jkstill/oracle/admin/sql,target=/opt/sql So the SQLPATH variable for the container will be set to /opt/sql-lib:/opt/sql Start up the new image again, using bash will work.
$ docker run --dns=192.168.1.2 --dns-search=jks.com -ti --rm jkstill/oracle-12.2-instantclient /bin/bash
 bash-4.2#
 
Now commit the image again, setting the SQLPATH variable.
$ docker ps
 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
 2b5f493b6b0f jkstill/oracle-12.2-instantclient "/bin/bash" 43 seconds ago Up 42 seconds musing_montalcini
 
 $ docker commit -c 'ENV SQLPATH=/opt/sql-lib:/opt/sql' -m 'added SQLPATH' 2b5f493b6b0f jkstill/oracle-12.2-instantclient:latest
 sha256:58891599275e28b8385a22fefeb30a06e02d30f30ca64ebccdc2260201ce2ed5
 
Now exit Docker, restart with the mount commands and see if everything is as expected.
docker run --dns=192.168.1.2 --dns-search=jks.com -ti --rm \
 --mount type=bind,source=/home/jkstill/oracle/oracle-script-lib/sql,target=/opt/sql-lib \
 --mount type=bind,source=/home/jkstill/oracle/admin/sql,target=/opt/sql \
 jkstill/oracle-12.2-instantclient /bin/bash
 
 bash-4.2# cd /opt
 bash-4.2# ls -l
 total 92
 drwxr-x--- 4 1000 1002 65536 Dec 24 19:36 sql
 drwxr-xr-x 3 1000 1002 24576 Dec 14 20:29 sql-lib
 
 bash-4.2# ls -l sql/*.sql | wc
 1381 12983 95660
 bash-4.2# ls -l sql-lib/*.sql | wc
 574 5182 39430
 
 bash-4.2# cat /etc/resolv.conf
 search jks.com
 nameserver 192.168.1.2
 
 bash-4.2# sqlplus jkstill/XXX@p1
 
 SQL*Plus: Release 12.2.0.1.0 Production on Fri Dec 28 17:11:31 2018
 
 Copyright (c) 1982, 2016, Oracle. All rights reserved.
 
 Last Successful login time: Fri Dec 28 2018 16:51:34 +00:00
 
 Connected to:
 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
 
 SQL$
 
Looks good, now to try with sqlplus directly.
$ docker run --dns=192.168.1.2 --dns-search=jks.com -ti --rm \
 --mount type=bind,source=/home/jkstill/oracle/oracle-script-lib/sql,target=/opt/sql-lib \
 --mount type=bind,source=/home/jkstill/oracle/admin/sql,target=/opt/sql \
 jkstill/oracle-12.2-instantclient sqlplus -L jkstill/XXX@p1
 
 SQL*Plus: Release 12.2.0.1.0 Production on Fri Dec 28 17:12:48 2018
 
 Copyright (c) 1982, 2016, Oracle. All rights reserved.
 
 Last Successful login time: Fri Dec 28 2018 17:11:31 +00:00
 
 Connected to:
 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
 
 SQL$ @who
 
 USERS LOGGED ON SESSIONS
 --------------- ----------
 JKSTILL 1
 SYS 1
 
 SQL$ @who2
 
 V_OVERSION_MAJOR
 --------------------------------------------------------------------------------
 12
 
 1 row selected.
 
 PL/SQL procedure successfully completed.
 
 CLIENT SRVR
 USERNAME SID SERIAL# SQL ID PID STATUS MACHINE OSUSER CLIENT PROGRAM PID SERVER PROGRAM PID LOGON TIME IDLE TIME
 ---------- ------ ------- -------------- ------ ---------- ---------- ---------- -------------------- ------------------------ -------------------- ----- ----------------- -----------
 JKSTILL 52 64215 chmy5m24rfhvp 82 ACTIVE 4cfdbbea9d root sqlplus@4cfdbbea9d93 1 oracle@ora122rac02.j 24627 12/28/18 09:12:49 00:00:00:00
 93
 
 SYS 6 17304 12 ACTIVE ora122rac0 oracle oracle@ora122rac02.j 4308_4311 oracle@ora122rac02.j 4308 10/24/18 22:08:05 64:12:04:47
 2.jks.com
 
 2 rows selected.
 
 SQL$
 
Success! It's a good idea to create a shell script or an alias to use that rather lengthy command, as you don't want to have to type that out. Here is an example bash script:
#!/usr/bin/env bash
 
 debug=1
 
 # use this line to supply default password if desired
 #password=${password:-'MYPASSWORD'}
 username=${username:-'jkstill'}
 instance=${instance:-'p1'}
 
 if [ -n "$sysdba" ]; then
  sysdba=' as sysdba'
 else
  sysdba=''
 fi
 
 # build the command to prompt for password if not supplied
 if [[ -n "$password" ]]; then
  sqlCmd="sqlplus -L ${username}/${password}@${instance} ${sysdba}"
 else
  sqlCmd="sqlplus -L ${username}@${instance} ${sysdba}"
 fi
 
 [[ $debug -gt 0 ]] && {
  echo Username: $username
  echo Password: $password
  echo Instance: $instance
  echo " Sysdba: $sysdba"
  echo " CMD:" $sqlCmd
 }
 
 
 docker run --dns=192.168.1.2 --dns-search=jks.com -ti --rm \
  --mount type=bind,source=/home/jkstill/oracle/oracle-script-lib/sql,target=/opt/sql-lib \
  --mount type=bind,source=/home/jkstill/oracle/admin/sql,target=/opt/sql \
  jkstill/oracle-12.2-instantclient $sqlCmd
 
 
And now some usage examples: Prompt for password.
> instance=p3 12-2.sh
 Username: jkstill
 Password:
 Instance: p3
  Sysdba:
  CMD: sqlplus -L jkstill@p3
 
 SQL*Plus: Release 12.2.0.1.0 Production on Wed Jan 2 16:03:53 2019
 
 Copyright (c) 1982, 2016, Oracle. All rights reserved.
 
 Enter password:
 Last Successful login time: Wed Jan 02 2019 16:00:15 +00:00
 
 Connected to:
 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
 
 SQL>
 
Supply the password on the command line.
> password=XXX instance=p3 12-2.sh
 Username: jkstill
 Password: XXX
 Instance: p3
  Sysdba:
  CMD: sqlplus -L jkstill/XXX@p3
 
 SQL*Plus: Release 12.2.0.1.0 Production on Wed Jan 2 16:05:05 2019
 
 Copyright (c) 1982, 2016, Oracle. All rights reserved.
 
 Last Successful login time: Wed Jan 02 2019 16:03:55 +00:00
 
 Connected to:
 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
 
 SQL>
 
Logon as SYSDBA
> sysdba=1 password=XXX instance=p3 12-2.sh
 Username: jkstill
 Password: XXX
 Instance: p3
  Sysdba: as sysdba
  CMD: sqlplus -L jkstill/XXX@p3 as sysdba
 
 SQL*Plus: Release 12.2.0.1.0 Production on Wed Jan 2 16:06:09 2019
 
 Copyright (c) 1982, 2016, Oracle. All rights reserved.
 
 
 Connected to:
 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
 
 SQL>
 
 
Also, if you need to save some space, the Oracle Instant client image is no longer required and can be deleted.

What's next

A Docker image with an 18c client would sure be nice to have. My work environment is Ubuntu Mate 16.x, with Oracle 11.2 and 12.1 full client software installed. Due to changes in libraries with 12.2 and 18c, I found it was impossible to install either of these in the current environment. Using Docker makes is possible to use the 12.2 client, and eventually the 18c client as well. Currently, there isn't an 18c client Docker image that I know of, but one could be crafted for that purpose. That will have to wait for a later blog.

Comments (1)

Subscribe by email