21.1. Introduction to Containers
Table of Contents
Why Containers Matter for Backend Developers
Containers are a way to package your application with everything it needs so it runs the same way everywhere, from your laptop to production servers.
Traditional deployments often suffer from the “it works on my machine” problem. Your code might rely on specific versions of Python, system libraries, or tools that are not present, or are different, on another machine.
Containers solve this by putting your app and its environment into a single, portable unit.
A container is a lightweight, isolated runtime environment that packages your application code together with its dependencies, but shares the host machine’s operating system kernel.
You will use containers a lot in backend development, especially when:
- Running your API in production
- Running databases like PostgreSQL locally
- Running Redis, message brokers, or workers
- Setting up consistent environments for your team and CI/CD
This chapter focuses on core ideas. Details about Docker, images, and Dockerfiles come later in this section of the course.
Containers vs Virtual Machines
Many beginners confuse containers with virtual machines (VMs). Both isolate applications, but in very different ways.
Conceptual Comparison
| Feature | Virtual Machine | Container |
|---|---|---|
| Isolation | Full OS isolation | Process level isolation |
| Runs its own kernel | Yes | No, shares host kernel |
| Boot time | Slow, often tens of seconds or minutes | Very fast, often under a second |
| Resource usage | Heavy, each VM needs full OS | Light, many containers per host possible |
| Typical use | Running many different OSs on one host | Running many isolated apps on one OS |
With a VM, you install a full operating system inside a virtual machine. With containers, you only package your app plus its user space libraries. The kernel is shared.
An analogy:
- VM: Renting a full house. You get everything, but it is expensive and heavy.
- Container: Renting an apartment in a shared building. You share some infrastructure, but still have your own isolated space.
Container Isolation Basics
Containers rely on operating system features such as:
- Namespaces, to give each container its own view of processes, filesystems, and network
- Control groups (cgroups), to limit CPU and memory usage
From inside a container, it looks like you have your own system, but behind the scenes you are just a set of processes on the host with restricted visibility and resources.
Images and Containers: The Core Concepts
You will see two terms all the time: image and container.
Image vs Container
| Term | What it is | Analogy |
|---|---|---|
| Image | Read-only template that describes a filesystem | Class definition or a cake recipe |
| Container | Running instance created from an image | Object instance or a baked cake |
An image includes:
- Your application code
- Runtime (for example Python, Node.js, Java)
- System tools and libraries your app needs
- A default command to run
A container is:
- A running process or group of processes
- Using the filesystem described by the image
- Attached to isolated network and resources
Rule: You build images and you run containers from those images.
In Docker commands, for example:
- Build an image from a Dockerfile:
docker build -t my-api . - Run a container from that image:
docker run my-api
Layered Images
Container images are built in layers. Each step in the build process adds a new layer.
Example conceptually:
- Start from official base image:
python:3.12-slim - Install system packages
- Copy your application code
- Install Python dependencies
- Set default command
If multiple images share the same base layers, the host can reuse them. This makes images efficient in storage and faster to transfer.
You will see how to define these layers with Dockerfiles in the "Dockerfiles" chapter.
How Containers Help Backend Development
Containers are especially useful for backend work, where many services and dependencies must work together.
Consistent Environments
Backend apps often depend on:
- Database (PostgreSQL)
- Cache (Redis)
- Message broker (RabbitMQ or Redis)
- Web server or application server (Gunicorn, Uvicorn)
- Language runtime and packages
Without containers, setting all this up on each developer’s machine is error prone.
With containers you can:
- Use the same versions across all machines
- Start all services with a single command (often using Docker Compose)
- Ensure that your code runs the same in development, testing, and production
Example scenario:
- You define a
webcontainer for your FastAPI app. - You define a
dbcontainer for PostgreSQL. - Each developer just runs
docker compose upand gets a working environment.
Easy Dependency Management
Inside a container you control exactly:
- Which OS packages are installed
- Which Python version is used
- Which libraries and tools are installed
Example:
- Your app needs
libpqfor PostgreSQL andimagemagickfor image processing. - In the container image you explicitly install these packages.
- On any host system that runs this image, your app has them available.
You are not relying on what is installed on the host machine.
Isolation and Security Benefits
Containers are not a full security boundary like a VM, but they provide isolation that helps:
- Run different applications without them interfering
- Limit damage from a misbehaving app (for example high CPU usage)
- Apply resource limits to avoid one service starving others
For backend developers, this means you can:
- Run a test version of your API next to production, on the same server, in separate containers
- Try new backend services without risking system-wide issues
Basic Container Lifecycle
Even before using Docker commands, it is useful to know the typical lifecycle of a container.
Lifecycle Stages
- Build image
- Define steps in a Dockerfile
- Run a build command to create an image
- Store image
- Locally on your machine
- Remotely in a registry (for example Docker Hub, GitHub Container Registry)
- Run container
- Start a new container from the image
- Attach ports, volumes, environment variables
- Stop container
- Graceful or forced shutdown
- Remove container
- Remove the stopped container if no longer needed
- Update image
- Change code or dependencies, rebuild image, redeploy
Example flow for a FastAPI backend:
- Build image:
mycompany/task-api:1.0.0 - Push image to registry
- On server, pull the image and run container
- When you release version
1.1.0, build a new image and replace the old container with a new one
Important: Containers are ephemeral. Anything you want to keep permanently (databases, uploaded files, logs) should use volumes or external storage, not the container’s internal filesystem.
Containers and Networking
Backend services need to talk to each other and to the outside world. Containers have their own isolated network view.
Key ideas:
- Each container can have its own IP address on a virtual network
- Containers can expose ports that the host can map to its own ports
- Containers can communicate with each other over a virtual network
Common pattern:
- A
webcontainer exposes port8000inside the container - The host maps that internal port to an external port, for example
80or8080 - A
dbcontainer is on the same Docker network and listens on port5432 - The
webcontainer connects todb:5432instead oflocalhost:5432
You will learn concrete Docker networking commands and Docker Compose configuration in later chapters, but keep this idea: containers talk over virtual networks and explicit port mappings.
Containers vs Bare-Metal Deployment
Before containers, many backend deployments were done by:
- Copying code to servers via SSH
- Installing system packages and language runtimes manually
- Running processes with tools like
systemdorsupervisor
This approach still works, but has drawbacks:
- Harder to reproduce environments
- Manual steps increase risk of mistakes
- Upgrades and rollbacks are more complex
With containers:
- You build once, then deploy the same image everywhere
- You can roll back by simply starting an older image
- You can run multiple versions side by side
This is why containers are so common in modern backend stacks.
Common Container Use Cases in This Course
Throughout this course you will meet containers in many places.
Databases
You will often run PostgreSQL in a container:
- Easily start and stop databases
- Keep production and development versions separate
- Avoid cluttering your host OS with multiple database installs
Example usage (conceptual):
postgres:16image for your database- Volume to store data persistently
- Environment variables for user and password
Redis and Message Brokers
For caching and background jobs you will use Redis or other brokers. Containers let you:
- Run Redis for development testing
- Run a separate broker for staging or production
- Keep configurations consistent across environments
Application Servers
Your FastAPI app will often be containerized:
- Container image includes Python, dependencies, and code
- Container runs Uvicorn or Gunicorn
- You can scale by running multiple containers behind a load balancer
Limitations and Misconceptions
Containers are powerful, but they are not magic.
Misconception 1: “Containers are just small virtual machines.”
They are not VMs. They share the host kernel and are typically lighter and faster to start. They are closer to isolated processes than full operating systems.
Misconception 2: “Containers automatically make apps scalable.”
Containers are easy to start and stop, which helps scaling. But you still need:
- Proper app design (statelessness, external storage)
- Load balancing
- Database scaling
Misconception 3: “Anything inside the container is permanent.”
If a container is removed, its internal filesystem is lost. Important data must be stored in volumes or external services.
Misconception 4: “Containers are always more secure.”
Containers add isolation, but they also add complexity. Misconfigured images, open ports, or running as root inside the container can still be serious security risks.
How Containers Fit into DevOps and CI/CD
Containers are a key building block for continuous integration and deployment.
Typical workflow:
- Developer pushes code to GitHub
- CI pipeline builds a container image
- Tests run inside containers
- On success, image is pushed to a registry
- Deployment system pulls the image and runs new containers
This approach has several benefits:
- Consistent test and production environments
- Simple versioned artifacts (images with tags)
- Clear separation between build and run stages
You will see this in detail in the CI/CD and Deployment sections of the course.
Summary
In this chapter you learned that:
- A container is a lightweight, isolated environment to run applications.
- A container image is a read-only template, and a container is a running instance of that image.
- Containers share the host operating system kernel, unlike VMs.
- Containers help backend developers by providing consistent environments, easy dependency management, and isolation.
- Containerized services communicate over virtual networks and mapped ports.
- Containers are central to modern backend workflows, especially with Docker, Compose, and CI/CD.
Next, you will learn about Docker itself, the most common container platform, and how to build and run your own containers for backend applications.
Views: 8
KAHIBARO