Docker Operations Manual

19 min read
On this page

Identify the daemon and Compose project first, then distinguish containers, images, volumes, and ports. Examples use myapp. Commands run on the client, but bind-mount paths belong to the daemon host.

TaskStart here
Exit or restart loopState and logs
Publish ports and retain dataCreate and map paths
Update Compose servicesConfiguration to runtime
Disk use is highClean by object

Identify the daemon, then inspect state

Identify the target daemon

# Read the selected context
docker context show

Compare the endpoint with docker context ls. CLI --context and DOCKER_HOST / DOCKER_CONTEXT can affect the target; docker info verifies the connection and daemon identity. On failure, check the endpoint, service, and permissions.

Identify the container and exit cause

# List names, state, and ports, including stopped containers
docker ps -a --format '{{.Names}}	{{.Status}}	{{.Ports}}'

-a includes stopped instances. Replace myapp below with the name found here. Exited means the process ended; Restarting means retries are occurring. Neither identifies the cause.

# Read exit status, OOM flag, and health state
docker inspect myapp --format '{{json .State}}'

Read ExitCode, OOMKilled, Error, and start/finish timestamps. If Health exists, inspect its Log probe output; use the evidence table below.

# Read up to 100 recent log lines
docker logs --tail 100 --since 10m myapp

--tail limits lines and --since limits time. Add --follow for streaming; Ctrl-C ends the viewer. These are stdout/stderr logs via the logging driver, not necessarily application log files.

Check resource use and processes separately

# Take one CPU, memory, and I/O sample
docker stats --no-stream myapp

Compare memory usage with its limit. Watch continuously for peaks; a low sample does not rule out an earlier OOM.

# List current processes to check application startup
docker top myapp

Process presence does not replace log or application checks.

EvidenceInterpretation and next step
ExitCode / ErrorRead application exit logs; nonzero does not imply a Docker bug
OOMKilled=trueCheck limits, host memory and kernel logs; 137 alone is not proof of OOM
unhealthyInspect Health.Log; the container may still be running
RestartingFind the exit cause, then RestartPolicy

Make port and data locations explicit

Prepare a network and persistent volume

This example creates new objects; use unused names or inspect existing objects before reuse. Resolve creation failures before starting the container.

# Create a user-defined application network
docker network create app-net

Success prints a network ID; containers on this network can communicate by name.

# Create a volume whose lifetime is independent of the container
docker volume create app-data

Success prints its name. This creates storage, not application persistence settings.

Run a container on a loopback-bound port

# Create an instance using the prepared network and volume
docker run -d --name myapp \
  --network app-net \
  --publish 127.0.0.1:8080:80 \
  --mount type=volume,src=app-data,dst=/app/data \
  --restart unless-stopped \
  --memory 512m \
  nginx:stable

-d detaches, --name names the instance, --memory limits memory, and unless-stopped selects restart behavior. A returned ID proves creation, not health; check ps/logs and the port/mount checks below.

This demonstrates creation syntax: nginx does not automatically write application data to /app/data. Configure the real application to use its mounted path. Do not put comments after continuation backslashes. Pin production images to the version or digest required by the project.

Preparing the visual
Where does data survive container removal?

Stopping preserves the writable layer. Container removal loses that layer but retains a named volume. Compose down -v also removes this project’s non-external named volume, not its image.

ObjectMeaning
127.0.0.1:8080:80Daemon-host loopback 8080 → container 80; peers use service-name:80 on a user-defined network
--mount type=bindHost path mapping; hides existing image content at the mountpoint
--mount type=volumeDocker-managed data object with a separate lifetime
EXPOSEImage metadata; does not publish a host port

Verify port and storage paths

# Check the actual published host address and port
docker port myapp

Expect 80/tcp mapped to 127.0.0.1:8080. If absent, inspect creation options.

# Inspect volume identity, destination, and write access
docker inspect myapp --format '{{json .Mounts}}'

Check Type, Name, Destination, and RW, then confirm the application writes there. Correct mounts do not protect data written elsewhere in the container layer.

# Check network membership, addresses, and aliases
docker inspect myapp --format '{{json .NetworkSettings.Networks}}'

