Expected Outcome:
-
Install Docker Tooling
-
Build the Pet Store application within a Container
-
Deploy the Pet Store application to a Wildfly based Application Server
Lab Requirements: None
Average Lab Time: 30-45 minutes
The Pet Store application is a Java 7 based application that runs on top of the Wildfly (JBoss) application server. The application is built using Maven. We will walk through the steps to build the application using a Maven container then deploying our WAR file to the Wildfly container. We will be using multi-stage builds to facilitate creating a minimal container.
-
To get started, switch to the
containerize-application
folder within this repository. Then create a new fileDockerfile
. Then open the Dockerfile in your editor of choice. -
The first stage of our
Dockerfile
will be to build the application. We will use themaven:3.5-jdk-7
container from Docker Hub as our base image. The first stage of ourDockerfile
will need to copy the code into the container, install the dependencies, then build the application using Maven. -
The second stage of our
Dockerfile
will be to build our Wildfly application server. We will need to copy the WAR file we created in the first stage to the second stage. The WAR file is built to/usr/src/app/target/applicationPetstore.war
in the first stage. We will need to copy that WAR file to the/opt/jboss/wildfly/standalone/deployments/applicationPetstore.war
. We will also need to copy thestandalone.xml
file to the proper location/opt/jboss/wildfly/standalone/configuration/standalone.xml
. Wildfly will deploy that application on boot. You will also need to install the PostgreSQL driver which is already downloaded. Include the script below to install.
# install postgresql support
RUN mkdir -p $JBOSS_HOME/modules/system/layers/base/org/postgresql/main
COPY ./postgresql $JBOSS_HOME/modules/system/layers/base/org/postgresql/main
RUN /bin/sh -c '$JBOSS_HOME/bin/standalone.sh &' \
&& sleep 10 \
&& $JBOSS_HOME/bin/jboss-cli.sh --connect --command="/subsystem=datasources/jdbc-driver=postgresql:add(driver-name=postgresql,driver-module-name=org.postgresql, driver-class-name=org.postgresql.Driver)" \
&& $JBOSS_HOME/bin/jboss-cli.sh --connect --command=:shutdown \
&& rm -rf $JBOSS_HOME/standalone/configuration/standalone_xml_history/ \
&& rm -rf $JBOSS_HOME/standalone/log/*
Let’s review the Dockerfile
and walk through the result. The first stage will be based off our "tools" container, in this case that is maven. This container could be a container within your organization that houses all the tools your development team needs. We alias this first stage as the "build" stage.
FROM maven:3.5-jdk-7 AS build
Next we are going to install the dependencies. We do this ahead of time so that we can leverage the Docker build cache to increase the speed of build times. To accomplish this we copy the pom.xml and install the dependencies. We then copy our application code and build the applicaiton. This enables developers to iterate on their code without having to install dependencies each time.
# set the working directory
WORKDIR /usr/src/app
# copy just the pom.xml
COPY ./app/pom.xml /usr/src/app/pom.xml
# just install the dependencies for caching
RUN mvn dependency:go-offline
Finally, we build the application.
# copy the application code
COPY ./app /usr/src/app
# package the application
RUN mvn package -Dmaven.test.skip=true
Next, in the same Dockerfile
we create a new stage called "application." Then from the build stage, we copy the WAR file we compiled to the Wildfly deployments folder. Wildfly will deploy this WAR on boot. We then expose port 8080 for our application and port 9990 for Wildfly management. We then define the command to start the application.
# create our Wildfly based application server
FROM jboss/wildfly:11.0.0.Final AS application
# install postgresql support
RUN mkdir -p $JBOSS_HOME/modules/system/layers/base/org/postgresql/main
COPY ./postgresql $JBOSS_HOME/modules/system/layers/base/org/postgresql/main
RUN /bin/sh -c '$JBOSS_HOME/bin/standalone.sh &' \
&& sleep 10 \
&& $JBOSS_HOME/bin/jboss-cli.sh --connect --command="/subsystem=datasources/jdbc-driver=postgresql:add(driver-name=postgresql,driver-module-name=org.postgresql, driver-class-name=org.postgresql.Driver)" \
&& $JBOSS_HOME/bin/jboss-cli.sh --connect --command=:shutdown \
&& rm -rf $JBOSS_HOME/standalone/configuration/standalone_xml_history/ \
&& rm -rf $JBOSS_HOME/standalone/log/*
# copy war file from build layer to application layer
COPY --from=build /usr/src/app/target/applicationPetstore.war /opt/jboss/wildfly/standalone/deployments/applicationPetstore.war
# copy our configuration
COPY ./standalone.xml /opt/jboss/wildfly/standalone/configuration/standalone.xml
# expose the application port and the management port
EXPOSE 8080 9990
# run the application
ENTRYPOINT [ "/opt/jboss/wildfly/bin/standalone.sh" ]
CMD [ "-b", "0.0.0.0", "-bmanagement", "0.0.0.0" ]
Important
|
Before you can run this in a Cloud9 environment you will need to install docker-compose by running the following commands.
|
sudo curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose-`uname -s`-`uname -m` | sudo tee /usr/local/bin/docker-compose > /dev/null
sudo chmod +x /usr/local/bin/docker-compose
Next, we need to define how our application will run. Docker comes with a tool called Docker Compose that allows you to orchestrate mutliple containers.
-
Create a new file called
docker-compose.yml
. To start your file should look like this:
version: '3'
services:
-
Create the PostgreSQL service. The PostgreSQL service will run our database. We will use the official PostgreSQL image available from Docker Hub. Next, we will map the PostgreSQL port
5432
to the our machine port for easy access. Finally, we will define a few environment variables to configure our instance.
version: '3'
services:
postgres:
image: postgres:9.6
ports:
- 5432:5432
environment:
- 'POSTGRES_DB=petstore'
- 'POSTGRES_USER=admin'
- 'POSTGRES_PASSWORD=password'
-
Finally, we will define our Pet Store application. Docker Compose supports building containers as well, so we will use a special syntax for defining this container. In our yaml file we will create a new service called
petstore
and configure our build configuration. Next, will add adepends_on
config so that thepetstore
container boots after ourpostgres
container. Similar to ourpostgres
ports we will map port 8080 to our machine for easy access. Now we will use some environment variables to configure our database with the application.
petstore:
build: ./
depends_on:
- postgres
ports:
- 8080:8080
environment:
- 'DB_URL=jdbc:postgresql://postgres:5432/petstore?ApplicationName=applicationPetstore'
- 'DB_HOST=postgres'
- 'DB_PORT=5432'
- 'DB_NAME=petstore'
- 'DB_USER=admin'
- 'DB_PASS=password'
-
Our final, file should look as follows.
version: '3'
services:
postgres:
image: postgres:9.6
ports:
- 5432:5432
environment:
- 'POSTGRES_DB=petstore'
- 'POSTGRES_USER=admin'
- 'POSTGRES_PASSWORD=password'
petstore:
build:
context: ./
dockerfile: Dockerfile.result
depends_on:
- postgres
ports:
- 8080:8080
environment:
- 'DB_URL=jdbc:postgresql://postgres:5432/petstore?ApplicationName=applicationPetstore'
- 'DB_HOST=postgres'
- 'DB_PORT=5432'
- 'DB_NAME=petstore'
- 'DB_USER=admin'
- 'DB_PASS=password'
To run the application we will execute the following Docker Compose commands.
-
Run the database container in the background (
-d
or daemon flag). We don’t need the database logs to clog our application logs.
docker-compose up -d postgres
-
Build out petstore service.
docker-compose build petstore
-
Run the application container in the foreground and live stream the logs to stdout. If you hit an error hit
Ctrl+C
, make updates to the Dockerfile and re-build the container using step 2.
docker-compose up petstore
-
Visit http://localhost:8080/applicationPetstore to view the application.