Table of Contents
Conceptual View: A Container in One Sentence
A container is a lightweight, isolated runtime environment that packages an application together with everything it needs to run (its file system, libraries, and configuration), while sharing the host operating system kernel with other containers.
It is:
- More than a process, because it has its own file system, network view, and resource limits.
- Less than a virtual machine, because it does not include its own operating system kernel.
Key Characteristics of a Container
1. Isolated but Not Separate Machines
A container is process-level isolation, not a full separate computer.
From inside the container, it looks like you have:
- Your own file system (e.g.,
/,/usr,/bin). - Your own process tree (you may see only a subset of processes).
- Your own network stack (e.g., own IP address, ports).
- Your own users and groups (e.g., a
rootuser inside the container).
But under the hood:
- These processes are just normal processes on the host.
- Isolation is achieved with kernel features such as:
- Namespaces: isolate what a process can see (PIDs, network, mounts, etc.).
- Control groups (cgroups): limit what resources it can use (CPU, memory, I/O).
You will see how containers differ from virtual machines in another chapter; here, the important idea is that containers are isolated views over shared kernel resources.
2. A Complete Runtime Environment
A container is not just a running process; it brings its own runtime environment:
- Application binaries and scripts.
- Required shared libraries (e.g., specific versions of
glibc, SSL libs). - Language runtimes (e.g., Python, Node.js, Java).
- Configuration defaults.
- Directory structure relevant to that application.
This environment is defined by a container image, which you will see later, but for now:
- Think of the image as the recipe and filesystem snapshot.
- Think of the container as a running instance of that image.
Analogy:
- Image: a class in programming.
- Container: an object (instance) created from that class.
3. Immutable Base + Ephemeral Runtime
Containers encourage an immutable infrastructure style:
- The image is built once and does not change at runtime.
- A running container is expected to be:
- Ephemeral: you can stop, remove, and recreate it at any time.
- Replaceable: instead of patching inside, you build a new image and start a new container.
Direct consequences:
- You do not treat containers like pets (carefully patched servers).
- You treat them like cattle or disposable units:
- If something is wrong, you redeploy.
- Data you want to keep must be stored outside the container’s ephemeral filesystem (e.g., in volumes or external services; those are covered in storage chapters).
4. Predictable and Portable
A container is designed to make software behave the same across:
- A developer’s laptop.
- A test/QA environment.
- A production cluster like OpenShift.
This works because the container includes the application’s own dependencies and environment:
- The host only needs:
- A container runtime (e.g., CRI-O, containerd, Docker engine).
- An appropriate operating system kernel.
Everything else travels with the container image, so:
- “It works on my machine” becomes “it works the same on every machine that runs this container.”
Portability has practical limits (e.g., CPU architecture, kernel features), but for most cloud-native use cases, containers are highly portable.
5. Resource-Constrained Units of Work
A container is a bounded unit of work:
- You can set resource limits:
- CPU shares/cores.
- Memory limits.
- I/O throughput (to some extent).
- If a container exceeds its memory limit, it can be killed by the runtime.
- This makes containers suitable for:
- Packing many workloads on the same node.
- Avoiding “noisy neighbor” issues.
On platforms like OpenShift:
- These resource settings become part of your deployment configuration.
- The platform’s scheduler uses them to decide where containers should run.
6. Minimal by Design
Containers are ideally small and focused:
- A container usually runs one main process (e.g., a web server, worker, database process).
- Supporting processes may exist, but they are there to support the main one.
- If that main process exits, the container is considered finished (exited).
Practical implications:
- Logging is typically done to stdout/stderr instead of writing to local files.
- Background daemons and cron jobs are usually handled differently (e.g., separate containers or platform features).
The single-process focus enables:
- Easier health checking (is the main process alive?).
- Easier restarts and scaling.
- Clear separation of concerns between different parts of an application.
7. Standardized Packaging Format
While different tools exist, most modern containers follow Open Container Initiative (OCI) standards:
- OCI image format: how images are stored, layered, and distributed.
- OCI runtime spec: how containers are run from images.
From a conceptual standpoint:
- A container conforms to a standard packaging format.
- This allows multiple runtimes (CRI-O, containerd, Docker) and platforms (Kubernetes, OpenShift, others) to run the same container images.
You don’t need the low-level details here; what matters is that a container is:
- A standard artifact you can build, push, pull, and run across different environments.
What a Container Is *Not*
To avoid confusion, it helps to be explicit about what containers are not:
- Not a full virtual machine:
- No separate kernel.
- Smaller footprint, faster start, but also different isolation properties.
- Not just a
.tararchive of files: - It also carries metadata: entrypoint, environment, default user, exposed ports, etc.
- Not inherently “more secure”:
- Containers rely heavily on the underlying OS security.
- They reduce attack surface in some ways (smaller images) but introduce new concerns (image provenance, runtime isolation).
- Not long-lived pets:
- Containers are not meant to be manually configured and maintained over time.
- Configuration changes should usually be made by rebuilding the image or updating external configuration objects.
Lifecycle of a Container (High-Level)
Without going into orchestration (that’s for Kubernetes/OpenShift chapters), the basic container lifecycle is:
- Image is available:
- Built from a definition (e.g., Dockerfile, BuildConfig).
- Stored in a container registry.
- Container is created:
- The runtime:
- Sets up namespaces and cgroups.
- Prepares the container filesystem from the image layers.
- Applies configuration (env vars, volumes, ports).
- Container is started:
- The main process specified by the image (
ENTRYPOINT/CMD) runs. - From inside, it behaves as if it has its own small OS environment (but shares the kernel).
- Container runs:
- Handles requests, does computations, etc.
- Emits logs to stdout/stderr.
- May read/write data to:
- Its own ephemeral layer (lost when removed).
- Attached persistent storage or external services (durable).
- Container stops:
- The main process exits (successfully or due to an error).
- Or it is terminated by the platform (e.g., scale down, node drain).
- Container is removed:
- The ephemeral runtime state and temporary filesystem changes are discarded.
- The image remains in the registry for future use unless explicitly removed.
In OpenShift and Kubernetes:
- You rarely manage containers directly.
- You define higher-level objects that describe:
- What images to run.
- How many replicas.
- What resources and configuration they need.
- The platform then creates and manages containers for you.
Why Containers Matter for OpenShift
OpenShift is a container platform. Understanding what a container is clarifies:
- What OpenShift is actually scheduling and running: containers (wrapped in Pods).
- Why images and registries are central concepts in the platform.
- How applications gain portability and consistency: via containerized packaging.
- Why many design patterns (12-factor apps, microservices) fit naturally: they align with the container model of small, focused, immutable units.
Later chapters will:
- Compare containers to virtual machines in more detail.
- Explain container images, registries, and build pipelines.
- Show how orchestrators like Kubernetes and OpenShift manage containers at scale.
For this chapter, the key takeaway is:
A container is a lightweight, portable, isolated runtime environment for an application, created from a container image, sharing the host OS kernel, and designed to be ephemeral, resource-constrained, and easy to deploy consistently across environments.