Create and verify a Docker image

To run an application in a container, you must create an image that contains the required software dependencies. An image is created by writing and then building a Dockerfile. The following image shows the steps in this process:

In this guide, we will provide the Dockerfile that is used to create the image used in this example, and we will walk through each step. Be sure to place the downloaded Fast Model package .zip file next to this Dockerfile for it to build properly.

Let’s take a look at the Dockerfile that we will use in our example.

Every Dockerfile must start with a FROM command, specifying what the image is built from. In our example, the FROM command is a custom image, with Arm tools pre-installed on a minimalist Ubuntu 16.04 image, that is pulled from Docker Hub. Additional packages are installed to support Arm Fast Models and Python scripting. You can see this in the following code:

FROM ubuntu:16.04

# Needed test packages so newer Fast Model versions work (11.10 and up)
RUN apt-get update -y
RUN apt-get install -y software-properties-common
RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test
RUN apt-get update -y
RUN apt-get install -y gcc-7 g++-7
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 80 --slave /usr/bin/g++ g++ /usr/bin/g++-7

# Install packages
RUN apt-get update && apt-get install -y apt-utils
RUN apt-get install -y \
  #FMs
    lsb-core \
    libxext6 \
    libsm6 \
    libxcursor1 \
    libxft2 \
    libxrandr2 \
    libxt6 \
    libxinerama1 \ 
  #Python
    python2.7 \
    python-pip

To ensure image security, we create a new user with limited privileges. The group name and username are jenkins, as shown here:

# Create new user with GID and UID of jenkins          # RUN useradd --create-home --shell /bin/bash jenkins
RUN   mkdir --parents /home/jenkins &&\
      groupadd --system jenkins &&\
      useradd --system --home /home/jenkins --shell /sbin/nologin --gid jenkins jenkins
ENV   JENKINS_HOME=/home/jenkins

Next, we install Fast Models. This involves adding the tarball to the Docker image (the ADD command automatically untars compressed files) and running the install script setup.sh with relevant parameters. For the Dockerfile to work with your downloaded Fast Models tarball, you must update the path names to match the version and release numbers that are specific to your .tgz downloaded version, as you can see in the following code:

# Install FMs
ADD FastModels_11-4-043_Linux64.tgz $JENKINS_HOME/
RUN cd $JENKINS_HOME/FastModels_11-4-043_Linux64/ && ./setup.sh --i-accept-the-license-agreement --basepath "$JENKINS_HOME/Arm/" &&\
  rm -r $JENKINS_HOME/FastModels_11-4-043_Linux64/

Next, we reference the license file, to ensure that the example model can build properly. Replace localhost with the network path to your license, if the license server is installed on a remote machine. Make sure that there is no space between the = and your file location. Use these commands:

# Set License file path
ENV   ARMLMD_LICENSE_FILE=7010@localhost

Copy over the example code, and the Fast Model virtual platform is built on the Docker image. The required Fast Model scripts are set in your bashrc file. You can invoke the scripts automatically when you run the image manually from inside the Docker container. You must also change the Fast Models version in these variables to match your version. Use these commands:

# Setup example FM system
COPY  ./m4_system/ $JENKINS_HOME/m4_system/
COPY  ./ITMTrace/  $JENKINS_HOME/plugins/
COPY  ./run_m4.py  $JENKINS_HOME
RUN   . $JENKINS_HOME/Arm/FastModelsTools_11.4/source_all.sh &&\
      cd $JENKINS_HOME/m4_system/model/ &&\
      ./linux_build.sh  

# Set FM startup sourcing for manual code work
RUN   echo "\n#FM Startup Code\n" >> $JENKINS_HOME/.bashrc &&\
              echo "source $JENKINS_HOME/Arm/FastModelsTools_11.4/source_all.sh\n" >> $JENKINS_HOME/.bashrc

Finally, switch the user to jenkins, with rights to files and folders in that home directory. Use these commands:

# Switch to jenkins user with proper rights to files in $JENKINS_HOME
RUN chown -R jenkins:jenkins $JENKINS_HOME
USER  jenkins
WORKDIR /home/Jenkins

