So far, with the manuals both on Oracle’s website as well as the ones found on blogs etc. I never really succeeded in putting up the APEX stack on docker.
However, starting to try with some more (docker) experience after procrastinating APEX in the recent 3 years, and with new energy, I found some key hints to get it done.
This docker project contains the following:
Here’s the recipe to get this done:
I wanted to use the following images:
The ords-developer image does not contain and install APEX, but there’s a solution.
A few remarks about the names of objects:
I generally try to name docker containers, networks etc. by using prefixes so I can identify them easier in, e.g., lists (docker ls ...
) or when searching for their repositories (directories).
In this context, rad
is short for Rapid Application Development, and, since there are several platforms, oracle-apex
is the second prefix.
express
and ords
are then the specifying parts of the name.
In the case of docker service names, I use only express
and ords
because those service names are referred to only within the compose file.
Start in the docker project’s direcctory.
According to Oracle, the following rights have to be applied to the directory ./express/oradata
:
-v /opt/oracle/oradata
The data volume to use for the database.
Has to be writable by the Unix "oracle" (uid: 54321) user inside the container.
If omitted the database will not be persisted over container recreation.
sudo bash -c '
mkdir -p ./express/{oradata,cfgtoollogs,scripts/startup,scripts/setup} &&
chown -R 54321:54321 ./express/{oradata,cfgtoollogs} &&
mkdir -p ./ORDS/{variables,config} &&
chown -R 54321:54321 ./ORDS/{config,variables} &&
chmod -R 777 ./ORDS/config
'
The cfgtoollogs
-diretory is for analysis in case of database creation failure (./cfgtoollogs/dbca/XE/XE.log
).
Create .env
file containing a ORACLE_PWD
variable and a password (do not use special characters, only numbers, small and caps for compatibility reasons; Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9]. Note that the same password will be used for SYS, SYSTEM and PDBADMIN accounts):
ORACLE_PWD=<password without quotes of any kind>
, e.g., 1230321abcABC
.
Script: :heavy_check_mark::heavy_check_mark:
#!/bin/bash
# Prompt user for ORACLE_PWD
read -p "Enter a value for ORACLE_PWD: " ORACLE_PWD
# Write the variable to .env file
echo "ORACLE_PWD=$ORACLE_PWD" > ./.env
echo "Password has been written to ./.env"
Download and extract the latest APEX files to the project directory; the APEX ZIP file contains the apex directory as root, so no extra dir has to be created.
If you have unzip: :heavy_check_mark::heavy_check_mark:
curl -o apex.zip https://download.oracle.com/otn_software/apex/apex-latest.zip && \
unzip -o apex.zip
If you have 7z (e.g., Synology NAS): :heavy_check_mark::heavy_check_mark:
curl -o apex.zip https://download.oracle.com/otn_software/apex/apex-latest.zip && \
7z x apex.zip
The files should now reside in ./apex
.
for img in express ords; do
docker pull "container-registry.oracle.com/database/$img:latest"
done
echo "container-registry.oracle.com/database/"{express,ords}":latest" \
| xargs -n1 docker pull
Run the following command to :heavy_check_mark::heavy_check_mark:
rad-oracle-apex-temp
rad-oracle-apex-express-temp
./express/oradata
)docker network create rad-oracle-apex-temp & \
docker run \
-d \
--name rad-oracle-apex-express-temp \
--network rad-oracle-apex-temp \
--hostname express \
--env-file ./.env \
-p 1521:1521 \
-v "$(pwd)/express/oradata/:/opt/oracle/oradata" \
-v "$(pwd)/express/cfgtoollogs/:/opt/oracle/cfgtoollogs" \
-v "$(pwd)/apex/:/opt/oracle/oradata/apex" \
container-registry.oracle.com/database/express:latest && \
docker logs -f rad-oracle-apex-express-temp
[!NOTE]
- Note that
-e ORACLE_PWD=${ORACLE_PWD}
as in the original documentation has been removed from the script above because the password is defined in the .env file- running the container for the first time (initialization of persistent data) takes a long time - on my Synology DS918+, it took ~2.5hrs, on a laptop, however, it takes, e.g., under 10 minutes
[!IMPORTANT] If the first time fails, a second run with the code above might solve it.
Keep the container running for the next steps of the installation (until you start the containers with docker-compose).
Already done in the preparation steps above.
docker exec -it rad-oracle-apex-express-temp bash
cd /opt/oracle/oradata/apex
sqlplus /nolog
(note that unlike described in the documentation, steps 4 and 6, instead of sql
, sqlplus
is used)
CONNECT SYS@<express hostname>:1521/XEPDB1 as SYSDBA
.env
-file)CONNECT SYS/<ORACLE_PWD>@<express hostname>:1521/XEPDB1 as SYSDBA
cd /opt/oracle/oradata/apex && sqlplus sys/${ORACLE_PWD}@<express hostname>:1521/XEPDB1 AS SYSDBA
e.g.,
cd /opt/oracle/oradata/apex && sqlplus sys/${ORACLE_PWD}@express:1521/XEPDB1 AS SYSDBA
(note that ${ORACLE_PWD}
does not have to be replaced here since taken from the environment variable in this case; also, this will be used for the CONN_STRING file below, but there, ORACLE_PWD needs to be explicit)
@apexins.sql SYSAUX SYSAUX TEMP /i/
After successful installation, leave SQL open for the next step@apxchpwd.sql
to create the workspace admin account.
ALTER USER APEX_PUBLIC_USER ACCOUNT UNLOCK;
ALTER USER APEX_PUBLIC_USER IDENTIFIED BY <new_password>;
create profile apex_public limit
password_life_time unlimited;
alter user apex_public_user
profile apex_public;
- `quit` the SQL prompt
- `exit` the container's bash
[!NOTE] Things have changed since release of ORDS v25. A container can be started in 2 ways:
- with an interactive CLI can be started in order to generate the configuration files in
./ORDS/config
and establish the connection between ORDS and Express:docker run \ -it \ --rm \ --network rad-oracle-apex-temp \ --name rad-oracle-apex-ords-temp \ -v ./ORDS/config:/etc/ords/config \ container-registry.oracle.com/database/ords:latest \ install
- automated setup (no interaction) - works for this tutorial:
docker run \ -i \ --rm \ --network rad-oracle-apex-temp \ --name rad-oracle-apex-ords-temp \ -v ./ORDS/config:/etc/ords/config \ -v ./apex/:/opt/oracle/apex \ container-registry.oracle.com/database/ords:latest \ install \ --admin-user SYS \ --db-hostname express \ --db-port 1521 \ --db-servicename XEPDB1 \ --feature-sdw true \ --password-stdin < <(grep '^ORACLE_PWD=' .env | cut -d= -f2-)
Double-check if the network name is correct (must be same as for the Express temporary container).
docker rm -f rad-oracle-apex-{ords-temp,express-temp}
services:
express: # XE database
image: container-registry.oracle.com/database/express:latest # 21.3.0-xe
container_name: rad-oracle-apex-express
# hostname: oracledev
restart: unless-stopped
environment:
- ORACLE_PWD=${ORACLE_PWD} # make sure the declaration is in the .env file as ORACLE_PWD=<your password, non complex, min. 8 chars small, cap, & numbers>
networks:
- apex
#ports:
# - 1521:1521
# - 5500:5500
# depends_on:
# - oracle-ords
volumes:
- ./express/oradata:/opt/oracle/oradata
- ./express/scripts/setup:/opt/oracle/scripts/setup
- ./express/scripts/startup:/opt/oracle/scripts/startup
- ./apex:/opt/oracle/apex
healthcheck:
#test command below is with grep because in my case, the output of checkDBstatus.sh is always "The Oracle base remains unchanged with value /opt/oracle" which seems to indicate the DB is fine.
#test: /opt/oracle/checkDBStatus.sh | grep -q 'remains unchanged'
test: [ "CMD", "/opt/oracle/checkDBStatus.sh"]
interval: 30s
timeout: 30s
retries: 100
start_period: 600s
ords:
#image: container-registry.oracle.com/database/ords-developer:latest
image: container-registry.oracle.com/database/ords:latest
container_name: rad-oracle-apex-ords
restart: unless-stopped
#depends_on:
# express:
# condition: service_healthy
volumes:
- ./ORDS/variables:/opt/oracle/variables
- ./ORDS/config:/etc/ords/config
- ./apex/:/opt/oracle/apex
networks:
- apex
ports:
#- 8181:8181 this is for the developer image
- 8080:8080
networks:
apex:
name: rad-oracle-apex
In case you want to debug the healthcheck, use docker inspect --format "" rad-oracle-apex-express | jq
:
Once the express-container has started up, the exit code changes from 3 over 2 to 0 (0=healthy).
http://<docker-host>
.internal
ADMIN
Welcome_1
[!WARNING] If you changed the password during log-in check from running the temporary ORDS-Developer container, use the updated password!
http://<docker-host>
.admin
Welcome_1
toWell, that’s a whole different story: The workspace/database schema needs to be enabled for SDW as follows:
docker exec -it oracle-apex-express sqlplus sys/<ORACLE_PWD>@//localhost:1521/XEPDB1 as sysdba
docker exec -it oracle-apex-express sh
and then enter sqlplus sys/<ORACLE_PWD>@//localhost:1521/XEPDB1 as sysdba
at the promptBEGIN
ords_admin.enable_schema(
p_enabled => TRUE,
p_schema => 'schema-name',
p_url_mapping_type => 'BASE_PATH',
p_url_mapping_pattern => 'schema-alias',
p_auto_rest_auth => NULL
);
commit;
END;
/
[!IMPORTANT]
- The value of
p_schema
(schema-name
) has to be all upper case!- The value of
p_url_mapping_pattern
(schema-alias
) has to be all lower case!- The
/
at the end of the statement is important in order to execute the statement.1
E.g.,
BEGIN
ords_admin.enable_schema(
p_enabled => TRUE,
p_schema => 'WORKSPACE1',
p_url_mapping_type => 'BASE_PATH',
p_url_mapping_pattern => 'workspace1',
p_auto_rest_auth => NULL
);
commit;
END;
/
p_schema
) has been enabled with select username from all_users order by username
alter user <user> identified by <password>;
(replace <user
) - every workspace, in the database, is basically a user, hence this stephttp(s)://<domain name>/ords/sql-developer
and log in with the credentials used above[!WARNING] There seems to be a bug in ORDS which prevents objects from loading in SDW’s Data Modeler and SQL Navigator. The DB user (equals workspace name) therefore needs to be granted resource permissions as follows:
grant <privilege> to <user>
This solution might work, with me, it didn’t. However, the ORDS update from Nov. 8, 2024, solved the issue.
Put the following 2 lines into ./ORDS/config/global/settings.xml
, replacing <your apex domain, no trailing slash>
with your domain’s name:
<entry key="security.externalSessionTrustedOrigins">http://<your apex domain, no trailing slash>, https://<your apex domain, no trailing slash>:443</entry>
<entry key="security.forceHTTPS">true</entry>
The complete settings.xml might now look similar to:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Saved on Mon Oct 21 16:07:13 UTC 2024</comment>
<entry key="database.api.enabled">true</entry>
<entry key="db.invalidPoolTimeout">5s</entry>
<entry key="debug.printDebugToScreen">true</entry>
<entry key="standalone.static.path">/opt/oracle/apex/images</entry>
<entry key="security.externalSessionTrustedOrigins">http://<your apex domain, no trailing slash>, https://<your apex domain, no trailing slash>:443</entry>
<entry key="security.forceHTTPS">true</entry>
</properties>
select username from dba_users;
APEX_
and the old version ID, e.g. APEX_240100
) as opposed to new schma (same user name with a higher version ID)drop user <user name> cascade;
, e.g. drop user APEX_240100 cascade;
ORA-28014: cannot drop administrative user or role
), enter alter session set "_oracle_script"=TRUE;
and repeat the previous commandORDS has been released in a v25. In order to configure the ORDS images (starting with v25), run a container and start the bash:
docker run -it --name ords_new -v ./ORDS/config:/etc/ords/config container-registry.oracle.com/database/ords:latest <command>
E.g.,
docker run -it --name ords_new -v ./ORDS/config:/etc/ords/config container-registry.oracle.com/database/ords:latest install
… and a few more.
See also https://docs.oracle.com/en/database/oracle/oracle-database/21/sqpug/slash.html ↩