Create a Dockerized Customer Managed ORDS for ADB on OCI
Q. Why do we need a Customer Managed ORDS when ADB has an Oracle Managed ORDS that works perfectly fine?
A. Because we may want, at some point, to change a single ORDS setting. Its not possible do change the default ORDS settings (proof) for Oracle Managed ORDS. Therefore just one ORDS setting change requires you create a custom ORDS. OK it is possible to change a limited number of next-to-usless settings in case someone points this out
Q. Why do I need change an ORDS setting?
A. Many reasons
You have a SaaS/Mulit-tennant Application and you need an ORDS Pre-Hook for REST
You want a quick way of identifying the tenant by URL
You want to take advantage of the QoL ORDS Settings
You want to use SAML Authentication
You want to see ORDS logs
See? Many reasons!
Before we steps
If you are following the Load Balancer Steps, I advise you create this compute instance in the VCN of the other Computes - i.e not the Load Balancers (vcn-lb) VCN, but the one joined by the Local Peering Gateway.
Steps
Get a compute instance by following this guide
Install Docker-CE by following this guide
Download your Autonomous DB Wallet (sorry I don’t have a guide)
You must have static files set to a CDN URL. This is because custom ORDS requires it. You can instead maintain a local copy if you wish, however the next few steps will guide you through this process.
Find out which version of APEX you are on - not sure? fire up an APEX page and type this in the console
apex.env.APEX_VERSION
Next, find out which CDN URL you should be using for your version of APEX by using this link and search for CDN URL and find the table.
Finally run a version of this to set the image location - changing the URL below to match the one in the table
begin apex_instance_admin.set_parameter( p_parameter => 'IMAGE_PREFIX', p_value => 'https://static.oracle.com/cdn/apex/24.1.1/' ); commit; end;
You need to transfer your wallet to your compute (and in the next step to your docker). For this I use WinSCP, which will reuse my putty sessions
open ports 8623, 9643 & 9622 by following this guide
Get the slim image of OL8 (I’m going for the more secure FIPS-compliant version, which includes cryptographic packages needed for FIPS mode). Ive tried a few flavours and none appear to give more benefits over the other - so I’m going for slimmer size.
docker pull oraclelinux:8-slim-fips
Now start the a container. The following commands are a bit of a mouthful, but I wanted to create an entrypoint.sh to run code on startup - i.e ORDS. This is because systemd is typically not used in docker images, including all OL8 flavors, so this is a decent workaround I believe 🤞
docker run -d -it --name customords -p 8623:8080 -p 9643:8443 -p 9622:22 container-registry.oracle.com/os/oraclelinux:8-slim-fips docker exec customords mkdir -p /home/oracle/scripts/ docker exec customords touch /home/oracle/scripts/entrypoint.sh docker exec customords bash -c 'echo -e "#!/bin/bash\nexec /bin/bash" > /home/oracle/scripts/entrypoint.sh' docker exec customords chmod +x /home/oracle/scripts/entrypoint.sh docker commit --change='ENTRYPOINT ["/home/oracle/scripts/entrypoint.sh"]' customords customords-image docker stop customords docker rm customords docker run -d -it --name customords -p 8623:8080 -p 9643:8443 -p 9622:22 customords-image
Move your wallet from compute to docker
docker exec customords mkdir -p /home/oracle/wallet docker cp Wallet.zip customords:/home/oracle/wallet
Then move your certificates to container (changing the domain name in line one).
export MYDOMAIN='example.com' docker exec customords mkdir -p /root/keystore docker cp key.pem customords:/root/keystore/$MYDOMAIN-key.pem docker cp cert.pem customords:/root/keystore/$MYDOMAIN-cert.pem
Now enter bash
docker exec -it customords /bin/bash
Make some folders
mkdir /home/oracle/logs mkdir /var/log/ords
Add the ORDS repo
cat <<EOF > /etc/yum.repos.d/oracle-software.repo [oracle-software] name=Oracle Linux 8 Software Repository baseurl=https://yum.oracle.com/repo/OracleLinux/OL8/oracle/software/x86_64 gpgcheck=1 enabled=1 EOF
Install packages
microdnf install -y sudo nano java-17-openjdk ords openssl
Now perform steps 4-12 (inclusive) from the Configure ORDS steps of this blog to prepare your SSL keys
Run the following changing the Wallet.zup and the first password on the 4th bottom line. Note: the 3rd & 2nd bottom are the ORDS_PUBLIC_USER2 & ORDS_PLSQL_GATEWAY2 passwords which you can also change if you like
su - <<'EOSU' ords --config /etc/ords/config install adb \ --wallet /home/oracle/wallet/Wallet.zip \ --admin-user ADMIN \ --db-user ORDS_PUBLIC_USER2 \ --feature-db-api true \ --feature-rest-enabled-sql true \ --feature-sdw true \ --gateway-user ORDS_PLSQL_GATEWAY2 \ --password-stdin type-your-adb-admin-password-here EllandRd!LUFC2024 EllandRd!LUFC2024 EOSU
Enable Response Compression (thanks to Jon)
mkdir /etc/ords/config/global/standalone mkdir /etc/ords/config/global/standalone/etc cat <<EOF > /etc/ords/config/global/standalone/etc/jetty-compression.xml <?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> <Configure id="Server" class="org.eclipse.jetty.server.Server"> <Call name="insertHandler"> <Arg> <New id="GZipHanlder" class="org.eclipse.jetty.server.handler.gzip.GzipHandler"> <Set name="IncludedMimeTypes"> <Array type="java.lang.String"> <Item>text/html</Item> <Item>text/xml</Item> <Item>text/css</Item> <Item>text/javascript</Item> <Item>application/javascript</Item> <Item>application/json</Item> </Array> </Set> <Set name="minGzipSize">128</Set> </New> </Arg> </Call> </Configure> EOF
Perform some QoL changes (thanks to Jon)
su - <<'EOSU' export ORDS_CONFIG=/etc/ords/config ords --config $ORDS_CONFIG config set standalone.access.log /var/log/ords ords --config $ORDS_CONFIG config set jdbc.InitialLimit 15 ords --config $ORDS_CONFIG config set jdbc.MinLimit 15 ords --config $ORDS_CONFIG config set jdbc.MaxLimit 25 ords --config $ORDS_CONFIG config set cache.metadata.enabled true ords --config $ORDS_CONFIG config set cache.metadata.timeout 1m EOSU
If you are on Always Free ADB then you must run the following. Only do this on Always Free ADB.
su - <<'EOSU' export ORDS_CONFIG=/etc/ords/config ords --config $ORDS_CONFIG config set jdbc.InitialLimit 6 ords --config $ORDS_CONFIG config set jdbc.MinLimit 9 ords --config $ORDS_CONFIG config set jdbc.MaxLimit 6 EOSU
You may have to play with these values:
I suggest values of 6, 9, 6 which I tried to set as high as possible without any side affects. 3, 6, 3 also worked for me. Timo suggests values of 1, 3, 0, which have definitely helped some people. As I say, you have to play with the values and see what works for you for Always Free.
If you get these parameters very small you’ll get:
Maximum retry attempts to refresh connection pool named: default reached
If you get these parameters a titchy bit small you’ll get:
error
in APEX Page DesignerIf you get this too big you’ll get:
ORA-12530, TNS:listener: rate limit reached
Make it SSL - just double check before you run this that you have der files & change the example.com
su - <<'EOSU' export MYDOMAIN='example.com' ords --config /etc/ords/config config set standalone.https.host $MYDOMAIN ords --config /etc/ords/config config set standalone.https.port 8443 ords --config /etc/ords/config config set standalone.https.cert ~/keystore/$MYDOMAIN.der ords --config /etc/ords/config config set standalone.https.cert.key ~/keystore/$MYDOMAIN-key.der EOSU
Create Start/Stop ORDS Scripts
su - <<EOF echo 'export ORDS_HOME=/usr/local/bin/ords' > /home/oracle/scripts/start_ords.sh echo 'export _JAVA_OPTIONS="-Xms1126M -Xmx1126M"' >> /home/oracle/scripts/start_ords.sh echo 'LOGFILE=/home/oracle/logs/ords-$(date +"%Y%m%d").log' >> /home/oracle/scripts/start_ords.sh echo 'nohup \${ORDS_HOME} --config /etc/ords/config serve >> \$LOGFILE 2>&1 & echo "View log file with : tail -f \$LOGFILE"' >> /home/oracle/scripts/start_ords.sh EOF su - <<EOF echo 'kill \`ps -ef | grep [o]rds.war | awk "{print \$2}"\`' > /home/oracle/scripts/stop_ords.sh sed -i 's/"/'\''/g' /home/oracle/scripts/stop_ords.sh EOF su - <<EOF chmod +x /home/oracle/scripts/start_ords.sh chmod +x /home/oracle/scripts/stop_ords.sh EOF
If you need, you can start and stop ORDS manually like this (commented out to stop anyone accidentally running them)
# sudo sh /home/oracle/scripts/start_ords.sh # sudo sh /home/oracle/scripts/stop_ords.sh
Put the startup in the entry point
cat <<EOF > /home/oracle/scripts/entrypoint.sh #!/bin/bash sudo sh /home/oracle/scripts/start_ords.sh exec /bin/bash EOF
Exit the docker bash
exit
Restart the container - this will start ORDS on reboot
docker restart customords
ENJOY
Whats next? if you try to access it through IP, you’ll probably get a HTTP ERROR 400 Invalid SNI
error from Jetty/ORDS (see picture below - credits GitHub). However you are now all set up for the following links
If you were linked to this blog by another of my blogs, return to that blog now
If you want to access this ORDS via a Vanity URL click here
If you want to access this ORDS via a Load Balancer click here
If you seriously want to access it via HTTP/IP, then remove the SSL certificates settings from ORDS and revert it back to HTTP on port 8080.. after restart of ORDS this will resolve the SNI error
ENJOY!
What’s the picture? Its Knaresborough Castle from the side (its on top of a hill). Here is someone flying a drone around it.
Subscribe to my newsletter
Read articles from Matt Mulvaney directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Matt Mulvaney
Matt Mulvaney
With around 20 years on the job, Matt is one of the most experienced software developers at Pretius. He likes meeting new people, traveling to conferences, and working on different projects. He’s also a big sports fan (regularly watches Leeds United, Formula 1, and boxing), and not just as a spectator – he often starts his days on a mountain bike, to tune his mind.