Subtopic•What is Docker

Containerization Overview

Before you can understand Docker, you need to understand what containerization is and the problem it solves.

Imagine you are a DevOps engineer and a developer comes to you saying: "The application works perfectly on my laptop, but it crashes on the server."

You have probably heard this before. It is one of the most common problems in software development. The root cause is almost always the same — the laptop and the server have different environments. Different operating system versions, different library versions, different configurations.

Containerization is the solution to this problem.

Containerization is a method of packaging an application together with everything it needs to run — its code, runtime, libraries, environment variables, and configuration files — into a single, self-contained unit called a container.

Once you package an application into a container, it runs the same way everywhere. On your laptop, on a server, on AWS, on a colleague's machine — the behavior is identical because the environment inside the container is always the same.

The Problem Before Containerization

To truly appreciate containerization, you need to understand what life looked like before it.

The Traditional Deployment Problem

In the early days, deploying an application meant:

  1. Setting up a physical server or a virtual machine
  2. Installing the operating system
  3. Installing the correct version of the language runtime (Python 3.8, Node.js 14, Java 11, etc.)
  4. Installing all the dependencies the application needs
  5. Configuring environment variables
  6. Deploying the application code
  7. Hoping that everything matches what the developer tested on locally

This process was slow, error-prone, and impossible to repeat consistently. Each server became a unique snowflake — slightly different from every other server in ways that were hard to track and fix.

The "It Works on My Machine" Problem

Developers work on their laptops. Operations teams deploy to servers. The laptop and the server have different:

  • Operating system versions
  • Library versions
  • System configurations
  • Environment variables

A developer might have Python 3.9 installed locally, but the server runs Python 3.7. A library that works in 3.9 might not exist or behave differently in 3.7. The application breaks in production, but the developer cannot reproduce the bug locally.

This is the "works on my machine" problem. It costs teams enormous amounts of time debugging issues that should never exist in the first place.

The Dependency Conflict Problem

Imagine you have two applications on the same server:

  • App A requires Python 3.7
  • App B requires Python 3.9

You cannot install both versions of Python on the same machine without complex workarounds. The two applications conflict with each other. Traditionally, you would need two separate servers — one for each application. This wastes money and adds management overhead.


What is a Container?

A container is a lightweight, isolated environment that runs your application.

Think of a container like a shipping container on a cargo ship. Before shipping containers were invented, loading cargo onto a ship was slow and chaotic — every piece of cargo was different shapes and sizes, and workers had to figure out how to pack everything manually.

Shipping containers changed everything. Now every piece of cargo gets packed into a standard-sized metal box. The ship does not care what is inside — it just loads and unloads boxes. Trucks, trains, and cranes all know how to handle the standard box. The contents are isolated from the outside world and arrive exactly as packed.

Software containers work the same way. Your application gets packed into a standard container. The server does not care what language the app is written in or what libraries it needs. It just runs containers. The application inside is isolated and behaves exactly the same wherever the container runs.

A container includes:

  • Your application code
  • The runtime (Python, Node.js, Java, Go, etc.)
  • Libraries and dependencies the application needs
  • Environment variables and configuration
  • A minimal filesystem to support the application

A container does NOT include:

  • A full operating system
  • A kernel
  • Hardware drivers

This is what makes containers lightweight. They share the host operating system's kernel but run in their own isolated space.


How Containerization Works

Containers use features built into the Linux kernel to create isolation. The two key technologies are:

Linux Namespaces

Namespaces create isolation for different system resources. Each container gets its own:

  • Process namespace — the container can only see its own processes, not the host's processes
  • Network namespace — the container gets its own network interface and IP address
  • Filesystem namespace — the container sees its own filesystem, separate from the host
  • User namespace — the container can have its own user IDs

From inside a container, it looks like you have an entire machine to yourself. You cannot see or interact with other containers or the host system (unless you explicitly allow it).

Control Groups (cgroups)

Control groups limit how much of the host's resources a container can use:

  • CPU — you can limit a container to use only 50% of one CPU core
  • Memory — you can set a maximum RAM limit of 512MB for a container
  • Disk I/O — you can limit how fast a container reads and writes to disk
  • Network bandwidth — you can control how much network traffic a container can generate

