Containers: Packaging and Isolating Applications
📑 On this page
- A concrete example: three web applications
- Containers are isolated processes
- Images are immutable templates
- Build once, run consistently
- Containers are not full virtual machines
- Resource limits are essential
- Containers should be replaceable
- Networking is virtualized
- Orchestration manages many containers
- Health checks guide automation
- Image security
- Logs and observability
- When containers help
- Knowledge check
- The one idea to remember
Software often works on one developer's machine and fails elsewhere because library versions, system packages, environment variables, or file layouts differ.
Containers help make the application environment repeatable.
A container packages an application and its dependencies while isolating its processes and sharing the host operating-system kernel.
Containers are usually smaller and faster to start than virtual machines because they do not boot a complete guest kernel.
A concrete example: three web applications
One Linux host can run:
- A container with a Node.js application
- A container with a Python service
- A container with a reverse proxy
Each container sees its own process tree, filesystem view, network interfaces, and configured resources.
All three ultimately make system calls to the same host Linux kernel.
This differs from three VMs, each of which normally runs its own kernel.
Containers are isolated processes
At runtime, a container is not a miniature physical box. It is one or more ordinary operating-system processes with isolation and limits applied.
Linux container systems commonly use:
- Namespaces to provide separate views of processes, networks, mounts, users, and hostnames
- Control groups to account for and limit CPU, memory, and other resources
- Capabilities to divide powerful root privileges
- Security policies to restrict system calls and file access
The container runtime configures these features and starts the process.
Isolation is real but shares a kernel boundary, so secure configuration still matters.
Images are immutable templates
A container image contains application files, runtime dependencies, and metadata describing how to start.
An image is built in layers:
FROM node:24-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]Layers can be reused across images, reducing build and transfer work.
The running container adds a writable layer, but durable application data should not depend on that temporary layer.
Build once, run consistently
An image can move through:
- Developer testing
- Automated checks
- A container registry
- Staging
- Production
Using the same image reduces environmental drift. Configuration such as database addresses and credentials is supplied separately for each environment.
"Same image" does not mean identical behavior if CPU architecture, kernel features, attached services, or configuration differ.
Reproducibility requires controlling both the image and its runtime contract.
Containers are not full virtual machines
Containers do not normally include or boot their own kernel.
Consequences include:
- Faster startup
- Lower memory overhead
- Higher workload density
- Dependence on the host kernel family
- A shared kernel security boundary
A Linux container requires a Linux kernel. Desktop tools that run Linux containers on Windows or macOS generally use a Linux VM underneath.
This is why containers and VMs often complement rather than replace each other.
Resource limits are essential
Without limits, one container can consume enough memory or CPU to harm neighbors.
A runtime or orchestrator can define:
- Memory limits
- CPU shares or quotas
- Process limits
- Storage quotas
If a process exceeds its memory limit, the operating system may terminate it. CPU limits usually throttle rather than terminate.
Limits should reflect measured needs. Too low causes instability; too high weakens scheduling and protection.
Applications also need to understand the container limit rather than assume they can use all host resources.
Containers should be replaceable
A healthy container is treated as a replaceable instance of an image.
Instead of logging in and manually repairing one container, teams typically:
- Fix the image definition.
- Build and test a new image.
- Replace old instances.
This reduces undocumented drift.
It does not mean every workload is stateless. Stateful systems can run in containers, but their durable data must live in managed volumes or external services with careful identity, ordering, backup, and recovery.
Networking is virtualized
Containers can have virtual network interfaces and private addresses. Port mapping exposes selected ports from the host or platform.
An orchestrator may provide:
- Service discovery
- Internal DNS
- Network policies
- Load balancing
- Ingress from outside
Container IP addresses are often temporary. Applications should discover services through stable names rather than record one instance's current address.
Network policies should restrict traffic to required paths rather than assume all internal traffic is trustworthy.
Orchestration manages many containers
Running one container is straightforward. Running hundreds across many machines requires scheduling and coordination.
An orchestrator such as Kubernetes can:
- Place containers on suitable hosts
- Restart failed instances
- Maintain a desired replica count
- Roll out new versions
- Attach storage
- Provide service discovery
- Enforce resource and security policies
Orchestration adds a substantial control system. A small application may be better served by a simpler managed container platform.
The tool should fit operational needs, not serve as proof of sophistication.
Health checks guide automation
Platforms need evidence that a container is usable.
Common checks include:
- Startup: Has initialization finished?
- Readiness: Can this instance receive traffic?
- Liveness: Is it stuck and in need of restart?
Using one shallow check for all three can create failures. A process may be alive but unable to reach a required dependency. Conversely, restarting it because a shared database is briefly unavailable may worsen an outage.
Checks should reflect what the platform can safely act upon.
Image security
Container images can contain:
- Vulnerable operating-system packages
- Unneeded tools
- Embedded secrets
- Malicious dependencies
- Incorrect file permissions
Good practices include:
- Use trusted minimal base images.
- Pin and review dependencies.
- Rebuild regularly for security fixes.
- Scan images.
- Sign and verify artifacts where appropriate.
- Run as a non-root user.
- Remove unnecessary capabilities.
- Keep secrets outside image layers.
Minimal does not automatically mean secure, but smaller images reduce attack surface and maintenance.
Logs and observability
Containers are temporary, so logs stored only inside their writable filesystem disappear when replaced.
Platforms usually collect standard output, metrics, and traces into external systems.
Useful telemetry includes:
- Image and application version
- Container and workload identity
- Resource throttling
- Restart reason
- Request correlation identifiers
- Deployment event
Observability should make replacement routine rather than turn each instance into a unique artifact that investigators fear losing.
When containers help
Containers fit:
- Repeatable application packaging
- Services that need independent deployment
- Batch jobs
- CI workloads
- Portable managed runtimes
- Efficient use of shared hosts
They do not automatically solve:
- Poor application architecture
- Data consistency
- Security
- Monitoring
- Cost
- Organizational ownership
A badly designed application remains badly designed inside a well-built image.
Knowledge check
- What host resource does a container share that a VM usually does not?
- What do namespaces and control groups provide?
- Why should durable data not live only in a container's writable layer?
- What is the difference between readiness and liveness?
- Why are containers often run inside VMs?
The one idea to remember
Containers package applications as isolated, replaceable processes that share a host kernel. Their speed and density come from that shared layer, while secure limits, durable storage, and thoughtful orchestration remain essential.