CrackOps
Interview PrepTracksLinuxAWS LabSoonInterview RoomSoon
Sign inStart free
CrackOps

Interview prep for the people who keep production up.

[email protected]
ProductInterview PrepTracksDashboardInterview Room
RolesDevOpsSREPlatformCloud
CompanyAboutContactPrivacyTerms
© CrackOps
Linux / Docker / docker run

docker run

Create and start a container from an image

Beginnercontainersessentialruntime

docker run creates a new container from an image and starts it: pulling the image if needed, giving it its own filesystem, network and process tree, and running the image's command as PID 1. Its flags decide ports, env, volumes, limits and restart behaviour.

Syntaxdocker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

Watch it run

You want to see what a container really is: a process with its own hostname and filesystem that ends when its command ends.

devops@devops-lab: ~ — zsh — 96×28
➜ ~
Step 1 of 3
docker run --rm alpine:3.21 sh -c 'echo hello from $(hostname); id'

The image wasn't on this host, so docker pulled it first. Then the command ran inside the container: the hostname is the short container ID and you are root inside it. --rm deletes the stopped container afterwards.

Anatomy of a command

$
commanddocker run

Create a new container and start it. It is docker create plus docker start (plus attach unless -d).

How it works

The docker CLI is only a client: it sends REST calls to dockerd over /var/run/docker.sock. POST /containers/create fails with 404 if the image is missing, so the CLI pulls it and retries. dockerd then prepares the container: a writable overlayfs layer on top of the read-only image layers, a veth pair plugged into the docker0 bridge, NAT rules for every -p, and the mounts. It hands the spec to containerd, which starts a containerd-shim and calls runc. runc clone()s a process into new pid, mount, net, uts, ipc and cgroup namespaces, puts it in a cgroup with your -m and --cpus limits, drops capabilities, applies seccomp and AppArmor, pivots into the rootfs and execs ENTRYPOINT + CMD as PID 1. runc exits; the container lives exactly as long as that PID 1 does.

The CLI only sends API calls; dockerd, containerd and runc build namespaces and cgroups around one process.

JSON specpull if missingcreate taskrootfsspawnrunYoudocker run -ddocker CLIAPI clientdockerddocker.sockRegistryDocker Hub / ECRcontainerd+ shimImage layersoverlayfsruncOCI runtimeContainerPID 1 = your app
1/7
The CLI turns flags into an API call

docker is just a client. It parses your flags into a JSON container spec and POSTs it to dockerd over the unix socket /var/run/docker.sock.

← → to step

Options you'll actually use

-d, --detachRun in the background and print the container ID
-itInteractive with a TTY: keep STDIN open and allocate a terminal (for shells)
--rmDelete the container automatically when it exits
--name NAMEGive the container a fixed, unique name
-p HOST:CONTAINERPublish a container port on the host (add an IP to limit the interface)
-e KEY=VAL, --env-file FILESet environment variables inside the container
-v SRC:DEST[:ro]Mount a named volume or host path into the container
--network NETAttach to a network (bridge, host, none or a user-defined one)
-m, --memory 512mHard memory limit; going over it gets PID 1 OOM-killed (exit 137)
--cpus 1.5CPU quota: at most 1.5 CPUs' worth of time per period
--restart POLICYno, on-failure[:N], always or unless-stopped
-u, --user UID[:GID]Run the process as this user instead of the image's default
--entrypoint CMDOverride the image's ENTRYPOINT (handy for debugging)
--read-onlyMount the container's root filesystem read-only

Common mistakes

docker run -e DB_PASSWORD=s3cret shop-api:1.4.0

The secret lands in shell history and in docker inspect output, readable by anyone in the docker group.

docker run --env-file /etc/shop/api.env shop-api:1.4.0 (file mode 600), or a real secret store
docker run -d -p 5432:5432 postgres:16 on a public VM

Published ports bypass ufw on Ubuntu (docker writes its own iptables rules), so the database is open to the internet.

docker run -d -p 127.0.0.1:5432:5432 postgres:16, or no -p at all and a shared user-defined network
docker run nginx:1.27-alpine nginx -g 'daemon on;'

If the main process forks into the background and exits, PID 1 is gone and the container stops immediately.

Keep the app in the foreground: nginx -g 'daemon off;' (the image default)
Running docker run again after editing the app and expecting the change

run uses the image as it was built. Code changes need a rebuild and a new container (or a bind mount during development).

docker build -t shop-api:1.4.1 . && docker rm -f api && docker run ... shop-api:1.4.1

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Run nginx:1.27-alpine detached, named web2, serving container port 80 on host port 8081 only on localhost, then check it answers with curl.

  2. 2

    Start a throwaway interactive Ubuntu shell that is deleted when you exit. Inside, check the OS release and which processes exist, then exit.

  3. 3

    A container shows 'Exited (137)'. Compute what signal killed it, then check your answer in the sandbox shell with kill -l.

  4. 4

    Write a docker run for the API that limits it to 512 MB and 1 CPU, restarts it on failure at most 5 times, and loads env vars from /etc/shop/api.env. Then try it for real in the CrackOps AWS Lab as an ECS task definition.

Related commands

