Docker for Developers: Images, Containers, and Compose

DevOps2026-10-11TryQuickToolBox

You've written code that works on your machine, but when a teammate tries to run it, they hit missing dependencies, version conflicts, or obscure errors. Docker solves this by packaging your application and its environment into a single, portable unit. In this guide, you'll learn Docker fundamentals: images, containers, and Compose, with practical steps to containerize a simple web app.

What is Docker?

Docker is a platform for building, running, and sharing applications in containers. A container is a lightweight, standalone executable package that includes everything needed to run software: code, runtime, system tools, libraries, and settings. Containers isolate applications from each other and from the host system, ensuring consistency across development, testing, and production.

Images vs Containers: The Blueprint and the Running Instance

An image is a read-only template that defines a container. It's like a class in object-oriented programming. A container is a runnable instance of an image, like an object. You can create many containers from the same image.

Images are built from a Dockerfile, a text file with instructions. Containers are started with docker run.

Key differences

ImageContainer
Read-only templateRunnable instance
Built with docker buildStarted with docker run
Stored in registry (e.g., Docker Hub)Runs on host
Layered filesystemWritable layer on top

Building Your First Image

Let's containerize a simple Node.js app. Create a file named Dockerfile:

# Use an official Node.js runtime as a parent image
FROM node:18-alpine

# Set the working directory
WORKDIR /app

# Copy package.json and install dependencies
COPY package*.json ./
RUN npm install

# Copy the rest of the application
COPY . .

# Expose the port the app runs on
EXPOSE 3000

# Define the command to run the app
CMD ["node", "server.js"]

Build the image with a tag:

docker build -t my-node-app .

The -t flag names and tags the image. The . at the end specifies the build context (current directory).

Running Containers

Start a container from your image:

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

Check running containers with docker ps. Stop the container with docker stop my-app.

Managing Data with Volumes

Containers are ephemeral; data inside them is lost when the container is removed. To persist data, use volumes. For example, to persist database data:

docker run -v my-db-data:/var/lib/mysql -d mysql:8

This creates a named volume my-db-data that survives container restarts and removals.

Simplifying Multi-Container Apps with Docker Compose

Real applications often need multiple services: a web server, a database, a cache, etc. Docker Compose lets you define and run multi-container apps with a single YAML file.

Create a docker-compose.yml:

version: '3.8'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
  db:
    image: postgres:15
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=mydb
volumes:
  postgres_data:

Run everything with:

docker compose up -d

Compose builds the web image, starts the database, and connects them on a shared network. The depends_on ensures the database starts before the web service.

Essential Docker Commands

Best Practices for Development

FAQ

What is the difference between a Docker image and a container?

An image is a read-only template that defines the application and its environment. A container is a running instance of that image. You can create multiple containers from the same image.

How do I persist data in Docker?

Use volumes. Named volumes (e.g., docker run -v my-vol:/data) are stored outside the container's filesystem and persist across container restarts and removals.

When should I use Docker Compose?

Use Compose when your application consists of multiple services (e.g., web + database) that need to run together. It simplifies orchestration for development and testing.

Ready to containerize your next project? Start by writing a simple Dockerfile and running your first container. For more developer tools, check out TryQuickToolBox's JSON Formatter to validate API responses while testing your containerized services.