A cloud container is an ordinary process running on a shared kernel, with the operating system lying to it about what it can see. Namespaces restrict its view of the filesystem, the network and the process list; cgroups cap the CPU and memory it can consume. There is no second operating system and no virtual hardware, which is why a container starts in milliseconds and why its isolation is weaker than a virtual machine’s.
The lightweight virtual machine analogy is the most common way containers are explained and it is the source of most container confusion, because it implies a boundary that is not there. Once you replace it with process plus restricted view, the surprising behaviours stop being surprising.
Table of contents
- A container is a process with a restricted view
- The image, and why it is not a disk snapshot
- Containers versus virtual machines
- State, and the rule that surprises everyone
- Orchestration, and whether you need it
- When a container is the wrong tool
- How this fits the rest of the stack
- FAQ
A container is a process with a restricted view
Run a container and then look at the host’s process list. The process is right there, visible, owned by a user on the host. It is not inside anything. It has simply been started with a set of restrictions.
Two kernel features do the work:
- Namespaces control what the process can see. A mount namespace gives it a different filesystem root. A PID namespace makes it believe it is process 1 and that nothing else is running. A network namespace gives it its own interfaces and ports. A user namespace can map its root user to an unprivileged user on the host.
- Control groups control what it can use: a CPU quota, a memory limit, IO bandwidth. Exceeding the memory limit gets the process killed by the kernel, which is where a container that vanishes with no application error comes from.
That is the entire mechanism. There is no hypervisor, no emulated hardware, no guest kernel. The container shares the host’s kernel, which is why a Linux container cannot run on a Windows kernel without a Linux virtual machine underneath, and why the phrase runs anywhere has an asterisk on it.
The image, and why it is not a disk snapshot
An image is a stack of read-only layers plus a small amount of metadata saying which command to run, which environment variables to set and which user to run as. Each layer is a set of filesystem changes from the layer below.
When a container starts, the layers are stacked and a thin writable layer is added on top. Everything the process writes goes into that top layer, which is discarded when the container is removed. That is the entire storage model and it explains the rule everyone learns the hard way.
The layering has two consequences worth designing around:
- Layers are cached and shared. Ten containers from the same image share one copy of the read-only layers on disk, which is why containers are cheap to run many of.
- A file deleted in a later layer is still present in the earlier one. Copying a secret in and deleting it in a subsequent instruction leaves it in the image, retrievable by anyone who pulls it. Use build secrets or multi-stage builds instead.
# Multi-stage: the toolchain and the source never reach the final image
FROM node:22-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-slim
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]
Containers versus virtual machines
The comparison is worth making precisely, because the differences are not a matter of degree.
- Boot time. A virtual machine boots an operating system, which takes tens of seconds. A container starts a process, which takes milliseconds. This is not an optimisation; there is simply nothing to boot.
- Overhead. A virtual machine carries a full guest OS in memory. A container carries its application and nothing else, so the same host runs an order of magnitude more of them.
- Isolation. A virtual machine is isolated by the hypervisor and has its own kernel. A container is isolated by kernel features and shares the kernel. A kernel vulnerability is a container escape and is not a virtual machine escape.
- Kernel choice. Every virtual machine can run a different operating system. Every container on a host shares that host’s kernel.
The isolation difference is the one that matters for architecture decisions. Running your own services in containers on a shared host is normal and fine. Running untrusted third-party code from different customers in containers on a shared kernel is a materially different risk, and it is why platforms doing that either use virtual machine boundaries per tenant or a sandboxed runtime that puts a kernel boundary back.
In practice most cloud container platforms are containers inside virtual machines: the VM provides the tenant boundary, the container provides the packaging and the speed. You get both models, and the layering is invisible until you read the billing.
State, and the rule that surprises everyone
The writable layer is destroyed with the container. Not on crash, not on error: on every normal replacement, which includes every deploy, every scale event and every restart after a memory limit kill.
This is not a limitation to work around. It is the property that makes the rest work. A container that holds nothing important can be killed and replaced freely, which is what allows rolling deploys, autoscaling and self-healing restarts to be safe operations.
So state goes somewhere designed for it:
- Rows in a database, which is a separate service with its own lifecycle.
- Uploaded files in object storage, or on a volume explicitly attached to the container and outliving it.
- Sessions in a cache or a database, never in process memory, or a user gets logged out on every deploy.
- Configuration in environment variables, and secrets in a secret store, never baked into the image.
- Logs to standard output, where the platform collects them, not to a file inside the container that disappears with it.
An application following those five rules can be moved between container platforms in an afternoon. One that does not is pinned to wherever it currently runs, and the pinning is invisible until the migration starts.
Orchestration, and whether you need it
Once there is more than one container, something has to decide where each one runs, restart the failed ones, route traffic to the healthy ones and replace them during a deploy. That is orchestration, and it exists at several levels of complexity.
- One container on one host, started by the system service manager. Perfectly adequate for a great many applications and almost never the recommended answer online.
- A compose file describing several containers on one host. Good for development, and reasonable in production for a small application where a single host is acceptable.
- A managed container platform where you supply an image or a repository and the platform handles scheduling, health checks, scaling and rolling deploys. The right answer for most teams.
- A full cluster orchestrator. Genuinely necessary at a certain scale and organisational shape, and a substantial ongoing operational commitment below it.
The honest guidance is that most teams reaching for the fourth option would be better served by the third for another year or two. The cluster is not hard to start; it is hard to keep, and the cost is paid continuously by whoever is on call.
When a container is the wrong tool
Containers are the default packaging format now, which means they get used in places where they add work without adding value.
- A static site. It is files. It needs a CDN and a build step, not a runtime and an image registry.
- A workload needing a specific kernel version, kernel module or direct hardware access. Shared kernel means you get the host’s kernel and its modules.
- A stateful database you are not prepared to operate. Running one in a container is entirely possible and means owning the storage, backup, failover and upgrade path yourself.
- A single scheduled script. A cron entry is a smaller thing than an image, a registry and a scheduler.
- Local development where the application has no unusual dependencies and the language toolchain runs natively. The container adds a filesystem-sync problem you did not have.
The useful question is not whether something can be containerised, because almost everything can. It is whether the packaging boundary is buying you anything: reproducibility, a dependency you cannot install natively, or a deployment target that expects an image. If it is not buying one of those, it is overhead with good branding.
How this fits the rest of the stack
Deciding between a container platform, a virtual machine and a managed runtime is mostly a question of what each shape costs once storage, the database and the bandwidth are counted alongside the compute. The RunxBuild hosting calculator lists those separately so the comparison is made on real line items. On RunxBuild a Docker image or a repository in Node, Python, Go, Ruby, Java or .NET deploys the same way, with build logs, environment variables, a live route, runtime logs, persistent storage and autoscaling between a floor and a ceiling plan you choose, which covers the third option above without the cluster.
Useful related references:
- Deploy a Docker Container for Free
- Container Technology: Namespaces, cgroups, UnionFS, and Why It Works
- Container Runtime Security: A Practical, Defensible Setup
- Docker services on RunxBuild
FAQ
Is a container a virtual machine?
No. A container is a process on the host’s kernel with a restricted view of the filesystem, network and process list, plus limits on CPU and memory. A virtual machine emulates hardware and runs its own kernel. That difference explains both the millisecond startup and the weaker isolation.
Why does my container lose data when it restarts?
Because everything written inside a container goes to a thin writable layer that is destroyed when the container is replaced, which happens on every deploy, scale event and restart. Persistent data belongs in a database, in object storage, or on a volume explicitly attached to the container.
Are containers secure enough to run untrusted code?
Not by themselves on a shared kernel. Container isolation is enforced by kernel features, so a kernel vulnerability can be a container escape. Platforms running untrusted multi-tenant code use a virtual machine boundary per tenant or a sandboxed runtime that restores a kernel boundary.
Do I need Kubernetes to run containers in the cloud?
No, and most teams do not. A single container under a service manager, a compose file on one host, or a managed container platform all run containers in production. A cluster orchestrator is justified by scale and organisational shape, and it is an ongoing operational commitment rather than a one-time setup.
What is the difference between an image and a container?
An image is the read-only stack of filesystem layers plus metadata about how to run it. A container is a running instance of an image with a thin writable layer on top. One image can back many containers, and they share the read-only layers on disk.