Building a Beautiful Docker Image for OpenShift
Small Tips!
There are some practices that OpenShift Container Platform recommends to follow them. Here, guidelines that apply when creating container images if you use OpenShift Container Platform.
First
What does mean by beautiful Docker image?
Minimal size, Security and Performance.
Dockerfile Instructions
RUN
The RUN
instruction executes commands in a new layer on top of the current image and then commits the results to be used in the next step. In Dockerfile, each instruction is a new layer; that means if you have instructions like this:
RUN pip install virtualenv
RUN virtualenv /venv
RUN . /venv/bin/activate
RUN pip install setuptools -U
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
Then, you will be have image with 6 layers resulting in images that are unnecessarily large. Therefore, it’s important that you minimized the number of layers in your images to ensure getting the best performance which are faster to deploy. For example, to have the minimal layers from the previous example use && command separator to execute multiple commands within a single RUN
instruction:
RUN pip install virtualenv && virtualenv /venv && \
. /venv/bin/activate && \
pip install setuptools -U && \
pip install --upgrade pip && \
pip install -r requirements.txt
Now, it produces only one layer.
With Docker v1.10 and later, only the
RUN
,COPY
, andADD
instructions create layers.
LABEL
The LABEL
instruction is key-value pairs that contains the metadata of image such as versions, description, name, and any other details. In OpenShift, the label name prefix with io.openshift
and for Kubernetes io.k8s
. The below table is showing some of the most commonly used tags:
It recommends to use only one instruction for all labels and separate each key-value pair with an equal sign (=) like this:
LABEL description="This is an example for label uses" \
version="1.0" \
creationDate="26-01-2021"
WORKDIR
The WORKDIR
instruction is working directory path. It’s recommended to use it instead of multiple RUN
instructions to help in maintaining, read and troubleshoot.
ENV
The ENV
instruction is environment variables provided to the container. If you have for example web application that contains two docker images, one image is back-end and the other is front-end and you need to write IP back-end’s IP in front-end’s then using ENV
is the best way to define the IP if the IP changes or you want to use the image in different place instead of hard-coding it. Similar to LABEL
to specify multiple environment variables use layering concept, separate each key-value pair with an equal sign (=):
ENV MYSQL_DATABASE_USER="my_database_user" \
MYSQL_DATABASE="my_database"
USER
For security reason, run your image as a non-root user. By default OpenShift uses Security Context Constraints (SCCs) which allow administrators to control permissions for pods named restricted
. Therefore, it makes OpenShift uses a random userid other than the root userid (0) to run containers. To enable use root user, you need to use the anyuid
SCC. First, create a service account bound to a pod:
oc create serviceaccount sa-name
Then as cluster-admin, associate the service account with an SCC:
oc adm policy add-scc-to-user anyuid -z sa-name
Finaly, assign the service account to the deployment:
oc set serviceaccount deployment deployment-name sa-name
The folders and files in the container should be owned by the root group so, you have to add RUN instruction to change group ID and permissions to access them in the container:
RUN chgrp -R 0 /some-path && \
chmod -R g=u /some-path
Use the root group minimizes security risks since it does not have any special permissions. Moreover, use group execute permissions for files that shuld be executed. In addition, since the processes running in container as a privileged user; they must not listen on privileged ports (ports below 1024).
VOLUME
Use VOLUME
instructions for persistent data to create a mount point inside the container.
ONBUILD
The ONBUILD
instruction triggers only when building a child image. It executes before any command in a child Dockerfile. ONBUILD
useful to automate the build if you need to used as the base for another build.
😘
References: