EX180 Series: Using Podman to Build Images and Run Containers

Part 2 of the EX180 series.

The Plan

We are going to have a look at the EX180 exam objectives for Podman, review commands for Dockerfile and perform 4 hands-on tasks to get familiar with an image creation process.

Pre-requisites

A Red Hat account is required in order to access Red Hat Developer portal and Red Hat Quay image repository.

Exam Objectives: Podman

These are official EX180 objectives related to Podman (we will not cover any OpenShift objectives in this article).

You should be able to implement images using Podman:

  1. Understand and use FROM (the concept of a base image) instruction.
  2. Understand and use RUN instruction.
  3. Understand and use ADD instruction.
  4. Understand and use COPY instruction.
  5. Understand the difference between ADD and COPY instructions.
  6. Understand and use WORKDIR and USER instructions.
  7. Understand security-related topics.
  8. Understand the differences and applicability of CMD vs. ENTRYPOINT instructions.
  9. Understand ENTRYPOINT instruction with param.
  10. Understand when and how to expose ports from a Docker file.
  11. Understand and use environment variables inside images.
  12. Understand ENV instruction.
  13. Understand container volume.
  14. Mount a host directory as a data volume.
  15. Understand security and permissions requirements related to this approach.
  16. Understand lifecycle and cleanup requirements of this approach.

You should be able to manage container images:

  1. Understand private registry security.
  2. Interact with many different registries.
  3. Understand and use image tags.
  4. Push and pull images from and to registries.
  5. Back up an image with its layers and meta data vs. backup a container state.

You should be able to run containers locally using Podman:

  1. Get container logs.
  2. Listen to container events on the container host.
  3. Use Podman inspect.

In order to get started, let’s see what a Dockerfile is, and perform a couple of tasks that would cover the Podman objectives.

What is a Dockerfile?

In order to implement images using Podman, you need to be able to write a Dockerfile.

A Dockerfile is a text document that contains all the commands to build an image. We will discuss several important commands here, however, we are not going to cover all available commands that one could use in a Dockerfile. For that, please take a look at this brilliant Dockerfile reference https://docs.docker.com/engine/reference/builder/.

When writing a Dockerfile, the first non-comment instruction must be a FROM instruction to specify the base image.

ADD instruction copies files or folders from a local or remote source and adds them to the container’s file system. If you are copying local files, the files must be in the working directory. If you are copying local compressed .tar files, these files will be unpacked to the destination image directory.

COPY copies files from the local source (working directory) and adds them to the container’s file system (similar to ADD). It does not however copy remote files nor unpack .tar files.

EXPOSE indicates that the container listens on the specified TCP port at runtime (unless you specify UDP), however, it does not publish the port and it does not make the port accessible from the host.

WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it.

USER instruction sets the user name (or UID) to use as the default user for the remainder of the current stage. The specified user is used for RUN instructions and at runtime, runs the relevant ENTRYPOINT and CMD commands. You should never run as root but use a dedicated user for your containers instead.

Important: both instructions ADD and COPY copy source files with root as the owner, even if the USER instruction is specified. What that means is that all new files and directories are created with a UID and GID of 0 by default.

ENTRYPOINT instruction allows you to configure a container that will run as an executable. ENTRYPOINT can define both the command to be executed and the parameters.

CMD instruction provides defaults for an executing container.

There should be at most one ENTRYPOINT and one CMD instruction.

Now that we are somewhat familiar with Dockerfile commands, let us containerise a simple Java application.

Podman Task 1: Containerise a JBoss Application

Write a Dockerfile to containerise a JBoss EAP 7.4 application to meet all of the following requirements (listed in no particular order):

  1. Use the latest version of Red Hat Universal Base Image 8 ubi8 from the registry registry.access.redhat.com as a base.
  2. Install the java-1.8.0-openjdk-devel package.
  3. Create a system group for jboss with a GID of 1100.
  4. Create a system user for jboss with a UID 1100.
  5. Set the jboss user’s home directory to /opt/jboss.
  6. Set the working directory to jboss user’s home directory.
  7. Recursively change the ownership of the jboss user’s home directory to jboss:jboss.
  8. Expose port 8080.
  9. Make the container run as the jboss user.
  10. Unpack the jboss-eap-7.4.0.zip file to the /opt/jboss directory.
  11. Set the environment variable JBOSS_HOME to /opt/jboss/jboss-eap-7.4.
  12. Start container with the following executable: /opt/jboss/jboss-eap-7.4/bin/standalone.sh -b 0.0.0.0 -c standalone-full-ha.xml.

