Back to Containers & Runtime Environments Mastery Series

Part 6: Docker CLI Mastery

May 14, 2026 Wasil Zafar 30 min read

The Docker CLI is where architecture meets daily workflow. This article takes you from help commands to production-grade container management — covering lifecycle operations, image workflows, inspection with Go templates, resource monitoring, and productivity tips that turn you from a Docker user into a Docker power user.

Table of Contents

  1. CLI Philosophy
  2. Container Lifecycle
  3. Running Containers
  4. Executing in Containers
  5. Image Management
  6. Inspection & Debugging
  7. Resource Monitoring
  8. Export/Import & Save/Load
  9. System Maintenance
  10. CLI Tips & Productivity
  11. Exercises
  12. Conclusion & Next Steps

CLI Philosophy & Structure

Docker's CLI has evolved from a flat list of commands (docker ps, docker rm) into a structured hierarchy of management commands. Understanding this structure is the first step to CLI mastery.

Management Commands vs Legacy Shorthand

Docker 1.13 introduced management commands that group operations logically. The legacy shorthand still works, but the management command form is more explicit and discoverable:

Management Command Legacy Shorthand Purpose
docker container lsdocker psList running containers
docker container rmdocker rmRemove containers
docker image lsdocker imagesList images
docker image rmdocker rmiRemove images
docker network ls(same)List networks
docker volume ls(same)List volumes
docker container inspectdocker inspectInspect container details
docker container logsdocker logsView container logs
Best Practice: Use management commands (docker container ls) in scripts and documentation for clarity. Use shorthand (docker ps) for interactive terminal sessions where speed matters. Both produce identical results.

The Help System

Docker's built-in help is your best reference. Every command supports --help, and the management command structure makes discovery natural:

# Discover all management commands
docker --help
# Management Commands:
#   builder     Manage builds
#   config      Manage Swarm configs
#   container   Manage containers
#   image       Manage images
#   network     Manage networks
#   system      Manage Docker
#   volume      Manage volumes

# Discover all container sub-commands
docker container --help
# Commands:
#   attach    Attach to a running container
#   commit    Create new image from container changes
#   cp        Copy files between container and host
#   create    Create a new container
#   diff      Inspect filesystem changes
#   exec      Execute a command in running container
#   inspect   Display detailed container info
#   kill      Kill a running container
#   logs      Fetch container logs
#   ls        List containers
#   pause     Pause all processes in container
#   port      List port mappings
#   prune     Remove all stopped containers
#   rename    Rename a container
#   restart   Restart a container
#   rm        Remove containers
#   run       Create and run a new container
#   start     Start stopped containers
#   stats     Display resource usage statistics
#   stop      Stop running containers
#   top       Display running processes
#   unpause   Unpause a paused container
#   update    Update container configuration
#   wait      Block until container stops

# Get detailed help for a specific command
docker container run --help
# Shows all flags: -d, -it, --name, -p, -v, -e, --network, etc.

Container Lifecycle Commands

A Docker container transitions through well-defined states. Understanding these transitions — and the commands that trigger them — is fundamental to container management.

Container Lifecycle State Diagram
stateDiagram-v2
    [*] --> Created: docker create
    Created --> Running: docker start
    [*] --> Running: docker run
    Running --> Paused: docker pause
    Paused --> Running: docker unpause
    Running --> Stopped: docker stop (SIGTERM → SIGKILL)
    Running --> Stopped: docker kill (SIGKILL)
    Stopped --> Running: docker start / docker restart
    Stopped --> Removed: docker rm
    Running --> Stopped: container exits (process ends)
    Removed --> [*]

    style Created fill:#16476A,color:#ffffff
    style Running fill:#3B9797,color:#ffffff
    style Paused fill:#BF092F,color:#ffffff
    style Stopped fill:#132440,color:#ffffff
    style Removed fill:#666666,color:#ffffff
                            

Lifecycle Commands in Detail

# CREATE: Prepare a container without starting it
# Useful when you want to configure before running
docker create --name my-nginx -p 8080:80 nginx:latest
# Returns container ID: a1b2c3d4e5f6...
# Container is in "Created" state

# START: Begin execution of a created/stopped container
docker start my-nginx
# Container moves to "Running" state

# RUN: Create + Start in one command (most common)
docker run -d --name web -p 8080:80 nginx:latest
# Equivalent to: docker create + docker start