In common Dockerfile syntax, the \ character denotes a multi-line command, and the && indicates that there is another command to run after the current one finishes.

Run the following command in your terminal or command prompt to build a Docker image that is based on our example Dockerfile. In our example, we tag the Docker image as the user zach. You can use your Docker ID if you have one, or you can use a name of your choice:

docker build -t zach/fm-m4-example-itm:latest -f Dockerfile .

The -t specifies the tag for the image, -f points to the Dockerfile, and the period '.' at the end specifies the build context. The build context is what files look at when building the image. Because it is a period '.', the build context is the current directory. Sub-directories can be named here if needed, but are not needed in this case. The COPY command must point to a file or directory within the noted build context. After building, check that the image was created with the docker images command, as you can see here:

To execute the docker container, run the following command:

docker run --rm -ti --cap-drop=all --memory=2G --cpus=1 zach/fm-m4-example-itm:latest

The docker run command options specify, in order:

--rm
Enables a proper clean-up after you exit container
-ti
Opens an interactive shell
--cap-drop=all
Restricts permissions of the container even further for security
--memory=2G and --cpus=1
Restricts the maximum resource usage that the container can use at one time for security reasons
zach/fm-m4-example:latest
Points to the correct image to run, that is the image that we just built.

When running, the Docker image will start in the home directory of the user jenkins. The command prompt should look like the following screenshot:

Run an example program on a Cortex-M4 system, noted as startup_Cortex-M4.axf under the m4_system/app_helloWorld directory. Your example includes a simple Python script to automate the process, using the Fast Model scripting language PyCADI as seen in the following code block:

# Import libraries
import sys,os
# Set python path to Fast Models, as a check to see if FM installed properly
try:
    sys.path.append(os.path.join(os.environ['PVLIB_HOME'], 'lib', 'python27'))
except KeyError as e:
    print "Error! Make sure you source all from the fast models directory."
    sys.exit(1) # Exit with error
import fm.debug
  

def ITM_redirect(file_name):
    targets = model.get_target_info()
    for target_info in targets:        
        if target_info.target_name.find("ITMtrace") >= 0:
            target = model.get_target(target_info.instance_name)
            target.parameters["trace-file"] = file_name  
    
    
jenkins_home = os.environ['JENKINS_HOME']

plugin_path = str(jenkins_home)+"/plugins/ITMtrace.so"  
model_path = str(jenkins_home)+"/m4_system/model/cadi_system/cadi_system_Linux64-Release-GCC-5.4.so"
app_path = str(jenkins_home)+"/m4_system/app_helloWorld/startup_Cortex-M4.axf"
out_path = str(jenkins_home)+"/output.txt"

# Set Environmental variable
os.environ["FM_TRACE_PLUGINS"] = plugin_path
# Load model
model = fm.debug.LibraryModel(model_path)
# Get cpu
cpu = model.get_cpus()[0]
# Load app onto cpu
cpu.load_application(app_path)

# Send ITM to stdout
ITM_redirect(out_path)

# Run the model, exit after timeout.
try:
    model.run(timeout=1)
except:
    sys.exit(0)

When you run this Python script in the created container, you generate a new file called output.txt0 with some welcome messages. The 0 at the end of the filename indicates that ITM channel 0 was the used channel. This screenshot shows the commands and their respective outputs:

The file output.txt0 is created after running the test, which contains a welcome message and the traditional "Hello World!". In this case, the creation of file output.txt0 indicates that the Hello world application ran successfully. This indication is verified by the command head output.txt0 returning the contents of the generated file. A more complicated application might generate multiple files based on some given input, or any other test application that is used to verify code integrity.

Moving to automation

Having one Docker image to share between a team creates a reliable and consistent development environment to operate in. To get the most benefits out of the Docker platform, automating these test runs will be introduced in Introduction to Jenkins.

Automation adds additional benefits, like saving time and version control management. In the following sections of the guide, we will explain Jenkins and set up a working example.

Previous Next