Operations 21 min read

Master Dockerfile: Essential Commands and Best Practices for Building Efficient Images

This article explains how Docker images are created, introduces Dockerfile syntax and key instructions such as FROM, COPY, RUN, CMD, and ENTRYPOINT, and provides practical guidelines and real‑world examples for building clean, lightweight containers.

Raymond Ops
Raymond Ops
Raymond Ops
Master Dockerfile: Essential Commands and Best Practices for Building Efficient Images

Image Generation Methods

Image
Image

About Dockerfile

Dockerfile is the source code for building Docker images; it is a plain‑text file.

When building an image from a Dockerfile, the file must reside in a specific directory. The filename must start with a capital "D". To exclude files from the build context, a

.dockerignore

file can be defined. Finally,

docker build

creates the image.

Dockerfile Instructions

FROM

FROM is the first non‑comment line in a Dockerfile and specifies the base image for the build.

The base image can be any available image; if it does not exist locally, Docker pulls it from Docker Hub.

If the image cannot be found,

docker build

returns an error.

Syntax:

FROM [image[:tag]]

or

FROM image@digest

MAINTAINER (deprecated)

Provides author information; placement is not restricted but is usually placed after FROM.

Syntax:

MAINTAINER "Name <[email protected]>"

LABEL

Syntax:

<code>LABEL key=value key=value ...</code>

COPY

Copies files from the build context into the image.

Syntax:

COPY src dest

or

COPY ["src", "dest"]

If the destination path contains spaces, the JSON form should be used.

Files must be inside the build context; directories are copied recursively but the directory itself is not created unless it already exists.

ADD

Similar to COPY but also supports extracting TAR archives and downloading from URLs.

Syntax:

ADD src dest

or

ADD ["src", "dest"]

WORKDIR

Sets the working directory for subsequent RUN, CMD, ENTRYPOINT, COPY and ADD instructions.

Syntax:

WORKDIR /path

VOLUME

Creates a mount point inside the image.

Syntax:

VOLUME /path

or

VOLUME ["/path"]

EXPOSE

Documents which ports the container listens on.

Syntax:

EXPOSE 80/tcp 443/tcp

ENV

Defines environment variables for later instructions.

Syntax:

ENV VAR=value

or

ENV VAR1=value1 VAR2=value2

RUN

Executes commands during image build.

Two forms: shell form

RUN command

and exec form

RUN ["executable","param1","param2"]

CMD

Specifies the default command to run when a container starts.

Only the last CMD in the Dockerfile takes effect.

Syntax similar to RUN.

ENTRYPOINT

Defines a container's main executable; arguments from

docker run

are appended.

Unlike CMD, ENTRYPOINT cannot be overridden unless

--entrypoint

is used.

Only the last ENTRYPOINT is effective.

USER

Specifies the user (or UID) under which subsequent instructions run.

Default user is root.

HEALTHCHECK

Defines a command to test container health.

Options include

--interval

,

--timeout

,

--retries

, and

--start-period

.

Only the last HEALTHCHECK is used.

ONBUILD

Registers a trigger instruction that runs when the image is used as a base for another build.

Cannot be nested and does not trigger FROM or MAINTAINER.

Basic Dockerfile Guidelines

Containers should be short‑lived (ephemeral).

Use

.dockerignore

to exclude unnecessary files (syntax same as

.gitignore

).

Prefer multi‑stage builds to reduce final image size.

Avoid installing unnecessary packages.

Each container should do one thing; separate services into separate containers.

Only RUN, COPY, and ADD create image layers; minimize layer count.

Order instructions to maximize cache reuse; use

--no-cache

to force rebuild.

Dockerfile Examples

Build an sshd image

<code># Dockerfile
FROM centos:centos7
LABEL maintainer="hukey<[email protected]>"
RUN yum install -y openssh* net-tools iproute NetworkManager && \
    echo "UseDNS no" >> /etc/ssh/sshd_config && \
    sed -i '/pam_loginuid.so/d' /etc/pam.d/sshd && \
    echo '123123' | passwd --stdin root && \
    ssh-keygen -A && yum clean all
EXPOSE 22
CMD ["/usr/sbin/sshd","-D"]
</code>

Build a systemd image (based on the sshd image)

<code># Dockerfile
FROM sshd:v0.1-2
LABEL maintainer="hukey<[email protected]>"
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done) && \
    rm -f /lib/systemd/system/multi-user.target.wants/* && \
    rm -f /etc/systemd/system/*.wants/* && \
    rm -f /lib/systemd/system/local-fs.target.wants/* && \
    rm -f /lib/systemd/system/sockets.target.wants/*udev* && \
    rm -f /lib/systemd/system/sockets.target.wants/*initctl* && \
    rm -f /lib/systemd/system/basic.target.wants/* && \
    rm -f /lib/systemd/system/anaconda.target.wants/*
VOLUME ["/sys/fs/cgroup"]
CMD ["/usr/sbin/init"]
</code>

Build an nginx image

<code># Dockerfile
FROM centos:centos7
LABEL maintainer="hukey<[email protected]>"
ENV NGX_PACKAGE="nginx-1.18.0"
ADD http://192.168.118.45/${NGX_PACKAGE}.tar.gz /usr/local/src/
WORKDIR /usr/local/src/${NGX_PACKAGE}
RUN tar xf /usr/local/src/${NGX_PACKAGE}.tar.gz && \
    yum install -y proc-devel gcc gcc-c++ zlib zlib-devel make openssl-devel wget && \
    ./configure --prefix=/usr/local/nginx \
        --with-http_ssl_module \
        --with-http_gzip_static_module \
        --with-http_stub_status_module \
        --with-http_realip_module && \
    make -j2 && make install && \
    echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf && yum clean all && rm -rf /var/cache/yum/*
EXPOSE 80/tcp 443/tcp
ADD run.sh /run.sh
CMD ["/run.sh"]
</code>

Build a tomcat image

<code># Dockerfile
FROM centos:centos7
LABEL maintainer="hukey <[email protected]>"
ADD jdk-8u77-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-8.5.61.tar.gz /usr/local/
ENV JAVA_HOME="/usr/local/java" \
    JAVA_BIN="/usr/local/java/bin" \
    JRE_HOME="/usr/local/java/jre" \
    PATH="$PATH:/usr/local/java/bin:/usr/local/java/jre/bin" \
    CLASSPATH="/usr/local/java/jre/bin:/usr/local/java/lib:/usr/local/java/jre/lib/charsets.jar"
WORKDIR /usr/local/
RUN mv jdk1.8.0_77 java && mv apache-tomcat-8.5.61 tomcat8
EXPOSE 8080
ENTRYPOINT ["/usr/local/tomcat8/bin/catalina.sh","run"]
</code>

These examples illustrate how to define base images, set environment variables, copy files, expose ports, and combine

CMD

and

ENTRYPOINT

for flexible container startup.

Dockerbest practicesMulti‑Stage BuildDockerfileContainer Images
Raymond Ops
Written by

Raymond Ops

Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.