© 2017, Mahesh Acharya

Hippo CMS — Docker Containerization

Mahesh Acharya
6 min readOct 27, 2018

--

Containers are everywhere, there are many benefits to adopting a containerized deployment model. Hippo CMS is an Open Source Content Management System — one of the finest Java web application out there.

Downloading Hippo CMS from a public registry like Docker Hub, created by someone else is good for testing purposes, the true benefit of container images can be realized when you make your own project to produce Docker images.

The focus of this article is to provide step by step guide on how to enable docker image building capabilities to Hippo CMS project.

Goals

Add Maven profile to Hippo CMS project to build Docker images for,

  1. H2DB persistence storage.
  2. MySQL persistence storage.

Reference Implementation Project

Git Repo: https://github.com/maheshacharya/hippo-docker-example
Hippo CMS version: 12.04
We use Spotify Docker Maven plugin:
https://github.com/spotify/docker-maven-plugin
Hippo CMS Deployment Schemes:
https://github.com/maheshacharya/hippo-docker-deployments

1. Maven profile for H2DB Persistence storage

The image created using this profile is useful for testing a single container Hippo CMS application — useful for developer testing, demos etc.

1.1 Add a new profile “docker.image” to root pom.xml
Dockerfile commands are embedded within the pom.xml to take advantage of maven project environment variables such as project name, version etc. You can also create a separate Dockerfile if that makes sense — refer to Spotify documentation for more options.

<profile>
<id>docker.image</id>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>distro-assembly</id>
<phase>validate</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>${project.basedir}/src/main/assembly/docker-distribution.xml
</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-resources</id>
<!-- here the phase you need -->
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/docker</outputDirectory>
<resources>
<resource>
<directory>${basedir}/target</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- https://mvnrepository.com/artifact/com.spotify/docker-maven-plugin -->
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<baseImage>ubuntu:16.04</baseImage>
<maintainer>maheshacharya@hotmail.com</maintainer>
<cmd><![CDATA[
ENV DEBIAN_FRONTEND noninteractive
ENV TOMCAT_VERSION 8.0.53
# Install dependencies
RUN apt-get update && \
apt-get install -y git build-essential curl wget software-properties-common
# Install Java (JDK) 8
RUN \
echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
add-apt-repository -y ppa:webupd8team/java && \
apt-get update && \
apt-get install -y oracle-java8-installer
#wget unzip tar && \
#rm -rf /var/lib/apt/lists/* && \
#rm -rf /var/cache/oracle-jdk8-installer
# JAVA_HOME variable
ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
# Install Tomcat
RUN wget --quiet http://www.gtlib.gatech.edu/pub/apache/tomcat/tomcat-8/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz && \
tar xzvf apache-tomcat-${TOMCAT_VERSION}.tar.gz && \
mv apache-tomcat-${TOMCAT_VERSION} /usr/local/tomcat && \
rm apache-tomcat-${TOMCAT_VERSION}.tar.gz && \
rm -rf /usr/local/tomcat/webapps/examples && \
rm -rf /usr/local/tomcat/webapps/docs && \
rm -rf /usr/local/tomcat/webapps/ROOT && \
chgrp -R 0 /usr/local/tomcat/ && \
chmod -R g=u /usr/local/tomcat/
ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $PATH:$CATALINA_HOME/bin
VOLUME "/usr/local/tomcat/webapps"
WORKDIR /usr/local/tomcat
#Hippo specific environment configurations
ENV CATALINA_OPTS "${JVM_OPTS} -Djava.security.egd=file:/dev/./urandom"
ADD ${project.artifactId}-${project.version}-distribution.tar.gz /usr/local/tomcat/
EXPOSE 8080
CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]
]]>
</cmd>
<imageName>hippo/${project.artifactId}</imageName>
</configuration>
</plugin>
</plugins>
</build>
</profile>

1.2 Add “docker-distribution.xml file under “src/main/assembly” folder.

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>distribution</id>
<formats>
<format>tar.gz</format>
</formats>
<files>
<file>
<source>conf/catalina.properties</source>
<outputDirectory>/conf</outputDirectory>
<destName>catalina.properties</destName>
</file>
</files>
<includeBaseDirectory>false</includeBaseDirectory>
<componentDescriptors>
<componentDescriptor>conf-component.xml</componentDescriptor>
<componentDescriptor>webapps-component.xml</componentDescriptor>
<componentDescriptor>common-lib-component.xml</componentDescriptor>
<componentDescriptor>shared-lib-component.xml</componentDescriptor>
<componentDescriptor>shared-lib-development-data-component.xml</componentDescriptor>
</componentDescriptors>
</assembly>

