Introduction
In the previous post, we showed you how to run an Oracle XE instance in a docker container and then run ORDS in another container to use it to connect to APEX.
We first downloaded the Images we needed, then we had to write some codes in the console/Terminal to configure the networks and volumes and for each time we wanted to spin up a DB container or an ORDS container, we had to write a docker-console command and pass all the parameters.
There is an easier way that we can use to run all the containers with the configurations in just one command, and that tool is docker-compose. In this post, we will show you how to use docker-compose and how to run APEX in docker just as we did last time.
Docker Compose file
In docker-compose, we use a YAML file to define the services we want to run. By services we mean containers, so each container is represented as a service in docker-compose. Under each service, we can list all the configurations that are related to that service. One advantage of using docker-compose is to make your commands structured, easy to read, and maintain or change. For example, see how the command for running a docker container looks like we you want to write it in the terminal:
docker run -d --name db-container\
> -p 1521:1521\
> -e ORACLE_PWD=1230123\
> -v db-demo-volume:/opt/oracle/oradata\
> --network=demo-network\
> --hostname database
> oracle-xe-21.3
It is not easy to read right π
Now let's see how docker-compose will help us make this more efficient.
For using docker-compose we just need to create a YAML file wherever we want, so let's create a folder on the desktop and name it demo. In that folder create a file with the name docker-compose.yml
Oracle XE Service
We will first define the Oracle XE service with its related configurations in our compose file:
version: '3.9'
services:
devdb:
container_name: devdb
image: container-registry.oracle.com/database/express:latest
ports:
- 1521:1521
environment:
- ORACLE_PWD=1230123
volumes:
- dev-vol:/opt/oracle/oradata
hostname: oracledev
Keep in mind that the first line of every docker-compose file is for specifying the Compose file format version. In our example, we are using version 3.9.
The third line is the services we want this file to run, by services we mean containers. Under the services, we will list the containers we want to run.
devdb is the name for our first service (container), the name can be anything but you better give meaningful names. Under this service, we will list the configurations related to it.
container_name This is equivalent to the --name tag when using the terminal.
image is the image to be used for spinning up the container
ports to map the ports between the container and the host. The first port is the host port and the second specifies the container port. This is equivalent to -p.
environment under this we pass the environment variable to the container, in our example, we are passing the oracle_pwd. This is equivalent to -e (You can create an env file and save all environment variables in it).
volumes to specify the paths to mount on the host and the container. The first path is the host and the second is the containers' path. This is equivalent to -v (At the end of the file we will define our volumes).
hostname giving a name to the DB host machine. This is equivalent to --hostname.
As you see this looks much cleaner than before π
ORDS Service
We will continue by defining the next service in the document. But before we do that, we need the connection string to tell ORDS how to connect to the database. So, we will create a new folder where the compose file is located, name the folder variables and inside the folder create the text file conn_string and write the following in it.
CONN_STRING=sys/1230123@oracledev:1521/XEPDB1
Now back to the compose file, under the services we continue by adding the following:
ords:
container_name: ords
restart: always
depends_on:
- devdb
volumes:
- ./variables:/opt/oracle/variables
ports:
- 8181:8181
image: container-registry.oracle.com/database/ords:latest
As you see, it is almost the same as the first service, we have changed the name of the service and container, ports, volume, and the image to use. We just added three lines 16, 17, and 18.
restart this will restart the service every time it fails. The database will take some time to be ready to use, in this time ORDS will try to connect to the database and it will fail, so we are retrying to connect every time until the connection is established.
depends_on we don't want ORDS service to start before the database service starts. So we are telling the compose that this service has to start after the devdb service.
Network and Volumes
Now we will define the Networks and Volumes that we want to use. As we saw in line 12 of the compose file, we are mounting dev-vol volume to the path in the database container where the data are saved. In this way, we are saving the data on the host machine to prevent losing it when the container gets deleted. We will define this volume and give it a meaningful name, so we don't delete it later by mistake. Then we will define the network where the services will live, this is to make communication between the services possible. Please note, if you use docker-compose, it will take care of the network configuration but it will give a random name, what we are doing is just giving a name to the network.
In the same compose file add the following:
volumes:
dev-vol:
name: db-vol
external: false
networks:
default:
name: demo-network
Final Compose file
In the end, you should have a docker-compose file that looks like this:
version: '3.9'
services:
devdb:
container_name: devdb
image: container-registry.oracle.com/database/express:latest
ports:
- 1521:1521
environment:
- ORACLE_PWD=1230123
volumes:
- dev-vol:/opt/oracle/oradata
hostname: oracledev
ords:
container_name: ords
restart: always
depends_on:
- devdb
volumes:
- ./variables:/opt/oracle/variables
ports:
- 8282:8181
image: container-registry.oracle.com/database/ords:latest
volumes:
dev-vol:
name: db-vol
external: false
networks:
default:
name: demo-network
Keep in mind, that the indentation in the docker-compose file is important.
Docker Compose commands
Up
After we have done with the compose file, it is time to run it. Open a command line in the same folder where the compose file is located and write the following:
docker-compose up
This command will take care of running the containers, mapping the ports, and configuring the volumes and networks. You will use this command every time you want to run the containers.
Down
This command will stop the running containers, removing them and remove the networks associated, but it will keep the volumes:
docker-compose down
Stop
This command will stop the running containers without removing anything:
docker-compose stop
P.s: If you don't have the images locally, you have to log in to the oracle container registry before running the Up command. Execute the following command in the Terminal and give your credentials
docker login container-registry.oracle.com
So that's it for docker-compose, we hope you found this useful