Before you start, log in to Red Hat Developer portal and download the jboss-eap-7.4.0.zip file to your working directory. See the weblink below (which requires a Red Hat account):

https://developers.redhat.com/content-gateway/file/jboss-eap-7.4.0.zip

Solution to Podman Task 1

This is how the Dockerfile should look like. Comments are provided for references.

# Use base image
FROM registry.access.redhat.com/ubi8:latest

# Install the java-1.8.0-openjdk-devel package
# We also need the unzip package to unpack the JBoss .zip archive
RUN yum install -y java-1.8.0-openjdk-devel unzip && yum clean all

# Create a system user and group for jboss, they both have a UID and GID of 1100
# Set the jboss user's home directory to /opt/jboss
RUN groupadd -r -g 1100 jboss && useradd -u 1100 -r -m -g jboss -d /opt/jboss -s /sbin/nologin jboss

# Set the environment variable JBOSS_HOME to /opt/jboss/jboss-eap-7.4.0
ENV JBOSS_HOME="/opt/jboss/jboss-eap-7.4"

# Set the working directory to jboss' user home directory
WORKDIR /opt/jboss

# Unpack the jboss-eap-7.4.0.zip file to the /opt/jboss directory
ADD ./jboss-eap-7.4.0.zip /opt/jboss
RUN unzip /opt/jboss/jboss-eap-7.4.0.zip

# Recursively change the ownership of the jboss user's home directory to jbosis:jboss
# Make sure to RUN the chown after the ADD command and and before it, as ADD will
# create new files and directories with a UID and GID of 0 by default
RUN chown -R jboss:jboss /opt/jboss

# Make the container run as the jboss user
USER jboss

# Expose JBoss port
EXPOSE 8080

# Start JBoss, use the exec form which is the preferred form
ENTRYPOINT ["/opt/jboss/jboss-eap-7.4/bin/standalone.sh", "-b", "0.0.0.0", "-c", "standalone-full-ha.xml"]

The task is complete.

Podman Task 2: Build a JBoss Container Image and Run a Container

Use podman command to build a container image using the Dockerfile from task 1 and create a new container from the image to meet all of the following requirements:

  1. Tag the container image as jboss-eap:7.4.0.
  2. Create a new container in detached mode.
  3. Name the container jboss-from-dockerfile.
  4. Port forward from host port 38080 to container port 8080.
  5. Inspect the running container to determine its arguments (Args). You can use the following JSON format: '{{.Args}}'.
  6. Retrieve the last 15 lines of the running container logs.

Solution to Podman Task 2

Make sure that the file jboss-eap-7.4.0.zip has been downloaded and is in the working directory:

$ ls -1
Dockerfile
jboss-eap-7.4.0.zip

Build the image:

$ podman build -t jboss-eap:7.4.0 .

View all local images:

$ podman images
REPOSITORY                       TAG         IMAGE ID      CREATED        SIZE
localhost/jboss-eap              7.4.0       04522ac82423  2 minutes ago  1.45 GB
registry.access.redhat.com/ubi8  latest      16fb1f57c5af  2 weeks ago    214 MB

Run a new container using the image:

$ podman run -d --name jboss-from-dockerfile -p 38080:8080 jboss-eap:7.4.0

Verify that the container is running:

$ podman ps
CONTAINER ID  IMAGE                      COMMAND     CREATED         STATUS             PORTS                    NAMES
a3e1f164097e  localhost/jboss-eap:7.4.0              37 seconds ago  Up 37 seconds ago  0.0.0.0:38080->8080/tcp  jboss-from-dockerfile

Inspect the running container:

$ podman inspect --format '{{.Args}}' jboss-from-dockerfile
[-b 0.0.0.0 -c standalone-full-ha.xml]

Retrieve the last 15 lines of the running container logs:

$ podman logs --tail=5 jboss-from-dockerfile

The task is complete.

Podman Task 3: Save Container Image

Perform all of the following tasks:

  1. Save the jboss-eap:7.4.0 container image to the jboss-eap-7.4.0-backup.tar file.
  2. Update the running jboss-from-dockerfile container and replace the content of the /opt/jboss/jboss-eap-7.4/welcome-content/index.html file with a single word JBOSS.
  3. Stop the running jboss-from-dockerfile container and commit your changes to create a new container image.
  4. The new container image should be called jboss-eap and have a tag of 7.4.0-dev.
  5. Author name of the new container image should be set to “Home Lab”.

Solution to Podman Task 3

Save the image to a file:

$ podman save -o jboss-eap-7.4.0-backup.tar jboss-eap:7.4.0
Copying blob 33204bfe17ee done  
Copying blob ca59617ea9ea done  
Copying blob cf12abd501e1 done  
Copying blob 8b490fc98797 done  
Copying blob f3f0bffa6c8c done  
Copying blob 8c9ee159685e done  
Copying config 04522ac824 done  
Writing manifest to image destination
Storing signatures

Verify that the backup file has been created:

$ ls -1
Dockerfile
jboss-eap-7.4.0-backup.tar
jboss-eap-7.4.0.zip

Connect to the running jboss-from-dockerfile container and update the index file as requested:

$ podman exec -it jboss-from-dockerfile /bin/bash
[jboss@a3e1f164097e ~]$ echo JBOSS > /opt/jboss/jboss-eap-7.4/welcome-content/index.html
[jboss@a3e1f164097e ~]$ cat /opt/jboss/jboss-eap-7.4/welcome-content/index.html
JBOSS
[jboss@a3e1f164097e ~]$ exit

Optionally, verify with curl:

$ curl http://127.0.0.1:38080
JBOSS

Stop the running jboss-from-dockerfile container image:

$ podman stop jboss-from-dockerfile

Commit the changes to a new jboss-eap:7.4.0-dev container image:

$ podman commit --author "Home Lab" jboss-from-dockerfile jboss-eap:7.4.0-dev
Getting image source signatures
Copying blob 33204bfe17ee skipped: already exists  
Copying blob ca59617ea9ea skipped: already exists  
Copying blob cf12abd501e1 skipped: already exists  
Copying blob 8b490fc98797 skipped: already exists  
Copying blob f3f0bffa6c8c skipped: already exists  
Copying blob 8c9ee159685e skipped: already exists  
Copying blob 0a00603d8194 done  
Copying config ec66f8b31b done  
Writing manifest to image destination
Storing signatures
ec66f8b31b6854285f7e5718e80df73d935da59d43afa7fa7eeda9adcbf5a1dc

Verify to make sure that the new image has been created:

$ podman images
REPOSITORY                       TAG         IMAGE ID      CREATED         SIZE
localhost/jboss-eap              7.4.0-dev   ec66f8b31b68  11 seconds ago  1.47 GB
localhost/jboss-eap              7.4.0       04522ac82423  32 minutes ago  1.45 GB
registry.access.redhat.com/ubi8  latest      16fb1f57c5af  2 weeks ago     214 MB

The task is complete.

Podman Task 4: Push and Pull Images from Registries

For this task you are going to need to have a free account on Red Hat’s quay.io repository so that you can push a container image to it. If you don’t have one, feel free to use any other container image registry that you may have an account with (e.g. Docker Hub, AWS ECR etc).

Perform all of the following tasks:

  1. Use podman command to search and locate the docker.io/httpd official container image.
  2. Pull the latest version of the httpd container image from docker.io Docker Hub image repository.
  3. Use podman command to login to a Red Hat’s quay.io image repository.
  4. Tag the httpd image as quay.io/$USERNAME/httpd:1.0-test, where $USERNAME is your quay.io username.
  5. Push the tagged container image to Red Hat’s quay.io repository.

Solution to Podman Task 4

Search for the official httpd image:

$ podman search --filter=is-official docker.io/httpd 
NAME                     DESCRIPTION
docker.io/library/httpd  The Apache HTTP Server Project

Pull the latest version of the httpd image from Docker Hub:

$ podman pull docker.io/httpd:latest
Trying to pull docker.io/library/httpd:latest...
Getting image source signatures
Copying blob b1c114085b25 done  
Copying blob 4691bd33efec done  
Copying blob 9df1012343c7 done  
Copying blob ff7b0b8c417a done  
Copying blob a603fa5e3b41 done  
Copying config 8653efc8c7 done  
Writing manifest to image destination
Storing signatures
8653efc8c72daee8c359a37a1dded6270ecd1aede2066cbecd5be7f21c916770

Login to quay.io container image repository:

$ podman login quay.io
Username:
Password:
Login Succeeded!

Tag the httpd:latest image:

$ podman tag httpd:latest quay.io/lisenet/httpd:1.0-test

Push the image to quay.io image repository:

$ podman push quay.io/lisenet/httpd:1.0-test
Getting image source signatures
Copying blob 7603afd8f9aa done  
Copying blob ec4a38999118 done  
Copying blob a4a57da7ddfc done  
Copying blob a0b242781abd done  
Copying blob 29657939e55a done  
Copying config 8653efc8c7 done  
Writing manifest to image destination
Storing signatures

The task is complete.

What’s Next?

We will look into deploying a multi-container application with Podman.

One thought on “EX180 Series: Using Podman to Build Images and Run Containers

Leave a Reply

Your email address will not be published. Required fields are marked *