Introducing gvenzl/oracle-xe: Oracle Database XE Docker images

One of the things that kept me busy lately was experimenting with how much an Oracle XE database setup could be streamlined inside a Docker image for things like CI/CD consumption. Pretty much ever since I put together the first official build scripts for Oracle Database, people have asked for faster image pull and startup times to speed up their continuous integration tests. A lot of things have changed since then, and I’m happy that my engineering colleagues at Oracle have taken on the maintenance and further enhancements of Oracle’s official Docker build files and images, and integrated them into the internal processes.

However, my own needs for some of my private projects such as #csv2db have also caused me to think about how to better streamline and integrate Oracle XE into my own pipelines. I too needed a quick and easy XE Docker image, yet Oracle’s Container Registry did not host an XE image yet (it does now, since about two weeks ago), and all images on Docker Hub that I could find were old 11g R2 XE ones. So, on some Saturday, I sat down to “quickly” put together some new build files for XE, applying some of the lessons learned in the process. And about five months later, the outcome is yet another Docker Hub repository: https://hub.docker.com/r/gvenzl/oracle-xe

Why a repository?

While I was at it, I thought of the many conversations that I had about the trade-off between image size and additional functionality. Sure, sometimes I want to be able to just quickly pull a small image to test a bunch of INSERTs, but I also want to be able to use, e.g., Oracle’s Spatial functionality. More functionality means more libraries and files in the $ORACLE_HOME and that, in turn, means a bigger image. The only way I saw to provide the best of both worlds was to offer them; by providing a small, stripped-down image and a big one with all the great bells and whistles of Oracle XE. So I ventured off on a journey of stripping down the XE installation and quickly realized that I needed to document those steps for when a new version of XE will come out. A git repository was obviously the way to go, and so I did: https://github.com/gvenzl/oci-oracle-xe.

Next, I needed to put the images into some repository from where I could pull them. Luckily, Docker (still) provides free repositories. At first, I thought of a private one that would only be visible to me. But soon I realized that this would require a docker login from anywhere I want to pull the image (including GitHub Actions), so I thought: “well, why not share it (the repository) with the world then? Perhaps others can use these images as well.” And as I thought about that, it came to my mind that then there should at least be also an image that was not amended to my purposes at all, an image “as is”, meaning with just all the bits and pieces as they come from the regular Oracle XE installation. So I ended up with three images: a small one, a big one, and an “unchanged” one. Although, I did not quite name them that way, but instead a SLIM, [NOTHING] and a FULL image:

[gvenzl@localhost ~]$ podman images
REPOSITORY                  TAG      IMAGE ID      CREATED      SIZE
docker.io/gvenzl/oracle-xe  18-slim  f23caf0d8123  4 weeks ago  2.45 GB
docker.io/gvenzl/oracle-xe  18       b0afdca7c19f  4 weeks ago  3.37 GB
docker.io/gvenzl/oracle-xe  18-full  e415e9b70b63  5 weeks ago  6.38 GB
docker.io/gvenzl/oracle-xe  11-slim  044e6381c4c5  5 weeks ago  612 MB
docker.io/gvenzl/oracle-xe  11       4e27255d6f37  5 weeks ago  701 MB
docker.io/gvenzl/oracle-xe  11-full  ddbea6f88946  5 weeks ago  849 MB

You can see above that I also put together some 11g R2 images, although I mentioned that there were already so many on Docker Hub. The reason for that was that I wanted to provide users that are fond of the 11g R2 images, for whatever the reasons may be, with the same end-user experience that my 18c images have, which brings me to the next point.

Image != image

There are many images for Oracle XE on Docker Hub provided by many different people all with their own needs and ideas of how the image should work. When I put together my images, I sat back and researched what common functionalities users would expect these days. Many images allow passing on some environment variables that further customize the running container. I found a couple of those variables that one could consider “standard”, such as variables to set the password for the database or generate a random one. I also found the need for myself to allow for the creation of an application user, so that not, e.g., all integration test scripts would test as one of the superusers (SYS, SYSTEM) but also so that I don’t always have to mess around with additional setup steps. And, of course, I made sure that the mechanism for initialization scripts will also be present, as that has already come in handy so many times for myself.

