Docker ์ž…๋ฌธ

Docker ์ž…๋ฌธ — ์ปจํ…Œ์ด๋„ˆ·์ด๋ฏธ์ง€·Compose ํ•œ ๋ฒˆ์— ์ •๋ฆฌ. "๋‚ด ์ปดํ“จํ„ฐ์—์„  ๋๋Š”๋ฐ"๋ผ๋Š” ๋ง์ด ์‚ฌ๋ผ์ง€๋Š” ์ด์œ ๊ฐ€ Docker๋‹ค. ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋ฌด์—‡์ธ์ง€๋ถ€ํ„ฐ ์ด๋ฏธ์ง€ ๋งŒ๋“ค๊ธฐ(Dockerfile), ์—ฌ๋Ÿฌ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋ฌถ๋Š” docker compose๊นŒ์ง€, ์‹ค์ œ ๋ช…๋ น๊ณผ ์ถœ๋ ฅ์„ ํ•จ๊ป˜ ์ •๋ฆฌํ•œ๋‹ค.


๋“ค์–ด๊ฐ€๋ฉฐ

์ƒˆ ํŒ€์›์ด ๋“ค์–ด์™”๋‹ค. ํ”„๋กœ์ ํŠธ๋ฅผ ๋ฐ›์•„ ์‹คํ–‰ํ•˜๋ ค๋Š”๋ฐ, Node ๋ฒ„์ „์ด ์•ˆ ๋งž๊ณ , ๋กœ์ปฌ PostgreSQL์ด ์—†๊ณ , ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ๋น ์กŒ๋‹ค. ๋ฐ˜๋‚˜์ ˆ์„ ํ™˜๊ฒฝ ์„ธํŒ…์— ์“ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ง‰์ƒ ๋ฐฐํฌํ•˜๋ฉด ๋˜ ํ„ฐ์ง„๋‹ค — "์ œ ์ปดํ“จํ„ฐ์—์„  ๋๋Š”๋ฐ์š”."

์ด ๊ณ ์งˆ์ ์ธ ๋ฌธ์ œ๋ฅผ ๊ฑฐ์˜ ์‚ฌ๋ผ์ง€๊ฒŒ ๋งŒ๋“  ๋„๊ตฌ๊ฐ€ Docker๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ทธ ์‹คํ–‰ ํ™˜๊ฒฝ(OS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ๋Ÿฐํƒ€์ž„, ์˜์กด์„ฑ, ์„ค์ •)๊นŒ์ง€ ํ†ต์งธ๋กœ ์ปจํ…Œ์ด๋„ˆ(container)๋ผ๋Š” ์ƒ์ž์— ๋‹ด์•„, ์–ด๋””์„œ๋“  ๋˜‘๊ฐ™์ด ์‹คํ–‰๋˜๊ฒŒ ํ•œ๋‹ค. ๊ฐœ๋ฐœ์ž PC, ๋™๋ฃŒ PC, ์šด์˜ ์„œ๋ฒ„์—์„œ ๊ฐ™์€ ์ƒ์ž๊ฐ€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋ˆ๋‹ค.

Docker์˜ ํ•ต์‹ฌ ํ•œ ์ค„: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๊ทธ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด, ์–ด๋””์„œ๋‚˜ ๋™์ผํ•˜๊ฒŒ ์‹คํ–‰ํ•œ๋‹ค. ํ™˜๊ฒฝ์ด ์ฝ”๋“œ๊ฐ€ ๋˜๋Š” ์ˆœ๊ฐ„, "๋‚ด ์ปดํ“จํ„ฐ์—์„  ๋๋Š”๋ฐ"๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค.

์ด ๊ธ€์—์„œ๋Š” ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋ฌด์—‡์ธ์ง€(๊ฐ€์ƒ ๋จธ์‹ ๊ณผ ๋ฌด์—‡์ด ๋‹ค๋ฅธ์ง€)๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด, ์ด๋ฏธ์ง€·์ปจํ…Œ์ด๋„ˆ·๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๊ฐœ๋…์„ ์žก๊ณ , Dockerfile๋กœ ์ง์ ‘ ์ด๋ฏธ์ง€๋ฅผ ๋งŒ๋“ค๊ณ , ๋ณผ๋ฅจ·๋„คํŠธ์›Œํฌ๋ฅผ ๋‹ค๋ฃจ๊ณ , ๋งˆ์ง€๋ง‰์œผ๋กœ docker compose๋กœ ์—ฌ๋Ÿฌ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ•œ ๋ฒˆ์— ๋„์šฐ๋Š” ๋ฐ๊นŒ์ง€ ๊ฐ„๋‹ค. ๋ชจ๋“  ๋ช…๋ น์€ ์‹ค์ œ ์ถœ๋ ฅ๊ณผ ํ•จ๊ป˜ ๋ณธ๋‹ค.


1. Docker๋ž€ ๋ฌด์—‡์ธ๊ฐ€ — ์ปจํ…Œ์ด๋„ˆ์˜ ๊ฐœ๋…

