Skip to main content

Command Palette

Search for a command to run...

Dockerfile Complete Guide: From Beginner to Interview Ready

Updated
13 min read
A

Hi there! I'm Aditya, a passionate Full-Stack Developer driven by a love for turning concepts into captivating digital experiences. With a blend of creativity and technical expertise, I specialize in crafting user-friendly websites and applications that leave a lasting impression. Let's connect and bring your digital vision to life!

What is Docker Compose?

Docker Compose is a tool used to define and manage multiple Docker containers using a single YAML file.

Instead of running multiple docker commands manually, Docker Compose allows you to define all services in one configuration file.

Without Compose:

docker run postgres
docker run redis
docker run backend
docker run frontend

With Compose:

docker compose up

Everything starts automatically.


Why Do We Need Docker Compose?

Modern applications rarely consist of a single container.

A typical application may contain:

Service Purpose
Frontend React / Next.js
Backend Node.js / Express
Database PostgreSQL
Cache Redis
Reverse Proxy Nginx

Managing these individually becomes difficult.

Docker Compose solves this problem.


Docker Compose Workflow

compose.yml
      ↓
docker compose up
      ↓
Network Creation
      ↓
Volume Creation
      ↓
Container Creation
      ↓
Application Running

Compose automatically creates:

  • Containers
  • Networks
  • Volumes
  • Service communication

Basic Docker Compose File

services:
  app:
    build: .

  db:
    image: postgres:16

This starts:

  • One application container
  • One PostgreSQL container

Services

Services are the most important concept in Docker Compose.

Each service represents a container.

services:
  frontend:
    build: ./frontend

  backend:
    build: ./backend

  postgres:
    image: postgres:16

Three services create three containers.


Build

Used when Docker should build an image using a Dockerfile.

services:
  backend:
    build: .

Equivalent command:

docker build .

Custom path:

services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile.prod

Image

Used when Docker should pull an image from Docker Hub.

services:
  postgres:
    image: postgres:16

Examples:

image: redis:7

image: nginx:latest

image: mongo:7

Build vs Image

Feature Build Image
Uses Dockerfile Yes No
Builds Locally Yes No
Pulls From Registry No Yes
Used For Custom Apps Yes Yes

Interview Question:

When should you use build instead of image?

Answer

Use build when creating your own application image. Use image when using pre-built images from Docker Hub.


Container Name

Provides a custom container name.

services:
  backend:
    container_name: backend-app

Without this:

project_backend_1

With this:

backend-app

Ports

Maps host ports to container ports.

ports:
  - "3000:3000"

Format:

HOST:CONTAINER

Example:

ports:
  - "8080:3000"

Request:

localhost:8080

Container receives:

3000

Interview Question:

What is the format of port mapping?

Answer

HOST_PORT


Environment Variables

Pass runtime variables.

environment:
  NODE_ENV: production
  PORT: 3000

Example:

services:
  backend:
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/app

Access:

process.env.DATABASE_URL

Env File

Store variables in a separate file.

.env

DATABASE_URL=mydb
PORT=3000

Compose:

env_file:
  - .env

Benefits:

  • Cleaner configuration
  • Easier secret management

Volumes

Volumes persist data.

volumes:
  - postgres-data:/var/lib/postgresql/data

Without volumes:

Container Deleted
      ↓
Data Deleted

With volumes:

Container Deleted
      ↓
Data Preserved

Common use cases:

  • PostgreSQL
  • MySQL
  • MongoDB
  • File uploads

Named Volumes

services:
  postgres:
    image: postgres:16
    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:

Docker manages storage automatically.


Bind Mounts

Map local folders into containers.

volumes:
  - .:/app

Benefits:

  • Live code updates
  • Faster development

Common for Next.js and Node.js projects.


Networks

Compose automatically creates a network.

Example:

services:
  backend:
  postgres:

Backend can connect to database using:

postgres

instead of:

localhost

Connection string:

DATABASE_URL=postgresql://user:pass@postgres:5432/db

Interview Question:

How do containers communicate inside Docker Compose?

Answer

Containers communicate through the automatically created Docker network using service names.


Depends On

Controls startup order.

services:
  backend:
    depends_on:
      - postgres

Docker starts:

Postgres
    ↓
Backend

Important:

depends_on does not wait until the database is ready.

It only starts containers in order.

Interview Question:

Does depends_on guarantee database readiness?

Answer

No. It only guarantees startup order.


Restart Policies

Automatically restart containers.

restart: always

Options:

restart: always

restart: unless-stopped

restart: on-failure

restart: no

Common production setting:

restart: unless-stopped

Command

Override Dockerfile CMD.

Dockerfile:

CMD ["npm", "start"]

Compose:

command: npm run dev

Compose command takes precedence.


Healthcheck

Monitors container health.

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3000"]
  interval: 30s
  timeout: 10s
  retries: 3

