Learning Guides
Menu

Getting Started with Docker

10 min readDocker for Developers

Getting Started with Docker

This chapter covers installing Docker on your system, verifying the installation, and running your first containers. You'll learn the essential commands that form the foundation of all Docker work.

Installing Docker

Docker installation varies by operating system. For the best development experience, Docker Desktop is recommended for Mac and Windows users.

Docker Desktop for Mac

  1. Download Docker Desktop from docker.com
  2. Open the downloaded .dmg file
  3. Drag Docker to your Applications folder
  4. Launch Docker from Applications
  5. Complete the setup wizard
BASH
# Verify installation
docker --version
# Docker version 25.0.3, build 4debf41
 
docker compose version
# Docker Compose version v2.24.5

Docker Desktop for Windows

  1. Ensure Windows 10/11 64-bit (Pro, Enterprise, or Education) with WSL 2
  2. Enable WSL 2 feature and install a Linux distribution
  3. Download and install Docker Desktop
  4. Start Docker Desktop from the Start menu
POWERSHELL
# Enable WSL 2 (run as Administrator)
wsl --install
 
# After restart, verify Docker
docker --version

Warning

Docker Desktop for Windows requires WSL 2 (Windows Subsystem for Linux) for the best experience. The Hyper-V backend is available but not recommended for most development workflows.

Docker on Linux

On Linux, install Docker Engine directly:

BASH
# Ubuntu/Debian
# Remove old versions
sudo apt-get remove docker docker-engine docker.io containerd runc
 
# Install using the repository
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
 
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
 
# Set up the repository
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
 
# Install Docker Engine
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Post-Installation (Linux)

Add your user to the docker group to run commands without sudo:

BASH
# Add your user to the docker group
sudo usermod -aG docker $USER
 
# Apply the new group membership
newgrp docker
 
# Verify it works without sudo
docker run hello-world

Note

On Linux, you may need to log out and back in for group changes to take effect. The newgrp command applies changes to the current shell session.

Verifying Your Installation

Confirm Docker is installed and working:

BASH
# Check Docker version
docker --version
 
# Check detailed version information
docker version
 
# View system-wide information
docker info
 
# Run a test container
docker run hello-world

The hello-world container should produce output like:

PLAINTEXT
Hello from Docker!
This message shows that your installation appears to be working correctly.
 
To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

Your First Container

Let's run a more practical container—an nginx web server:

BASH
# Run nginx in the foreground
docker run nginx
 
# In another terminal, check if it's running
docker ps

Press Ctrl+C to stop the container. Now let's run it properly:

BASH
# Run nginx in the background (detached mode)
docker run -d -p 8080:80 --name my-nginx nginx
 
# Verify it's running
docker ps

Open http://localhost:8080 in your browser—you'll see the nginx welcome page.

Understanding the Run Command

BASH
docker run -d -p 8080:80 --name my-nginx nginx

                └─ Image name
          └─ Container name
   └─ Port mapping (host:container)
           └─ Detached mode (run in background)

Essential Docker Commands

Managing Containers

BASH
# List running containers
docker ps
 
# List all containers (including stopped)
docker ps -a
 
# Stop a container
docker stop my-nginx
 
# Start a stopped container
docker start my-nginx
 
# Restart a container
docker restart my-nginx
 
# Remove a stopped container
docker rm my-nginx
 
# Force remove a running container
docker rm -f my-nginx

Container Information

BASH
# View container logs
docker logs my-nginx
 
# Follow logs in real-time
docker logs -f my-nginx
 
# Show last 100 lines
docker logs --tail 100 my-nginx
 
# Inspect container details
docker inspect my-nginx
 
# View container resource usage
docker stats
 
# View running processes in a container
docker top my-nginx

Executing Commands in Containers

BASH
# Run a command in a running container
docker exec my-nginx ls /usr/share/nginx/html
 
# Open an interactive shell
docker exec -it my-nginx /bin/bash
 
# Run as a different user
docker exec -u root my-nginx whoami

Note

The -it flags are almost always used together: -i keeps STDIN open, and -t allocates a pseudo-TTY. Together, they give you an interactive terminal session.

Working with Container Names and IDs

Every container gets a unique ID and can have a name:

BASH
# Docker generates a random name if you don't specify one
docker run -d nginx
# Container name might be: zealous_darwin
 
# Specify a name explicitly
docker run -d --name webserver nginx
 
# Reference containers by name or ID
docker stop webserver
docker stop a1b2c3d4e5f6
 
# You can use just the first few characters of the ID
docker stop a1b2

Container IDs and Names

BASH
$ docker ps
CONTAINER ID   IMAGE   COMMAND                  CREATED         STATUS         PORTS                  NAMES
a1b2c3d4e5f6   nginx   "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes   0.0.0.0:8080->80/tcp   my-nginx
f7e8d9c0b1a2   redis   "docker-entrypoint.s…"   5 minutes ago   Up 5 minutes   6379/tcp               redis-cache

Port Mapping

Port mapping connects container ports to host ports:

BASH
# Map container port 80 to host port 8080
docker run -d -p 8080:80 nginx
 
# Map to a specific interface
docker run -d -p 127.0.0.1:8080:80 nginx
 
# Map multiple ports
docker run -d -p 80:80 -p 443:443 nginx
 
# Map a port range
docker run -d -p 8000-8010:8000-8010 myapp
 