์ปจํ…Œ์ด๋„ˆ๋Š” ํ˜ธ์ŠคํŠธ OS ์œ„์—์„œ ๊ฒฉ๋ฆฌ๋˜์–ด ๋„๋Š” ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค ๋ฌถ์Œ์ด๋‹ค. ์ž๊ธฐ๋งŒ์˜ ํŒŒ์ผ ์‹œ์Šคํ…œ, ๋„คํŠธ์›Œํฌ, ํ”„๋กœ์„ธ์Šค ๊ณต๊ฐ„์„ ๊ฐ–์ง€๋งŒ, ๊ทธ ์•„๋ž˜ ์šด์˜์ฒด์ œ ์ปค๋„์€ ํ˜ธ์ŠคํŠธ์™€ ๊ณต์œ ํ•œ๋‹ค. ์ด "์ปค๋„ ๊ณต์œ "๊ฐ€ ๊ฐ€์ƒ ๋จธ์‹ (VM)๊ณผ์˜ ๊ฒฐ์ •์  ์ฐจ์ด๋‹ค.

๊ฐ€์ƒ ๋จธ์‹ ์€ ํ•˜์ดํผ๋ฐ”์ด์ € ์œ„์— ์•ฑ๋งˆ๋‹ค ๊ฒŒ์ŠคํŠธ OS๋ฅผ ํ†ต์งธ๋กœ ์˜ฌ๋ฆฐ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฌด๊ฒ๊ณ (์ˆ˜ GB), ๋ถ€ํŒ…๋„ ์ˆ˜์‹ญ ์ดˆ ๊ฑธ๋ฆฐ๋‹ค. ๋ฐ˜๋ฉด ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ฒŒ์ŠคํŠธ OS ์—†์ด ํ˜ธ์ŠคํŠธ ์ปค๋„์„ ํ•จ๊ป˜ ์“ฐ๋ฏ€๋กœ, ํฌ๊ธฐ๋Š” ์ˆ˜์‹ญ~์ˆ˜๋ฐฑ MB์— ์‹œ์ž‘์€ ๋ณดํ†ต 1์ดˆ ์•ˆ์ชฝ์ด๋‹ค.

์ •๋ฆฌํ•˜๋ฉด, ์ปจํ…Œ์ด๋„ˆ๋Š” "VM๋งŒํผ ๊ฒฉ๋ฆฌ๋˜๋ฉด์„œ ํ”„๋กœ์„ธ์Šค๋งŒํผ ๊ฐ€๋ฒผ์šด" ์ ˆ์ถฉ์ ์ด๋‹ค. ๊ทธ๋ž˜์„œ ํ•œ ์„œ๋ฒ„์— ์ˆ˜์‹ญ ๊ฐœ๋ฅผ ๋„์šฐ๊ณ , ์ดˆ ๋‹จ์œ„๋กœ ์ผœ๊ณ  ๋„๊ณ , ๋˜‘๊ฐ™์€ ๋ณต์ œ๋ณธ์„ ๋ฌดํ•œ์ • ์ฐ์–ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ์ด ํŠน์„ฑ์ด ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค·CI/CD·์˜คํ† ์Šค์ผ€์ผ๋ง์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ ํ† ๋Œ€๋‹ค.


2. ํ•ต์‹ฌ ๊ฐœ๋… — ์ด๋ฏธ์ง€, ์ปจํ…Œ์ด๋„ˆ, ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ

Docker๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด ์„ธ ๋‹จ์–ด๋งŒ ์žก์œผ๋ฉด ๋œ๋‹ค.

  • ์ด๋ฏธ์ง€(Image) — ์‹คํ–‰์— ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ(๋ฒ ์ด์Šค OS, ๋Ÿฐํƒ€์ž„, ์ฝ”๋“œ, ์˜์กด์„ฑ, ์„ค์ •)์„ ๋‹ด์€ ์ฝ๊ธฐ ์ „์šฉ ํ…œํ”Œ๋ฆฟ. ํ•œ ๋ฒˆ ๋งŒ๋“ค๋ฉด ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ์ปจํ…Œ์ด๋„ˆ(Container) — ์ด๋ฏธ์ง€๋ฅผ ์‹คํ–‰ํ•œ ์ธ์Šคํ„ด์Šค. ๊ฐ™์€ ์ด๋ฏธ์ง€๋กœ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋„์šธ ์ˆ˜ ์žˆ๊ณ , ๊ฐ์ž ๋…๋ฆฝ์ ์œผ๋กœ ๋Œ๋ฉฐ, ์‚ญ์ œํ•˜๋ฉด ์‚ฌ๋ผ์ง„๋‹ค.
  • ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ(Registry) — ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅ·๊ณต์œ ํ•˜๋Š” ์ €์žฅ์†Œ. ๊ณต๊ฐœ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๊ฐ€ Docker Hub์ด๊ณ , nginx·postgres ๊ฐ™์€ ๊ณต์‹ ์ด๋ฏธ์ง€๋ฅผ ์—ฌ๊ธฐ์„œ ๋ฐ›๋Š”๋‹ค(docker pull).

