The applications built on the Grails framework can be run (often referred to deployment) on either standalone or embedded Tomcat. Grails applications can be deployed in a number of ways, each of which has its pros and cons. In this blog, we have recently published a post to share with you how to deploy a web-based app on a Tomcat Docker container in which Grails based app can be employed this approach without any exception. Therefore, this post will give you another way of running your Grails app on an embedded Tomcat Docker container.
Table of Contents
Introduction
As mentioned earlier, Grails based applications can be deployed on an embedded Tomcat like the way of running the applications in development mode. In the production mode, we need to tweak options to tell Grails apps a few configurations from which they are different comparing to the development phase. An embedded Tomcat server is launched that loads the web application from the development sources, thus allowing it to pick up changes to application files. Running a Grails app in this way, you should be very familiar with the grails run-app command.
[box type=”info” ]Notes: Read more about how to deploy applications in Grails 2.5.6 at https://grails.github.io/grails2-doc/2.5.6/guide/deployment.html or in Grails 3.3.11 at https://docs.grails.org/3.3.11/guide/single.html#deployment[/box]
Going with this approach, the Grails framework allows us to specify a mode, i.e. dev or prod, when starting the application.
How to dockerise Grails app
Start Grails application from the development sources
# Grails 2/3 grails [environment] run-app
whereby the environment can be prod
, test
, dev
. Some options could be found in Grails documentation. I believe --non-interactive
is a very important option to be taken into account in Kubernetes deployment. If one of the plugins or dependencies in your Grails app has been upgraded or downgraded, Grails engine will ask us to confirm to install or uninstall this artifact. This option sounds alike unattended installation in automatic update scheduled procedure of Operating System.
You can run the app using the bootRun Gradle task in Grails 3 or above. The next command uses the Gradle Wrapper.
./gradlew bootRun
You can specify an environment supply grails.env system property.
./gradlew -Dgrails.env=prod bootRun
Please read more about the run-app command at Grails2 or Grails3.
Start Grails application from runnable WAR or JAR file
Since Grails 3, we have been supported to generate either war or jar file.
Another way to deploy in Grails 3.0 or above is to use the new support for runnable JAR or WAR files. To create runnable archives, run grails package
:
grails package
Alternatively, you could use the assemble
Gradle task.
./gradlew assemble
You can then run either the WAR file or the JAR using your Java installation:
java -Dgrails.env=prod -jar build/libs/mywar-0.1.war (or .jar)
Review Dockerfile file
Let’s take a closer insight into the following Dockerfile file to build an image to deploy BioModels on the cloud.
FROM biomodels/jummp-biomodels:1.2-dependencies LABEL maintainer="biomodels-developers@lists.sf.net" # install tools and utilities RUN apt-get update && apt-get install -y mysql-client && rm -rf /var/lib/apt # set environment options #ENV MAVEN_OPTS="-Xmx1024m" ENV JAVA_OPTS="-Xms64m -Xmx1024m -XX:MaxMetaspaceSize=128m" ENV GRAILS_OPTS="-server -Xmx2g -Xms2g -Dfile.encoding=UTF-8" #ENV ANT_OPTS="-Xmx2g -XX:MaxPermSize=1024m" # expected database port EXPOSE 3306 EXPOSE 4372 EXPOSE 8080 ARG UID ARG USERNAME ARG GID ARG GROUP RUN echo "$GROUP ($GID) - $USERNAME ($UID)" ENV HOME=/home/$USERNAME RUN mkdir -p $HOME RUN addgroup --gid "$GID" "$USERNAME" \ && adduser \ --uid "$UID" \ --disabled-password \ --gecos "" \ --ingroup "$USERNAME" \ --no-create-home \ "$USERNAME" ENV APP_HOME=/home/$USERNAME/biomodels ## SETTING UP THE APP ## RUN mkdir -p $APP_HOME RUN chown -R $USERNAME:$USERNAME $HOME # *** # Do any custom logic needed prior to adding your code here # *** # Copy in the application code. #ADD . $APP_HOME # Chown all the files to the app user. #RUN chown -R "$USERNAME":"$USERNAME" $APP_HOME # Below is equivalent to the above commands, just speeds up and reduces image size COPY --chown=$USERNAME:$USERNAME . $APP_HOME # Change to the app user. USER $USERNAME WORKDIR $APP_HOME RUN ["chmod", "+x", "grailsw"] ENTRYPOINT ["/bin/bash", "-lc", "./grailsw prod run-app --non-interactive --stacktrace"]
This Dockerfile file includes several concepts but I just explain the segments concerning this post. The rest will be discussed in future posts. The most concerning snippet are extracted below.
# Copy in the application code. # ADD . $APP_HOME # Chown all the files to the app user. # RUN chown -R "$USERNAME":"$USERNAME" $APP_HOME # Below is equivalent to the above commands, just speeds up and reduces image size COPY --chown=$USERNAME:$USERNAME . $APP_HOME # Change to the app user. USER $USERNAME WORKDIR $APP_HOME RUN ["chmod", "+x", "grailsw"] ENTRYPOINT ["/bin/bash", "-lc", "./grailsw prod run-app --non-interactive --stacktrace"]
Working with Docker, you are probably very familiar with ADD, COPY, WORKDIR or RUN
. I don’t waste your valuable time by ignoring their explanation to get clear the key point here. Traditionally, the required environment has Grails framework installed to run a Grails application from source code. From that point, we can use Grails wrapper in place of Grails installation. Therefore, we have to ensure grailsw
executable.
Adapter to Grails 3
As revised above, we have to copy WAR or JAR file instead of the development sources. Consequently, ENTRYPOINT instruction should be changed to
ENTRYPOINT ["/bin/bash", "-lc", "java -Dgrails.env=prod -jar myapp-0.1.war"]
Summary
I have represented how to dockerise a Grails app to able to run it in an embedded Tomcat running on a Docker container. All constructive feedback is always welcomed. If you are interested in this post, please consider donating us by following either of the instructions below.
References
- Deploy applications in Grails 2.x accessed on 31/05/2020
- Deploy applications in Grails 3.x or above accessed on 31/05/2020