Building Docker Image on the Top of Jelastic CentOS 7 Template

With Jelastic, the process of preparing your own Docker image can be greatly simplified by building it on the basis of the already existing one (namely - on the top of the Jelastic CentOS 7 base template). This allows to skip all the steps, that are already accomplished within that “parent” template, and add the required adjustments only. We’ll consider this procedure on the example of preparing custom WildFly 9 image - flexible and lightweight Java application server, which is a direct successor of the popular JBoss one.

The most common way of building Docker images is composing a Dockerfile - special manifest, which allows to achieve the additional automation through listing the desired commands into a simple text file, which will be read and executed by Docker daemon. In such a way, a new template will be created automatically basing on the comprised instructions (while otherwise you need to call every necessary operation manually, one by one).

Below, we’ll consider all the specifics of a custom image running at our platform, and, as a result, you’ll get the ready-to-work dockerized version of the WildFly server right inside the Cloud. So, let’s walk through the required operations step-by-step:

Composing Dockerfile

To start with, create an empty text file - we’ll declare all the appropriate operations directly in it - and proceed with the following instructions.

Note: This sections is exploratory in its nature and includes just the required basis for your dockerfile preparation. However, if you’d like to dive into the specifics of the process and get more detailed guidance, you can examine the official dockerfile references.

Also, you can download the already prepared dockerfile (with our WildFly image example) in advance and just look through this section for the performed actions’ explanations, skipping the manual file creation.

1. The initial step is specifying the base template for our image building - we’ll use the jelasticdocker/jelastic-centos7-base one with the already configured CentOS 7 operation system inside. In order to set this within dockerfile, the FROM command should be used:

FROM jelasticdocker/jelastic-centos7-base:latest

2. Next, you can specify the general image information (like author and other internal variables), which will be required during the further configurations. Use the example below to set the needed values:

MAINTAINER Jelastic,Inc

ENV WILDFLY_VERSION 9.0.1.Final
ENV ADMIN_USER jelastic
ENV ADMIN_PASSWORD jelastic

where:

  • MAINTAINER - allows you to set the author of the Docker image, that will begenerated from this file (any preferred value can be specified here)
  • ENV - sets the main environment variables, i.e.:
    • WILDFLY_VERSION - version of WildFly to build; can be changed to another release if necessary (the currently available versions are listed here)
    • ADMIN_USER - the arbitrary administrator name for the subsequent accessing WildFly admin panel
    • ADMIN_PASSWORD - the desired password for the specified user

3. Now, you can start declaring the required configurations using the shell commands - the RUN operator should be used for this purpose.

First of all, you need to install the Java Development Kit (OpenJDK of the 8th version in our case) and the tar archiver (which will be used for decompressing the downloaded files):

RUN yum -y install java-1.8.0-openjdk-devel tar && yum -y update;

This command ends with calling the installed packages’ general update.

4. Next, let’s declare a few additional operations for downloading the WildFly source code from the official website and extracting it to the /opt folder.

RUN cd /opt && curl -O https://download.jboss.org/wildfly/$WILDFLY_VERSION/wildfly-$WILDFLY_VERSION.tar.gz \&& $(which tar) xf wildfly-$WILDFLY_VERSION.tar.gz \&& rm wildfly-$WILDFLY_VERSION.tar.gz

5. At this step, you need to create a symlink in order to shorten the path to the WildFly main directory and, as a result, to make it easily accessible:

RUN ln -s /opt/wildfly-$WILDFLY_VERSION /opt/wildfly

6. Let’s proceed with creation of the main configuration file for our WildFly server and putting all the needed options to it:

RUN echo -en "JAVA_HOME=\"/usr/lib/jvm/java\""'\n'\
"JBOSS_HOME=\"/opt/wildfly\""'\n'\
"JBOSS_USER=wildfly"'\n'\           
"JBOSS_MODE=standalone"'\n'\                       
"JBOSS_CONFIG=standalone.xml"'\n'\
"STARTUP_WAIT=60"'\n'\
"SHUTDOWN_WAIT=60"'\n'\
"JBOSS_CONSOLE_LOG=\"/var/log/wildfly/console.log\""'\n'\
"JBOSS_OPTS=\"-b 0.0.0.0 -bmanagement=0.0.0.0\"" >> /etc/default/wildfly.conf