# STOP: Graceful shutdown (SIGTERM, then SIGKILL after timeout)
docker stop my-nginx
# Sends SIGTERM to PID 1, waits 10s (default), then SIGKILL
# Change timeout: docker stop -t 30 my-nginx

# KILL: Immediate termination (SIGKILL by default)
docker kill my-nginx
# Instantly terminates — no graceful shutdown
# Send specific signal: docker kill -s SIGUSR1 my-nginx

# RESTART: Stop + Start
docker restart my-nginx
# Equivalent to: docker stop + docker start

# PAUSE: Freeze all processes (uses cgroup freezer)
docker pause my-nginx
# All processes suspended — no CPU consumed, memory retained

# UNPAUSE: Resume frozen processes
docker unpause my-nginx

# RM: Remove a stopped container
docker rm my-nginx
# Force remove a running container:
docker rm -f my-nginx  # Sends SIGKILL first, then removes

# Remove all stopped containers at once
docker container prune -f
# WARNING! This will remove all stopped containers.
Signals & Shutdown

docker stop vs docker kill — When to Use Each

docker stop sends SIGTERM first, allowing the application to flush buffers, close connections, and save state. After the grace period (default 10 seconds), it escalates to SIGKILL. docker kill sends SIGKILL immediately — no cleanup happens.

  • Use docker stop for production containers: databases, web servers, message queues — anything that needs graceful shutdown
  • Use docker kill for stuck containers that don't respond to SIGTERM, or testing crash scenarios
  • Increase timeout for slow-shutdown apps: docker stop -t 60 postgres-db

Many Docker images fail to handle signals correctly because they use shell form CMD which runs under /bin/sh (PID 1) — the actual app doesn't receive the signal. We'll address this in Part 7 (Dockerfile Fundamentals).

SIGTERM SIGKILL Graceful Shutdown

Running Containers: docker run Deep Dive

docker run is the most complex and most-used Docker command. It combines image pull, container creation, and container start — with dozens of flags controlling every aspect of execution.

Flag Purpose Example
-dDetached mode (run in background)docker run -d nginx
-itInteractive + TTY (for shell access)docker run -it ubuntu bash
--nameAssign a name to the containerdocker run --name web nginx
-pPort mapping (host:container)docker run -p 8080:80 nginx
-vVolume mount (host:container or named)docker run -v data:/app/data nginx
-eSet environment variabledocker run -e NODE_ENV=production node
--networkConnect to a specific networkdocker run --network mynet nginx
--rmAuto-remove when container stopsdocker run --rm alpine echo hi
--restartRestart policydocker run --restart unless-stopped nginx
-mMemory limitdocker run -m 512m nginx
--cpusCPU limitdocker run --cpus 1.5 nginx
--env-fileRead environment from filedocker run --env-file .env app
-wSet working directorydocker run -w /app node npm start
-uRun as specific userdocker run -u 1000:1000 app
--read-onlyRead-only root filesystemdocker run --read-only nginx

Practical docker run Examples

# Development web server with live code reload
docker run -d --name dev-server \
    -p 3000:3000 \
    -v $(pwd)/src:/app/src \
    -e NODE_ENV=development \
    --rm \
    node:20-alpine sh -c "cd /app && npm run dev"

# Production database with resource limits and persistence
docker run -d --name postgres-prod \
    -p 5432:5432 \
    -v pgdata:/var/lib/postgresql/data \
    -e POSTGRES_USER=admin \
    -e POSTGRES_PASSWORD=secretpassword \
    -e POSTGRES_DB=myapp \
    -m 2g --cpus 2.0 \
    --restart unless-stopped \
    postgres:16-alpine

# One-off utility container (auto-removes when done)
docker run --rm -v $(pwd):/workspace -w /workspace \
    python:3.12-slim python -c "
import json
with open('config.json') as f:
    data = json.load(f)
print(f'Found {len(data)} entries')
"

# Redis with custom configuration
docker run -d --name cache \
    -p 6379:6379 \
    -v redis-data:/data \
    --restart always \
    redis:7-alpine redis-server --appendonly yes --maxmemory 256mb

# Security-hardened container
docker run -d --name secure-app \
    --read-only \
    --tmpfs /tmp:size=100m \
    --tmpfs /run \
    -u 1000:1000 \
    --cap-drop ALL \
    --cap-add NET_BIND_SERVICE \
    --security-opt no-new-privileges:true \
    myapp:latest
Security Warning: Never use --privileged in production. This flag disables all security restrictions and gives the container full access to the host — effectively equivalent to root access on the host machine. If you need specific capabilities, use --cap-add to grant only what's required.