๊ฐ์ฒด์ง€ํ–ฅ์— ๋น—๋Œ€๋ฉด ์ด๋ฏธ์ง€๋Š” ํด๋ž˜์Šค, ์ปจํ…Œ์ด๋„ˆ๋Š” ์ธ์Šคํ„ด์Šค๋‹ค. ํด๋ž˜์Šค ํ•˜๋‚˜๋กœ ๊ฐ์ฒด๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์ฐ์–ด๋‚ด๋“ฏ, ์ด๋ฏธ์ง€ ํ•˜๋‚˜๋กœ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋งŒ๋“ ๋‹ค. ์š”๋ฆฌ์— ๋น—๋Œ€๋ฉด ์ด๋ฏธ์ง€๋Š” ๋ ˆ์‹œํ”ผ, ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ทธ ๋ ˆ์‹œํ”ผ๋กœ ๋งŒ๋“  ์š”๋ฆฌ๋‹ค.


3. ์„ค์น˜ํ•˜๊ณ  ์ฒซ ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰ํ•˜๊ธฐ

์„ค์น˜๋Š” ์šด์˜์ฒด์ œ๋ณ„ Docker Desktop(Windows·macOS) ๋˜๋Š” Docker Engine(Linux)์œผ๋กœ ํ•œ๋‹ค. ์„ค์น˜๋˜๋ฉด ๊ฐ€์žฅ ๋จผ์ € ๋™์ž‘ ํ™•์ธ์„ ํ•œ๋‹ค.

docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
...

์ด์ œ ์ง„์งœ ์„œ๋ฒ„ ํ•˜๋‚˜๋ฅผ ๋„์›Œ๋ณด์ž. ์›น ์„œ๋ฒ„ nginx๋ฅผ ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ์‹คํ–‰ํ•œ๋‹ค.

docker run -d -p 8080:80 --name web nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
... Pull complete
Status: Downloaded newer image for nginx:latest
9c2f3a1be1a3f0c8d4b7e6a5c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0

์˜ต์…˜์˜ ์˜๋ฏธ๋Š” ์ด๋ ‡๋‹ค.

  • -d (detached) — ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ์‹คํ–‰. ํ„ฐ๋ฏธ๋„์„ ์ ์œ ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • -p 8080:80ํ˜ธ์ŠคํŠธ์˜ 8080 ํฌํŠธ๋ฅผ ์ปจํ…Œ์ด๋„ˆ์˜ 80 ํฌํŠธ๋กœ ์—ฐ๊ฒฐ. ๋ธŒ๋ผ์šฐ์ €์—์„œ localhost:8080์œผ๋กœ ์ ‘์†ํ•˜๋ฉด ์ปจํ…Œ์ด๋„ˆ ์•ˆ nginx๊ฐ€ ์‘๋‹ตํ•œ๋‹ค.
  • --name web — ์ปจํ…Œ์ด๋„ˆ์— ์ด๋ฆ„ ๋ถ€์—ฌ. ์ดํ›„ ๋ช…๋ น์—์„œ ์ด ์ด๋ฆ„์œผ๋กœ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

๋กœ์ปฌ์— ์ด๋ฏธ์ง€๊ฐ€ ์—†์œผ๋ฉด Docker Hub์—์„œ ์ž๋™์œผ๋กœ ๋ฐ›์•„์˜จ๋‹ค(Unable to find ... locally → Pulling). ์‹คํ–‰ ์ค‘์ธ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ™•์ธํ•œ๋‹ค.

docker ps
CONTAINER ID   IMAGE     COMMAND                  STATUS         PORTS                  NAMES
9c2f3a1be1a3   nginx     "/docker-entrypoint.…"   Up 5 seconds   0.0.0.0:8080->80/tcp   web

์ž์ฃผ ์“ฐ๋Š” ๊ธฐ๋ณธ ๋ช…๋ น์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

docker images                 # ๋กœ์ปฌ์— ๋ฐ›์•„๋‘” ์ด๋ฏธ์ง€ ๋ชฉ๋ก
docker logs web               # ์ปจํ…Œ์ด๋„ˆ web์˜ ๋กœ๊ทธ ๋ณด๊ธฐ
docker exec -it web bash      # ์‹คํ–‰ ์ค‘์ธ ์ปจํ…Œ์ด๋„ˆ ์•ˆ์œผ๋กœ ์…ธ ์ง„์ž…
docker stop web               # ์ปจํ…Œ์ด๋„ˆ ์ค‘์ง€
docker rm web                 # ์ค‘์ง€๋œ ์ปจํ…Œ์ด๋„ˆ ์‚ญ์ œ
docker rmi nginx              # ์ด๋ฏธ์ง€ ์‚ญ์ œ

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฐ๊ฐ ํ•˜๋‚˜. ์ปจํ…Œ์ด๋„ˆ๋Š” ์–ธ์ œ๋“  ๋ฒ„๋ฆด ์ˆ˜ ์žˆ๋Š” ์ผํšŒ์šฉ์ด๋ผ๋Š” ์ ์ด๋‹ค. ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๊ณ ์น˜๊ธฐ๋ณด๋‹ค ์ง€์šฐ๊ณ  ๋‹ค์‹œ ๋„์šด๋‹ค. ์ด "์ง€์šฐ๊ณ  ๋‹ค์‹œ ๋งŒ๋“ ๋‹ค"๊ฐ€ Docker ์šด์˜์˜ ๊ธฐ๋ณธ ํƒœ๋„๋‹ค.


