Docker Compose Tutorial for Beginners | Multi-Container Apps Explained
이 글의 핵심
Learn Docker Compose from zero: what a service is, how containers talk by name, how volumes persist data, and the commands you use every day (up, logs, down).
Introduction
Docker packages an app and its dependencies into an image; a running image is a container. When you need more than one container—for example a Node API, a database, and optionally Nginx—you can orchestrate them with Docker Compose: one docker-compose.yml and commands like docker compose up -d.
This tutorial explains the mental model (services, networks, volumes) and gives a copy-paste example you can extend. For production-grade health checks and secrets, continue with Docker Compose for Node.js production.
Table of contents
Core concepts
| Concept | Meaning |
|---|---|
| Service | One container spec in Compose: image or build, ports, env, volumes. |
| Project | Default network name is derived from the project folder; all services in the file share it unless you customize networks. |
| Service DNS | Other services resolve mongo, app, etc.—not localhost from one container to another. |
| Volume | Named or bind mount to persist data (e.g. database files) when containers are recreated. |
| depends_on | Start order hint; for ready semantics use health checks (see the production article). |
Dockerfile recap
Compose often builds the API image from a Dockerfile:
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
Use a .dockerignore to exclude node_modules, .git, .env, and build artifacts.
Your first docker-compose.yml
Example: app + MongoDB + Nginx (reverse proxy). Adjust image tags and env for your project.
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PORT=3000
- MONGODB_URI=mongodb://mongo:27017/mydb
depends_on:
- mongo
restart: unless-stopped
volumes:
- ./logs:/app/logs
mongo:
image: mongo:7
ports:
- "27017:27017"
volumes:
- mongo-data:/data/db
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- app
restart: unless-stopped
volumes:
mongo-data:
Why mongo:27017 in MONGODB_URI?
mongo is the service name—Docker’s embedded DNS resolves it inside the network.
Daily commands
# Start in background
docker compose up -d
# Follow logs
docker compose logs -f
# Stop and remove containers (volumes kept unless -v)
docker compose down
# Restart services
docker compose restart
# Rebuild images after Dockerfile changes
docker compose up -d --build
Next steps
- Production: add health checks, named volumes for Postgres/Redis, and stricter env handling—Docker Compose for Node.js production.
- Deploy: automate image builds with GitHub Actions CI/CD.
- Edge: terminate TLS and proxy with Nginx reverse proxy.
Conclusion
Compose turns multiple containers into a single declarative stack: same file for teammates, CI, and servers. Master service names, volumes, and up/down, then layer production concerns from the linked guides.