Executing in Running Containers

docker exec is your primary debugging tool. It runs a new process inside an already-running container, inheriting the container's namespaces (but running as a separate PID).

# Open an interactive shell in a running container
docker exec -it my-nginx /bin/bash
# If bash isn't available (Alpine images):
docker exec -it my-nginx /bin/sh

# Run a single command and return output
docker exec my-nginx cat /etc/nginx/nginx.conf
# Prints the nginx configuration file

# Run as a specific user
docker exec -u root my-nginx apt-get update
# Executes as root even if container runs as non-root

# Set environment variables for the exec session
docker exec -e DEBUG=true my-app node /scripts/health-check.js

# Execute in a specific working directory
docker exec -w /var/log my-nginx ls -la
# Lists files in /var/log inside the container

# Debugging network connectivity
docker exec my-app ping -c 3 database
# PING database (172.25.0.3): 56 data bytes
# 64 bytes from 172.25.0.3: seq=0 ttl=64 time=0.089 ms

docker exec my-app nslookup database
# Server:    127.0.0.11
# Name:      database
# Address 1: 172.25.0.3

# Check what processes are running
docker exec my-app ps aux
# PID   USER  COMMAND
# 1     node  node server.js
# 45    node  /bin/sh  (your exec session)

# Copy a configuration file for debugging
docker exec my-app cat /app/config/production.yml > local-debug.yml
exec vs attach: docker exec starts a new process in the container. docker attach connects your terminal to the container's PID 1 stdout/stdin. Use exec for debugging (it won't kill the container if you Ctrl+C). Use attach only when you need to interact with the main process directly.

Image Management

Images are the building blocks of containers. The Docker CLI provides complete control over the image lifecycle — from pulling and building to tagging, pushing, and cleanup.

# Pull an image from a registry
docker pull nginx:latest
# latest: Pulling from library/nginx
# a2abf6c4d29d: Pull complete   ← individual layer downloads
# a9edb18cadd3: Pull complete
# Digest: sha256:abc123...
# Status: Downloaded newer image for nginx:latest

# Pull a specific platform variant
docker pull --platform linux/arm64 python:3.12-slim

# List all local images
docker images
# REPOSITORY   TAG          IMAGE ID       CREATED        SIZE
# nginx        latest       605c77e624dd   3 days ago     187MB
# python       3.12-slim    d4a34e5a8c23   1 week ago     130MB
# postgres     16-alpine    f9b577fb1ed6   2 weeks ago    243MB

# Filter images
docker images --filter "dangling=true"    # Untagged images ()
docker images --filter "reference=nginx"  # Only nginx images
docker images --format "{{.Repository}}:{{.Tag}} ({{.Size}})"
# nginx:latest (187MB)
# python:3.12-slim (130MB)

# Tag an image (create a new reference to the same image)
docker tag nginx:latest myregistry.io/team/nginx:v2.1.0
docker tag nginx:latest myregistry.io/team/nginx:latest

# Push to a registry
docker push myregistry.io/team/nginx:v2.1.0
docker push myregistry.io/team/nginx:latest

# Remove images
docker rmi nginx:latest              # Remove by name:tag
docker rmi 605c77e624dd              # Remove by ID
docker rmi $(docker images -q -f "dangling=true")  # Remove all dangling

# Image history (show layers)
docker history nginx:latest
# IMAGE          CREATED       CREATED BY                                      SIZE
# 605c77e624dd   3 days ago    CMD ["nginx" "-g" "daemon off;"]                0B
#       3 days ago    EXPOSE map[80/tcp:{}]                           0B
#       3 days ago    STOPSIGNAL SIGQUIT                              0B
#       3 days ago    RUN /bin/sh -c set -x && apt-get update...     58MB

# Build an image from a Dockerfile
docker build -t myapp:latest .
docker build -t myapp:v1.2.3 -f Dockerfile.production .

# Prune unused images
docker image prune -f          # Remove dangling images only
docker image prune -a -f       # Remove ALL unused images (not used by any container)

Inspection & Debugging

When containers misbehave, the Docker CLI provides powerful inspection tools. Mastering docker logs and docker inspect (especially with Go template formatting) separates beginners from experts.

docker logs — Container Output

# View all logs from a container
docker logs my-nginx

