← all articles
devops

Docker Environment Setup

Get Docker installed and working correctly on macOS, Windows, and Linux, plus the handful of commands you'll actually use day to day.

4 min read·July 10, 2026

Docker lets you package an application with everything it needs to run — runtime, libraries, config — into a single image that behaves the same on your laptop, a teammate's machine, and a production server. This guide covers installing it correctly on each platform and the core commands you'll reach for constantly.

Install Docker

macOS and Windows: install Docker Desktop. It bundles the Docker engine (running in a small Linux VM under the hood), the docker CLI, and Docker Compose in one installer. On Windows, make sure WSL2 integration is enabled during setup — Docker Desktop uses WSL2 as its backend now, and containers run noticeably faster with it than with the older Hyper-V backend.

Linux: install the engine directly, no VM needed:

curl -fsSL https://get.docker.com | sh

Then add your user to the docker group so you don't need sudo for every command:

sudo usermod -aG docker $USER

Log out and back in (or run newgrp docker) for the group change to take effect.

Verify the install

docker run hello-world

If that pulls an image and prints a welcome message, Docker is working end to end — the daemon is running, it can pull from Docker Hub, and it can start a container.

warning

Linux: "permission denied while trying to connect to the Docker daemon socket." You're not in the docker group yet, or the group change hasn't taken effect in your current shell. Run groups — if docker isn't listed, log out and back in.

Commands you'll use daily

# build an image from a Dockerfile in the current directory
docker build -t myapp:latest .
 
# run a container from an image, mapping host port 3000 to container port 3000
docker run -p 3000:3000 myapp:latest
 
# run in the background (detached) and name it
docker run -d --name myapp -p 3000:3000 myapp:latest
 
# see what's running
docker ps
 
# see everything, including stopped containers
docker ps -a
 
# follow a container's logs
docker logs -f myapp
 
# get a shell inside a running container
docker exec -it myapp sh
 
# stop and remove a container
docker stop myapp && docker rm myapp

Docker Compose for multi-container setups

Most real projects are more than one container — an app plus a database, say. Compose describes the whole stack in one YAML file:

# docker-compose.yml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: devpassword
    volumes:
      - db-data:/var/lib/postgresql/data
 
volumes:
  db-data:
docker compose up        # start everything, logs in the foreground
docker compose up -d     # start everything, detached
docker compose down      # stop and remove containers (keeps volumes)
tip

Note the space: modern Docker uses docker compose (a subcommand of the main CLI), not the old standalone docker-compose binary. Both still work on most installs, but docker compose is the one that keeps getting updates.

Keeping images small and builds fast

  • Use .dockerignore. Same idea as .gitignore — keep node_modules, .git, and build artifacts out of the build context so builds stay fast.
  • Order Dockerfile layers from least to most frequently changing. Copy dependency manifests (package.json, requirements.txt) and install dependencies before copying the rest of your source, so Docker's layer cache can skip the install step when only your code changed.
  • Prefer slim or distroless base images for production builds — smaller images pull faster and have a smaller attack surface.

Common gotchas

warning

Containers can't reach the internet, or builds hang on apt-get update. Usually a corporate VPN or proxy intercepting traffic in a way Docker's VM doesn't inherit. Check Docker Desktop's network settings, or on Linux, confirm /etc/resolv.conf inside the container has a working nameserver.

warning

Docker Desktop uses all the RAM/CPU on my machine. Docker Desktop → Settings → Resources lets you cap how much of the host's memory and CPU the VM is allowed to use. Worth setting explicitly rather than leaving it on defaults if you're running other heavy tools alongside it.

With the daemon running and these commands in muscle memory, "containerize it" stops being a separate skill and becomes just another step in running the project.