Benefits:

  • Better monitoring
  • Automatic recovery
  • Production readiness

Profiles

Run only selected services.

services:
  postgres:
    profiles:
      - development

Run:

docker compose --profile development up

Useful for:

  • Development
  • Testing
  • Production

Real World Example

Node.js + PostgreSQL

services:
  backend:
    build: .

    ports:
      - "3000:3000"

    environment:
      DATABASE_URL: postgresql://admin:secret@postgres:5432/app

    depends_on:
      - postgres

  postgres:
    image: postgres:16

    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app

    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:

Start:

docker compose up

Everything starts automatically.


Common Docker Compose Commands

Start:

docker compose up

Background mode:

docker compose up -d

Stop:

docker compose down

View logs:

docker compose logs

Follow logs:

docker compose logs -f

List containers:

docker compose ps

Restart:

docker compose restart

Build:

docker compose build

Rebuild:

docker compose up --build

Common Interview Questions

What is Docker Compose?

A tool used to define and manage multi-container Docker applications using a YAML file.


Dockerfile vs Docker Compose?

Dockerfile Docker Compose
Builds Images Runs Containers
Defines Environment Defines Services
Creates Images Creates Application Stack

How do containers communicate?

Through Docker networks using service names.


What is depends_on?

Defines container startup order.


Does depends_on wait for readiness?

No.


What is the purpose of volumes?

Persistent data storage.


What is the difference between bind mounts and named volumes?

Bind Mount Named Volume
Uses Host Directory Managed By Docker
Good For Development Good For Production

What happens when docker compose down is executed?

Containers and networks are removed.

Volumes remain unless explicitly deleted.


Can Compose build images?

Yes.

Using:

build: .

Production Best Practices

  1. Use explicit image versions.
image: postgres:16

Avoid:

image: postgres:latest
  1. Use healthchecks.

  2. Use named volumes for databases.

  3. Store secrets in environment files.

  4. Separate development and production configurations.

  5. Use restart policies.

  6. Avoid hardcoded credentials.

  7. Keep services isolated.


Common Mistakes

Mistake Problem
Using latest tag Unexpected updates
No volumes Data loss
No healthchecks Difficult monitoring
Hardcoded secrets Security risk
Using localhost for DB Container communication failure

Docker Compose Revision Sheet

Keyword Purpose
services Define containers
build Build image
image Pull image
container_name Custom name
ports Port mapping
environment Runtime variables
env_file External variables
volumes Persistent storage
networks Service communication
depends_on Startup order
restart Auto restart
command Override CMD
healthcheck Health monitoring
profiles Environment-specific services

Docker Compose Interview Scenarios

In real interviews, Docker Compose questions are usually scenario-based.

Interviewers want to evaluate:

  • Service communication
  • Networking knowledge
  • Volume management
  • Environment variables
  • Startup dependencies
  • Production readiness

This guide contains common interview scenarios and their solutions.


Scenario 1: Backend + PostgreSQL

Interview Question

You have a Node.js backend and PostgreSQL database.

Requirements:

  • Backend should run on port 3000
  • PostgreSQL should run on port 5432
  • Backend should connect to PostgreSQL
  • Database data should persist after container restart

Write a Docker Compose file.


Solution

services:
  backend:
    build: .

    ports:
      - "3000:3000"

    environment:
      DATABASE_URL: postgresql://admin:secret@postgres:5432/app

    depends_on:
      - postgres

  postgres:
    image: postgres:16

    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app

    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:

Interview Explanation

Backend connects using:

postgres

NOT

localhost

Because containers communicate through service names.

Correct:

DATABASE_URL=postgresql://admin:secret@postgres:5432/app

Wrong:

DATABASE_URL=postgresql://admin:secret@localhost:5432/app

Follow-Up Questions

Why use a volume?

To prevent database data loss.

Why use depends_on?

To ensure PostgreSQL starts before Backend.

Does depends_on wait for database readiness?

No.


Scenario 2: Backend + Redis

Interview Question

Create a Compose file where:

  • Backend runs on port 3000
  • Redis runs on port 6379
  • Backend uses Redis for caching

Solution

services:
  backend:
    build: .

    ports:
      - "3000:3000"

    environment:
      REDIS_URL: redis://redis:6379

    depends_on:
      - redis

  redis:
    image: redis:7

Interview Explanation

Backend can access Redis using:

redis

because Redis service name becomes DNS hostname.


Follow-Up Question

How does Backend discover Redis?

Answer:

Docker Compose automatically creates a network and service names become hostnames.


Scenario 3: Frontend + Backend

Interview Question

You have:

  • React Frontend
  • Express Backend

Both should communicate through Docker network.

Frontend runs on:

localhost:5173

Backend runs on:

localhost:3000

Solution

