Docker Basics

Getting started with Docker containers -- install Docker, run containers, and manage images

Docker lets you run applications in containers – lightweight, isolated environments that bundle an app with everything it needs (OS libraries, dependencies, config). Think of it like a virtual machine but much faster and smaller. The main selling point: if it works in a container on your machine, it works the same on every other machine. No more "works on my machine" problems.

Installing Docker Desktop

Docker Desktop is the easiest way to get Docker on macOS. It includes the Docker engine, CLI tools, and a GUI for managing containers.

  1. Download Docker Desktop from docker.com/products/docker-desktop
  2. Open the .dmg and drag Docker to Applications
  3. Launch Docker from Applications
  4. Docker needs a moment to start – you'll see the whale icon in your menu bar when it's ready

Or install via Homebrew:

brew install --cask docker

Verify the installation:

docker --version
docker compose version

Running your first container

Pull and run an Nginx web server:

docker run -d -p 8080:80 nginx

This downloads the nginx image from Docker Hub, starts it in the background (-d), and maps port 8080 on your Mac to port 80 inside the container. Open http://localhost:8080 in your browser to see it.

Essential commands

List running containers:

docker ps

List all containers (including stopped):

docker ps -a

Stop a container:

docker stop <container_id>

You only need the first few characters of the ID (e.g., docker stop a1b2).

Remove a stopped container:

docker rm <container_id>

List downloaded images:

docker images

Pull an image without running it:

docker pull postgres

Remove an image:

docker rmi nginx

Docker Hub

Docker Hub (hub.docker.com) hosts thousands of pre-built images. Common ones:

  • postgres – PostgreSQL database
  • redis – Redis cache/store
  • nginx – web server and reverse proxy
  • node – Node.js runtime
  • python – Python runtime
  • mysql – MySQL database

Run a Postgres database:

docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=mysecret postgres

The -e flag sets an environment variable inside the container.

Building your own image

A Dockerfile describes how to build an image. Here's a simple one for a Node.js app:

FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "server.js"]
  • FROM – base image to start from
  • WORKDIR – set the working directory inside the container
  • COPY – copy files from your machine into the image
  • RUN – run a command during the build (install dependencies)
  • CMD – the command to run when the container starts

Build it:

docker build -t my-app .

Run it:

docker run -d -p 3000:3000 my-app

Docker Compose

Docker Compose lets you define and run multiple containers together. Create a docker-compose.yml file:

services:
  web:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: mysecret
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Start everything:

docker compose up -d

Stop everything:

docker compose down

Volumes (persist data)

Containers are temporary by default – when you remove a container, its data is gone. Volumes let you persist data:

docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=mysecret -v pgdata:/var/lib/postgresql/data postgres

The -v pgdata:/var/lib/postgresql/data creates a named volume that survives container restarts and removals.

Cleanup

Docker images and stopped containers accumulate over time. Free up space:

docker system prune

This removes stopped containers, unused networks, and dangling images. Add -a to also remove all unused images (not just dangling ones):

docker system prune -a

When NOT to use Docker

  • Simple scripts you run once
  • Quick one-off tasks
  • When your app has no dependencies beyond what's already installed
  • Learning a language for the first time (start without the extra complexity)

Frequently Asked Questions

What's the difference between a container and a virtual machine?

Both provide isolated environments, but containers share the host OS kernel, making them much lighter and faster to start (seconds vs minutes). A VM runs a full separate operating system. Containers use less RAM and disk space, but VMs provide stronger isolation. For development, containers are almost always the better choice.

Will Docker slow down my computer?

Docker Desktop uses some RAM and CPU even when idle (it runs a lightweight VM on Mac and Windows). If you're on a machine with 8GB or less RAM, you may notice it. You can quit Docker Desktop when you're not using it. On Linux, Docker Engine has minimal overhead since it runs natively.

What's the difference between `docker-compose` and `docker compose`?

They do the same thing. docker-compose (with a hyphen) was the original standalone tool. docker compose (with a space) is the newer version built into the Docker CLI as a plugin. The newer docker compose is now the standard and comes pre-installed with Docker Desktop and recent Docker Engine packages.

How do I get inside a running container?

Use docker exec -it <container_id> /bin/bash (or /bin/sh if bash isn't available). This gives you a terminal session inside the container. Type exit to leave. Useful for debugging or inspecting what's happening inside.

Do I need Docker for every project?

No. Docker is most useful when a project has complex dependencies, needs a database, or you're working with a team and want everyone on the same setup. For simple scripts, learning exercises, or projects with minimal dependencies, Docker adds unnecessary complexity.