Skip to main content
Broadpin

SOA Suite on Docker, Part 3: Building a Patched Image, and Reacting to CPUs in Minutes

This blog post was written by Johannes Michler (Chief Technology Officer (CTO) @ Broadpin & Oracle Ace Director).

In Part 1 I described the certified, containerized 14.1.2 platform, and in Part 2 how we migrated onto it. This post is about the part I am most pleased with: how we build the SOA Suite image, and how that same process turns patching from a maintenance-window ordeal into a container restart.

The important thing to understand up front is that there is no separate "patching procedure." The command that builds the image for the initial deployment is the same command we run for every patch round. Patching a SOA Suite environment becomes: build a new image with the new patches, ship it, and restart the container on the new image. That is the whole story, and it is why this matters as much on day one as it does every quarter.

And the cadence is the real driver. Oracle ships Critical Patch Updates (CPUs) quarterly, and there is now a monthly Critical Security Patch Update (CSPU) cadence on top of that. If applying a patch set means a painful in-place OPatch session and a long outage (took us up to 2 hours with 12c and in-place OPatch application), you will not keep up. If it means rebuilding an image and bouncing a container, you can.

SOA Suite on Docker, Part 2: Upgrading 12c to 14c, Composite by Composite

Attempt 1: building on top of Oracle's CPU image

Oracle publishes pre-patched images on the Oracle Container Registry, including a soasuite_cpu repository that already contains the latest Critical Patch Update. The obvious approach is to start from that image and layer on anything extra you need with the WebLogic Image Tool:

JAVA_HOME=/usr/java/jdk-21 imagetool/bin/imagetool.sh update \
  --fromImage container-registry.oracle.com/middleware/soasuite_cpu:14.1.2.0-jdk21-ol9-260118 \
  --tag xxis_soa14:260303_6 \
  --patches 37944602,39032647_14.1.2.0.251022,39029919,39023318_14.1.2.0.251120,39076336,39113739 \
  --user <oracle-sso-user> --password --pull

This works, and it is genuinely quick. The catch is timing. The CPU images on the Container Registry are only refreshed when Oracle rebuilds and republishes them, and that lags the actual patch availability. At the time of writing (July 2026), the newest soasuite_cpu image available is still the January 2026 CPU. If you depend on Oracle having baked the latest patches into a base image, you are always a couple of steps behind, which defeats the point of reacting quickly to a new CPU or monthly CSPU.

Attempt 2: building from a clean base

So we went one level down and build the image ourselves, from a plain Oracle Linux base, pulling the patches straight from My Oracle Support the moment they are released:

JAVA_HOME=/usr/java/jdk-21 ./imagetool.sh create \
  --jdkVersion=21u11 --pull \
  --type=SOA --version=14.1.2.0.0 \
  --tag xxis_soa14:260616_1 \
  --fromImage ghcr.io/oracle/oraclelinux:9-slim \
  --recommendedPatches \
  --additionalBuildFiles /home/opc/soa-ops/oracle-docker-images/container-scripts/ \
  --additionalBuildCommands /home/opc/soa-ops/oracle-docker-images/additionalBuildCmds.txt \
  --patches 39113739_14.1.2.0.251022,39076336,39032647_14.1.2.0.251022,39029919,37944602,38391376,39064305 \
  --strictPatchOrdering \
  --user <oracle-sso-user> --password

A few things worth calling out in that command:

  • --fromImage ghcr.io/oracle/oraclelinux:9-slim starts from a clean, current Oracle Linux 9 base rather than a pre-built SOA image.

  • --recommendedPatches is what keeps the image current. It pulls Oracle's latest recommended set for the release, so each rebuild picks up the newest CPU automatically.

  • The explicit --patches list on top of that is a fairly stable set of overlay patches we additionally need. It changes little from one CPU to the next, only when a new CPU requires a new overlay patch.

  • --strictPatchOrdering applies those patches in the exact order given. We need it because some of them cannot be applied together in a single opatch napply session, so ordering them strictly avoids the conflict, at the cost of a slightly longer build.

  • --additionalBuildFiles and --additionalBuildCommands inject the container scripts from Oracle's docker-images repository, so the resulting image behaves exactly like the official SOA container image (same domain creation and startup scripts), only freshly patched.

The payoff is that the image is current within minutes of a patch being published, because we are not waiting for Oracle to rebuild anything. The effort to produce it is one command line and roughly 20 to 30 minutes of waiting. The same command, with an updated patch list and a new tag, is what we run for the initial build and for every patch round afterwards.

A thank-you to the WebLogic Image Tool team

