Basic Docker Commands: Images, Containers, Volumes

Week 1, Wednesday - Morning Session

Lecture Overview

In this session, we'll explore the fundamental Docker commands that allow you to work with the three core components of Docker: images, containers, and volumes. By the end of this session, you'll have a practical understanding of how to create, manage, and interact with these components using the Docker command-line interface (CLI). These skills form the foundation of working with Docker in your development workflow.

Docker Command Structure

Before diving into specific commands, let's understand the general structure of Docker commands:

docker [command] [subcommand] [options] [arguments]

Docker also supports a more traditional command style for many operations:

docker run nginx  # Instead of docker container run nginx

Both forms work, but we'll focus primarily on the newer command structure as it's more consistent and clearer about which Docker object you're working with.

Analogy: Docker commands are like giving instructions to a warehouse manager. You first specify which department you want to talk to (images, containers, volumes), then what action you want them to take (create, list, remove), followed by any special conditions (options) and finally what items you're referring to (arguments).

Working with Docker Images

Docker images are the blueprints for containers. They contain all the code, runtime, libraries, and dependencies your application needs. Let's explore the essential commands for working with images:

Listing Images

To see what images are available on your system:

docker image ls
# or the shorter form
docker images

Example output:

REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
nginx         latest    605c77e624dd   3 weeks ago    142MB
python        3.10      a7830c32cb83   4 weeks ago    917MB
ubuntu        latest    27941809078c   5 weeks ago    77.8MB

Pulling Images

To download an image from a registry (default is Docker Hub):

docker image pull [OPTIONS] NAME[:TAG]

# Examples:
docker image pull nginx
docker image pull python:3.9
docker image pull redis:alpine

If you don't specify a tag, Docker uses latest by default.

Best practice: Always specify a version tag in production to ensure consistency. The latest tag can change over time as new versions are released.

Searching for Images

To search for images available on Docker Hub:

docker search [OPTIONS] TERM

# Example:
docker search python

Image Details

To see detailed information about an image:

docker image inspect [OPTIONS] IMAGE

# Example:
docker image inspect nginx

This provides a JSON output with comprehensive details about the image, including its layers, configuration, and creation metadata.

Building Images

To build an image from a Dockerfile:

docker image build [OPTIONS] PATH

# Example:
docker image build -t myapp:1.0 .

The -t flag tags the image with a name (and optionally a tag), and the path . tells Docker to look for a Dockerfile in the current directory.

Example Dockerfile:

FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "app.py"]

Removing Images

To delete an image from your local system:

docker image rm [OPTIONS] IMAGE [IMAGE...]
# or the shorter form
docker rmi [OPTIONS] IMAGE [IMAGE...]

# Examples:
docker image rm nginx
docker image rm python:3.8
docker image rm a7830c32cb83  # Remove by image ID

You can remove multiple images by listing them with spaces between.

Note: You cannot remove an image if it's being used by a container. You'll need to stop and remove the container first.

Saving and Loading Images

To save an image to a tar archive (useful for transferring without a registry):

docker image save -o filename.tar IMAGE

# Example:
docker image save -o myapp.tar myapp:1.0

To load an image from a tar archive:

docker image load -i filename.tar

# Example:
docker image load -i myapp.tar

Tagging Images

To create a new tag for an existing image:

docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

# Example:
docker image tag myapp:1.0 myapp:latest
docker image tag myapp:1.0 registry.example.com/myapp:1.0

Real-world application: When developing a web application, you might pull a base image like python:3.9-slim, build your application on top of it with a Dockerfile, tag it with your application name and version, and then push it to a registry for deployment. Each image version represents a specific state of your application, enabling easy rollbacks if needed.

Working with Docker Containers

Containers are running instances of Docker images. They are isolated environments where your applications run. Here are the essential commands for managing containers:

Creating and Running Containers

To create and start a container in one command:

docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]
# or the shorter form
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

# Examples:
docker container run nginx
docker container run -d --name my-nginx -p 8080:80 nginx
docker container run -it --rm ubuntu bash

Common options:

Analogy: If an image is like a blueprint for a house, then a container is like an actual house built from that blueprint. Running a container is like moving into the house - you're making the static blueprint into a living, functional space. The options are like specifying features of the house: whether it's connected to the city water supply (-p), what furniture goes in it (-v), and whether it should be demolished when you move out (--rm).

Listing Containers

To list running containers:

docker container ls
# or the shorter form
docker ps

To list all containers (including stopped ones):

docker container ls -a
# or
docker ps -a

Starting and Stopping Containers

To stop a running container:

docker container stop [OPTIONS] CONTAINER [CONTAINER...]
# or
docker stop [OPTIONS] CONTAINER [CONTAINER...]

# Example:
docker container stop my-nginx

To start a stopped container:

docker container start [OPTIONS] CONTAINER [CONTAINER...]
# or
docker start [OPTIONS] CONTAINER [CONTAINER...]

# Example:
docker container start my-nginx

To restart a container:

docker container restart [OPTIONS] CONTAINER [CONTAINER...]
# or
docker restart [OPTIONS] CONTAINER [CONTAINER...]

# Example:
docker container restart my-nginx

Removing Containers

To remove a container:

docker container rm [OPTIONS] CONTAINER [CONTAINER...]
# or
docker rm [OPTIONS] CONTAINER [CONTAINER...]

# Example:
docker container rm my-nginx

To force removal of a running container:

docker container rm -f my-nginx

To remove all stopped containers:

docker container prune

Viewing Container Logs

To view the logs of a container:

docker container logs [OPTIONS] CONTAINER
# or
docker logs [OPTIONS] CONTAINER

# Examples:
docker container logs my-nginx
docker container logs --follow my-nginx  # Stream the logs
docker container logs --tail 100 my-nginx  # Show only the last 100 lines

Executing Commands in Running Containers

To run a command inside a running container:

docker container exec [OPTIONS] CONTAINER COMMAND [ARG...]
# or
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

# Examples:
docker container exec my-nginx ls -la
docker container exec -it my-nginx bash  # Interactive shell

Common use case: Using exec to get a shell in a running container for debugging:

docker exec -it my-python-app /bin/bash
# Now you're inside the container and can run commands
ls -la
cat /etc/hosts
python -m pip list
exit  # Exit the container shell

Copying Files To/From Containers

To copy files between your host and a container:

docker container cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
docker container cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH
# or
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH

# Examples:
docker container cp my-nginx:/etc/nginx/nginx.conf ./nginx.conf  # From container to host
docker container cp ./index.html my-nginx:/usr/share/nginx/html/  # From host to container

Inspecting Containers

To view detailed information about a container:

docker container inspect [OPTIONS] CONTAINER [CONTAINER...]
# or
docker inspect [OPTIONS] CONTAINER [CONTAINER...]

# Example:
docker container inspect my-nginx

To view container resource usage statistics:

docker container stats [OPTIONS] [CONTAINER...]
# or
docker stats [OPTIONS] [CONTAINER...]

# Examples:
docker container stats  # All containers
docker container stats my-nginx  # Specific container

Working with Docker Volumes

Volumes are the preferred way to persist data generated and used by Docker containers. Let's explore the essential commands for working with volumes:

Creating Volumes

To create a named volume:

docker volume create [OPTIONS] [VOLUME]

# Example:
docker volume create my-data

Note: You don't always need to explicitly create volumes. When you use a volume mount in a docker run command with a volume that doesn't exist, Docker will create it automatically.

Listing Volumes

To list all volumes:

docker volume ls [OPTIONS]

# Example:
docker volume ls

Inspecting Volumes

To view detailed information about a volume:

docker volume inspect [OPTIONS] VOLUME [VOLUME...]

# Example:
docker volume inspect my-data

This will show you where the volume is stored on your host machine, along with other metadata.

Using Volumes with Containers

To use a volume when running a container:

docker container run -v volume_name:/container/path [OTHER_OPTIONS] IMAGE

# Examples:
docker container run -v my-data:/app/data nginx
docker container run -v postgres_data:/var/lib/postgresql/data postgres:13

Analogy: If containers are like temporary rental apartments, volumes are like storage units that remain even after you move out. When you rent a new apartment (start a new container), you can connect it to your existing storage unit (volume) to access your persistent belongings (data).