7. CentOS 7 is started using the Systemd initiation script by default, but WildFly server requires the more traditional SystemV Init one, thus you need to copy the default initscript to the /etc/init.d folder and edit the appropriate configs to avoid the systemd redirect:

RUN cp /opt/wildfly/bin/init.d/wildfly-init-redhat.sh /etc/init.d/wildfly; sed -i "/# Source function library/a\SYSTEMCTL_SKIP_REDIRECT=1" /etc/init.d/wildfly

8. Next, we’ll state WildFly to be run on container startup through adding the corresponding system user and changing files’ ownership for him:

RUN chkconfig --add wildfly; chkconfig wildfly on; mkdir -p /var/log/wildfly; adduser wildfly; chown -R wildfly:wildfly /opt/wildfly-$WILDFLY_VERSION; chown wildfly:wildfly /opt/wildfly; chown wildfly:wildfly /var/log/wildfly

9. Also, let’s add the user credentials we’ve defined within the 1st instruction step for accessing the server’s admin panel:

RUN /opt/wildfly/bin/add-user.sh --user $ADMIN_USER --password $ADMIN_PASSWORD --silent --enable

10. Now, we can correct a link to the admin panel itself at the default index.html page by defining the corresponding redirect (as in case our image will be deployed to a container without the external IP attached, the 4949th port and HTTP connection should be used here):

RUN sed -i "s/<a href=\"\/console\">/<a href=\"\/console\" onclick=\"javascript:event.target.port=4949;event.target.protocol=\'http:\';\">/" /opt/wildfly/welcome-content/index.html

11. Also, the default iptables rules need to be changed to the ones with the appropriate permissions and restrictions declared, to make WildFly accessible for external requests.

The following ports are known to be used for the requests’ handling:
  • 8080 - for HTTP requests
  • 8743 - for HTTPS requests
  • 8009 - for AJP requests
  • 9990 - for HTTP access to admin panel
  • 9993 - for HTTPs access to admin panel

And in order to ensure the image will work properly, the following redirects should be set:
  • 80 to 8080 - for HTTP requests
  • 443 to 8743 - for HTTPS requests
  • 4848 to 9993 - for HTTPS access to admin panel
  • 4949 to 9990 - for HTTP access to admin panel

So, let’s replace the existing /etc/sysconfig/iptables file’s content with the following one:

RUN rm -f /etc/sysconfig/iptables && touch /etc/sysconfig/iptables && chmod 600 /etc/sysconfig/iptables;
RUN echo -en "*mangle"'\n'\
":PREROUTING ACCEPT [3:204]"'\n'\
":INPUT ACCEPT [3:204]"'\n'\
":FORWARD ACCEPT [0:0]"'\n'\
":OUTPUT ACCEPT [3:260]"'\n'\
":POSTROUTING ACCEPT [3:260]"'\n'\
"COMMIT"'\n'\
"*nat"'\n'\
":PREROUTING ACCEPT [0:0]"'\n'\
":POSTROUTING ACCEPT [0:0]"'\n'\
":OUTPUT ACCEPT [0:0]"'\n'\
"-A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080"'\n'\
"-A PREROUTING -p tcp -m tcp --dport 4949 -j REDIRECT --to-ports 9990"'\n'\
"-A PREROUTING -p tcp -m tcp --dport 4848 -j REDIRECT --to-ports 9993"'\n'\
"-A PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8443"'\n'\
"COMMIT"'\n'\
"*filter"'\n'\
":INPUT ACCEPT [0:0]"'\n'\
":FORWARD ACCEPT [0:0]"'\n'\
":OUTPUT ACCEPT [0:0]"'\n'\
"-A INPUT -p tcp -m tcp --dport 9993 -j ACCEPT"'\n'\
"-A INPUT -p tcp -m tcp --dport 9990 -j ACCEPT"'\n'\
"-A INPUT -p tcp -m tcp --dport 8443 -j ACCEPT"'\n'\
"-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT"'\n'\
"-A INPUT -p tcp -m tcp --dport 8009 -j ACCEPT"'\n'\
"-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT"'\n'\
"-A INPUT -p icmp -j ACCEPT"'\n'\
"-A INPUT -i lo -j ACCEPT"'\n'\
"-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT"'\n'\
"-A INPUT -j REJECT --reject-with icmp-host-prohibited"'\n'\
"-A FORWARD -j REJECT --reject-with icmp-host-prohibited"'\n'\
"COMMIT" >> /etc/sysconfig/iptables;

