I have a Docker Compose group consisting of a web server and an Oracle database. I use this for development only, not in production. The web server depends_on Oracle and so waits for Oracle before it starts up.
version: '3.9'
services:
frontend:
image: "${FRONTEND_IMAGE_TAG}"
env_file:
- .env
volumes:
- .:/var/www/
ports:
- ${httpsport}
restart: always
depends_on:
oracle:
condition: service_healthy
oracle:
image: container-registry.oracle.com/database/enterprise:${ORACLE_VERSION}
env_file:
- .env
ports:
- ${ORACLE_LISTEN_PORT}:1521
- ${ORACLE_TCPS_PORT}:2484
- ${ORACLE_EM_PORT}:5500
volumes:
- ${ORACLE_ORADATA}:/opt/oracle/oradata
- ${ORACLE_TRANSFER}:/opt/oracle/transfer
It works very well as long as I only run a single instance of my group. But often during development, I'd like to run multiple development groups e.g.
cd /web/dev
docker compose up -d
cd /web/test
docker compose up -d
The problem here is that it will attempt to run a 2nd Oracle database, which I absolutely do not want to happen, as I'm using a volume to persist data (plus it seems like a big unnecessary load on the machine). I only want to run the Oracle Docker container once and share it among any 2nd and subsequent attempts to run my Compose group.
Some approaches I'm considering:
use Docker Network to split out Oracle into its own service. Then I'd have to figure out a way to check if the Oracle service was up and running, and start it when it's not etc. Seems unclear how this would work
use Docker Compose extends to split out Oracle. I think this will have the same problems as previous approach
maybe write some shell script to do the checks and start Oracle service. I don't like doing this though, it feels like Docker should have a in-built solution
There is a Github issue with many people requesting this feature from Docker. Until that gets updated I'd love to hear some workarounds.
In the end I wrote a shell script to manage this. I split my Docker Compose file into 2 files, one for Oracle running on its own network, and one for the front end. The shell script checks that Oracle is up and healthy before starting the front end.
oracle.yaml looks like this:
version: '3.9'
networks:
mynetwork:
services:
oracle:
image: container-registry.oracle.com/database/enterprise:${ORACLE_VERSION}
env_file:
- .env
ports:
- ${ORACLE_LISTEN_PORT}:1521
- ${ORACLE_TCPS_PORT}:2484
- ${ORACLE_EM_PORT}:5500
volumes:
- ${ORACLE_ORADATA}:/opt/oracle/oradata
- ${ORACLE_TRANSFER}:/opt/oracle/transfer
networks:
- mynetwork
and the frontend one looks like this:
version: '3.9'
services:
frontend:
image: "${FRONTEND_IMAGE_TAG}"
env_file:
- .env
volumes:
- .:/var/www/
ports:
- ${httpsport}
restart: always
Here's the shell script:
#!/bin/bash
# This script can be used to share an Oracle Docker instance with multiple Docker front end containers
# It checks if an Oracle Docker instance is running, starts it if necessary, then starts a frontend Docker instance
# This script must be run from the same directory as your docker-compose.yaml and oracle.yaml files
echo "Checking for a running Oracle Docker process..."
# Check if there is already a healthy Oracle Docker process running
docker_ps_output=$(docker ps --filter "name=oracle" --filter "health=healthy" | sed '1d')
if [[ -n $docker_ps_output ]]; then
echo "Oracle is running. Starting frontend Docker container."
else
echo "No healthy Oracle Docker process found. Starting Oracle Docker container now."
# Start the Oracle Docker process
docker compose -f oracle.yaml up -d
# Loop until a healthy Oracle Docker process is found
while true; do
docker_ps_output=$(docker ps --filter "name=oracle" --filter "health=healthy" | sed '1d')
if [[ -n $docker_ps_output ]]; then
echo "Oracle Docker process is healthy. Starting frontend Docker container."
break
else
echo "Oracle Docker process is not yet healthy. Continuing to check..."
sleep 5
fi
done
fi
# Start our frontend Docker container (ignore warnings about removing orphans)
export COMPOSE_IGNORE_ORPHANS=True
docker compose up -d
echo "frontend is starting"