For container-to-container access, check shared networks and the listening address. Inspect DNS configuration separately with docker exec myapp cat /etc/resolv.conf.

# Request the published HTTP port on the daemon host
curl -v http://127.0.0.1:8080/

Inspect connection address, HTTP status, and response body. For a remote context, run this on the daemon host, not the client loopback.

Inspect running files or enter the container

# Copy the running configuration to the client for review
docker cp myapp:/etc/nginx/nginx.conf ./nginx.running.conf

Source is in the container; destination is in the client current directory. Use a new or backed-up destination. Copying does not reload configuration. For interactive diagnosis use docker exec -it myapp sh; leaving that shell does not stop the main process.

Run the HTTP verification curl on the daemon host; with a remote context, local localhost is a different machine. A shell-less image may reject exec sh; use inspect, logs, cp, or suitable debugging tools.

Restart does not apply new configuration

Verify the Compose project

Run in the intended compose.yaml directory. Obtain service name app from config output; it is not necessarily container name myapp. Different directories, -f, or -p may target different objects.

# Validate parsing without printing expanded configuration
docker compose config --quiet

Success is normally silent. Fix configuration or environment errors before publishing.

# List services included in this configuration
docker compose config --services

Compare with existing instances in docker compose ps -a and confirm app is the intended service.

Pull, apply, then verify

# Fetch the configured image without recreating the container
docker compose pull app

Resolve registry, network, or reference failures before up. For source-built services use docker compose build app instead; pull and build are not mandatory consecutive steps.

# Create or update app and required dependencies from configuration
docker compose up -d app

This may recreate containers and interrupt connections. Restarting existing processes does not apply changes such as container environment settings.

# Check the updated instance and health status
docker compose ps -a app

Follow with docker compose logs --tail 100 app and a real request. On failure retain logs, restore the recorded previous image/configuration, and run up again. Image rollback does not undo data migrations.

Run in the intended Compose directory, or specify -f and -p. restart reuses existing containers and does not apply edited environment variables; up -d recreates when necessary. Add --build for locally built code. Full config output may contain expanded credentials.

CommandEffect
docker stop -t 30 myappRequests stop using the configured signal, then kills after timeout
docker compose downRemoves project containers/networks; named volumes stay by default
docker compose down -vAlso removes managed named and attached anonymous volumes; external volumes are excluded

Locate usage before deleting objects

Choose objects from the usage inventory

# Inspect image, container, volume, and cache usage
docker system df -v

Reclaimable is a reference-based estimate, not permission to delete business data. Shared layers prevent simple addition of sizes.

# List stopped containers for individual retention review
docker container ls -a --filter status=exited

Inspect logs, metadata, mounts, and needed writable-layer files before deletion. Being stopped does not make the data disposable.

# Remove a reviewed, no-longer-needed stopped container
docker rm myapp

This removes the writable layer while named volumes remain. If running, stop and verify first instead of forcing removal. Confirm absence with docker ps -a.

# Identify the volume, labels, and mount location
docker volume inspect app-data

Also inspect references with docker ps -a --filter volume=app-data and test the backup. Run docker volume rm app-data only when data destruction is intended; unreferenced does not mean worthless.

Separate image cleanup from transfer

# Locate the image reference and size
docker image ls

Use docker image history nginx:stable to inspect layers. Remove a reviewed image with docker image rm IMAGE, selecting IMAGE from the list rather than clearing everything.

# Export the image and layers to a client archive
docker save nginx:stable -o nginx-image.tar

Choose a path that does not overwrite an existing backup. Transfer the archive before running the next step on the destination client.

# Import the archive into the destination daemon
docker load -i nginx-image.tar

Check loaded tags and the image ID with docker image inspect nginx:stable. Save/load excludes volumes, runtime settings, and current container writable layers.

Confirm backups and retention needs before targeted rm/rmi/volume rm. Prune determines eligibility from references, not business value; avoid using system prune -a --volumes as a routine fix. Image save/load and container commit do not back up mounted volumes.

Access to docker.sock generally grants powerful host control; do not fix permissions with chmod 666. Inspect the daemon firewall backend and networks; setting "iptables": false does not select the nftables backend.

Docker storage · Compose up · Docker nftables