What Containers Are and Why They Became Dominant
A container is a lightweight, portable software packaging unit that bundles an application with all its dependencies — libraries, configuration files, and runtime environment — into a single artefact that runs consistently on any system that has the container runtime installed. The container isolation provided by Linux kernel features (namespaces and control groups) gives each container its own view of the file system, network, and process space without the overhead of a full virtual machine, enabling containers to start in seconds and consume a fraction of the resources that virtual machine equivalents require.
The software deployment problem that containerisation most effectively solved: the works on my machine problem. The application that works correctly in the developer’s local environment but fails in the staging or production environment due to differences in operating system versions, library versions, configuration, or file paths has been the source of a significant proportion of the deployment failures that software teams have historically spent significant time debugging. The container that packages the application with exactly the environment it was developed and tested in eliminates the environment difference as a source of deployment failures — the container that runs correctly on the developer’s machine runs correctly in every environment where the container runtime is available.
Docker: The Container Standard
Docker’s contribution to making containers practically accessible: the Dockerfile format that specifies how to build a container image (the series of instructions that install dependencies, copy application code, and configure the runtime environment), the Docker image registry ecosystem (Docker Hub and its alternatives) that enables sharing and distributing container images, and the Docker CLI that provides a consistent interface for building, running, and managing containers. Docker standardised the container experience in a way that made the underlying Linux container technology accessible to developers who were not Linux kernel experts, driving the mainstream adoption that earlier container tools had not achieved.
The Docker workflow that most clearly explains how the technology improves the development-to-deployment pipeline: the developer who builds a container image on their laptop, pushes it to a container registry, and deploys it to a production server by pulling the same image has eliminated the environment difference between development and production entirely. The production server runs exactly the same container image that the developer ran locally — the same code, the same dependencies, the same configuration. The deployment that previously required careful coordination of library versions and configuration between environments requires only pulling and running the container image that has already been tested in the development environment.
Kubernetes: Orchestrating Containers at Scale
Kubernetes (K8s) is the open-source container orchestration platform that manages the deployment, scaling, and operation of containerised applications across a cluster of machines. Where Docker addresses the packaging and running of individual containers, Kubernetes addresses the operational challenges that arise when running many containers across many machines: the scheduling decisions about which container should run on which machine, the scaling decisions about how many container instances should run based on current load, the health monitoring that detects and replaces failed containers, the service discovery that enables containers to find and communicate with each other, and the rolling update management that replaces running containers with updated versions without service interruption.
The Kubernetes abstraction that most clearly explains the difference between the container-level thinking of Docker and the cluster-level thinking of Kubernetes: the Pod — the smallest deployable unit in Kubernetes, which wraps one or more containers that should always be scheduled together on the same machine and share the same network namespace and storage volumes. The Pod abstraction enables the common patterns of co-located service and sidecar containers (a main application container and a logging agent container that must run together) while maintaining the isolation between different applications that separate Pod scheduling provides. Kubernetes schedules Pods across the cluster based on resource requests, affinity rules, and available capacity, rather than requiring the operator to manually decide which Pod runs on which machine.
Container Security Considerations
The container security vulnerabilities that most commonly affect containerised applications in production: the vulnerable base image that contains operating system packages with known CVEs (the container image built on an unpatched base image inherits all the vulnerabilities in that base image and carries them into every environment where the image is deployed), the overprivileged container that runs as the root user inside the container (which provides the process running in the container with elevated capabilities that increase the impact of a container escape vulnerability), and the container escape vulnerability in the container runtime that allows a malicious process inside a container to break out and access the host system or other containers.
The container security practice that most efficiently reduces the vulnerability surface of containerised applications: the minimal base image approach that starts from the smallest possible base image that provides only the runtime dependencies the application requires. The container built on an Alpine Linux base image (approximately 5MB) has a dramatically smaller vulnerability surface than the one built on a full Ubuntu base image (approximately 200MB) — the hundreds of operating system packages that Ubuntu includes but that a typical application does not use are each a potential source of CVEs that the Alpine-based container simply does not contain. The distroless base image approach (base images that contain only the application runtime without a package manager or shell) reduces the attack surface even further by removing the tools that an attacker who achieves container access would use to explore and pivot.
When to Use Docker Without Kubernetes
The deployment scenario where Docker provides significant value without the additional complexity of Kubernetes: the single-server or small-scale deployment where the orchestration capabilities of Kubernetes (multi-node scheduling, automatic scaling, complex networking) are not required. The web application that runs on a single VPS, the internal tool that needs to be deployed consistently across developer machines, and the CI/CD pipeline that builds and tests code in consistent container environments all benefit from Docker’s packaging and environment consistency without needing the cluster management capabilities of Kubernetes.
The Kubernetes adoption decision framework that most clearly indicates when the orchestration complexity is justified: the scale at which the manual equivalents of Kubernetes’s automated functions consume significant operational effort. The team that is manually restarting failed containers, manually scaling application instances in response to load, and manually managing which services are accessible to which other services has outgrown what Docker alone can provide and has a clear operational motivation to adopt Kubernetes’s automation of these functions. The team whose containerised application runs on one or two servers with stable load and simple deployment requirements benefits from Docker’s simplicity without the orchestration infrastructure that Kubernetes requires.