# Publish all exposed ports to random ports
docker run -d -P nginx

Warning

Binding to 0.0.0.0 (the default) exposes the port on all network interfaces. For local development, consider binding to 127.0.0.1 to prevent external access.

Viewing Port Mappings

BASH
# See port mappings for a container
docker port my-nginx
# 80/tcp -> 0.0.0.0:8080
 
# List all containers with their ports
docker ps --format "{{.Names}}: {{.Ports}}"

Environment Variables

Pass configuration to containers via environment variables:

BASH
# Set a single variable
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql
 
# Set multiple variables
docker run -d \
  -e POSTGRES_USER=admin \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=myapp \
  postgres
 
# Load from a file
docker run -d --env-file ./database.env postgres

Environment File Format

BASH
# database.env
POSTGRES_USER=admin
POSTGRES_PASSWORD=secret
POSTGRES_DB=myapp
PGDATA=/var/lib/postgresql/data/pgdata

Interactive Containers

Some containers are meant for interactive use:

BASH
# Run Ubuntu interactively
docker run -it ubuntu bash
 
# You're now inside the container
root@a1b2c3d4e5f6:/# cat /etc/os-release
root@a1b2c3d4e5f6:/# exit
 
# Run Python interactively
docker run -it python:3.12 python
 
# Run Node.js REPL
docker run -it node:20 node

Attaching to Running Containers

BASH
# Attach to a container's main process
docker attach my-container
 
# Detach without stopping: Ctrl+P, Ctrl+Q
 
# Attach with a new shell instead
docker exec -it my-container /bin/bash

Note

Use docker exec instead of docker attach when you want a new shell session. attach connects to the container's main process, while exec starts a new process.

Container Cleanup

Containers accumulate quickly. Keep your system clean:

BASH
# Remove a stopped container
docker rm my-nginx
 
# Remove multiple containers
docker rm container1 container2 container3
 
# Remove all stopped containers
docker container prune
 
# Remove all stopped containers (alternative)
docker rm $(docker ps -aq)
 
# Stop and remove all containers
docker stop $(docker ps -q) && docker rm $(docker ps -aq)

Auto-Remove Containers

BASH
# Automatically remove container when it exits
docker run --rm nginx echo "Hello"
# Container is removed after the command completes
 
# Useful for one-off commands
docker run --rm -it python:3.12 python -c "print('Hello from Python')"

Running Containers with Resource Limits

Control how much CPU and memory containers can use:

BASH
# Limit memory to 512MB
docker run -d --memory=512m nginx
 
# Limit CPU to 1.5 cores
docker run -d --cpus=1.5 nginx
 
# Combine limits
docker run -d \
  --memory=1g \
  --memory-swap=2g \
  --cpus=2 \
  nginx
 
# Reserve memory (for orchestrators)
docker run -d --memory-reservation=256m nginx

Resource Limits

FlagDescription
--memoryMaximum memory the container can use
--memory-swapTotal memory + swap allowed
--cpusNumber of CPUs available
--cpu-sharesCPU shares (relative weight)
--memory-reservationSoft limit (for scheduling)

Container Restart Policies

Control what happens when a container stops:

BASH
# Never restart (default)
docker run -d --restart=no nginx
 
# Always restart
docker run -d --restart=always nginx
 
# Restart on failure
docker run -d --restart=on-failure nginx
 
# Restart on failure, max 5 attempts
docker run -d --restart=on-failure:5 nginx
 
# Restart unless manually stopped
docker run -d --restart=unless-stopped nginx

Warning

Use always carefully—it will restart containers even after a system reboot if Docker is set to start on boot. For development, unless-stopped is often more appropriate.

Viewing and Following Logs

Container logs are essential for debugging:

BASH
# View all logs
docker logs my-nginx
 
# Follow logs (like tail -f)
docker logs -f my-nginx
 
# Show timestamps
docker logs -t my-nginx
 
# Show last N lines
docker logs --tail 50 my-nginx
 
# Show logs since a time
docker logs --since 1h my-nginx
docker logs --since 2024-01-15T10:00:00 my-nginx
 
# Combine options
docker logs -f --tail 100 -t my-nginx

Practical Examples

Running a Database

BASH
# PostgreSQL with persistent data
docker run -d \
  --name postgres \
  -e POSTGRES_PASSWORD=mysecret \
  -p 5432:5432 \
  -v postgres-data:/var/lib/postgresql/data \
  postgres:16
 
# Connect using psql
docker exec -it postgres psql -U postgres

Running a Web Application Stack

BASH
# Start Redis
docker run -d --name redis redis:7
 
# Start your app, linking to Redis
docker run -d \
  --name myapp \
  --link redis:redis \
  -e REDIS_URL=redis://redis:6379 \
  -p 3000:3000 \
  myapp:latest

Quick Development Server

BASH
# Serve static files from current directory
docker run -d \
  --name devserver \
  -p 8080:80 \
  -v $(pwd):/usr/share/nginx/html:ro \
  nginx
 
# Now http://localhost:8080 serves files from your current directory

Command Quick Reference

CommandPurpose
docker runCreate and start a container
docker psList running containers
docker ps -aList all containers
docker stopStop a running container
docker startStart a stopped container
docker rmRemove a container
docker logsView container logs
docker execRun a command in a container
docker inspectView detailed container info
docker statsView resource usage

In the next chapter, we'll explore Docker images—the templates from which containers are created.