How to Use Dockerfiles: A Practical Introduction for DevOps Engineers

DevOpsDevOps News

YOUR COSMETIC CARE STARTS HERE

Find the Best Cosmetic Hospitals

Trusted • Curated • Easy

Looking for the right place for a cosmetic procedure? Explore top cosmetic hospitals in one place and choose with confidence.

“Small steps lead to big changes — today is a perfect day to begin.”

Explore Cosmetic Hospitals Compare hospitals, services & options quickly.

✓ Shortlist providers • ✓ Review options • ✓ Take the next step with confidence

With Docker images, you can deploy containers quickly without the overhead of full virtual machines. Base images pulled from Docker Hub are useful starting points, but real-world projects almost always require customization — installing packages, setting environment variables, or configuring application defaults. Doing this manually every time is error-prone and slow. That is exactly the problem Dockerfiles solve.

A Dockerfile is a plain-text file containing a sequential set of instructions that Docker uses to build an image automatically and repeatably. Once you have a Dockerfile, rebuilding the same image — or building variations of it — is a single command.

This guide walks through the core Dockerfile instructions, creates a working example, and shows how to build images from it.

Core Dockerfile Instructions

A Dockerfile is named exactly Dockerfile (no extension) and lives in a directory known as the build context. Docker reads it top to bottom when building an image. The following instructions cover the majority of real-world use cases:

InstructionPurpose
FROMSpecifies the base image to build on top of. Every Dockerfile must start with FROM (or ARG before it).
RUNExecutes a shell command during the image build process. Each RUN creates a new image layer.
CMDSets the default command to run when a container starts. Can be overridden at runtime.
ENTRYPOINTSets a fixed executable for the container. Unlike CMD, it is not easily overridden.
ENVDefines environment variables available at build time and runtime.
EXPOSEDocuments which port the container listens on. Does not actually publish the port.
ADDCopies files from the host (or a URL) into the container filesystem. Also auto-extracts tar archives.
COPYCopies files or directories from the build context into the container. Preferred over ADD for simple copies.
WORKDIRSets the working directory for subsequent RUN, CMD, ENTRYPOINT, COPY, and ADD instructions.
USERSets the user (UID or username) that subsequent instructions and the container process run as.
VOLUMECreates a mount point and marks it as holding externally-mounted data.
LABELAdds metadata to an image as key-value pairs (replaces the deprecated MAINTAINER instruction).

You do not need to use every instruction in every Dockerfile. A minimal, functional Dockerfile may use only FROM, RUN, and CMD.

Writing Your First Dockerfile

The example below builds a custom Ubuntu image that is fully updated and has the build-essential package installed — a common starting point for development environments.

Step 1: Create a build directory

mkdir ~/mydockerbuild
cd ~/mydockerbuild

Step 2: Create the Dockerfile

Create a file named Dockerfile in that directory with the following content:

# Dockerfile
FROM ubuntu:latest

LABEL maintainer="Your Name <your.email@example.com>"

RUN apt-get -y update && \
    apt-get -y upgrade && \
    apt-get install -y build-essentialCode language: PHP (php)

A few things worth noting about this Dockerfile:

  • FROM ubuntu:latest — pulls the latest official Ubuntu image as the base. In production, pinning to a specific version (e.g., ubuntu:22.04) is strongly recommended for reproducibility.
  • LABEL maintainer — the modern replacement for the deprecated MAINTAINER instruction. Labels are arbitrary key-value metadata.
  • Chaining RUN commands with && — combining update, upgrade, and install into a single RUN instruction keeps them in one layer, avoiding the cached-stale-index problem that occurs when they are split across separate RUN lines.

Building the Image

With your Dockerfile in place, build the image using docker build. The -t flag tags the image with a human-readable name, and the trailing . tells Docker to use the current directory as the build context.

docker build -t myubuntu-dev .

If you want to build multiple purpose-specific images from the same Dockerfile, simply run the command with different tag names:

docker build -t webdev .
docker build -t appdev .
docker build -t secdev .

The trailing . is required — it defines the build context Docker sends to the daemon.

Verifying your images

Once the build completes, list all locally available images:

docker images

You should see each tagged image listed with its ID, creation time, and size.

Running a Container from Your Image

To start an interactive container from a built image, use docker run:

docker run -it myubuntu-dev /bin/bash
  • -i keeps STDIN open.
  • -t allocates a pseudo-TTY, giving you an interactive shell.
  • /bin/bash is the command to run inside the container.

Best Practices to Keep in Mind

  • Pin base image versions. Using ubuntu:latest means your build may differ between runs as the upstream image changes. Use a specific tag like ubuntu:22.04 for stable, reproducible builds.
  • Minimize layers. Each RUN instruction creates a layer. Combine related commands with && and clean up package manager caches in the same layer (e.g., rm -rf /var/lib/apt/lists/*) to keep image sizes small.
  • Use COPY instead of ADD for simple file copies. ADD has implicit behavior (URL fetching, tar extraction) that can be surprising.
  • Avoid running as root. Use the USER instruction to switch to a non-root user before the final CMD or ENTRYPOINT.
  • Use a .dockerignore file. Similar to .gitignore, this prevents unnecessary files (logs, local configs, node_modules) from being sent to the Docker daemon as part of the build context.

Summary

Dockerfiles give you a declarative, version-controllable way to define exactly what goes into a Docker image. The workflow is straightforward: write a Dockerfile, run docker build -t <name> ., and run docker run against the resulting image. The example above is intentionally simple, but the same principles scale to multi-stage builds, complex microservice images, and CI/CD pipelines where image consistency is critical.

Once you are comfortable with the basics, explore multi-stage builds — a powerful pattern for producing lean production images without separate build environments.

0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x