How-to: Create simple Pineapple Docker image

Overview

This example illustrates how the Docker plugin can be used to create a Docker image based on Oracle Linux 7 with Java 11 and Pineapple installed.

Pineapple is installed in the most simple fashion, basically an unzip with no consideration for the used user within the Docker image. The user root will be used.

Part of the default configuration

This example named docker-005-pineapple-image-from-dockerfile-centos, including all configuration files, is included in the default configuration which is created by Pineapple, so there is no need to create it by hand.

Installation of Docker

This example requires the presence of a Docker daemon. The example How-to: Install latest Docker version in a Vagrant box with CentOS 7.6 using SSH. describes how Pineapple can be used to install Docker on a Vagrant box for the purpose of the example.

For the remaining part of this example is assumed that Docker is installed using the above example. The assumed configuration is:

  • The Vagrant box is running CentOS 7.6 and has IP address 192.168.34.10.
  • The Docker daemon is accessible at 192.168.34.10:8082.

This is relevant since Pineapple will be accessed using HTTP from the docker container within the Docker daemon within the Vagrant box.

Define the module

Pineapple's unit of work is modules. A module is a self contained unit which can contain models, scripts and binaries. Models serves to specify test cases, deployment of applications, configuration of devices or execution of scripts.

The default directory for modules is ${user.home}/.pineapple/modules so we will create a module named docker-005-pineapple-image-from-dockerfile-centos there. The module for this example will end up with the structure:

docker-005-pineapple-image-from-dockerfile-centos
 |
 +--- models     
 |     +--- linux-vagrant.xml 
 +--- dockersrc  
       +--- Dockerfile
       +----pineapple-standalone-web-client-1.12.0.zip       

Define the module model

The model file for definition of the image:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<mmd:models xmlns:mmd="http://pineapple.dev.java.net/ns/module_model_1_0"       
    xmlns:dkp="http://pineapple.dev.java.net/ns/plugin/docker_1_0" >
    <mmd:model target-resource="docker-node" description="Define tagged Docker image: pineapple/pineapple:1.12.0 from Dockerfile" >
        <mmd:content>
            <dkp:docker>
                <dkp:image-from-dockerfile source-directory="modulepath:dockersrc" pull-image="false" >
                    <dkp:target-image repository="pineapple/pineapple" tag="1.12.0" />
                </dkp:image-from-dockerfile>
            </dkp:docker>                       
        </mmd:content>
    </mmd:model>    
</mmd:models>

The configuration details

Two schema are used in the model file. The http://pineapple.dev.java.net/ns/module_model_1_0 is used to define the namespace mmd which defines the general infrastructure for models. The http://pineapple.dev.java.net/ns/plugin/docker_1_0 schema is used to define the namespace dkp which is used to define the model for the Docker plugin. Since multiple schemas are used to define the model file, the elements are qualified.

The target-resource attribute defines a reference to the resource which is targeted when the model executed. In this case, the value docker-node is a reference to a resource which defines a Docker daemon.

The dkp:docker element defines the root of model for the Docker plugin.

The dkp:image-from-dockerfile element defines a tagged Docker image which can be used for creation or deletion depending on the invoked operation.

When the model is invoked with the deploy-configuration operation, then target image is created from the source image. The source image is defined by the DockerFile (see detail below).

When the image is created then source directory, defined by the source-directory attribute on element dkp:image-from-dockerfile, is compressed into a TAR archive and uploaded to Docker. Please notice that source directory is defined using the variable modulepath:dockersrc which is resolved at runtime to the directory dockersrc within the module.

Docker unpacks the archive and looks for a Dockerfile in the root of the archive. The Dockerfile along with other file material in the archive is used to create the image.

The name of the target image is defined by the dkp:target-image element.

Dockerfile

The Dockerfile contains:


# Pull base image for builder image
# ----------------------------------
FROM openjdk:11.0-jdk-oraclelinux7 as builder

LABEL maintainer="einheriii@gmail.com"

ARG PINEAPPLE_VERSION=1.12.0
ARG PINEAPPLE_HOME=/var/pineapple
ARG PINEAPPLE_INSTALL=/opt/pineapple

# Map arguments into environment variables
ENV PINEAPPLE_VERSION=${PINEAPPLE_VERSION} \
        PINEAPPLE_HOME=${PINEAPPLE_HOME} \
    PINEAPPLE_INSTALL=${PINEAPPLE_INSTALL}
                
RUN set -eux; \
        yum install -y unzip; \
        rm -rf /var/cache/yum

# Install Pineapple binary 
COPY pineapple-standalone-web-client-${PINEAPPLE_VERSION}.zip /tmp/archive.zip 
RUN unzip /tmp/archive.zip -d /opt; \
        mv /opt/pineapple-standalone-web-client-${PINEAPPLE_VERSION} ${PINEAPPLE_INSTALL}

# make script executable
RUN mkdir -p ${PINEAPPLE_HOME} \
        && chmod +x ${PINEAPPLE_INSTALL}/runPineapple.sh 

# Pull base image for final image
# --------------------------------
FROM openjdk:11.0-jdk-oraclelinux7 

LABEL maintainer="einheriii@gmail.com"