Another difference that these images have is that they all include a database ready to go. Because the $ORACLE_SID for XE is anyway hard-coded to XE, one has not to worry about users wanting to create databases with a different SID. That, in turn, helps the startup times, because the database does not need to be created any longer. However, it also does increase the image size itself. That’s why the database files inside the image are all compressed and will be uncompressed first at the container startup. The trade-off still plays in favor of including the database images: the additional image size is not that much but the image startup time is much, much faster that way (below 30 seconds usually altogether).

GitHub Actions

Another nice extra that I made sure to document on the repository page, is how to use the image(s) with GitHub Actions for CI/CD tests. GitHub Actions provide a mechanism known as service containers, but the documentation says little about Oracle XE. So, if you want to use any of these images inside your GitHub Actions, just use a script similar to this one here:

services:

      # Oracle service
      oracle:

        # Docker Hub image (feel free to change the tag "latest" to any other available one)
        image: gvenzl/oracle-xe:latest

        # Provide passwords and other environment variables to container
        env:
          ORACLE_RANDOM_PASSWORD: true
          APP_USER: my_user
          APP_USER_PASSWORD: my_password_which_I_really_should_change

        # Forward Oracle port
        ports:
          - 1521:1521

        # Provide healthcheck script options for startup
        options: >-
          --health-cmd healthcheck.sh
          --health-interval 10s
          --health-timeout 5s
          --health-retries 10

Putting it all together

So here is the cool part, if you want to just spin up an Oracle 18c XE image, all you have to do is to, for example, execute: docker run --name oracle-xe-slim -p 1521:1521 -e ORACLE_RANDOM_PASSWORD=true gvenzl/oracle-xe:18-slim

[gvenzl@localhost ~]$ docker run --name oracle-xe-slim -p 1521:1521 -e ORACLE_RANDOM_PASSWORD=true gvenzl/oracle-xe:18-slim
Unable to find image 'gvenzl/oracle-xe:18-slim' locally
Trying to pull repository docker.io/gvenzl/oracle-xe ...
18-slim: Pulling from docker.io/gvenzl/oracle-xe
9a62c8a45386: Pull complete
9b0d4886444a: Pull complete
Digest: sha256:6777d42c5fe2bea135fe24155174a9742b6a56efaa146b7e969a9969881b89a2
Status: Downloaded newer image for gvenzl/oracle-xe:18-slim
CONTAINER: starting up...
CONTAINER: first database startup, initializing...
CONTAINER: uncompressing database data files, please wait...
CONTAINER: done uncompressing database data files, duration: 18 seconds.
CONTAINER: starting up Oracle Database...

LSNRCTL for Linux: Version 18.0.0.0.0 - Production on 15-AUG-2021 02:25:28

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

Starting /opt/oracle/product/18c/dbhomeXE/bin/tnslsnr: please wait...

TNSLSNR for Linux: Version 18.0.0.0.0 - Production
System parameter file is /opt/oracle/product/18c/dbhomeXE/network/admin/listener.ora
Log messages written to /opt/oracle/diag/tnslsnr/3a0d8b311e67/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC_FOR_XE)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521)))

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 18.0.0.0.0 - Production
Start Date                15-AUG-2021 02:25:28
Uptime                    0 days 0 hr. 0 min. 0 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Default Service           XE
Listener Parameter File   /opt/oracle/product/18c/dbhomeXE/network/admin/listener.ora
Listener Log File         /opt/oracle/diag/tnslsnr/3a0d8b311e67/listener/alert/log.xml
Listening Endpoints Summary...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC_FOR_XE)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521)))
The listener supports no services
The command completed successfully
ORACLE instance started.