# Follow logs in real-time (like tail -f)
docker logs -f my-nginx
# 172.17.0.1 - - [14/May/2026:10:15:30 +0000] "GET / HTTP/1.1" 200 615
# (streams new log entries as they occur)
# Ctrl+C to stop following

# Show only the last N lines
docker logs --tail 50 my-nginx

# Show logs since a specific time
docker logs --since 2026-05-14T10:00:00 my-nginx
docker logs --since 30m my-nginx    # Last 30 minutes
docker logs --since 2h my-nginx     # Last 2 hours

# Show timestamps with each log line
docker logs -t my-nginx
# 2026-05-14T10:15:30.123456789Z 172.17.0.1 - "GET / HTTP/1.1" 200

# Combine flags for debugging sessions
docker logs -f --tail 100 --since 5m my-nginx

# View logs from a stopped container (useful for crash analysis)
docker logs crashed-container 2>&1 | tail -50

docker inspect — Deep Container Metadata

docker inspect returns the complete JSON metadata for any Docker object. The real power comes from Go template formatting to extract exactly the fields you need:

# Full JSON output (verbose)
docker inspect my-nginx | jq .

# Get container IP address
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-nginx
# 172.17.0.2

# Get container state (running, paused, stopped)
docker inspect -f '{{.State.Status}}' my-nginx
# running

# Get restart count and last start time
docker inspect -f 'Restarts: {{.RestartCount}}, Started: {{.State.StartedAt}}' my-nginx
# Restarts: 0, Started: 2026-05-14T10:00:00.123456Z

# Get port bindings
docker inspect -f '{{json .NetworkSettings.Ports}}' my-nginx | jq .
# { "80/tcp": [{"HostIp": "0.0.0.0", "HostPort": "8080"}] }

# Get mounted volumes
docker inspect -f '{{range .Mounts}}{{.Type}}: {{.Source}} → {{.Destination}}{{"\n"}}{{end}}' my-app
# volume: /var/lib/docker/volumes/data/_data → /app/data
# bind: /home/user/config → /app/config

# Get environment variables
docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' my-app
# NODE_ENV=production
# DATABASE_URL=postgres://...
# PATH=/usr/local/bin:/usr/bin

# Get the full command that's running
docker inspect -f '{{.Config.Cmd}}' my-nginx
# [nginx -g daemon off;]

# Get image used by container
docker inspect -f '{{.Config.Image}}' my-nginx
# nginx:latest

# Get container health status (if HEALTHCHECK defined)
docker inspect -f '{{.State.Health.Status}}' my-app
# healthy

# Compare configs of two containers
diff <(docker inspect container-a) <(docker inspect container-b)
Debugging Toolkit

docker diff & docker top — Lesser-Known Gems

Two often-overlooked commands provide critical debugging information:

  • docker diff <container> — Shows all filesystem changes since the container started (added/modified/deleted files). Invaluable for understanding what a container modifies at runtime.
  • docker top <container> — Shows running processes inside the container as seen from the host (with host PIDs). Unlike docker exec ps, this doesn't require ps to be installed in the container.
# See what files a container has changed
docker diff my-nginx
# C /var           (Changed)
# C /var/cache     (Changed)
# A /var/cache/nginx/client_temp  (Added)
# C /run           (Changed)
# A /run/nginx.pid (Added)

# See processes from the host's perspective
docker top my-nginx
# UID    PID    PPID   CMD
# root   4567   4545   nginx: master process
# www    4589   4567   nginx: worker process
# www    4590   4567   nginx: worker process
Filesystem Forensics Process Inspection Runtime Analysis

Resource Monitoring

Understanding resource consumption is essential for capacity planning and debugging performance issues. Docker provides real-time statistics and system-wide disk usage reporting.

# Real-time resource usage (like top for containers)
docker stats
# CONTAINER ID   NAME        CPU %   MEM USAGE / LIMIT     MEM %   NET I/O          BLOCK I/O
# a1b2c3d4e5f6   web         0.15%   45.2MiB / 512MiB      8.83%   1.2kB / 648B     0B / 0B
# f6e5d4c3b2a1   postgres    1.20%   128MiB / 2GiB         6.25%   2.1kB / 1.8kB    12MB / 45MB
# 9f8e7d6c5b4a   redis       0.05%   12MiB / 256MiB        4.69%   890B / 450B      0B / 2.1MB

# Stats for specific containers only
docker stats web postgres redis

# Single snapshot (non-streaming) — useful in scripts
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# NAME        CPU %     MEM USAGE / LIMIT
# web         0.15%     45.2MiB / 512MiB
# postgres    1.20%     128MiB / 2GiB

