๐ณ Docker๋ก ๋ชจ๋ ํ๋ก์ ํธ ์คํํ๊ธฐ: ์๋ฒฝ ๊ฐ์ด๋
Source: Dev.to
์ ๋ก๋ถํฐ ๋ช ๋ถ ์์ ์ปจํ ์ด๋ํ โ โ๋ด ์ปดํจํฐ์์๋ ๋์ํดโ๋ ์ด์ ๊ทธ๋ง
์๋ง ํ ๋ฒ์ฏค ๋ค์ด๋ณด์
จ์ ๊ฒ๋๋ค: โ๋ด ์ปดํจํฐ์์๋ ๋์ํด.โ Docker๋ ์ด ๋ง์ ์ฌ๋ผ์ง๊ฒ ๋ง๋ค๊ธฐ ์ํด ์กด์ฌํฉ๋๋ค.
Docker๋ ์ ํ๋ฆฌ์ผ์ด์
๊ณผ ๊ทธ ๋ชจ๋ ์์กด์ฑ(๋ฐํ์, ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ์ค์ ํ์ผ ๋ฑ)์ ์ปจํ
์ด๋๋ผ๋ ํ๋์ ์ด์ ๊ฐ๋ฅํ ๋จ์์ ๋ฌถ์ด์ค๋๋ค. ๊ทธ ์ปจํ
์ด๋๋ ๋
ธํธ๋ถ, ํ์์ Windows PC, CI ์๋ฒ, ํน์ ํด๋ผ์ฐ๋ VM ์ด๋์๋ ๋์ผํ๊ฒ ์คํ๋ฉ๋๋ค.
์์ํ๊ธฐ ์ ์ ๊ธฐ์ตํด ๋๋ฉด ์ข์ ๊ฐ๋
- Image โ ์ค๊ณ๋(๊ฐ์ฒด์งํฅ์์ ํด๋์ค์ ๊ฐ์ ๊ฐ๋ )
- Container โ ์ด๋ฏธ์ง์ ์คํ ์ธ์คํด์ค(๊ฐ์ฒด์ ๊ฐ์ ๊ฐ๋ )
- Dockerfile โ ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค๊ธฐ ์ํ ๋ ์ํผ
- Docker Compose โ ์ฌ๋ฌ ์ปจํ ์ด๋๋ฅผ ํจ๊ป ์ค์ผ์คํธ๋ ์ด์ ํ๋ ๋๊ตฌ
ํ์ ์ฌ์ ์กฐ๊ฑด
- Docker Desktop ์ค์น(Compose ํฌํจ)
- ๊ธฐ๋ณธ ํฐ๋ฏธ๋ ์ฌ์ฉ๋ฒ ์ต์ํจ
- ์ปจํ ์ด๋ํํ ํ๋ก์ ํธ(์์๋ก Node.js, Python, ๊ทธ๋ฆฌ๊ณ ์ผ๋ฐ์ ์ธ ์ ๊ทผ๋ฒ์ ์ฌ์ฉํ ์์ )
์ค์น ํ์ธ
docker --version
# Docker version 26.x.x
docker compose version
# Docker Compose version v2.x.x
Dockerfile์ด๋?
Dockerfile์ Docker๊ฐ ์์์ ์๋๋ก ์ฝ์ด ์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๋ ํ๋ ์ธ ํ ์คํธ ํ์ผ์ ๋๋ค.
# 1. Base image โ what you're building ON TOP OF
FROM node:20-alpine
# 2. Set the working directory inside the container
WORKDIR /app
# 3. Copy dependency files first (for layer caching)
COPY package*.json ./
# 4. Install dependencies
RUN npm install
# 5. Copy the rest of your source code
COPY . .
# 6. Expose the port your app listens on
EXPOSE 3000
# 7. The command to run when the container starts
CMD ["node", "server.js"]
| ๋ช ๋ น์ด | ๋ชฉ์ |
|---|---|
| FROM | ๋ฒ ์ด์ค ์ด๋ฏธ์ง๋ฅผ ์ง์ ํฉ๋๋ค. ํญ์ ์ฒซ ๋ฒ์งธ ๋ช ๋ น์ด์ ๋๋ค. |
| WORKDIR | ์ดํ ๋ช ๋ น์ด๋ค์ ์์ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ค์ ํฉ๋๋ค. ์กด์ฌํ์ง ์์ผ๋ฉด ์์ฑ๋ฉ๋๋ค. |
| COPY | ํธ์คํธ์ ํ์ผ์ ์ด๋ฏธ์ง ์์ผ๋ก ๋ณต์ฌํฉ๋๋ค. |
| RUN | ๋น๋ ๋จ๊ณ์์ ๋ช ๋ น์ ์คํํฉ๋๋ค(ํจํค์ง ์ค์น, ์ฝ๋ ์ปดํ์ผ ๋ฑ). |
| ENV | ๋ฐํ์์ ์ฌ์ฉํ ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํฉ๋๋ค. |
| EXPOSE | ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฌ์ฉํ๋ ํฌํธ๋ฅผ ๋ฌธ์ํํฉ๋๋ค(์ค์ ํฌํธ ๊ฐ๋ฐฉ์ ์๋). |
| CMD | ์ปจํ ์ด๋ ์์ ์ ๊ธฐ๋ณธ์ผ๋ก ์คํ๋ ๋ช ๋ น์ ์ง์ ํฉ๋๋ค. Dockerfile๋น ํ๋๋ง ๊ฐ๋ฅํฉ๋๋ค. |
| ENTRYPOINT | CMD์ ๋น์ทํ์ง๋ง ๋ฎ์ด์ฐ๊ธฐ ์ด๋ ค์ โํญ์ ์คํํด์ผ ํ๋โ ๋ช ๋ น์ ์ฌ์ฉํฉ๋๋ค. |
ํ: Dockerfile์ ๋ณ๊ฒฝ ๋น๋๊ฐ ๋ฎ์ ์์ผ๋ก ์์ฑํ์ธ์. Docker๋ ๊ฐ ๋ ์ด์ด๋ฅผ ์บ์ํ๋ฏ๋ก, ์์กด์ฑ ์ค์น์ ๊ฐ์ ์์ ์ ์ธ ๋ ์ด์ด๋ ๋ณ๊ฒฝ๋์ง ์์ ๋ ์ฌ์คํ๋์ง ์์ต๋๋ค.
์์ ํ๋ก์ ํธ ๊ตฌ์กฐ
my-app/
โโโ src/
โ โโโ index.js
โโโ package.json
โโโ package-lock.json
โโโ Dockerfile
FROM node:20-alpine
WORKDIR /app
# ์บ์ ํจ์จ์ ์ํด lockfile๊ณผ package.json์ ๋จผ์ ๋ณต์ฌ
COPY package*.json ./
RUN npm ci --only=production
COPY src/ ./src/
EXPOSE 3000
CMD ["node", "src/index.js"]
# ์ด๋ฏธ์ง ๋น๋ ๋ฐ ํ๊ทธ ์ง์
docker build -t my-node-app .
# ํธ์คํธ ํฌํธ 8080์ ์ปจํ
์ด๋ ํฌํธ 3000์ ๋งคํํ์ฌ ์คํ
docker run -p 8080:3000 my-node-app
http://localhost:8080 ์ ์ ์ํ๋ฉด Docker ์์์ ์คํ ์ค์ธ ์ฑ์ ํ์ธํ ์ ์์ต๋๋ค.
Python ์์
FROM python:3.12-slim
WORKDIR /app
# ์์กด์ฑ ์ค์น
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
์ฃผ์:
--host 0.0.0.0์ต์ ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ง์ ๊ฐ๋ฐ ์๋ฒ๊ฐ127.0.0.1(์ปจํ ์ด๋ ๋ด๋ถ)๋ง ๋ฐ์ธ๋ฉํ๊ธฐ ๋๋ฌธ์, ์ธ๋ถ ์ฐ๊ฒฐ์ ํ์ฉํ๋ ค๋ฉด ๋ฐ๋์0.0.0.0์ผ๋ก ๋ฐ์ธ๋ฉํด์ผ ํฉ๋๋ค.
Docker Compose๋ก ๋ค์ค ์๋น์ค ๊ตฌ์ฑํ๊ธฐ
์ค์ ํ๋ก์ ํธ๋ ๋ณดํต ํ๋์ ์๋น์ค๋ง ์์ง ์์ต๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค, ์บ์, ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ปค ๋ฑ์ด ํ์ํ์ฃ . Docker Compose๋ฅผ ์ฌ์ฉํ๋ฉด ์ด ๋ชจ๋ ์๋น์ค๋ฅผ ํ๋์ ํ์ผ์ ์ ์ํ๊ณ ๋์์ ์คํํ ์ ์์ต๋๋ค.
# docker-compose.yml
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:password@db:5432/mydb
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
volumes:
- .:/app # ์ฝ๋ ๋ณ๊ฒฝ ์ ์๋ ๋ฆฌ๋ก๋๋ฅผ ์ํด ๋ง์ดํธ
- /app/node_modules # ํธ์คํธ์ node_modules๊ฐ ๋ฎ์ด์ฐ๋ ๊ฒ์ ๋ฐฉ์ง
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: mydb
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
interval: 5s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
# ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ชจ๋ ์๋น์ค ์์
docker compose up -d
# ์ฑ ๋ก๊ทธ ์ค์๊ฐ ๋ณด๊ธฐ
docker compose logs -f app
# ์ ์ฒด ์๋น์ค ์ค์ง
docker compose down
# ๋ณผ๋ฅจ๊น์ง ์ญ์ (๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ)
docker compose down -v
๋น๋ฐ ์ ๋ณด๋ ์ ๋ ํ๋์ฝ๋ฉํ์ง ์๊ธฐ
.env ํ์ผ์ ํ์ฉํด ํ๊ฒฝ ๋ณ์๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
# .env (git์ ์ปค๋ฐ๋์ง ์๋๋ก .gitignore์ ์ถ๊ฐ!)
POSTGRES_PASSWORD=supersecret
API_KEY=abc123
Docker Compose๋ ๊ฐ์ ๋๋ ํฐ๋ฆฌ์ .env ํ์ผ์ ์๋์ผ๋ก ์ฝ์ด๋ค์
๋๋ค.
services:
app:
environment:
- API_KEY=${API_KEY}
db:
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
ํ๋ก๋์ ํ๊ฒฝ์์๋ Docker Secrets, Vault, AWS Secrets Manager ๋ฑ ์ ์ฉ ๋น๋ฐ ๊ด๋ฆฌ ์๋ฃจ์ ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
ํ๊ฒฝ๋ณ Compose ํ์ผ ๋ถ๋ฆฌ
ํ๋ก์ ํธ ๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ ์์:
my-app/
โโโ docker-compose.yml # ๊ธฐ๋ณธ ์ค์
โโโ docker-compose.dev.yml # ๊ฐ๋ฐ์ฉ ์ค๋ฒ๋ผ์ด๋(ํซ ๋ฆฌ๋ก๋, ๋๋ฒ๊ทธ ํฌํธ)
โโโ docker-compose.prod.yml # ํ๋ก๋์
์ฉ ์ค๋ฒ๋ผ์ด๋(๋ ํ๋ฆฌ์นด, ๋ก๊น
)
๊ฐ๋ฐ์ฉ ์ค๋ฒ๋ผ์ด๋ (docker-compose.dev.yml)
services:
app:
volumes:
- .:/app
command: npm run dev
environment:
- NODE_ENV=development