services:
  frontend:
    build: ./frontend

    ports:
      - "5173:5173"

  backend:
    build: ./backend

    ports:
      - "3000:3000"

Communication

Frontend should call:

http://backend:3000

inside Docker network.

Not:

http://localhost:3000

Interview Trap

Many candidates use:

localhost

This is wrong because each container has its own localhost.


Scenario 4: Full Stack Application

Interview Question

Create a Compose file containing:

  • Next.js
  • Express
  • PostgreSQL
  • Redis

All services should communicate.


Solution

services:
  frontend:
    build: ./frontend

    ports:
      - "3000:3000"

  backend:
    build: ./backend

    ports:
      - "4000:4000"

    environment:
      DATABASE_URL: postgresql://admin:secret@postgres:5432/app

      REDIS_URL: redis://redis:6379

    depends_on:
      - postgres
      - redis

  postgres:
    image: postgres:16

    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app

    volumes:
      - postgres-data:/var/lib/postgresql/data

  redis:
    image: redis:7

volumes:
  postgres-data:

Architecture

Frontend
    ↓
Backend
   ↓ ↓
Redis PostgreSQL

Follow-Up Questions

How many networks are created?

Answer:

One default network.


How does Backend connect to PostgreSQL?

Answer:

Using hostname:

postgres

How does Backend connect to Redis?

Answer:

Using hostname:

redis

Scenario 5: Custom Network

Interview Question

Create two services that communicate using a custom Docker network.


Solution

services:
  backend:
    build: .

    networks:
      - app-network

  postgres:
    image: postgres:16

    networks:
      - app-network

networks:
  app-network:

Architecture

backend
     ↓
app-network
     ↑
postgres

Interview Explanation

Both services belong to the same network.

Therefore:

backend

can communicate with:

postgres

Scenario 6: Multiple Networks

Interview Question

You have:

  • Frontend
  • Backend
  • Database

Database should NOT be accessible by Frontend.

Design the network architecture.


Solution

services:
  frontend:
    build: ./frontend

    networks:
      - public

  backend:
    build: ./backend

    networks:
      - public
      - private

  postgres:
    image: postgres:16

    networks:
      - private

networks:
  public:
  private:

Architecture

Frontend
    |
 Public
    |
Backend
    |
 Private
    |
Postgres

Why?

Frontend cannot directly access PostgreSQL.

Only Backend can.

This is a common production setup.


Scenario 7: Persistent Database

Interview Question

Your PostgreSQL data disappears after container recreation.

How would you fix it?


Solution

services:
  postgres:
    image: postgres:16

    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:

Follow-Up Question

What happens if the container is deleted?

Answer:

Data remains inside the volume.


Scenario 8: Environment Variables

Interview Question

Move all sensitive values out of compose.yml.


Solution

.env

POSTGRES_USER=admin
POSTGRES_PASSWORD=secret
POSTGRES_DB=app

compose.yml

services:
  postgres:
    image: postgres:16

    env_file:
      - .env

Why?

Better security.

Cleaner configuration.


Scenario 9: Health Checks

Interview Question

Ensure Backend starts only when PostgreSQL becomes healthy.


Solution

services:
  postgres:
    image: postgres:16

    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]

      interval: 10s

      timeout: 5s

      retries: 5

Interview Explanation

Health checks allow Docker to monitor service readiness.


Scenario 10: Production Ready Compose

Interview Question

What would you add before deploying to production?


Expected Answer

  • Named volumes
  • Health checks
  • Restart policies
  • Environment files
  • Fixed image versions
  • Separate networks
  • Resource limits
  • Logging configuration

Example:

restart: unless-stopped
healthcheck:
volumes:
env_file:

Most Common Interview Traps

Trap 1

Using localhost between containers.

Wrong:

localhost

Correct:

service-name

Trap 2

No volume for database.

Result:

Container Deleted
      ↓
Data Lost

Trap 3

Using latest image tag.

Wrong:

image: postgres:latest

Correct:

image: postgres:16

Trap 4

Thinking depends_on waits for readiness.

It does not.

It only controls startup order.


Trap 5

Exposing database publicly.

Wrong:

ports:
  - "5432:5432"

Not always necessary.

Expose only when needed.


15-Minute Interview Revision

Question Expected Answer
How do containers communicate? Service Name
What creates networking? Docker Compose
How to persist data? Volumes
Build vs Image? Custom vs Existing Image
What is depends_on? Startup Order
Does depends_on wait? No
How to store secrets? env_file
Why healthchecks? Readiness Monitoring
Why custom networks? Isolation
Why named volumes? Data Persistence

Conclusion

Docker Compose is used to manage multiple containers as a single application. It simplifies networking, storage, environment configuration, startup order, and deployment. Understanding services, build, image, ports, environment variables, volumes, networks, and depends_on is sufficient for handling most real-world projects and Docker-related interviews.