4. ์ด๋ฏธ์ง€ ์ง์ ‘ ๋งŒ๋“ค๊ธฐ — Dockerfile

๋‚จ์ด ๋งŒ๋“  ์ด๋ฏธ์ง€๋ฅผ ๋ฐ›์•„ ์“ฐ๋Š” ๊ฑธ ๋„˜์–ด, ๋‚ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด์•ผ ์ง„์งœ ์‹œ์ž‘์ด๋‹ค. ๊ทธ ์„ค๊ณ„๋„๊ฐ€ Dockerfile์ด๋‹ค. ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— Dockerfile์ด๋ผ๋Š” ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ๋ช…๋ น์„ ์œ„์—์„œ ์•„๋ž˜๋กœ ์ ๋Š”๋‹ค.

# 1. ๋ฒ ์ด์Šค ์ด๋ฏธ์ง€ — Node.js 20 (๊ฐ€๋ฒผ์šด alpine ๋ฒ„์ „)
FROM node:20-alpine

# 2. ์ปจํ…Œ์ด๋„ˆ ์•ˆ์—์„œ ์ž‘์—…ํ•  ๋””๋ ‰ํ„ฐ๋ฆฌ
WORKDIR /app

# 3. ์˜์กด์„ฑ ์ •์˜ ํŒŒ์ผ๋ถ€ํ„ฐ ๋ณต์‚ฌ (์บ์‹œ ์ตœ์ ํ™” — ์•„๋ž˜ ์„ค๋ช…)
COPY package*.json ./
RUN npm install

# 4. ๋‚˜๋จธ์ง€ ์†Œ์Šค ์ฝ”๋“œ ๋ณต์‚ฌ
COPY . .

# 5. ์•ฑ์ด ์‚ฌ์šฉํ•˜๋Š” ํฌํŠธ (๋ฌธ์„œํ™” ๋ชฉ์ )
EXPOSE 3000

# 6. ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹œ์ž‘๋  ๋•Œ ์‹คํ–‰ํ•  ๋ช…๋ น
CMD ["npm", "start"]

์ฃผ์š” ๋ช…๋ น์–ด์˜ ์—ญํ• ์€ ์ด๋ ‡๋‹ค.

  • FROM — ์ถœ๋ฐœ์ ์ด ๋˜๋Š” ๋ฒ ์ด์Šค ์ด๋ฏธ์ง€. ๋ชจ๋“  Dockerfile์€ ์—ฌ๊ธฐ์„œ ์‹œ์ž‘ํ•œ๋‹ค.
  • WORKDIR — ์ดํ›„ ๋ช…๋ น์ด ์‹คํ–‰๋  ์ž‘์—… ๋””๋ ‰ํ„ฐ๋ฆฌ.
  • COPY — ํ˜ธ์ŠคํŠธ์˜ ํŒŒ์ผ์„ ์ด๋ฏธ์ง€ ์•ˆ์œผ๋กœ ๋ณต์‚ฌ.
  • RUN — ์ด๋ฏธ์ง€๋ฅผ ๋งŒ๋“œ๋Š” ์‹œ์ ์— ์‹คํ–‰ํ•  ๋ช…๋ น(์˜์กด์„ฑ ์„ค์น˜ ๋“ฑ).
  • EXPOSE — ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ํฌํŠธ๋ฅผ ๋ช…์‹œ(์‹ค์ œ ๊ฐœ๋ฐฉ์€ -p๋กœ).
  • CMD — ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹œ์ž‘๋  ๋•Œ ์‹คํ–‰ํ•  ๊ธฐ๋ณธ ๋ช…๋ น.

์ž‘์„ฑํ–ˆ์œผ๋ฉด ๋นŒ๋“œํ•œ๋‹ค. -t๋กœ ์ด๋ฆ„(ํƒœ๊ทธ)์„ ๋ถ™์ด๊ณ , ๋งˆ์ง€๋ง‰ .์€ ๋นŒ๋“œ ์ปจํ…์ŠคํŠธ(ํ˜„์žฌ ํด๋”)๋‹ค.

docker build -t myapp:1.0 .
[+] Building 12.3s (10/10) FINISHED
 => [internal] load build definition from Dockerfile
 => [1/4] FROM docker.io/library/node:20-alpine
 => [2/4] WORKDIR /app
 => [3/4] COPY package*.json ./
 => [4/4] RUN npm install
 => exporting to image
 => => naming to docker.io/library/myapp:1.0

๋นŒ๋“œ๊ฐ€ ๋๋‚˜๋ฉด docker run -d -p 8080:3000 myapp:1.0์œผ๋กœ ๋‚ด ์•ฑ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ๋‹ค.

๋ ˆ์ด์–ด์™€ ์บ์‹œ — COPY ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•œ ์ด์œ 

