← Back to all articles

Image vs Container: They Are Not the Same in Docker

Cloud nativeBeginnerCI/CD

Image vs container

  • Image: a read-only template built from stacked layers; distributable and cacheable;
  • Container: one running instance of an image, with a writable layer on top.

Why layering helps

Shared base layers are reused across images, saving pull and storage. Changing one line usually rebuilds only the top layer.

Two pitfalls

  1. Writing data into the container: it vanishes when the container is removed; persist with volumes;
  2. Images grow unbounded: keep build tools in the image and it balloons; use multi-stage builds to ship only what runs.

Real-world cases: three costs of confusing images with containers

  1. Deleting a container and expecting free disk: removing a container drops only its writable layer; the image still occupies space. Distinguish docker rm (containers), docker rmi (images) and docker system prune.
  2. Expecting in-container edits to persist: changes live only in the writable layer and vanish on recreate. To keep them, put them in the Dockerfile and rebuild the image.
  3. The same image behaving differently: identical image but different env vars, mounts and networks — the difference is runtime, not the image. Compare docker inspect output before rebuilding.

FAQ

Are images read-only? Yes — an image is a read-only template and a container adds a writable layer on top. Why do containers start faster than VMs? No full OS boot; it just starts a process over an added writable layer. How many processes per container? Usually one main process; split multiple processes into separate containers for independent scaling and restarts. Do image layers waste space? Layers are shared between images, so with a common base the total is far below the sum of image sizes.

Slimming an image, highest impact first

  1. Change the base image: alpine or distroless often saves hundreds of MB, but mind musl versus glibc differences;
  2. Multi-stage builds: leave build dependencies in the builder stage and copy only artefacts into the runtime — often an order of magnitude smaller;
  3. A real .dockerignore: exclude node_modules, .git and build caches to keep the context small and layers stable;
  4. Order instructions by change frequency: copy the dependency manifest and install before copying source, so caching actually hits;
  5. Clean up install caches: delete /var/lib/apt/lists after apt-get and prune npm caches, in the same layer as the install.

Three runtime details often missed

  • Signal handling: the app must handle SIGTERM and shut down gracefully or rolling updates drop requests — use exec form (CMD ["node","server.js"], not shell form);
  • Run as non-root: set USER to a non-privileged account to shrink the blast radius;
  • Read-only filesystem: run with --read-only where possible and mount explicit volumes for writes.

Common misconceptions

  • Baking config into the image: inject environment-specific settings via env vars or mounts so one image deploys everywhere;
  • Using the latest tag: nothing is traceable and rollback is guesswork — use immutable tags (version or commit hash);
  • Running several processes in one container: process management and log collection get complicated; split them.

Volumes and lifecycle

  • The container filesystem dies with it: anything durable must live in a volume or bind mount, or a recreate wipes it;
  • Anonymous volumes get forgotten: those declared by VOLUME can linger after the container is gone — clean up with docker volume prune;
  • Bind mounts depend on host paths: deployments across machines fail when the path is missing, so named volumes are safer in production;
  • Volumes do not follow the image: updating an image does not migrate data in a volume; run migrations explicitly.

Where to start troubleshooting

  • docker inspect for config and mounts, docker logs for app output, docker exec to look inside;
  • Read the exit code first: 137 usually means OOM-killed, 139 points at a segfault;
  • If the image has no shell (distroless), rely on logs and probes rather than bolting one in.

Image scanning and compliance

Wire image scanning into CI so base image and dependency vulnerabilities are checked right after build, with a gate by severity — block merges on critical findings. Rebuild base images regularly for upstream security fixes; an image left untouched accumulates known vulnerabilities even when your code did not change.