Total System Global Area 1241512896 bytes
Fixed Size		    8895424 bytes
Variable Size		  452984832 bytes
Database Buffers	  771751936 bytes
Redo Buffers		    7880704 bytes
Database mounted.
Database opened.

CONTAINER: Resetting SYS and SYSTEM passwords.

User altered.


User altered.

############################################
ORACLE PASSWORD FOR SYS AND SYSTEM: NzJlNzMz
############################################

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

I myself actually already moved on to Linux 8 and Podman, which means that you can use these images with podman too (they are actually built with Buildah). All you have to do is to type podman instead of docker (or install the docker alias for Podman): podman run --name oracle-xe-slim -p 1521:1521 -e ORACLE_RANDOM_PASSWORD=true gvenzl/oracle-xe:18-slim

[gvenzl@localhost ~]$ podman run --name oracle-xe-slim -p 1521:1521 -e ORACLE_RANDOM_PASSWORD=true gvenzl/oracle-xe:18-slim
Trying to pull docker.io/gvenzl/oracle-xe:18-slim...
Getting image source signatures
Copying blob 9b0d4886444a done
Copying blob 9a62c8a45386 done
Copying config f23caf0d81 done
Writing manifest to image destination
Storing signatures
CONTAINER: starting up...
CONTAINER: first database startup, initializing...
CONTAINER: uncompressing database data files, please wait...
CONTAINER: done uncompressing database data files, duration: 21 seconds.
CONTAINER: starting up Oracle Database...

LSNRCTL for Linux: Version 18.0.0.0.0 - Production on 15-AUG-2021 02:32:40

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

Starting /opt/oracle/product/18c/dbhomeXE/bin/tnslsnr: please wait...

TNSLSNR for Linux: Version 18.0.0.0.0 - Production
System parameter file is /opt/oracle/product/18c/dbhomeXE/network/admin/listener.ora
Log messages written to /opt/oracle/diag/tnslsnr/655d0d492d4b/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC_FOR_XE)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521)))

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC_FOR_XE)))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 18.0.0.0.0 - Production
Start Date                15-AUG-2021 02:32:40
Uptime                    0 days 0 hr. 0 min. 0 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Default Service           XE
Listener Parameter File   /opt/oracle/product/18c/dbhomeXE/network/admin/listener.ora
Listener Log File         /opt/oracle/diag/tnslsnr/655d0d492d4b/listener/alert/log.xml
Listening Endpoints Summary...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC_FOR_XE)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521)))
The listener supports no services
The command completed successfully
ORACLE instance started.

Total System Global Area 1241512896 bytes
Fixed Size		    8895424 bytes
Variable Size		  452984832 bytes
Database Buffers	  771751936 bytes
Redo Buffers		    7880704 bytes
Database mounted.
Database opened.

CONTAINER: Resetting SYS and SYSTEM passwords.

User altered.


User altered.

############################################
ORACLE PASSWORD FOR SYS AND SYSTEM: Y2Y3ZTZm
############################################

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

What’s next?

Well, this blog post was long overdue. The images exist for a while now but other things occupied me before I managed to put this blog post together. Technically, I’m not even quite done yet with the images either but they are in a great working state and everything that is left is “icing on the cake”. Although the 18c images can never be as small as the 11g ones, too much great functionality has been added into the kernel in those 11 years in between to be able to strip it all out (easily), there are still some optimizations that I’m planning on to further reduce the 18 and 18-slim image sizes. Of course, there will be a new XE version coming soon, which I’m planning on adding to the repository as well in the same fashion. For everything else, the images serve me quite well, and I know that some other projects also already are using them successfully. However, there is always the possibility to raise enhancement requests on https://github.com/gvenzl/oci-oracle-xe/issues as well, so we shall see what’s still to come.

Author: Gerald

Developer, Oracle expert, performance enthusiast and genuine technology geek.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.