Bind Mounts

Bind mounts are similar to volumes but mount a specific directory from your host into the container:

docker container run -v /host/path:/container/path [OTHER_OPTIONS] IMAGE

# Example:
docker container run -v $(pwd):/app nginx

This is particularly useful during development to reflect code changes immediately in the container.

Practical development example:

docker container run -v $(pwd):/app -p 5000:5000 -w /app python:3.9 python app.py

This command:

  • Mounts the current directory into /app in the container
  • Publishes port 5000
  • Sets the working directory to /app
  • Uses the python:3.9 image
  • Runs the command python app.py

Any changes you make to your code on the host will be immediately available in the container.

Removing Volumes

To remove a volume:

docker volume rm [OPTIONS] VOLUME [VOLUME...]

# Example:
docker volume rm my-data

To remove all unused volumes:

docker volume prune

Warning: Removing a volume permanently deletes all data stored in it. Make sure to back up any important data before removing volumes.

Volume Drivers

Docker supports various volume drivers for different storage backends:

docker volume create --driver=local my-local-volume
docker volume create --driver=nfs my-nfs-volume

The default is the local driver, but plugins exist for many storage systems like NFS, Amazon EBS, and more.

Real-world application: In a production environment, you might use a cloud provider's volume driver to ensure data persistence even if containers move between hosts. For example, using Amazon EBS volumes with Docker containers running on AWS ensures that your data survives even if the underlying instance fails.

Combining Commands: Common Workflows

Let's explore some common workflows that combine various Docker commands:

Development Workflow with Python

# Pull a Python image
docker pull python:3.9-slim

# Run a container with the current directory mounted, in interactive mode
docker run -it --rm -v $(pwd):/app -w /app python:3.9-slim bash

# Inside the container:
pip install -r requirements.txt
python app.py
# The application is now running, and you can access it from your host

# Press Ctrl+C to stop the application
# Exit the container
exit
# The container is automatically removed due to the --rm flag

Running a Database with Persistent Storage

# Create a volume for database data
docker volume create postgres_data

# Run a PostgreSQL container with the volume
docker run -d --name my-postgres \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -v postgres_data:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:13

# Check container status
docker ps

# View logs to ensure the database started properly
docker logs my-postgres

# When done, stop the container
docker stop my-postgres

# Later, restart the container - data persists
docker start my-postgres

Building and Testing a Web Application

# Build a Docker image from the current directory
docker build -t mywebapp:1.0 .

# Run the application
docker run -d --name webapp -p 8080:80 mywebapp:1.0

# Check if it's running
docker ps

# Test it
curl http://localhost:8080

# View the logs
docker logs webapp

# Make changes and rebuild
docker stop webapp
docker rm webapp
docker build -t mywebapp:1.1 .
docker run -d --name webapp -p 8080:80 mywebapp:1.1

Cleanup Workflow

# Stop all running containers
docker stop $(docker ps -q)

# Remove all containers
docker rm $(docker ps -a -q)

# Remove unused images
docker image prune -a

# Remove unused volumes
docker volume prune

Warning: The cleanup workflow removes all containers, unused images, and volumes. Use with caution in shared or production environments.

Command Cheat Sheet

Image Commands

Command Description
docker image ls List images
docker image pull NAME[:TAG] Download an image
docker image build -t NAME:TAG PATH Build an image from a Dockerfile
docker image rm IMAGE Remove an image
docker image prune Remove unused images
docker image inspect IMAGE View image details

Container Commands

Command Description
docker container run IMAGE Create and start a container
docker container ls List running containers
docker container ls -a List all containers
docker container stop CONTAINER Stop a container
docker container start CONTAINER Start a stopped container
docker container rm CONTAINER Remove a container
docker container exec -it CONTAINER COMMAND Run a command in a running container
docker container logs CONTAINER View container logs
docker container inspect CONTAINER View container details
docker container prune Remove all stopped containers

Volume Commands

Command Description
docker volume create VOLUME Create a volume
docker volume ls List volumes
docker volume inspect VOLUME View volume details
docker volume rm VOLUME Remove a volume
docker volume prune Remove all unused volumes