This approach did not work on the first try. Building the latest SOA Suite image with create failed outright (issue #567), and separately the tool wrongly filtered out the UMS bundle patch, treating ARU product ID 16612 as invalid even though UMS is part of SOA Suite (issue #568). Both were blockers for the whole idea of building from a clean base.

I raised both on GitHub, and the WebLogic Image Tool team turned them around remarkably fast. That responsiveness is the reason this approach went from "promising but broken" to "the way we now do it" within days rather than months. Credit where it is due.

The patches we applied

For reference, here is the patch set from the build above, with the reason each one is there. Most of them cluster around two themes that mattered for this customer: outbound email deliverability, and attachment handling over REST and the UMS email adapter. One is there purely for Oracle Database 26ai compatibility.

  • 39113739_14.1.2.0.251022: sends host information in the Message-ID header of outbound mail. Without it, some providers were treating our mails as spam.

  • 39032647_14.1.2.0.251022: the same email context as 39113739. Without it the email driver throws an IllegalArgumentException about an unknown MessageHostName property (this is just defining the value in the configuration).

  • 39076336: fixes REST URI template values not being captured in BPEL for multipart/form-data requests, so the URL parameters on multipart attachment calls can be read.

  • 39029919: lets BPEL read and extract attachment data from multipart/form-data REST requests, through getAttachmentContent.

  • 37944602: makes the UMS adapter update SCA_ATTACHMENT_REF when it persists an attachment, which is what allows the mail attachments to be purged afterwards.

  • 38391376: Oracle Database 26ai compatibility. Without it the RCU prerequisite step fails while validating the database connection.

  • 39064305: fixes the UMS adapter getting stuck on inbound messages that carry email attachments (a deadlock).

As noted above, this explicit list changes little from one CPU to the next. The currency comes from --recommendedPatches; these entries are the stable overlays we layer on top, and the list only grows when a new CPU brings a new overlay requirement.

From the build host to production

We build on a dev or test host and promote the finished image to production, rather than building on production directly. That keeps the production host clean and guarantees that the image you tested is the exact image you run. The simplest way to move an image between hosts on a separate network is to stream it over SSH:

ssh opc@soadockertest.intern.dns 'docker save xxis_soa14:260616_1' | docker load
ssh opc@soadockertest.intern.dns 'docker save container-registry.oracle.com/middleware/ohs_cpu:14.1.2.0-jdk21-ol9' | docker load
docker tag xxis_soa14:260616_1 xxis_soa14:latest

The first line pulls our freshly built SOA image across. The second brings over the Oracle HTTP Server image, which we take directly from Oracle's Container Registry CPU repository. We do not build OHS ourselves: in the past the OHS team has published its CPU images noticeably faster than the SOA team, so the registry image is current enough to use as it comes. Building it yourself is only worth the effort where the published image lags, which for us is SOA. The third line tags the new build as latest so the compose file picks it up. For a more managed setup you would push to a local or OCI container registry instead, which is what I would recommend once you are doing this regularly.

What this buys you

On a single-instance production environment, this collapses patching downtime to a container restart. You build and test the new image elsewhere, ship it, stop the old container, and start the new one. The outage is measured in minutes rather than in the length of an OPatch session, and there is no half-patched state to recover from if something goes wrong, because you simply start the previous image again.

Build effort is one command and a coffee break. Production risk is a container swap with an instant fallback. That combination is what finally makes it realistic to stay current with a monthly security cadence.

Compared with SOA Suite on the Marketplace

It is worth saying how this differs from Oracle SOA Suite on the OCI Marketplace, which is the managed way to run SOA on OCI. The Marketplace offering provisions SOA Suite for you and integrates nicely with the rest of OCI, and if you want to rent (additional) SOA Suite licenses it is actually the only viable option. But it runs SOA as a traditional WebLogic domain on a VM, and it patches the traditional way: you connect to the administration VM, apply the bundle patch or Stack Patch Bundle with OPatch, and stop and start the servers. Patches from a newer Marketplace release are not applied to an existing instance automatically, so you do it by hand on each instance, and in a disaster-recovery setup you repeat the same procedure on the standby. Rollback, if a patch goes wrong, means restoring from backup.

That is precisely the workflow we wanted to leave behind. Building the image ourselves inverts it. The patched artifact is assembled away from the running host and tested before it ever reaches production, the cutover is a container swap, and rollback is starting the previous image. It is the difference between modifying a running server in place and replacing an immutable image, and for a monthly security cadence the immutable-image model is what keeps the effort sane.

Next

The image is only half of a running environment. In Part 4 I will get into the Docker Compose file we actually run, and the handful of production gotchas behind it: running two environments on one host, the late JVM overrides we inject for SSL and email handling, the trimmed-down domain script, and connecting to back-end systems such as E-Business Suite with a properly least-privileged account instead of the all-powerful one.

This is Part 3 of a four-part series on running and upgrading Oracle SOA Suite 14c in Docker.