ARG PINEAPPLE_HOME=/var/pineapple
ARG PINEAPPLE_INSTALL=/opt/pineapple
ARG PINEAPPLE_HTTP_HOST=0.0.0.0
ARG PINEAPPLE_HTTP_PORT=8080

# Pineapple is run with user `pineapple`, uid = 1000
# If a volume is mounted from the host or a data container, ensure the same UID is used.
ARG PINEAPPLE_USER=pineapple
ARG PINEAPPLE_GROUP=pineapple
ARG PINEAPPLE_UID=1000
ARG PINEAPPLE_GID=1000

# Map arguments into environment variables
ENV PINEAPPLE_HOME=${PINEAPPLE_HOME} \
    PINEAPPLE_INSTALL=${PINEAPPLE_INSTALL} \
        PINEAPPLE_HTTP_HOST=${PINEAPPLE_HTTP_HOST} \
        PINEAPPLE_HTTP_PORT=${PINEAPPLE_HTTP_PORT} 
        
# Copy directories from builder
COPY --from=builder ${PINEAPPLE_INSTALL} ${PINEAPPLE_INSTALL}
COPY --from=builder ${PINEAPPLE_HOME} ${PINEAPPLE_HOME}

# create user, gruoup and home directory
RUN groupadd -g ${PINEAPPLE_GID} ${PINEAPPLE_GROUP} \
        && useradd -m -u ${PINEAPPLE_UID} -g ${PINEAPPLE_GID} -o -s /bin/bash ${PINEAPPLE_USER} \       
        && chown ${PINEAPPLE_UID}:${PINEAPPLE_GID} ${PINEAPPLE_HOME} \  
        && chown ${PINEAPPLE_UID}:${PINEAPPLE_GID} ${PINEAPPLE_INSTALL}
        
# Set work directory
WORKDIR ${PINEAPPLE_INSTALL}

# Expose port to host
EXPOSE ${PINEAPPLE_HTTP_PORT}

# Define volume
VOLUME ${PINEAPPLE_HOME}

# Define user
USER ${PINEAPPLE_USER}

# Start pineapple when container is created
ENTRYPOINT ${PINEAPPLE_INSTALL}/runPineapple.sh

The image is constructed using a multi-stage build. A builder image is used and then a the final image is constructed.

The builder image

The FROM command specifies that the image openjdk:11.0-jdk-oraclelinux7 should be pulled from the local registry orDockerHub.

The LABEL command declares the proud author.

Some arguments (along with default values) are declares using the ARG command to support the construction of the image:

  • The version of Pineapple archive which is installed in the image.
  • The installation directory where Pineapple will be installed.
  • The Pineapple home directory (used for runtime files).

The arguments are mapped into environments variables using the ENV command.

The RUN command uses YUM to installs the unzip tool and clears the YUM cache.

THE COPY command copies the Pineapple archive from the uploaded TAR archive into the /tmp directory on image.

The RUN command unzips Pineapple.

The RUN command deletes the Pineapple archive from the /tmp directory.

The RUN command renames the installation directory to /opt/pineapple. command deletes the Pineapple archive from the /tmp directory.

The RUN command makes the Pineapple main script runPineapple.sh executable.

The RUN command creates the Pineapple home directory.

The final image

The FROM command specifies that the image openjdk:11.0-jdk-oraclelinux7 should be pulled from the local registry orDockerHub.

The LABEL command declares the proud author.

Some arguments (along with default values) are declares using the ARG command to support the construction of the image:

  • The installation directory where Pineapple is installed.
  • The Pineapple home directory (used for runtime files).
  • The listen address for Pineapple, because Docker doesn't like the default Pineapple listen address localhost. It is set to 0.0.0.0.
  • The listen port for Pineapple. It is set to 8080.
  • The user and group, i.e. pineapple:pineapple, used to run Pineapple.
  • The UID and GUI for the created user and group , i.e. 1000 and 1000.

The arguments are mapped into environments variables using the ENV command to ensure they are available in the final image.

The COPY commands is used to copy the installation and home directories from the builder image into the final image.

The RUN command creates the user, group and home directory.

The WORKDIR command defines Pineapple installation directory as the current directory.

The EXPOSE command exposes port 8080 from the image.

The VOLUME command defines a volume for the runtime directory where Pineapple writes its files.

The USER command sets the user running the container.

The ENTRYPOINT defines the command to run when a container is started.

Add binary

The Pineapple binary pineapple-standalone-web-client-1.12.0.zip must be downloaded and added to the dockersrc directory within the module.

Invoke Pineapple to execute model

Start your Pineapple:

  • Select the module named docker-005-pineapple-image-from-dockerfile-centos
  • Select the linux-vagrant model.
  • Invoke the deploy-configuration to create the Docker Image named pineapple/pineapple:1.12.0.

Create a container

To create a container a the command line within the Vagrant box:

sudo docker run --name="pineapple" -p 8080:8080 pineapple/pineapple:1.12.0

Pineapple will run at http:/0.0.0.0:8080 within the Docker image as the pineapple:pineapple user. The image defines exposure of port 8080 to the host with no port mapping. Pineapple is available at: http://192.168.34.10:8080 at the hosts (Vagrant box and the host hosting the Vagrant box).

Pineapple will be configured to use the home directory /var/pineapple. The home directory is mapped to a volume to retain data between container execution. Modules can be uploaded and run using either the GUI or the REST API.