Common Options

Option Description
-d, --detach Run container in background
--name NAME Assign a name to the container
-p, --publish HOST:CONTAINER Publish container ports to the host
-v, --volume SOURCE:TARGET Mount a volume or bind mount
-e, --env KEY=VALUE Set environment variables
-it Interactive mode with terminal
--rm Remove container when it exits

Common Patterns and Best Practices

Naming Conventions

Working with Containers

Data Management

Resource Management

Real-world strategy: In a development workflow, create a script or alias for common Docker commands to simplify repetitive tasks. For example, a script that starts your development environment with the right volumes, port mappings, and environment variables can save time and reduce errors.

Docker Command Scripting Examples

Here are a few examples of useful scripts that combine Docker commands for common tasks:

Python Development Environment

Create a bash script called dev_env.sh:

#!/bin/bash
# Start a Python development environment

docker run --rm -it \
  --name python-dev \
  -v "$(pwd):/app" \
  -w /app \
  -p 5000:5000 \
  -e FLASK_ENV=development \
  -e FLASK_APP=app.py \
  python:3.9 \
  bash -c "pip install -r requirements.txt && flask run --host=0.0.0.0"

Database Backup Script

Create a script to backup a PostgreSQL database container:

#!/bin/bash
# Backup a PostgreSQL database

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="./backups"

mkdir -p "$BACKUP_DIR"

# Execute pg_dump inside the container
docker exec -i postgres_container pg_dump -U postgres my_database > "$BACKUP_DIR/backup_$TIMESTAMP.sql"

echo "Backup created: $BACKUP_DIR/backup_$TIMESTAMP.sql"

Cleanup Script

A script to clean up Docker resources safely:

#!/bin/bash
# Clean up Docker resources

echo "Stopping all running containers..."
docker stop $(docker ps -q)

echo "Removing stopped containers..."
docker container prune -f

echo "Removing unused images..."
docker image prune -f

echo "Removing unused volumes (except named ones)..."
docker volume prune -f

echo "Cleanup complete."

Note: Make scripts executable with chmod +x script_name.sh before running them.

Troubleshooting Common Issues

Container Won't Start

Volume Issues

Image Build Failures

General Debugging Steps

  1. Check container logs: docker logs container_name
  2. Inspect configuration: docker inspect container_name
  3. Run an interactive session: docker exec -it container_name bash
  4. Check docker daemon logs: sudo journalctl -u docker (on Linux)
  5. Verify system resources: docker system df

Example debugging process: If a container exits immediately after starting, follow these steps:

  1. Check the exit code: docker ps -a (look at the STATUS column)
  2. View logs: docker logs container_name
  3. If the logs don't show anything useful, try running the container in interactive mode:
    docker run -it --rm image_name sh
    Then execute the command that would normally start your application to see errors directly.
  4. Check if the issue is related to volume mounts or environment variables by simplifying the run command.

Command Exploration Tools

Docker provides several ways to learn more about available commands:

Getting Help

To see all available Docker commands:

docker --help

To get help on a specific command:

docker COMMAND --help

# Examples:
docker container --help
docker container run --help
docker volume create --help

Exploring Docker Info

To see information about your Docker installation:

docker info

This provides details about:

Docker System Commands

To view disk usage:

docker system df

To clean up all resources (containers, networks, images, volumes):

docker system prune -a --volumes

Warning: The prune command with --volumes will remove all unused volumes and their data. Use with extreme caution.

Key Takeaways

With these basic commands, you have the foundation to work effectively with Docker in your development workflow.

Looking Ahead

In our afternoon session, we'll apply these commands by running your first container, exploring Docker Hub for public images, creating a Dockerfile, and building your own image. The commands you've learned today will be the tools you use throughout the rest of the course and your Docker journey.

Discussion Questions

  1. What Docker commands do you think you'll use most frequently in your development workflow? Why?
  2. How might persistent volumes in Docker change the way you think about application data?
  3. What challenges do you anticipate when working with Docker images and containers?
  4. How could you use Docker commands in an automated CI/CD pipeline?
  5. Compare Docker's approach to running applications with your current development workflow. What advantages do you see?

Additional Resources