Table of Contents
Docker as a Container Engine
Docker is one of the most widely used tools for building, running, and distributing containers. While OpenShift and modern Kubernetes-based platforms often use other runtimes under the hood (like crio or containerd), Docker is still useful as a teaching tool to understand:
- How container images are built
- How containers are started from images
- How images are stored and shared via registries
At a high level, Docker provides:
- A daemon (
dockerd) that manages images and containers - A CLI (
docker) to interact with that daemon - An image format and build system (Dockerfile)
- Integration with container registries (public or private)
You’ll later see how these same concepts appear in OpenShift using different tools and commands, but the ideas remain very similar.
What Is a Container Image?
A container image is:
- A read-only template that includes:
- The filesystem contents: application binaries, libraries, configuration files, runtime (e.g., Python, Java), tools
- Metadata: environment variables, default command, exposed ports, entrypoint, labels
- A versioned artifact that can be stored in a registry and pulled to any host that has a compatible container runtime
A container at runtime is essentially:
container = image + writable layer + runtime configuration
The image itself is immutable; any changes a running container makes (logs, temporary files, etc.) go into a separate, writable layer on top of the image.
Image Layers
Docker images are layered. Each instruction in a Dockerfile typically creates a new layer. Layers are:
- Stacked to form the final filesystem
- Content-addressed (identified by a hash)
- Shared between images when identical
Layering enables:
- Re-use: many images can share the same base OS layer
- Smaller downloads: you only pull layers you don’t already have
- Efficient builds: unchanged layers can be cached
Conceptually, an image might look like:
- Layer 1: Base OS (
ubuntu:22.04) - Layer 2: Installed packages (
apt-get install python3) - Layer 3: Application dependencies (
pip install -r requirements.txt) - Layer 4: Application code (
COPY . /app)
Each layer is read-only, and at runtime Docker adds a writable layer on top to create the container’s root filesystem.
Docker Image Naming and Tagging
Images are referenced using a structured name:
REGISTRY/USER_OR_ORG/REPOSITORY:TAG
Examples:
nginx:latest
(implicitlydocker.io/library/nginx:latest)quay.io/openshift/origin-cli:4.14registry.example.com/myteam/myapp:1.0.3
Components:
- Registry: where the image is stored (
docker.io,quay.io,registry.redhat.io, or a private registry) - Repository: logical name of the image (
nginx,myapp) - Tag: label that usually encodes a version (
1.0.3,4.14,prod,latest)
Tags are important for:
- Versioning your application images
- Distinguishing dev/test/prod variants
- Enabling rollbacks and reproducible deployments
Basic Docker CLI Workflow (Conceptual)
Even if you don’t run Docker directly in OpenShift, understanding the Docker-style workflow helps you understand image lifecycles.
Typical lifecycle:
- Build an image from a Dockerfile:
docker build -t myapp:1.0 .- Run a container from the image:
docker run --name myapp-container -p 8080:8080 myapp:1.0- Tag the image for a registry:
docker tag myapp:1.0 registry.example.com/myteam/myapp:1.0- Push the image to a registry:
docker push registry.example.com/myteam/myapp:1.0OpenShift will later perform similar operations:
- Build: via Source-to-Image (S2I) or Dockerfile builds
- Run: via Kubernetes Pods and Deployments
- Push/Pull: to and from container registries
Dockerfile Basics
A Dockerfile is a text file that describes how to build an image. Docker reads it and executes each instruction in order, creating layers along the way.
Typical structure:
- Choose a base image
- Install dependencies and tools
- Copy application code
- Configure runtime (ports, environment)
- Define the container’s default command
Example: a simple Python web app
# 1. Base image
FROM python:3.11-slim
# 2. Set working directory
WORKDIR /app
# 3. Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 4. Copy application code
COPY . .
# 5. Expose port and set default command
EXPOSE 8080
CMD ["python", "app.py"]Key instructions (conceptually):
FROM: sets the parent/base image; the first layer you start fromRUN: executes a command at build time and commits the result as a new layer (e.g., installing packages)COPY/ADD: copies files into the imageWORKDIR: sets the working directory for subsequent instructions and the default runtimeEXPOSE: documents which ports the application listens on (for humans and tooling; doesn’t publish ports by itself)CMD/ENTRYPOINT: defines the default process to run in the container
Image Size and Optimization Considerations
Even though this chapter is introductory, a few practical points matter early:
- Base image choice:
- Full OS images (e.g.,
ubuntu,centos) are larger - Minimal images (e.g.,
ubi-minimal,alpine,distroless) are smaller and often more secure - Layer efficiency:
- Combine related operations into a single
RUNwhen appropriate - Clean up temporary files in the same
RUNto avoid bloating layers - Reproducibility:
- Pin dependencies to specific versions
- Avoid relying on non-deterministic
latesttags for base images in production scenarios
These choices affect:
- Pull times (how fast workloads start)
- Network usage
- Storage consumption in registries and on cluster nodes
Relationship Between Docker Images and OpenShift
OpenShift does not require the Docker daemon, but it fully understands Docker/OCI-compatible images:
- Images you build with Docker (or another compatible tool) can run on OpenShift
- OpenShift’s build mechanisms (e.g., S2I, Dockerfile builds) produce container images in essentially the same format
- OpenShift stores and retrieves images from container registries using the same naming, tagging, and layering concepts
In other words:
- Learn Docker image concepts once.
- Apply them across different runtimes and platforms, including OpenShift.
Summary: What You Should Take Away
From this chapter you should be able to:
- Explain what a container image is and how it relates to a running container
- Recognize how layers make image sharing and caching efficient
- Understand image naming and tags as the core of versioning
- Read a simple Dockerfile and understand what each basic instruction does
- See how Docker-style image workflows map naturally to OpenShift’s way of building and running containers