4-Steps to Docker-Based Build Environments

Tyler Jewell
Codenvy Blog
Published in
5 min readDec 4, 2014

--

dockermain2

Any development language. Any environment. We’re not just saying that, we mean it. Codenvy does not impose restrictions on the build and runtime environment.

You can write any recipe you want and Codenvy will do the hard work of cooking it for you.

At Codenvy we love Ant and Maven and have them as our default build environments. Yet, there are so many other great build tools out there like Grails, Gradle, Leiningen, and others. Using those tools with Codenvy is a piece of cake — Here’s how!

Creating a Grails Builder

Every Docker recipe starts by inheriting a base image. We recommend using Codenvy base images because they are lightweight and optimized for performance. Plus, there’s Shell access to your running container in every image (we use Shellinabox to do this). You can get a list of all the Codenvy images on DockerHub (of course you can select any other image from DockerHub as well — they’ll all work with Codenvy).

For this environment we’ll use an image with JDK7 and Tomcat 7 inside. Why do we need Tomcat if Grails run-app command will pull Tomcat anyway? We’ll do it both ways — with a native Grails plugin and simply by packaging our app (which is the sample Petclinic app) into a WAR and deploying to own Tomcat that we control.

To inherit from a base image your Dockerfile recipe needs to open with the “FROM” command. In our case we are using:

FROM codenvy/jdk7_tomcat7

Once you have that the Java and Tomcat foundation is in place and you can begin tailoring your image to your specific needs.

Install the Packages

Everything is simple with a recipe: you download things; you unpack things; you tell your system where to find things.

RUN wget -q -P /home/user http://dist.springframework.org.s3.amazonaws.com/release/GRAILS/grails-2.4.4.zip
RUN cd /home/user && unzip grails-2.4.4.zip && rm -rf grails-2.4.4.zip


# set env variables and write them to .bashrc


ENV GRAILS_HOME /home/user/grails-2.4.4
RUN echo “export GRAILS_HOME=$GRAILS_HOME” >> /home/user/.bashrc
ENV PATH $GRAILS_HOME/bin:$PATH
RUN echo “export PATH=$PATH” >> /home/user/.bashrc

You’re probably wondering why we duplicated every ENV command with an echo to .bashrc? Unfortunately, there’s a limitation with Shellinabox that makes it impossible to use environment variables directly when you SSH into a container. If you don’t plan to do anything in the terminal, echoing to .bashrc can be dropped.

Optimizing your image should always be top-of-mind as it will keep your image lean and fast (our docs include best practices for optimization and an explanation of how to use a pre-built image for ultimate speed). To clean up this image we have removed the downloaded archive and anything else that would add size — the smaller your image, the faster your boot time.

Inject the Source Files

Now that we have a Grails environment, we need to inject project source files into the image. Codenvy makes your life easy by automatically pushing the latest source to your container as long as your container is set up to accept it. Let’s get that ready now…

Normally, we use the $app$ variable to unzip project sources into a selected directory with one command. However, ADD commands are performed by ROOT, while Grails will attempt to create files and folders as a user. There’s an easy way to bypass this limitation — add sources as zip and then unzip the archive, so instead of ADD $app$ /home/user/app/ we’ll have ADD $app$ /home/user/$app$ which will copy the archive. Once it’s copied, we can unzip it:

RUN mkdir /home/user/app
ADD $app$ /home/user/app/$app$


RUN cd /home/user/app && unzip grails-petclinic.zip

Create the Package

Now, that we have application sources waiting in the /app directory, let’s package the application into WAR and copy build artifact into Tomcat’s /webapps dir. To have Petclinic running in the root, we’ll rename petclinic-0.2.war to ROOT.war:

RUN cd /home/user/app && grails war
RUN cp /home/user/app/target/petclinic-0.2.war /home/user/tomcat7/webapps/ROOT.war

Start the Container

We’re almost there, we just need to start the Tomcat server: CMD /home/user/tomcat7/bin/catalina.sh run

Hurray! The Petclinic is now up and running.

Only 5-Steps to get a completely custom environment in Codenvy!

To recap, here’s the complete Dockerfile:

# start from a Codenvy JDK7 image with Tomcat 7 pre-installed


FROM codenvy/jdk7_tomcat7


# download and install Grails


RUN wget -q -P /home/user http://dist.springframework.org.s3.amazonaws.com/release/GRAILS/grails-2.4.4.zip && \
cd /home/user && unzip grails-2.4.4.zip && rm -rf grails-2.4.4.zip


# set env variables and write them to .bashrc


ENV GRAILS_HOME /home/user/grails-2.4.4
RUN echo “export GRAILS_HOME=$GRAILS_HOME” >> /home/user/.bashrc
ENV PATH $GRAILS_HOME/bin:$PATH
RUN echo “export PATH=$PATH” >> /home/user/.bashrc


# add project sources to the image


RUN mkdir /home/user/app
ADD $app$ /home/user/app/$app$
RUN cd /home/user/app && unzip grails-petclinic.zip && rm -r grails-petclinic.zip


# perform Grails build and copy build artifact


RUN cd /home/user/app && grails war && \
cp /home/user/app/target/petclinic-0.2.war /home/user/tomcat7/webapps/ROOT.war


# start Tomcat


CMD /home/user/tomcat7/bin/catalina.sh run

You can also run the app using the Grails run-app command. In this case, we don’t need Tomcat pre-installed at all since Grails will download one. However, this method will force you to wait while Tomcat downloads each time you run your app — that’s why we recommend building it into an optimized Docker image.

If you haven’t already tried the new Codenvy you can sign-up for free, or try one of our premium accounts.

Some Food for Thought…

Pre-Built Images are Faster

It takes a while to set up environment and build a WAR file. Moreover, each time you execute this script, Grails will be downloaded and unpacked. It is inefficient, of course. Building an image locally and pushing it to Docker Hub is a solution here. The resulting Dockerfile will be much more elegant and the app will start much faster.

Build in the Base Image for Speed

Another trick is an incremental build. Each time you run an image and build a WAR, all the dependencies and plugins are downloaded… That takes time. Why not build WAR already in the base image? Sure, sources of your application change during the “coding phase”, and new dependencies can show up. However, having performed a preliminary build, you will make sure all base dependencies and plugins are in the image, and your build tool can use them, without the need to download half of the Internet. This works well for Maven, Ant, Gradle, Grails, and Leiningen. Do as much as you can in the base image — this will make every run faster.

Share Environments & Code With a Single URL

As a Codenvy user you can write and store your recipes in any Codenvy project you build or import. Including the build and run environment recipes in the project keeps the code and environment synced and ensures that anyone who you share the project with can instantly build and run it with a single click.

Further Reading

Codenvy’s Thoughts on Rocket & Docker
8 Ways Codenvy’s CLI Makes You Faster
1-Minute Overview & Sample Factories
Full List of Codenvy’s Features
Are Cloud IDEs the Future of Development

Offer: Get Free RAM for Your Codenvy Account!

--

--

MD @ Dell Tech Capital. BOD @ NS1, Orion Labs. Prev: CEO @ WSO2, CEO @ Codenvy (acq. by RHT). Invest @ Sauce Labs, Cloudant, ZeroTurnaround, InfoQ, Sourcegraph.