# System-wide disk usage
docker system df
# TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
# Images          15        5         4.2GB     2.8GB (66%)
# Containers      8         3         120MB     95MB (79%)
# Local Volumes   12        4         1.5GB     800MB (53%)
# Build Cache     23        0         890MB     890MB (100%)

# Detailed breakdown
docker system df -v
# Shows individual images, containers, and volumes with sizes
Interpreting docker stats: The MEM % column shows usage relative to the container's memory limit (-m flag). If no limit is set, it shows percentage of total host memory. CPU % can exceed 100% on multi-core systems (200% = 2 full cores). NET I/O and BLOCK I/O are cumulative since container start.

Container Export/Import vs Image Save/Load

Docker provides two pairs of commands for moving containers and images between systems. They serve different purposes and produce different results:

Command Pair Input Output Preserves Layers Use Case
docker save / docker load Image (by name:tag) tar archive with all layers + metadata Yes (all layers, tags, history) Transfer images to air-gapped systems
docker export / docker import Container (running or stopped) tar archive of flattened filesystem No (single flat layer, no metadata) Snapshot a container's current filesystem state
# SAVE/LOAD: Transfer complete images with all layers
# Save one or more images to a tar file
docker save -o images-backup.tar nginx:latest postgres:16 redis:7
# File contains all layers, manifests, and tags

# Load images on the destination machine
docker load -i images-backup.tar
# Loaded image: nginx:latest
# Loaded image: postgres:16
# Loaded image: redis:7

# Pipe through SSH for direct transfer
docker save myapp:latest | ssh user@remote 'docker load'

# Compress for smaller transfer
docker save myapp:latest | gzip > myapp-latest.tar.gz
gunzip -c myapp-latest.tar.gz | docker load

# EXPORT/IMPORT: Snapshot a container's filesystem
# Export a container's current state to a flat tar
docker export my-container > container-snapshot.tar

# Import as a new image (loses all metadata, history, CMD, ENV, etc.)
docker import container-snapshot.tar myimage:snapshot
# Creates a single-layer image from the flat filesystem

# Import with custom CMD
cat container-snapshot.tar | docker import --change "CMD [\"nginx\", \"-g\", \"daemon off;\"]" - myimage:restored
Choose wisely: Use save/load for 99% of use cases — it preserves the full image with layers, history, and metadata. Use export/import only when you specifically need a flattened filesystem snapshot (e.g., forensic analysis or creating a minimal base image from a running container).

System Maintenance

Docker accumulates unused resources over time — stopped containers, dangling images, orphaned volumes, and build cache. Regular maintenance prevents disk exhaustion.

# Nuclear option: remove ALL unused resources
docker system prune -f
# Removes: stopped containers, unused networks, dangling images, build cache
# WARNING! This will remove:
#   - all stopped containers
#   - all networks not used by at least one container
#   - all dangling images
#   - all dangling build cache

# Include unused images (not just dangling)
docker system prune -a -f
# Also removes images not referenced by any container
# This can free gigabytes of space

# Include volumes (DANGEROUS — data loss possible!)
docker system prune -a --volumes -f
# Also removes all unused volumes (named and anonymous)

# Targeted cleanup — more surgical approach
docker container prune -f     # Remove all stopped containers
docker image prune -f         # Remove dangling images only
docker image prune -a -f      # Remove ALL unused images
docker volume prune -f        # Remove unused volumes
docker network prune -f       # Remove unused networks
docker builder prune -f       # Clear build cache

# Remove containers older than 24 hours
docker container prune -f --filter "until=24h"

# Remove images older than 7 days
docker image prune -a -f --filter "until=168h"

# Check what would be removed before pruning
docker system df              # See overall usage
docker images -f "dangling=true"   # List dangling images
docker ps -a -f "status=exited"    # List stopped containers
docker volume ls -f "dangling=true" # List orphaned volumes

CLI Tips & Productivity

Power users leverage aliases, format strings, and Docker's built-in filtering to work faster and more precisely.

# Useful shell aliases (add to ~/.bashrc or ~/.zshrc)
alias dps='docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"'
alias dpsa='docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"'
alias dimg='docker images --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}\t{{.CreatedSince}}"'
alias dlogs='docker logs -f --tail 100'
alias dexec='docker exec -it'
alias dprune='docker system prune -af && docker volume prune -f'
alias dstop='docker stop $(docker ps -q)'  # Stop all running containers