This prevents one container from consuming all the resources on a host and starving other containers — a problem known as the "noisy neighbor" problem.


Containers vs Processes

A container is essentially a process (or group of processes) running on the host machine, but with enforced isolation and resource limits.

When you run a containerized web server, the web server process is running on the host machine. But it thinks it is running alone on its own machine. It has its own filesystem, its own network, its own processes — all thanks to Linux namespaces and cgroups.

This is fundamentally different from a virtual machine, where the isolation happens at the hardware level (we cover this in the next file).


A Practical Example

Here is what containerization looks like in practice.

You have a Python Flask web application. Without containerization, deploying it means:

# On every server, manually:
sudo apt-get install python3.9
pip install flask==2.0.1
pip install sqlalchemy==1.4.0
pip install requests==2.26.0
export DATABASE_URL="postgresql://user:pass@db:5432/myapp"
python app.py

If any version is different between servers, you get bugs.

With containerization, you define everything the app needs in a single file:

FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

ENV DATABASE_URL="postgresql://user:pass@db:5432/myapp"

CMD ["python", "app.py"]

Now you build this into a container image once. That image runs identically:

  • On your laptop
  • On your staging server
  • On your production server on AWS
  • On your colleague's machine

The environment is baked into the container. There is no "it works on my machine" problem because the machine IS the container.


Benefits of Containerization

Consistency Across Environments

Since the container carries its own environment, it behaves identically everywhere it runs. Development, staging, and production use the exact same container image. If it works in testing, it works in production.

Speed of Deployment

Containers start in milliseconds. A virtual machine takes minutes to boot up. When you need to scale your application rapidly to handle a traffic spike, containers let you do it almost instantly.

Efficient Resource Usage

Containers are lightweight because they share the host OS kernel. You can run dozens or even hundreds of containers on a single server that could only run a handful of virtual machines. This dramatically reduces your AWS bill.

Isolation Without Overhead

Each container is isolated from others. A bug in one container does not bring down other containers. Two applications with conflicting dependencies can run side by side because each is in its own container with its own dependencies.

Faster CI/CD Pipelines

In a CI/CD pipeline, you can build a container image once and push it through your pipeline. The same image gets tested, then promoted to staging, then to production. No rebuilding, no environment differences.

Developer pushes code
        ↓
CI pipeline builds container image
        ↓
Image is tested (unit tests, integration tests)
        ↓
Same image deployed to staging
        ↓
Same image deployed to production on AWS ECS or EKS

Microservices Architecture

Containerization makes microservices practical. Each service runs in its own container with its own dependencies. Services can be written in different languages and deployed independently. A Python service and a Node.js service can run side by side without conflict.


Containerization in DevOps

Containerization is a foundational technology in modern DevOps. It enables:

  • Immutable infrastructure — instead of modifying servers, you replace containers with new versions
  • Infrastructure as Code — container definitions (Dockerfiles) are code that lives in Git
  • Faster releases — teams can ship changes multiple times per day because the container handles the environment consistency
  • Easier rollbacks — if a new container version has a bug, you roll back to the previous container image in seconds
  • Cloud-native applications — platforms like AWS ECS, AWS EKS, and Kubernetes are built around containers

When you deploy a containerized application to AWS, you can use:

  • Amazon ECS — AWS's managed container orchestration service
  • Amazon EKS — managed Kubernetes on AWS
  • AWS Fargate — serverless container execution (no servers to manage at all)

All of these services only work with containers. If you want to run applications on modern cloud platforms, you need to understand containerization.


Summary

  • Containerization packages an application together with everything it needs to run into a single isolated unit called a container
  • Before containerization, "it works on my machine" was a constant problem caused by environment differences between developer laptops and servers
  • Containers use Linux namespaces for isolation and control groups (cgroups) for resource limiting
  • A container is lightweight because it shares the host OS kernel — it does not need a full operating system
  • Containers bring consistency, speed, resource efficiency, and isolation to software deployment
  • Containerization is the foundation of modern DevOps — enabling CI/CD pipelines, microservices, and cloud-native deployments on AWS

In the next file, we compare containers to virtual machines in depth — understanding this difference is essential before you start working with Docker.

←Previous ModuleDocker Overview