Today, I was working with an application that uses Oracle as the database. We decided dockerize the application to make it easy for fellow developers to work with the beast. We found a working Oracle docker image by sath89. Oracle 12c Docker image is close to 5.7GB on disk so we are not talking about lightweight containers here :). Once image was dowloaded, running image was as easy as running the following command.
$ docker run -d -p 8080:8080 -p 1521:1521 sath89/oracle-12c
This will start the Oracle database in a container. On my machine, it takes close to 7-8 minutes for the database to become up and running. If you want to keep running container in the background then you just have to run container once and then use it.
We wanted to bootstrap the entire application with a single command using Docker Compose. Also, in the dev mode, we wanted to create database schema using Hibernate’s schema generation utilities. The problem is that Docker Compose does not wait for the Oracle container to become ready before starting application container. For example, let’s suppose we have two services — db
and web
. The web
service depends on the db
service as shown in the docker-compose.yml
shown below.
version: '3' services: db: image: sath89/oracle-12c web: image: com.example/myapp environment: SPRING_JPA_HIBERNATE_DDL-AUTO: create SPRING_PROFILES_ACTIVE: docker-oracle depends_on: - db
Now, when you start the application using docker-compose up
then Docker compose does not ensure that db
service is ready before web
service is started. This means your application will fail to start. The depends_on
only means that db
service should be started first but compose does not ensure db
service is full ready for connections. This cause issues in scenario where we need to have strict control.
wait-it-for to the rescue
wait-for-it
is a simple bash utility to test and wait for the availability of TCP host and port. The need for wait-for-it
arises when you want to make sure a container is up and running before another container. It took me time to figure out how to use it with Oracle so I am writing it down for fellow developers who might also need to use wait-for-it
in future.
To use it, first copy the wait-for-it.sh in your project directory.
Next, you will update docker-compose.yml
as shown below.
version: '3' services: db: image: sath89/oracle-12c web: image: com.example/myapp environment: SPRING_JPA_HIBERNATE_DDL-AUTO: create SPRING_PROFILES_ACTIVE: docker-oracle entrypoint: ["./wait-for-it.sh","db:8080","--timeout=0","--strict", "--", "java", "-jar","app.jar" ] depends_on: - db
In the docker-compose.yml
we added entrypoint
instruction. The entrypoint
instruction let you identity which executable should run when container is started from image.
As you can see in the entrypoint
value, we are using wait-for-it
to wait for indefinite time for port 8080 in the db container to become accessible. The Oracle docker image exposes management web console at port 8080. Once db container is available we start the application. You should read wait-for-it documentation to understand its document in case you are unclear about meaning of the options.
You will see logs like the following in compose shell.
web_1 | wait-for-it.sh: waiting for db:8080 without a timeout db_1 | Copying database files db_1 | 1% complete db_1 | 3% complete db_1 | 11% complete db_1 | 18% complete db_1 | 37% complete db_1 | Creating and starting Oracle instance db_1 | 40% complete db_1 | 45% complete db_1 | 50% complete db_1 | 55% complete db_1 | 56% complete db_1 | 60% complete db_1 | 62% complete db_1 | Completing Database Creation db_1 | 66% complete db_1 | 70% complete db_1 | 73% complete db_1 | 85% complete db_1 | 96% complete db_1 | 100% complete db_1 | Look at the log file "/u01/app/oracle/cfgtoollogs/dbca/xe/xe.log" for further details. db_1 | Configuring Apex console db_1 | Database initialized. Please visit http://#containeer:8080/em http://#containeer:8080/apex for extra configuration if needed db_1 | Starting web management console db_1 | db_1 | PL/SQL procedure successfully completed. db_1 | db_1 | Starting import from '/docker-entrypoint-initdb.d': db_1 | found file /docker-entrypoint-initdb.d//docker-entrypoint-initdb.d/* db_1 | [IMPORT] /entrypoint.sh: ignoring /docker-entrypoint-initdb.d/* db_1 | db_1 | Import finished db_1 | db_1 | Database ready to use. Enjoy! 😉 web_1 | wait-for-it.sh: db:8080 is available after 432 seconds
That’s it for this blog. I hope this will be useful to you.
Hi Thanks for the nice article. I just want to ask how I can get the app.jar