# Filtering with --filter
docker ps -f "status=running"
docker ps -f "name=web"
docker ps -f "ancestor=nginx"        # Containers from nginx image
docker ps -f "label=environment=prod"
docker images -f "before=nginx:1.24"  # Images created before this one

# Custom format strings for scripting
docker ps -q                          # Only container IDs
docker ps --format '{{.ID}}'          # Same as -q
docker ps --format '{{.Names}}: {{.Status}}'
docker inspect -f '{{.State.Pid}}' my-container  # Get PID

# Batch operations using subshells
docker stop $(docker ps -q)                    # Stop ALL running containers
docker rm $(docker ps -aq)                     # Remove ALL containers
docker rmi $(docker images -q -f dangling=true) # Remove dangling images

# Docker context — manage multiple Docker hosts
docker context create staging --docker "host=ssh://user@staging.example.com"
docker context use staging
docker ps                    # Now shows containers on staging server
docker context use default   # Switch back to local

# .docker/config.json — persistent settings
cat ~/.docker/config.json
# {
#   "psFormat": "table {{.Names}}\t{{.Status}}\t{{.Ports}}",
#   "imagesFormat": "table {{.Repository}}\t{{.Tag}}\t{{.Size}}",
#   "detachKeys": "ctrl-q,ctrl-q"
# }
Productivity Hack

Docker cp — Transfer Files Without Volumes

docker cp copies files between host and container at any time — the container can be running or stopped. It's invaluable for quick debugging without pre-configuring volumes:

# Copy from container to host
docker cp my-app:/app/logs/error.log ./debug/
docker cp my-app:/etc/nginx/nginx.conf ./nginx-backup.conf

# Copy from host to container
docker cp ./hotfix.js my-app:/app/src/hotfix.js
docker cp ./new-config.yml my-app:/app/config/

# Copy an entire directory
docker cp my-app:/app/data/ ./backup-data/

# Works with stopped containers too!
docker cp crashed-container:/var/log/app.log ./crash-analysis/
File Transfer Debugging Hot Patching

Exercises

  1. Lifecycle Marathon — Create a container with docker create, start it, pause it, unpause it, stop it, restart it, and finally remove it. At each step, verify the state with docker inspect -f '{{.State.Status}}'.
  2. Go Template Mastery — Using only docker inspect with format strings, extract: (a) the container's IP on a user-defined network, (b) all mounted volumes with their source paths, (c) the exact command running as PID 1, (d) the container's health check command.
  3. Resource Detective — Run 5 containers (nginx, postgres, redis, node app, python app) with different memory limits. Use docker stats --no-stream with a custom format to generate a markdown table of container name, CPU %, memory usage, and memory limit.
  4. Cleanup Audit — Run docker system df -v and identify: (a) images that are candidates for removal, (b) containers that have been stopped for more than 24 hours, (c) volumes not attached to any container. Write a cleanup script that removes only safe-to-remove resources.
  5. Air-Gap Transfer — Save a multi-layer image to a tar file, check the file size, compress it, transfer to a different Docker host (or simulate with docker rmi + docker load), and verify all tags and layers were preserved.

Conclusion & Next Steps

The Docker CLI is far more than docker run and docker stop. Mastering the full command set — lifecycle management, inspection with Go templates, resource monitoring, and system maintenance — gives you complete operational control over your container infrastructure.

Key takeaways from this article:

  • Management commands (docker container, docker image) provide discoverability; legacy shorthand provides speed
  • Container lifecycle follows a clear state machine: Created → Running → Paused/Stopped → Removed
  • docker run is the Swiss Army knife — understand every flag for both development and production scenarios
  • docker exec is your debugging entry point; docker logs and docker inspect are your diagnostic tools
  • Go template formatting transforms docker inspect from a JSON dump into a precision extraction tool
  • Regular maintenance with docker system prune prevents disk exhaustion in development and CI environments
  • save/load preserves image layers for transport; export/import flattens container filesystems

Now that you can drive Docker fluently from the command line, Part 7 takes you behind the scenes of image creation — the Dockerfile. You'll learn how every instruction translates to a layer, how build caching works, and how to write Dockerfiles that produce minimal, secure, and cache-efficient images.

Next in the Series

In Part 7: Dockerfile Fundamentals, we will master every Dockerfile instruction — FROM, RUN, COPY, CMD, ENTRYPOINT — and understand how the layer-by-layer build model affects image size, security, and build performance.