Back to Blog
Developer ToolsDockerDevOpsTutorial

Docker for Developers -- From Zero to Containerized in 20 Minutes

Published on April 4, 202614 min read

Docker for Developers -- From Zero to Containerized in 20 Minutes

You have heard "it works on my machine" enough times. Docker solves this by packaging your app and all its dependencies into a container that runs identically everywhere -- your laptop, your colleague's laptop, staging, production.

This is not a theory guide. By the end, you will have a working Dockerized application with a database, and you will understand every line of configuration.


Installing Docker

macOS

Download Docker Desktop from the official Docker website. Install it like any other app. Once running, you will see the whale icon in your menu bar. Verify in your terminal:

> docker --version

> docker compose version

Windows

Download Docker Desktop. During installation, enable WSL 2 backend when prompted. Restart your machine, then verify:

> docker --version

> docker compose version

Linux

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

> sudo usermod -aG docker $USER

Log out and back in, then verify with the same commands.


Your First Dockerfile

A Dockerfile is a recipe that tells Docker how to build your application image. Here is a real one for a Node.js app:

FROM node:20-alpine

>

WORKDIR /app

>

COPY package*.json ./

RUN npm ci --only=production

>

COPY . .

>

EXPOSE 3000

>

CMD ["node", "server.js"]

What Each Line Does

  • FROM node:20-alpine -- start with a lightweight Node.js base image. Alpine images are about 50MB vs 900MB for full images.
  • WORKDIR /app -- set the working directory inside the container. All subsequent commands run from here.
  • COPY package*.json ./ -- copy package.json and package-lock.json first. This is intentional -- Docker caches layers, so if your dependencies have not changed, it skips the npm install step.
  • RUN npm ci --only=production -- install dependencies. Using npm ci instead of npm install gives you reproducible builds.
  • COPY . . -- copy the rest of your application code.
  • EXPOSE 3000 -- document which port the app listens on. This does not actually publish the port.
  • CMD -- the command to run when the container starts.

Build and Run

> docker build -t my-app .

> docker run -p 3000:3000 my-app

Your app is now running at localhost:3000 inside a container. The -p flag maps port 3000 on your machine to port 3000 in the container.


The .dockerignore File

Just like .gitignore keeps files out of your repo, .dockerignore keeps files out of your container. Create one in your project root:

node_modules

.git

.env

npm-debug.log

Dockerfile

docker-compose.yml

.dockerignore

README.md

.DS_Store

This prevents Docker from copying unnecessary files into the image, making builds faster and images smaller.


Docker Compose -- Multi-Service Apps

Real applications rarely run alone. You need a database, maybe a cache, maybe a message queue. Docker Compose lets you define and run all of these together.

Create a docker-compose.yml file:

version: "3.9"

>

services:

app:

build: .

ports:

- "3000:3000"

environment:

- DATABASE_URL=postgres://user:password@db:5432/myapp

- REDIS_URL=redis://cache:6379

depends_on:

- db

- cache

volumes:

- .:/app

- /app/node_modules

>

db:

image: postgres:16-alpine

environment:

POSTGRES_USER: user

POSTGRES_PASSWORD: password

POSTGRES_DB: myapp

volumes:

- pgdata:/var/lib/postgresql/data

ports:

- "5432:5432"

>

cache:

image: redis:7-alpine

ports:

- "6379:6379"

>

volumes:

pgdata:

Start Everything

> docker compose up

That single command starts your app, a PostgreSQL database, and a Redis cache. They can communicate using their service names as hostnames -- your app connects to the database at db:5432, not localhost.

Useful Compose Commands

  • docker compose up -d -- start in background (detached mode)
  • docker compose down -- stop and remove all containers
  • docker compose logs -f app -- follow logs for the app service
  • docker compose exec app sh -- open a shell inside the running app container
  • docker compose build --no-cache -- rebuild images from scratch
  • docker compose ps -- see running containers and their status

Development vs Production

Your development Dockerfile and production Dockerfile should be different. Use multi-stage builds to keep production images small:

# Stage 1: Build

FROM node:20-alpine AS builder

WORKDIR /app

COPY package*.json ./

RUN npm ci

COPY . .

RUN npm run build

>

# Stage 2: Production

FROM node:20-alpine

WORKDIR /app

COPY --from=builder /app/dist ./dist

COPY --from=builder /app/node_modules ./node_modules

COPY package*.json ./

EXPOSE 3000

CMD ["node", "dist/server.js"]

The final image only contains the built output and production dependencies. Build tools, source code, and devDependencies are left behind in the builder stage.