Dockerfile์˜ ๊ฐ ๋ช…๋ น์€ ๋ ˆ์ด์–ด(layer) ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ ๋‹ค. ์ด๋ฏธ์ง€๋Š” ์ด ๋ ˆ์ด์–ด๋“ค์ด ์Œ“์ธ ๊ฒฐ๊ณผ๋ฌผ์ด๊ณ , Docker๋Š” ๋ฐ”๋€Œ์ง€ ์•Š์€ ๋ ˆ์ด์–ด๋Š” ์บ์‹œํ•ด์„œ ์žฌ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์œ„ ์˜ˆ์ œ์—์„œ package*.json์„ ๋จผ์ € ๋ณต์‚ฌํ•˜๊ณ  npm install์„ ํ•œ ๋’ค, ๋‚˜๋จธ์ง€ ์†Œ์Šค๋ฅผ ๋‚˜์ค‘์— ๋ณต์‚ฌํ–ˆ๋‹ค. ์†Œ์Šค ์ฝ”๋“œ๋งŒ ๊ณ ์น˜๊ณ  ์˜์กด์„ฑ์€ ๊ทธ๋Œ€๋กœ์ผ ๋•Œ, npm install ๋ ˆ์ด์–ด๊ฐ€ ์บ์‹œ์— ์ ์ค‘ํ•ด ๋นŒ๋“œ๊ฐ€ ๋ช‡ ์ดˆ๋กœ ๋๋‚˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ˆœ์„œ๋ฅผ ๋ฐ˜๋Œ€๋กœ ํ•˜๋ฉด ์ฝ”๋“œ ํ•œ ์ค„๋งŒ ๋ฐ”๊ฟ”๋„ ๋งค๋ฒˆ ์˜์กด์„ฑ์„ ์ƒˆ๋กœ ์„ค์น˜ํ•œ๋‹ค.

๋นŒ๋“œ ์ปจํ…์ŠคํŠธ์—์„œ ๋ถˆํ•„์š”ํ•œ ํŒŒ์ผ(์˜ˆ: node_modules, .git, .env)์„ ๋นผ๋ ค๋ฉด .dockerignore๋ฅผ ๋‘”๋‹ค. ๋นŒ๋“œ๊ฐ€ ๋นจ๋ผ์ง€๊ณ , ๋น„๋ฐ€ ๊ฐ’์ด ์ด๋ฏธ์ง€์— ์„ž์—ฌ ๋“ค์–ด๊ฐ€๋Š” ์‚ฌ๊ณ ๋„ ๋ง‰๋Š”๋‹ค.

node_modules
.git
.env
*.log

5. ๋ฐ์ดํ„ฐ์™€ ํ†ต์‹  — ๋ณผ๋ฅจ๊ณผ ๋„คํŠธ์›Œํฌ

๋ณผ๋ฅจ — ์‚ฌ๋ผ์ง€์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ

์ปจํ…Œ์ด๋„ˆ๋Š” ์ผํšŒ์šฉ์ด๋ผ, ์‚ญ์ œํ•˜๋ฉด ๊ทธ ์•ˆ์˜ ๋ฐ์ดํ„ฐ๋„ ํ•จ๊ป˜ ์‚ฌ๋ผ์ง„๋‹ค. DB๋ฅผ ์ปจํ…Œ์ด๋„ˆ๋กœ ๋„์› ๋‹ค๊ฐ€ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ง€์šฐ๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚ ์•„๊ฐ„๋‹ค๋Š” ๋œป์ด๋‹ค. ์ด๋ฅผ ๋ง‰์œผ๋ ค๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ปจํ…Œ์ด๋„ˆ ๋ฐ”๊นฅ์— ๋ณด๊ด€ํ•˜๋Š” ์žฅ์น˜๊ฐ€ ๋ณผ๋ฅจ(volume)์ด๋‹ค.

# Docker๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” named volume ์ƒ์„ฑ ํ›„ ์—ฐ๊ฒฐ
docker volume create pgdata
docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:17

-v pgdata:/var/lib/postgresql/data๋Š” ์ปจํ…Œ์ด๋„ˆ ์•ˆ PostgreSQL ๋ฐ์ดํ„ฐ ๊ฒฝ๋กœ๋ฅผ ๋ณผ๋ฅจ์— ์—ฐ๊ฒฐํ•œ๋‹ค. ์ด์ œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ง€์šฐ๊ณ  ๋‹ค์‹œ ๋งŒ๋“ค์–ด๋„ ๋ฐ์ดํ„ฐ๋Š” ๋ณผ๋ฅจ์— ๋‚จ์•„ ์žˆ๋‹ค. (ํ˜ธ์ŠคํŠธ์˜ ํŠน์ • ํด๋”๋ฅผ ์ง์ ‘ ์—ฐ๊ฒฐํ•˜๋Š” bind mount -v $(pwd)/data:/... ๋ฐฉ์‹๋„ ์žˆ๋‹ค.)

๋„คํŠธ์›Œํฌ — ์ปจํ…Œ์ด๋„ˆ๋ผ๋ฆฌ ๋Œ€ํ™”ํ•˜๊ธฐ