12. Another required action is to set our Docker image to listen to the required ports at the runtime. The EXPOSE command is intended for this:

EXPOSE 80 443 8080 8743 9990 9993 8009 4848 4949

13. Lastly, you need to set the ENTRYPOINT for defining a container to be run as executable. In our case, the bash shell should be specified:

ENTRYPOINT ["/bin/bash"]

That’s all! Just don’t forget to save all the declared settings to get the ready-to-go dockerfile.

Adding Image to Repository

Once the proper dockerfile is prepared, you are ready to build your WildFly image on its base and, subsequently, push it to the repository.

Note: Before starting, ensure you have the appropriate Docker engine version (according to the used OS type) installed for executing the below described commands at the currently used machine.

So, follow the next steps to accomplish that:

1. Run the docker build command with the required parameters to create a new image locally:

sudo docker build -t {image_name} {dockerfile_location}

,where

  • {image_name} - image repository appellation; optionally, a version tag could be added after the “:” separator (e.g. jelastic/wildfly:latest)
  • {dockerfile_location} - either local path or an URL to your dockerfile (could be set as “.” if the file is located in the current directory)

2. You should receive the build success message with the ID of your new image alongside. To ensure it is available at your workstation, you can request the list of all local templates to be output with:

sudo docker images

3. Finally, you need to push (upload) your image to a registry with the corresponding command:

sudo docker push {image_name}

Here, {image_name} should be stated the same to the one you’ve specified during the image building in the 1st step.

You’ll be additionally requested to confirm your account ownership (by specifying the corresponding username, password and email address) in order to complete this operation.

Tip: You can log into registry in advance using the corresponding docker login command (as a result, your credentials will be stored in the ~/.docker/config.json file at your local user’s home directory).

Deploying Image at Jelastic

As soon as your image is successfully stored at the repository, it becomes available for usage at the Jelastic Platform and can be added to an environment through the dedicated Dockers board, integrated to both Marketplace and topology wizard dashboard sections.

So, select the New environment button at the top dashboard’s pane, move to the Docker tab within the opened environment wizard and access the Select Container frame by means of clicking on the same-named button.

1. Here, you can use either the Search tab (for adding an image from any public repository) or switch to the Custom section, where you can operate images of any type (i.e. including the private ones) and store your templates for being easily accessible.

We’ll consider the latter one, so, once inside, choose the necessary environment layer to the left (App. Servers in our case) and click the Add New Image button.

2. At the opened Add New Image frame, type your image identifier within the Name field, i.e:
{registry_hostname} (can be skipped for official Hub Registry)/{account}/{image_name}

Also, in case of a private repository usage, the appropriate Username and Password should be specified.

We use the public repository, located within the central Registry Hub, so only the short repository name is required. Click Add when ready.

3. After that, your image will appear in the list. Out of here, it could be added to the topology with just a single click. Moreover, this template will be remembered and remain listed here so it can be easily found during the consequent container selections (till you remove it from the Custom list manually).

Set all the rest of necessary configurations on your own (the details on the available options can be read here) and finish the environment creation.

4. Once your Docker-based environment with the appropriate image inside appears at the dashboard, it can be accessed using the corresponding Open in browser button:

Note:  In case you haven’t placed your template to the App. Servers or Balancing environment layer, you’ll need to use the same-named button next to a particular container to open it.

As a result, you’ll see the default WildFly start page, which means everything was configured properly and your newly created Docker container is fully operationable.

Similarly to the described above, you can create any other preconfigured image due to your purposes and, consequently, easily run it within the Cloud!

If you face any issues while packaging or deploying your own image, feel free to appeal for our technical experts’ assistance at Stackoverflow.