Skip to content

Pratyusha108/welcome-to-docker

Repository files navigation

Multi-Container Docker Application: Todo App with MongoDB

A containerized full-stack Todo application built with Node.js, Express, and MongoDB, orchestrated using Docker Compose. This project demonstrates two distinct container deployment strategies — a production-oriented multi-service setup and a development workflow using bind mounts for live code reloading.

Published on Docker Hub: docker pull pratyusha108/welcome-to-docker


Architecture

┌─────────────────────────────────────────────────┐
│                 Docker Compose                  │
│                                                 │
│  ┌──────────────┐       ┌──────────────────┐    │
│  │   todo-app   │──────▶│  todo-database   │    │
│  │  Express.js  │       │    MongoDB 6     │    │
│  │  Port 3000   │       │   Port 27017     │    │
│  └──────────────┘       └──────────────────┘    │
│                                │                │
│                         Named Volume            │
│                        (persistent DB)          │
└─────────────────────────────────────────────────┘

Two configurations included:

Config Purpose App Port DB Port Volume Strategy
multi-container-app/ Production deployment 3000 27017 Named volume for DB persistence
bindmount-apps/ Development workflow 3001 27018 Bind mount for live code sync

Tech Stack

  • Runtime: Node.js 19 (Alpine)
  • Backend: Express.js 4.18
  • Database: MongoDB 6 (official image)
  • ODM: Mongoose 7.1
  • Templating: EJS
  • Dev Tools: Nodemon, LiveReload
  • Container Orchestration: Docker Compose

Project Structure

├── multi-container-app/          # Production-style deployment
│   ├── compose.yaml              # Compose config with named volumes
│   └── app/
│       ├── Dockerfile            # Multi-stage build with npm cache mounts
│       ├── server.js             # Express app with MongoDB connection
│       ├── models/Todo.js        # Mongoose schema
│       ├── routes/front.js       # CRUD routes (create, list, delete)
│       └── views/todos.ejs       # Bootstrap-styled UI
│
├── bindmount-apps/               # Development workflow
│   ├── compose.yaml              # Compose config with bind mounts
│   └── app/
│       ├── Dockerfile            # Non-root user, dev dependencies excluded
│       ├── server.js             # Same app, different port config
│       └── ...                   # Identical application code
│
└── Dockerfile                    # Root: React welcome page container

Getting Started

Prerequisites

Run the Production Setup

cd multi-container-app
docker compose up -d --build

Open http://localhost:3000 to access the Todo app.

Run the Development Setup (with live reload)

cd bindmount-apps
docker compose up -d --build

Open http://localhost:3001. Code changes in app/ are reflected immediately via bind mount + Nodemon.

Shut Down

docker compose down

To also remove the persistent database volume:

docker compose down -v

How It Works

Container Networking

The todo-app service connects to MongoDB using Docker's internal DNS resolution — the connection string references the service name (todo-database) directly, with no hardcoded IPs. Compose handles the network creation automatically.

Named Volumes vs Bind Mounts

  • multi-container-app uses a named volume (database:/data/db) so that todo data persists across container restarts.
  • bindmount-apps uses a bind mount (./app:/usr/src/app) to sync local code changes into the running container, with an anonymous volume to preserve node_modules inside the container.

Dockerfile Optimizations

  • Cache mounts on npm ci to speed up repeated builds
  • Non-root user (USER node) in the bind mount Dockerfile for security
  • Layer ordering — dependencies installed before copying source code to maximize Docker's build cache

Troubleshooting

Port already in use

Error: bind: address already in use

Another process is occupying the port. Find and stop it:

# Check what's using the port (Linux/macOS)
lsof -i :3000

# Windows
netstat -ano | findstr :3000
taskkill /PID <PID> /F

Or remap to a different port in compose.yaml:

ports:
  - "3002:3000"   # Change 3002 to any available port

Compose file not found

no configuration file provided: not found

You must run docker compose from the directory containing compose.yaml:

cd multi-container-app    # or cd bindmount-apps
docker compose up -d --build

Image pull vs local build

If Compose pulls a remote image instead of building locally, ensure your compose.yaml uses build: and not image: for the app service:

services:
  todo-app:
    build:
      context: ./app    # Builds from local Dockerfile

Run with --build to force a fresh build:

docker compose up -d --build

What I Learned

Working through this project gave me hands-on experience with problems that only surface in real container environments — not in tutorials. I debugged port conflicts when multiple services competed for the same port, resolved compose file not found errors caused by running commands from the wrong directory, and worked through the distinction between pulling pre-built images and building from a local Dockerfile.

Beyond debugging, I gained practical understanding of Docker Compose service orchestration: how containers discover each other through internal DNS, how named volumes provide data persistence independently of container lifecycle, and how bind mounts enable a fast development feedback loop without rebuilding images. I also published a container image to Docker Hub, completing the full build-ship workflow.

These are the kinds of operational skills that matter when deploying ML pipelines, standing up database-backed services, or working with containerized development environments in production teams.


Docker Hub

docker pull pratyusha108/welcome-to-docker

License

This project is based on Docker's welcome-to-docker educational repository, extended with multi-container and bind mount configurations.

About

Multi-container Docker Compose application (Node.js + Express + MongoDB) with production and development deployment configurations. Published on Docker Hub.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors