Podman Build Image from Dockerfile with Best Practices

Dockerfile is the original terminology, which was introduced by Docker. But CNCF the Cloud Native Computing Foundation had standardized the name to Containerfile. Containerfile is more generic, and  this decision was  because apart from Docker, there are other container solutions as well like Podman.

when we are building Dockerfiles we should know a little bit about parent- child image.  A child image is an image that is created from a parent image and incorporates everything in the parent images. On such example is, if we want to build an image for database application, the image built will be based on MariaDB or MySQL. In this case MariaDB or MySQL is the parent image and the image which we have created for our application will be the child image, which includes everything from the parent image in a different layer. Starting from a parent image makes it a lot easier to create a reliable image

Creating Dockerfile for podman image building

  • Docker file starts with FROM, which identifies the base image to use.
  • Instructions to be executed on that base image is written after the base image declaration
  • The order of instruction in the Dockerfile matters, as the order of execution of the instruction is from top to bottom
  • Each Docker file instruction runs in an independent container, using an intermediate image built from a previous command, which means that adding multiple instructions results in multiple layers
  • As a generic rule of thumbs, the number on the layers on the image should be minimal

Each project will have its own project Directory, where we will be creating the Dockerfile and its dependent requirement in that directory. For this exercise we have created a directory called podman_tut. Inside the directory i have my docker file and one other dependent file which i want to place in my image

Below code snippet shows the directory content and the dockerfile content

[root@localhost podman_tut]# pwd
/root/podman_tut
[root@localhost podman_tut]# ll
total 4
-rw-r--r--. 1 root root 205 Feb 11 15:27 Dockerfile
-rw-r--r--. 1 root root 0 Feb 11 15:23 sample_file.repo
[root@localhost podman_tut]# cat Dockerfile
FROM ubi
MAINTAINER Admin <[email protected]>

#Add file from local
ADD ./sample_file.repo /etc/yum.repos.d/

#Install extra rpms required

RUN yum -y install bash nmap && \
yum clean all

ENTRYPOINT ["/bin/bash"]
#CMD
  • From the docker file it can be seen that the docker file starts by defining a base image by using keyword "FROM". In our case, we will be using ubi image
  • We are using MAINTAINER keyword to specific the details of the maintainer and their email address
  • ADD keyword is used to add a fie from local machine/project directory (current directory) to the a path in the image. In our case we are placing a repo file "sample_file.repo" to /etc/yum.repos.d/ directory of the image
  • RUN command can be used to run other bash commands in the image. In our case we are using yum to install rpms
  • ENTRYPOINT defines the default command that will be running on the container.
  • CMD keyword is used to add argument to the ENTRYPOINT command, in our case we are not having any arguments so it left commented

Podman Build Image from Dockerfile

Podman image building with Dockerfile can be done by executing podman build . Podman build takes two arguments: -t name[:tag] directory.
Unless otherwise specfied, latest tag will be added to the images. Below is the sample command

podman build -t myimage .

Below code snippet shows the podman image building

[root@localhost podman_tut]# podman build -t linuxdataimage .
STEP 1/5: FROM ubi
STEP 2/5: MAINTAINER Admin <[email protected]>
--> 8fce1de157c
STEP 3/5: ADD ./sample_file.repo /etc/yum.repos.d/
--> 815f6126f4a
STEP 4/5: RUN yum -y install bash nmap && yum clean all
Updating Subscription Management repositories.
Unable to read consumer identity
Subscription Manager is operating in container mode.
--> a2ae480d837
STEP 5/5: ENTRYPOINT ["/bin/bash"]
COMMIT linuxdataimage
--> 3dd0d9ab3bf
Successfully tagged localhost/linuxdataimage:latest
3dd0d9ab3bffc2f84dea1806ff935670251f2330b9565a37646652c6e1e47cdf

podman image ls will show the built image in the local repository

[root@localhost podman_tut]# podman image ls
REPOSITORY                      TAG   IMAGE ID      CREATED                      SIZE
localhost/linuxdataimage latest 3dd0d9ab3bff About a minute ago 260 MB

Dockerfile Instructions

Apart from the keywords, which we have used for building our docker image, there are different other dockerfile instructions. We will see some of the common used dockerfile keywords

  • FROM identifies the base image to use
  • LABEL is an optional  key-value pair that is used for identification
  • MAINTAINER is the name of the person who maintains the image
  • RUN executes commands on the FROM image while building the image
  • EXPOSE has metadata only information on where the image should run
  • ENV defines environment variables to be used within the container
  • ADD copies files from the project directory to the image
  • COPY also copies files from the local project directory to the image, using ADD is preferred, as ADD offers more flexibility
  • USER specifies username for RUN, CMD and ENTRYPOINT instructions
  • ENTRYPOINT has the default command to be processed
  • CMD can have the default command, as well as arguments to the ENTRYPOINT command

Best Practices in Container Image Creation

Exec form is preferred

  • Options like ADD, COPY, ENTRYPOINT, CMD are used in shell form and in exec form
  • In Shell form, it is a list of items
    • ADD /my/file /mydir
    • ENTRYPOINT /usr/bin/nmap -sn 172.17.0.0/24
  • Exec form, it is a json array of items
    • ADD ["/my/file","/mydir"]
    • ENTRYPOINT["/usr/bin/nmap","-sn","172.17.0.0/24"]
  • Using Exec form is preferred, as shell form wraps command in a /bin/sh -c shell, which sometimes creates unnecessary shell process

Avoid Multi-layer Images

  • Each command used in a Dockerfile creates a new layer and this should be avoided
  • It should be noted that, each RUN command in the docker file will add an additional layer to the image
  • Use && to run multiple commands in a single RUN keyword
RUN yum --disablerepo=* --enablerepo="myrepo" && yum update -y && yum install nmap
  • When we use && for executing multiple commands, the length of the command will increase. To maintain readability, write the commands on different lines used && \ at the end of each line.
RUN yum --disablerepo=* --enablerepo="myrepo" && \ 
yum update -y && \
 yum install nmap

Clean yum caches and remove documenation

  • When installing software from  a Dockerfile, use dnf clean all -y to clean yum caches.
  • Exclude documentation as well as unnecessary dependencies from the container image. We  can use --nodocs for no documentation and --setopt install_weak_deps=False, that works with dnf install, and it makes sure that the number of dependencies installed will be minimized
RUN dnf install -y httpd --nodocs --setopt install_weak_deps=False

Base image Selection

  • While selection base image for FROM dockerfile instruction, use a minimal base image, if we are planning to use ubi image, instead of using regular ubi image, use ubi-minimal

Search on LinuxDataHub

Leave a Comment