๊ธฐ๋ณธ์ ์œผ๋กœ ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ฒฉ๋ฆฌ๋ผ ์žˆ๋‹ค. ๊ฐ™์€ ์‚ฌ์šฉ์ž ์ •์˜ ๋„คํŠธ์›Œํฌ์— ๋ฌถ์œผ๋ฉด, ์„œ๋กœ์˜ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„์„ ํ˜ธ์ŠคํŠธ๋ช…์ฒ˜๋Ÿผ ์จ์„œ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค.

docker network create app-net
docker run -d --name db   --network app-net postgres:17
docker run -d --name web  --network app-net myapp:1.0

์ด์ œ web ์ปจํ…Œ์ด๋„ˆ ์•ˆ์—์„œ๋Š” DB ์ฃผ์†Œ๋ฅผ IP๊ฐ€ ์•„๋‹ˆ๋ผ ๊ทธ๋ƒฅ db๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ ‘์†ํ•  ์ˆ˜ ์žˆ๋‹ค(postgres://user@db:5432/...). ์ด๋ฆ„ ๊ธฐ๋ฐ˜ ํ†ต์‹ ์ด ๊ฐ€๋Šฅํ•ด์ง€๋Š” ๊ฒŒ ํ•ต์‹ฌ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋‘์„ธ ๊ฐœ๋กœ ๋Š˜๋ฉด ์ด run ๋ช…๋ น๋“ค์„ ๋งค๋ฒˆ ์ˆœ์„œ ๋งž์ถฐ ์น˜๋Š” ๊ฒŒ ๋ฒˆ๊ฑฐ๋กœ์›Œ์ง„๋‹ค. ์—ฌ๊ธฐ์„œ Compose๊ฐ€ ๋“ฑ์žฅํ•œ๋‹ค.


6. ์—ฌ๋Ÿฌ ์ปจํ…Œ์ด๋„ˆ ํ•œ ๋ฒˆ์— — Docker Compose

์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋ณดํ†ต ์—ฌ๋Ÿฌ ์ปจํ…Œ์ด๋„ˆ์˜ ๋ฌถ์Œ์ด๋‹ค. ์›น ์•ฑ + DB + ์บ์‹œ(Redis)์ฒ˜๋Ÿผ. ์ด๊ฑธ docker run์œผ๋กœ ํ•˜๋‚˜์”ฉ ๋„์šฐ๋ ค๋ฉด ๋„คํŠธ์›Œํฌ ๋งŒ๋“ค๊ณ , ๋ณผ๋ฅจ ๋งŒ๋“ค๊ณ , ์ˆœ์„œ ๋งž์ถฐ ์‹คํ–‰ํ•˜๊ณ … ๊ธˆ์„ธ ๋ณต์žกํ•ด์ง„๋‹ค. Docker Compose๋Š” ์ด ์ „์ฒด ๊ตฌ์„ฑ์„ YAML ํŒŒ์ผ ํ•˜๋‚˜๋กœ ์ •์˜ํ•˜๊ณ , ๋ช…๋ น ํ•œ ๋ฒˆ์œผ๋กœ ์ „๋ถ€ ๋„์šด๋‹ค.

ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— compose.yml(๋˜๋Š” docker-compose.yml)์„ ๋งŒ๋“ ๋‹ค.

# compose.yml
services:
  web:
    build: .                       # ํ˜„์žฌ ํด๋”์˜ Dockerfile๋กœ ๋นŒ๋“œ
    ports:
      - "8080:3000"                # ํ˜ธ์ŠคํŠธ 8080 → ์ปจํ…Œ์ด๋„ˆ 3000
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/app
    depends_on:
      - db
      - cache

  db:
    image: postgres:17
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: app
    volumes:
      - db-data:/var/lib/postgresql/data   # ๋ฐ์ดํ„ฐ ์˜์†ํ™”

  cache:
    image: redis:7

volumes:
  db-data:

์ฝ๋Š” ๋ฒ•์€ ์ง๊ด€์ ์ด๋‹ค. services ์•„๋ž˜ ์ปจํ…Œ์ด๋„ˆ ์…‹(web, db, cache)์„ ์ •์˜ํ–ˆ๊ณ , web์€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—์„œ DB ์ฃผ์†Œ๋ฅผ db๋ผ๋Š” ์„œ๋น„์Šค ์ด๋ฆ„์œผ๋กœ ๊ฐ€๋ฆฌํ‚จ๋‹ค(Compose๊ฐ€ ๊ฐ™์€ ๋„คํŠธ์›Œํฌ์— ๋ฌถ์–ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฆ„์œผ๋กœ ์ ‘์†๋œ๋‹ค). depends_on์œผ๋กœ ์‹œ์ž‘ ์ˆœ์„œ๋ฅผ, volumes๋กœ DB ๋ฐ์ดํ„ฐ ์˜์†ํ™”๋ฅผ ์„ ์–ธํ–ˆ๋‹ค.

์ด์ œ ๋ช…๋ น ํ•œ ๋ฒˆ์œผ๋กœ ์ „๋ถ€ ๋„์šด๋‹ค.

docker compose up -d
[+] Running 4/4
 โœ” Network app_default     Created
 โœ” Container app-db-1      Started
 โœ” Container app-cache-1   Started
 โœ” Container app-web-1     Started

์ƒํƒœ ํ™•์ธ·๋กœ๊ทธ·์ข…๋ฃŒ๋„ ํ•œ ๊ณณ์—์„œ ํ•œ๋‹ค.

docker compose ps        # ์ด ํ”„๋กœ์ ํŠธ์˜ ์ปจํ…Œ์ด๋„ˆ ์ƒํƒœ
docker compose logs -f   # ์ „์ฒด ๋กœ๊ทธ ์‹ค์‹œ๊ฐ„ ํ™•์ธ
docker compose down      # ์ „๋ถ€ ์ค‘์ง€ํ•˜๊ณ  ์ •๋ฆฌ (๋ณผ๋ฅจ์€ ๊ธฐ๋ณธ ์œ ์ง€)

ํ”ํ•œ ํ•จ์ • — ์˜ค๋ž˜๋œ ํŠœํ† ๋ฆฌ์–ผ ์ฃผ์˜. ์˜ˆ์ „ ์ž๋ฃŒ๋Š” ํŒŒ์ผ ๋งจ ์œ„์— version: "3.8"์„ ์ ๊ณ , ๋ช…๋ น์€ docker-compose(ํ•˜์ดํ”ˆ)๋ฅผ ์ผ๋‹ค. ๋‘˜ ๋‹ค ์˜› ๋ฐฉ์‹์ด๋‹ค. ์ง€๊ธˆ์˜ Compose V2์—์„œ version ํ•„๋“œ๋Š” obsolete๋ผ ๊ทธ๋ƒฅ ๋นผ์•ผ ํ•˜๊ณ (๋„ฃ์œผ๋ฉด ๊ฒฝ๊ณ ๊ฐ€ ๋œฌ๋‹ค), ๋ช…๋ น๋„ docker compose(๋„์–ด์“ฐ๊ธฐ)๊ฐ€ ํ‘œ์ค€์ด๋‹ค. ํ•˜์ดํ”ˆ ๋ฒ„์ „(docker-compose)์€ ๋” ์ด์ƒ ์œ ์ง€๋˜์ง€ ์•Š๋Š”๋‹ค.


7. ํ•œ ๋‹จ๊ณ„ ๋” — ๋ฉ€ํ‹ฐ์Šคํ…Œ์ด์ง€ ๋นŒ๋“œ์™€ ๋ช…๋ น์–ด ์ •๋ฆฌ

์ด๋ฏธ์ง€๊ฐ€ ๋ฌด๊ฑฐ์šฐ๋ฉด ๋ฐฐํฌ๊ฐ€ ๋А๋ฆฌ๊ณ  ๋ณด์•ˆ ํ‘œ๋ฉด๋„ ๋„“์–ด์ง„๋‹ค. ๋ฉ€ํ‹ฐ์Šคํ…Œ์ด์ง€ ๋นŒ๋“œ๋Š” ๋นŒ๋“œ์šฉ ๋‹จ๊ณ„์™€ ์‹คํ–‰์šฉ ๋‹จ๊ณ„๋ฅผ ๋‚˜๋ˆ , ์ตœ์ข… ์ด๋ฏธ์ง€์—๋Š” ๊ฒฐ๊ณผ๋ฌผ๋งŒ ๋‹ด๋Š” ๊ธฐ๋ฒ•์ด๋‹ค. ๋นŒ๋“œ ๋„๊ตฌ๋Š” ๋ฒ„๋ฆฌ๊ณ  ์‚ฐ์ถœ๋ฌผ๋งŒ ๋‚จ๊ธด๋‹ค.

# 1๋‹จ๊ณ„: ๋นŒ๋“œ (๋ฌด๊ฑฐ์šด ๋นŒ๋“œ ๋„๊ตฌ ํฌํ•จ)
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# 2๋‹จ๊ณ„: ์‹คํ–‰ (๊ฒฐ๊ณผ๋ฌผ๋งŒ ๋ณต์‚ฌ → ์ตœ์ข… ์ด๋ฏธ์ง€๋Š” ๊ฐ€๋ฒผ์›€)
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm install --omit=dev
CMD ["node", "dist/index.js"]

COPY --from=builder๊ฐ€ ํ•ต์‹ฌ์ด๋‹ค. 1๋‹จ๊ณ„์—์„œ ๋งŒ๋“  ์‚ฐ์ถœ๋ฌผ(dist)๋งŒ 2๋‹จ๊ณ„๋กœ ๊ฐ€์ ธ์˜ค๊ณ , ๋ฌด๊ฑฐ์šด ๋นŒ๋“œ ์˜์กด์„ฑ์€ ์ตœ์ข… ์ด๋ฏธ์ง€์— ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ ์ž์ฃผ ์“ฐ๋Š” ๋ช…๋ น์„ ํ•œ ํ‘œ๋กœ ์ •๋ฆฌํ•œ๋‹ค.

๋ช…๋ น์–ด ํ•˜๋Š” ์ผ
docker ps / docker ps -a ์‹คํ–‰ ์ค‘ / ์ „์ฒด(๋ฉˆ์ถ˜ ๊ฒƒ ํฌํ•จ) ์ปจํ…Œ์ด๋„ˆ ๋ชฉ๋ก
docker images ๋กœ์ปฌ ์ด๋ฏธ์ง€ ๋ชฉ๋ก
docker build -t ์ด๋ฆ„:ํƒœ๊ทธ . Dockerfile๋กœ ์ด๋ฏธ์ง€ ๋นŒ๋“œ
docker run -d -p 8080:80 ์ด๋ฏธ์ง€ ์ปจํ…Œ์ด๋„ˆ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์‹คํ–‰ + ํฌํŠธ ์—ฐ๊ฒฐ
docker logs -f ์ด๋ฆ„ ์ปจํ…Œ์ด๋„ˆ ๋กœ๊ทธ ์‹ค์‹œ๊ฐ„ ํ™•์ธ
docker exec -it ์ด๋ฆ„ sh ์‹คํ–‰ ์ค‘์ธ ์ปจํ…Œ์ด๋„ˆ ์•ˆ ์…ธ ์ง„์ž…
docker stop / rm ์ด๋ฆ„ ์ปจํ…Œ์ด๋„ˆ ์ค‘์ง€ / ์‚ญ์ œ
docker compose up -d Compose์— ์ •์˜๋œ ์„œ๋น„์Šค ์ „๋ถ€ ์‹คํ–‰
docker compose down ์ „๋ถ€ ์ค‘์ง€ํ•˜๊ณ  ์ •๋ฆฌ

๋งˆ์น˜๋ฉฐ

Docker๋Š” "์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๊ทธ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ํ•˜๋‚˜๋กœ ๋ฌถ๋Š”๋‹ค"๋Š” ๋‹จ์ˆœํ•œ ๋ฐœ์ƒ์—์„œ ์ถœ๋ฐœํ•œ๋‹ค. ๊ทธ ๋ฌถ์Œ์ด ์ด๋ฏธ์ง€์ด๊ณ , ์ด๋ฏธ์ง€๋ฅผ ์‹คํ–‰ํ•œ ๊ฒŒ ์ปจํ…Œ์ด๋„ˆ์ด๋ฉฐ, Dockerfile๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋งŒ๋“ค๊ณ  docker compose๋กœ ์—ฌ๋Ÿฌ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ•œ ๋ฒˆ์— ๋„์šด๋‹ค. ์ด ๋ชจ๋ธ ์œ„์—์„œ "๋‚ด ์ปดํ“จํ„ฐ์—์„  ๋๋Š”๋ฐ"๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ , ๋ฐฐํฌ์™€ ํ˜‘์—…์ด ๋‹จ์ˆœํ•ด์ง„๋‹ค.

ํ•ต์‹ฌ๋งŒ ๋‹ค์‹œ ์งš์œผ๋ฉด, ์ด๋ฏธ์ง€(ํ…œํ”Œ๋ฆฟ) → ์ปจํ…Œ์ด๋„ˆ(์‹คํ–‰) → Compose(๋ฌถ์Œ) ์˜ ํ๋ฆ„๊ณผ, ๋ฐ์ดํ„ฐ๋Š” ๋ณผ๋ฅจ์œผ๋กœ ์‚ด๋ฆฌ๊ณ , ์ปจํ…Œ์ด๋„ˆ๋Š” ์ด๋ฆ„์œผ๋กœ ํ†ต์‹ ํ•œ๋‹ค๋Š” ๋‘ ๊ฐ€์ง€๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง€ ์žก์œผ๋ฉด ๋‚จ์ด ๋งŒ๋“  ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ๋‹จ๊ณ„๋ฅผ ๋„˜์–ด, ๋‚ด ์„œ๋น„์Šค๋ฅผ ์ปจํ…Œ์ด๋„ˆ๋กœ ํŒจํ‚ค์ง•ํ•˜๊ณ  ์šด์˜ํ•˜๋Š” ์ถœ๋ฐœ์„ ์— ์„  ๊ฒƒ์ด๋‹ค.

๋‹ค์Œ ๋‹จ๊ณ„๋Š” ์ด ์ด๋ฏธ์ง€๋ฅผ ์ž๋™์œผ๋กœ ๋นŒ๋“œ·๋ฐฐํฌํ•˜๋Š” CI/CD, ๊ทธ๋ฆฌ๊ณ  ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์—ฌ๋Ÿฌ ์„œ๋ฒ„์— ๊ฑธ์ณ ์šด์˜ํ•˜๋Š” ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜(Kubernetes)์ด๋‹ค. ๊ทธ๊ฑด ๋ณ„๋„ ๊ธ€์—์„œ ์ด์–ด๊ฐ€๊ฒ ๋‹ค.


์ฐธ๊ณ  ์ถœ์ฒ˜

Docker ๋ฐ Docker ๋กœ๊ณ (Moby Dock ๊ณ ๋ž˜)๋Š” Docker, Inc.์˜ ์ƒํ‘œ์ด๋ฉฐ, ๋ณธ ๊ธ€์—์„œ๋Š” ์‹๋ณ„·์„ค๋ช… ๋ชฉ์ ์œผ๋กœ๋งŒ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.