Hot Reload in Development

For development, you want code changes to reflect immediately without rebuilding the container. Use a volume mount:

services:

app:

build: .

volumes:

- .:/app

- /app/node_modules

command: npm run dev

The volume mount syncs your local files into the container. The /app/node_modules line prevents your local node_modules from overwriting the container's.


Common Patterns

Environment Variables

Never hardcode secrets in Dockerfiles. Use environment variables:

> services:

> app:

> env_file:

> - .env

Or pass them directly:

> docker run -e API_KEY=your_key my-app

Health Checks

Add health checks so Docker knows if your app is actually working:

> HEALTHCHECK --interval=30s --timeout=3s --retries=3 \

> CMD wget --quiet --tries=1 --spider http://localhost:3000/health || exit 1

Networking

By default, all services in a Docker Compose file share a network. They can reach each other by service name. If you need to isolate services, create custom networks:

> networks:

> frontend:

> backend:


Debugging Docker Issues

  • Container exits immediately? Check logs with docker logs container_name. Usually the app is crashing on startup.
  • Cannot connect to database? Make sure depends_on is set, and your app retries the connection on startup. depends_on only waits for the container to start, not for the database to be ready.
  • Build is slow? Check your .dockerignore. If node_modules or .git are being copied, it will take forever.
  • Out of disk space? Run docker system prune to clean up unused images, containers, and volumes.
  • Port already in use? Another service or container is using that port. Check with docker ps or lsof -i :3000.

Essential Docker Commands Cheat Sheet

  • docker ps -- list running containers
  • docker ps -a -- list all containers including stopped ones
  • docker images -- list all images
  • docker logs -f container -- follow container logs
  • docker exec -it container sh -- open a shell in a running container
  • docker stop container -- gracefully stop a container
  • docker rm container -- remove a stopped container
  • docker rmi image -- remove an image
  • docker system prune -a -- remove all unused images, containers, networks, and volumes

What Next?

Once you are comfortable with the basics:

  • Set up CI/CD -- build and push Docker images automatically with GitHub Actions
  • Learn Docker networking -- custom networks, host networking, overlay networks
  • Explore container orchestration -- Kubernetes or Docker Swarm for running containers at scale
  • Try multi-architecture builds -- build images that run on both Intel and ARM (Apple Silicon)

Docker is one of those tools that feels like overhead at first but becomes indispensable once it is part of your workflow. Start with one project, get comfortable, and gradually Dockerize everything.

For more developer guides, check out our blog and explore our free developer tools.

Explore Our Free Tools & Games

Check out our curated collection of completely free browser games, tools, and extensions.

Browse Free Stuff

Related Articles

Developer ToolsCI/CD

Set Up GitHub Actions CI/CD -- A Hands-On Guide for Any Project

Automate your testing, building, and deployment with GitHub Actions. This practical guide covers workflow syntax, real CI/CD pipelines for Node.js, Python, and Docker projects, plus caching and secrets management.

14 min readRead More→
Developer ToolsJSON

JSON for Beginners - What It Is and Why Developers Love It

New to JSON? This beginner-friendly guide explains what JSON is, how it works, why it is everywhere, and how to work with it using free tools.

7 min readRead More→
AIDeveloper Tools

A Beginner Guide to Building With AI APIs in 2026

Want to add AI to your app? This beginner-friendly guide walks you through AI APIs, how they work, and how to make your first API call to Claude, GPT, and Gemini.

11 min readRead More→
Web DevelopmentDeveloper Tools

How to Make a Favicon for Your Website in 2026 (All Sizes, All Platforms)

That tiny icon in the browser tab matters more than you think. Learn what sizes you need, how to generate them all, and get the HTML code -- all for free.

7 min readRead More→

Latest from the Blog

GamesMultiplayer

The Best Free Games to Play With Friends and Family Online

No console, no downloads, no setup - just open a browser and play. The best free 2-player and vs-computer games to enjoy with friends and family.

May 18, 2026Read More→
GamesBrain Games

Daily Puzzle Games: How a 5-Minute Habit Sharpens Your Brain

Daily puzzle games like Word Guess and Word Groups turn brain training into a habit. Here is why a 5-minute daily puzzle works - and which free ones to play.

May 17, 2026Read More→
GamesClassic Games

12 Timeless Classic Games You Can Play Free Online

Solitaire, Minesweeper, Snake, Pong and more - the classic games that defined gaming, all playable free in your browser with no download or sign-up.

May 16, 2026Read More→