Thursday, 23 July 2015

Creating a Docker image using BlueMix IBM Containers

In the previous post I created a grails application based on some Groovy scripts in DevOps Services on BlueMix. I created a build using BlueMix delivery pipeline service which builds the application and posted it it as a BlueMix's Cloud Foundry Application. I created a new project which will contain more scripts and added docker support found here: https://hub.jazz.net/project/kuschel/ucdscripts.

BlueMix also has Docker support in IBM Containers. What is Docker and why use it over or in addition to Cloud Foundry?

The good news is that it fairly easy to create a Docker build using the same source code base we are using for the Cloud Foundry build in DevOps services.  The big not-so-secret is that Cloud Foundry also uses a containers, called Warden that provides isolation between the application running within in. (A container is a isolated, ephemeral, and resource-controlled environment.). In the case of Cloud Foundry, the container is hidden behind APIs and runtime environments called "build packs". Cloud Foundry also has the ability to set up services that can be easily bound to application containers but the biggest difference is how these environments are built and interact. This is where I personally prefer Docker.

As opposed to Cloud Foundry, which uses hooks from Ruby for building the environment ("buildpack"), Docker provides a very familiar environment to anybody who is a Linux guru, it's basically a Linux kernel, isolated shell with a (default) empty file system and network connectivity. (Docker runs on Windows and Mac using a emulated kernel host using Boot2docker.)  To "build" a Docker image, a Dockerfile is required which provides the steps to copy executables, libraries, configurations and the default command to execute when the imagine is run as a container. This would be painful to do for every build as many dependencies are usually required just to run something like a JDK: shared libraries, executables, etc. Fortunately, Docker has an inheritance model that allows containers to be extended. So, there is are pre-made docker images that contain Linux distribution typical expected in a Linux distribution. There is a base image of the Ubuntu, Red Hat and many other distributions that already contain package managers and common utilities pre-installed.   Pre-built docker images are available in a registry on https://registry.hub.docker.com/ and Bluemix also has a image registry at registry.ng.bluemix.net.  There is also a Websphere Liberty docker container, which we extend for our Grails UrbanCode script application.

This is the Dockerfile for our grails UrbanCode script:

FROM websphere-liberty

RUN featureManager install jms-1.1 --when-file-exists=ignore --acceptLicense
RUN featureManager install openidConnectClient-1.0 --when-file-exists=ignore --acceptLicense
ENV LICENSE accept

RUN apt-get update
RUN apt-get install -y openjdk-7-jdk unzip wget
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENV JAVA_HOME /usr/lib/jvm/java-7-openjdk-amd64
ENV PATH $JAVA_HOME/bin:$PATH
RUN mkdir /build
ENV HOME /build
ADD . /build/
WORKDIR /build
RUN rm -f src/templates/war/web.xml
RUN ./grailsw war
COPY dockerServer/server.xml /opt/ibm/wlp/usr/servers/defaultServer/server.xml
RUN cp target/*.war /opt/ibm/wlp/usr/servers/defaultServer/apps/

In this script we install a few WebSphere Liberty features and a JDK 1.7 in order to run the grailsw build executable and copy the server configuration files to the image; the installation of WebSphere Liberty and the default executable is already provided by the websphere-liberty image, contained in the BlueMix image registry, that we inherit from. As the websphere-liberty image inherits the ubuntu image that has the apt-get (the installation package manager for ubuntu) pre-installed.

We have a build deploy step ("Docker Build") that builds the image using the Dockerfile and posts as new image to the BlueMix registry as registry.ng.bluemix.net/bkuschel/ucdscripts:<version>. There is also a a deploy step ("Docker Deploy") that deploys the application to IBM Containers as the ucdscripts_<version> container and binds it to a public IP available here.

If you wish to build and run the image locally Fork the project, load it, modify it as desired. Install docker or Boot2docker change to ucdscripts directory and run (You can call the image something other then bkuschel/ucdscripts) :

1. docker build -t bkuschel/ucdscripts .
2. docker run bkuschel/ucdscripts:latest

The script application will now be available at: http://localhost:9080/