1.3 Add “catalina.properties” under folder “conf

Most importantly, we need the “shared.loader” property appended with required parameters.

shared.loader="/usr/local/tomcat/shared/lib","/usr/local/tomcat/shared/lib/*.jar"

Building Container Image

To build a container image, first, build the project itself.

mvn clean verify

Next, build the container image. Please note, you will need docker installed on the system in order for this command to run successfully.

mvn -P docker.image

Verifying that the image has been created.

docker images

You will see the result like below.

REPOSITORY                   TAG      IMAGE ID     CREATED     SIZE
hippo/hippodockerexample latest d32e4699d49f 1 days ago 1.21GB

To run the image with container port 8080 mapped to host system port 8080.

docker run -d -p 8080:8080 hippo/hippodockerexample

2. Maven profile for MySQL Persistence storage

MySQL image is useful for deploying Hippo CMS to down-stream environment like Test, QA, and production — where more than one instance of Hippo CMS will be deployed as part of the cluster.

2.1 Add Maven profile “docker.image.mysql” to root pom.xml

<profile>
<id>docker.image.mysql</id>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>distro-assembly</id>
<phase>validate</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>${project.basedir}/src/main/assembly/docker-mysql-distribution.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-resources</id>
<!-- here the phase you need -->
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/docker</outputDirectory>
<resources>
<resource>
<directory>${basedir}/target</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- https://mvnrepository.com/artifact/com.spotify/docker-maven-plugin -->
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<baseImage>ubuntu:16.04</baseImage>
<maintainer>maheshacharya@hotmail.com</maintainer>
<cmd><![CDATA[ENV DEBIAN_FRONTEND noninteractive
ENV TOMCAT_VERSION 8.0.53
# Install dependencies
RUN apt-get update && \
apt-get install -y git build-essential curl wget software-properties-common
# Install Java (JDK) 8
RUN \
echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
add-apt-repository -y ppa:webupd8team/java && \
apt-get update && \
apt-get install -y oracle-java8-installer
#wget unzip tar && \
#rm -rf /var/lib/apt/lists/* && \
#rm -rf /var/cache/oracle-jdk8-installer
# JAVA_HOME variable
ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
# Install Tomcat
RUN wget --quiet http://www.gtlib.gatech.edu/pub/apache/tomcat/tomcat-8/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz && \
tar xzvf apache-tomcat-${TOMCAT_VERSION}.tar.gz && \
mv apache-tomcat-${TOMCAT_VERSION} /usr/local/tomcat && \
rm apache-tomcat-${TOMCAT_VERSION}.tar.gz && \
rm -rf /usr/local/tomcat/webapps/examples && \
rm -rf /usr/local/tomcat/webapps/docs && \
rm -rf /usr/local/tomcat/webapps/ROOT && \
chgrp -R 0 /usr/local/tomcat/ && \
chmod -R g=u /usr/local/tomcat/
ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $PATH:$CATALINA_HOME/bin
VOLUME "/usr/local/tomcat/webapps"
WORKDIR /usr/local/tomcat
#Hippo specific environment configurations
ENV CATALINA_OPTS "${JVM_OPTS} -Djava.security.egd=file:/dev/./urandom -Djava.security.egd=file:/dev/./urandom -Drepo.config=file:/usr/local/tomcat/conf/repository.xml"
ADD ${project.artifactId}-${project.version}-distribution.tar.gz /usr/local/tomcat/
EXPOSE 8080
CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]]]></cmd>
<imageName>hippo/${project.artifactId}</imageName>
</configuration>
</plugin>
</plugins>
</build>
</profile>