docker psList containers and their statedocker logsRead a container's stdout and stderrdocker execRun a command inside a running containerdocker buildBuild an image from a Dockerfiledocker networkCreate and manage container networks
PreviouscoredumpctlNextdocker build
Linux / Docker / docker run

docker run

Create and start a container from an image

Beginnercontainersessentialruntime

docker run creates a new container from an image and starts it: pulling the image if needed, giving it its own filesystem, network and process tree, and running the image's command as PID 1. Its flags decide ports, env, volumes, limits and restart behaviour.

Syntaxdocker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

Watch it run

You want to see what a container really is: a process with its own hostname and filesystem that ends when its command ends.

devops@devops-lab: ~ — zsh — 96×28
➜ ~
Step 1 of 3
docker run --rm alpine:3.21 sh -c 'echo hello from $(hostname); id'

The image wasn't on this host, so docker pulled it first. Then the command ran inside the container: the hostname is the short container ID and you are root inside it. --rm deletes the stopped container afterwards.

Anatomy of a command

$
commanddocker run

Create a new container and start it. It is docker create plus docker start (plus attach unless -d).

How it works

The docker CLI is only a client: it sends REST calls to dockerd over /var/run/docker.sock. POST /containers/create fails with 404 if the image is missing, so the CLI pulls it and retries. dockerd then prepares the container: a writable overlayfs layer on top of the read-only image layers, a veth pair plugged into the docker0 bridge, NAT rules for every -p, and the mounts. It hands the spec to containerd, which starts a containerd-shim and calls runc. runc clone()s a process into new pid, mount, net, uts, ipc and cgroup namespaces, puts it in a cgroup with your -m and --cpus limits, drops capabilities, applies seccomp and AppArmor, pivots into the rootfs and execs ENTRYPOINT + CMD as PID 1. runc exits; the container lives exactly as long as that PID 1 does.

The CLI only sends API calls; dockerd, containerd and runc build namespaces and cgroups around one process.

JSON specpull if missingcreate taskrootfsspawnrunYoudocker run -ddocker CLIAPI clientdockerddocker.sockRegistryDocker Hub / ECRcontainerd+ shimImage layersoverlayfsruncOCI runtimeContainerPID 1 = your app
1/7
The CLI turns flags into an API call

docker is just a client. It parses your flags into a JSON container spec and POSTs it to dockerd over the unix socket /var/run/docker.sock.

← → to step

Options you'll actually use

-d, --detachRun in the background and print the container ID
-itInteractive with a TTY: keep STDIN open and allocate a terminal (for shells)
--rmDelete the container automatically when it exits
--name NAMEGive the container a fixed, unique name
-p HOST:CONTAINERPublish a container port on the host (add an IP to limit the interface)
-e KEY=VAL, --env-file FILESet environment variables inside the container
-v SRC:DEST[:ro]Mount a named volume or host path into the container
--network NETAttach to a network (bridge, host, none or a user-defined one)
-m, --memory 512mHard memory limit; going over it gets PID 1 OOM-killed (exit 137)
--cpus 1.5CPU quota: at most 1.5 CPUs' worth of time per period
--restart POLICYno, on-failure[:N], always or unless-stopped
-u, --user UID[:GID]Run the process as this user instead of the image's default
--entrypoint CMDOverride the image's ENTRYPOINT (handy for debugging)
--read-onlyMount the container's root filesystem read-only

Common mistakes

docker run -e DB_PASSWORD=s3cret shop-api:1.4.0

The secret lands in shell history and in docker inspect output, readable by anyone in the docker group.

docker run --env-file /etc/shop/api.env shop-api:1.4.0 (file mode 600), or a real secret store
docker run -d -p 5432:5432 postgres:16 on a public VM

Published ports bypass ufw on Ubuntu (docker writes its own iptables rules), so the database is open to the internet.

docker run -d -p 127.0.0.1:5432:5432 postgres:16, or no -p at all and a shared user-defined network
docker run nginx:1.27-alpine nginx -g 'daemon on;'

If the main process forks into the background and exits, PID 1 is gone and the container stops immediately.

Keep the app in the foreground: nginx -g 'daemon off;' (the image default)
Running docker run again after editing the app and expecting the change

run uses the image as it was built. Code changes need a rebuild and a new container (or a bind mount during development).

docker build -t shop-api:1.4.1 . && docker rm -f api && docker run ... shop-api:1.4.1

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Run nginx:1.27-alpine detached, named web2, serving container port 80 on host port 8081 only on localhost, then check it answers with curl.

  2. 2

    Start a throwaway interactive Ubuntu shell that is deleted when you exit. Inside, check the OS release and which processes exist, then exit.

  3. 3

    A container shows 'Exited (137)'. Compute what signal killed it, then check your answer in the sandbox shell with kill -l.

  4. 4

    Write a docker run for the API that limits it to 512 MB and 1 CPU, restarts it on failure at most 5 times, and loads env vars from /etc/shop/api.env. Then try it for real in the CrackOps AWS Lab as an ECS task definition.

Related commands

docker psList containers and their statedocker logsRead a container's stdout and stderrdocker execRun a command inside a running containerdocker buildBuild an image from a Dockerfiledocker networkCreate and manage container networks
PreviouscoredumpctlNextdocker build