Skip to content

Docker Image and Container Mental Model

Use this note as a practical mental model for pulling and running containers. It explains what Docker downloads, what starts at runtime, where data lives, and how common docker run flags change the container.

Concept Meaning
Image Packaged application template with userland, app files, libraries, dependencies, startup scripts, and default ENTRYPOINT or CMD
Container A running instance created from an image
Disposable container Container removed after exit, usually with –rm
Persistent data Data kept outside the disposable container through bind mounts or named volumes

docker pull downloads an image from a container registry. Docker Hub is the default registry when no registry hostname is provided.

Terminal window
docker pull owner/image-name
# Equivalent default form
docker pull docker.io/owner/image-name:latest
# General form
docker pull registry/namespace/image:tag
Terminal window
docker pull nginx
docker pull postgres:16
docker pull redis:7-alpine
docker pull docker.io/library/ubuntu:24.04
docker pull ghcr.io/owner/image:tag
Command Effect
docker pull image-name Downloads or updates the image locally
docker run image-name Creates and starts a new container from the image
docker run missing-image Pulls automatically first, then starts the container

Use explicit docker pull when you want to update the local image before running it.

Terminal window
docker pull image-name:latest
docker pull image-name:1.2.3
  • latest is convenient but can change over time.
  • Fixed tags are better for stable deployments.
  • Images are built in layers such as base distro, system packages, language runtime, app code, and startup scripts.
  • docker pull downloads only missing or changed layers.

The image provides the container userland, such as Debian, Ubuntu, Alpine, or Fedora. The host provides the Linux kernel. An Ubuntu container on an Arch host runs Ubuntu binaries and libraries while sharing the Arch host kernel.

Terminal window
docker run --rm image-name cat /etc/os-release
docker run --rm image-name uname -a
  • /etc/os-release shows the container distro.
  • uname -a shows the host kernel because Linux containers share the host kernel.

ENTRYPOINT and CMD define what starts by default when the container runs.

Terminal window
docker inspect image-name --format '
Entrypoint: {{json .Config.Entrypoint}}
Cmd: {{json .Config.Cmd}}
WorkingDir: {{json .Config.WorkingDir}}
'
Terminal window
# Use the default image startup behavior
docker run image-name
# Start a shell instead of the default application
docker run -it --rm --entrypoint bash image-name
docker run -it --rm --entrypoint sh image-name
# Pass command arguments to the image's default entrypoint behavior
docker run --rm image-name command args
Flag Meaning
-i Keep STDIN open
-t Allocate a terminal
-it Use for shells, CLIs, TUIs, REPLs, and interactive agents
–rm Remove the container automatically after it exits
Terminal window
docker run -it --rm image-name
docker run image-name

A bind mount makes a host path appear inside the container. Reads and writes are bidirectional.

Terminal window
docker run -it --rm \
-v "$HOME/my-data:/data" \
image-name
Host path Container path
$HOME/my-data /data
$HOME/my-data/file.txt /data/file.txt
  • If the image already has files at /data, the bind mount hides those image files while the mount is active.
  • The mounted path is the host folder, not image contents plus host contents.
Terminal window
docker volume create app-data
docker run -it --rm \
-v app-data:/data \
image-name
Storage type Best use
Bind mount Explicit host paths, projects, configs, and local files you want to inspect from the host
Named volume Docker-managed persistent data for databases and app state

A common project pattern is to mount the current host folder into /workspace and start the container there.

Terminal window
docker run -it --rm \
-v "$PWD:/workspace" \
-w /workspace \
image-name
Terminal window
docker run --rm \
-e APP_ENV=development \
-e API_KEY="$API_KEY" \
image-name
Terminal window
docker run --rm \
--user "$(id -u):$(id -g)" \
-v "$PWD:/workspace" \
image-name
  • -e passes environment variables into the container for config, credentials, runtime settings, and user IDs.
  • –user runs the process as the host UID and GID, which helps avoid root-owned files in bind-mounted folders.
  • Some images use APP_UID and APP_GID style environment variables instead of –user.
Terminal window
# Host port 8080 maps to container port 80
docker run --rm \
-p 8080:80 \
image-name
# Localhost-only binding on the host
docker run --rm \
-p 127.0.0.1:8080:80 \
image-name
Terminal window
docker run -d \
--name app-name \
--restart unless-stopped \
image-name
  • -d runs the container in the background.
  • –name gives the container a stable name.
  • –restart unless-stopped restarts the container after reboot or crash unless it was manually stopped.
Command Use
docker ps Show running containers
docker ps -a Show running and stopped containers
docker logs -f container-name Follow container logs
docker exec -it container-name bash Enter a running container with bash
docker exec -it container-name sh Enter a running container with sh
docker inspect container-name Show container metadata

Docker container names are unique across the Docker daemon. A stopped container can still hold a name.

Terminal window
docker ps -a --filter "name=test"
docker rm -f test

Start a temporary shell without mounts to inspect what the image ships by default.

Terminal window
docker run -it --rm \
--entrypoint sh \
image-name
Terminal window
cat /etc/os-release
pwd
ls -lah /
ls -lah /opt
find / -maxdepth 2 -type d 2>/dev/null | head

Add mounts when you want to compare raw image contents with runtime mounted contents.

Terminal window
docker run -it --rm \
-v "$HOME/my-data:/data" \
--entrypoint sh \
image-name
Terminal window
docker system prune
docker volume ls
docker volume rm volume-name
  • docker system prune removes unused containers, networks, images, and build cache.
  • It does not remove active containers.
  • Remove named volumes only when you are sure the stored data is no longer needed.
Pattern Risk
-v “$PWD:/workspace” Safer project-scoped workspace
-v “$HOME/safe-folder:/data” Safer explicit data folder
-v “$HOME:/workspace” Risky because it exposes the whole home directory
-v “/:/host” Risky because it exposes the host root filesystem
-v “$HOME/.ssh:/root/.ssh” Risky because it exposes SSH credentials
-v “/var/run/docker.sock:/var/run/docker.sock” Risky because it gives host-level Docker control
–privileged Very risky because it grants broad container privileges
–network host Very risky because it removes normal network isolation

Mount only what the container should access.

Terminal window
docker run -it --rm \
--name app-test \
-e APP_ENV=development \
-v "$HOME/app-data:/data" \
-v "$PWD:/workspace" \
-w /workspace \
image-name:tag
  • Replace app-test with the container name.
  • Replace APP_ENV with the environment variables the image needs.
  • Replace $HOME/app-data with a persistent data path if needed.
  • Replace $PWD with the project or workspace path.
  • Replace image-name:tag with the Docker Hub or registry image.