2.2 Add “docker-mysql-distribution.xml under “src/main/assembly” folder.

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>distribution</id>
<formats>
<format>tar.gz</format>
</formats>
<files>
<file>
<source>conf/catalina.properties</source>
<outputDirectory>/conf</outputDirectory>
<destName>catalina.properties</destName>
</file>
<file>
<source>conf/repository-mysql.xml</source>
<outputDirectory>/conf</outputDirectory>
<destName>repository.xml</destName>
</file>
<file>
<source>conf/docker-mysql-context.xml</source>
<outputDirectory>/conf</outputDirectory>
<destName>context.xml</destName>
</file>
</files>
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>/common/lib</outputDirectory>
<scope>provided</scope>
<includes>
<include>javax.jcr:jcr</include>
<include>org.apache.geronimo.specs:geronimo-jta_1.1_spec</include>
<include>javax.mail:mail</include>
<include>mysql:mysql-connector-java</include>
</includes>
</dependencySet>
</dependencySets>
<includeBaseDirectory>false</includeBaseDirectory>
<componentDescriptors>
<componentDescriptor>conf-component.xml</componentDescriptor>
<componentDescriptor>webapps-component.xml</componentDescriptor>
<componentDescriptor>common-lib-component.xml</componentDescriptor>
<componentDescriptor>shared-lib-component.xml</componentDescriptor>
<componentDescriptor>shared-lib-development-data-component.xml</componentDescriptor>
</componentDescriptors>
</assembly>

2.3 Add “repository-mysql.xml under folder “conf”.
This repository descriptor defines all configurations essential for MySQL persistence storage. For more details go to Hippo CMS documentation.

2.4 Add “mysql-context.xml under folder “conf”
Note the JDBC connection URL “jdbc:mysql://hippo-mysql-database:3306/hippo”. the name “hippo-mysql-database” is something that becomes relevant how you link the database container with Hippo CMS Containers. You can name it anything you want, but this has to be mapped properly during the deployment so that containers can talk to each other on the same or different networks.

<?xml version='1.0' encoding='utf-8'?>
<Context useHttpOnly="true" useRelativeRedirects="false">
<!-- Disable session persistence across Tomcat restarts -->
<Manager pathname="" />
<Parameter name="repository-address" value="rmi://127.0.0.1:1099/hipporepository" override="false"/>
<Parameter name="repository-directory" value="${catalina.base}/../repository" override="false"/>
<Parameter name="start-remote-server" value="false" override="false"/>
<Parameter name="check-username" value="liveuser" override="false"/><Resource name="mail/Session" auth="Container"
type="javax.mail.Session" mail.smtp.host="localhost"/>
<!-- JNDI resource exposing database connection goes here --><Resource
name="jdbc/repositoryDS" auth="Container" type="javax.sql.DataSource"
maxTotal="20" maxIdle="10" initialSize="2" maxWaitMillis="10000"
testWhileIdle="true" testOnBorrow="false" validationQuery="SELECT 1"
timeBetweenEvictionRunsMillis="10000"
minEvictableIdleTimeMillis="60000"
username="hippo" password="hippo"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://hippo-mysql-database:3306/hippo?characterEncoding=utf8"/>

</Context>

Building Docker Image

mvn clean verify
mvn -P docker.image.mysql

Running Hippo CMS Container image with links to MySQL Container

First, run MySQL Container. For real environment deployments, use docker secrets to mange passwords.

docker run --name hippo-db  \
-e MYSQL_ROOT_PASSWORD=hippo \
-e MYSQL_DATABASE=hippo \
-e MYSQL_USER=hippo \
-e MYSQL_PASSWORD=hippo \
-e ON_CREATE_DB=hippo \
-d mysql:5.6.36

Next, run Hippo CMS Container, notice, how “hippo-mysql-database” mapped to the container with name “hippo-db”, basically the context file deployed under “tomcat/conf” is looking for a database accessible with name “hippo-mysql-database”.

docker run -d -p 8080:8080 --name hippo \
--link hippo-db:hippo-mysql-database hippo/hippodockerexample

Where to store your images for down-stream distribution?

A real Hippo CMS project might contain a lot of proprietary resources, therefore pushing an image to a public repository may not be viable. You can store images as private with restricted access on Docker Hub or push Images to your own private registry.

How to use Hippo CMS Docker images for down-stream deployments?

Checkout my git repository on how to use different deployment schemes using Docker Compose, Docker Swarm, and Kubernetes(OpenShift and Rancher).

Hippo CMS — Deployment using Docker Compose

https://medium.com/@maheshacharya_44641/hippo-cms-deployment-using-docker-compose-102a78a09ecb

--

--