Create a Dockerized Customer Managed ORDS for ADB on OCI

Matt MulvaneyMatt Mulvaney
7 min read

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

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

  1. Get a compute instance by following this guide

  2. Install Docker-CE by following this guide

  3. Download your Autonomous DB Wallet (sorry I don’t have a guide)

  4. 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.

  5. 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;
    
  6. 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

  7. open ports 8623, 9643 & 9622 by following this guide

  8. 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
    
  9. 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
    
  10. Move your wallet from compute to docker

    docker exec customords mkdir -p /home/oracle/wallet
    docker cp Wallet.zip customords:/home/oracle/wallet
    
  11. 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
    
  12. Now enter bash

     docker exec -it customords /bin/bash
    
  13. Make some folders

    mkdir /home/oracle/logs
    mkdir /var/log/ords
    
  14. 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
    
  15. Install packages

    microdnf install -y sudo nano java-17-openjdk ords openssl
    
  16. Now perform steps 4-12 (inclusive) from the Configure ORDS steps of this blog to prepare your SSL keys

  17. 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
    
  18. 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
    
  19. 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
    
  20. 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 Designer

    • If you get this too big you’ll get: ORA-12530, TNS:listener: rate limit reached

  21. 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
    
  22. 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
    
  23. 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
    
  24. 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
    
  25. Exit the docker bash

    exit
    
  26. 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.

0
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.