๐ ๋ชฉ์ฐจ
- Dockerfile ์์ฑํ๊ธฐ (Single-stage Dockerfile)
- Multi-stage ๋น๋๋ฅผ ํตํ ์ด๋ฏธ์ง ์ต์ ํ
- .dockerignore๋ก ๋ถํ์ํ ํ์ผ ์ ๊ฑฐ
- ์ฃผ์ Docker ๋ช ๋ น์ด
- Reference
์ฌ๋ด ์๋น์ค ํ๋ก์ ํธ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ ๋งก์ผ๋ฉด์ CI๋ฅผ ๊ตฌ์ถํด ๋ณผ ์ ์๋ ๊ธฐํ๊ฐ ์๊ฒผ๋ค.
ํ์ฌ ๊ฐ๋ฐ์ค์ธ ์๋น์ค๋ next.js ๊ธฐ๋ฐ์ผ๋ก ์ด๋ฃจ์ด์ ธ ์๋ค. ๋ด๊ฐ ๋งก์ ์ญํ ์ Dockerfile์ ์์ฑํ์ฌ ๋์ปค ์ด๋ฏธ์ง๋ฅผ ๋น๋ํ์ฌ Teamcity์ ์ฐ๋ํ๋ ๊ฒ์ด๋ค. ์ด ๊ณผ์ ์์ ํน์ ๋ธ๋์น์ ์
๋ฐ์ดํธ ๋ฐ์ ์, ๋์ปค ์ด๋ฏธ์ง๋ฅผ ๋น๋ ํ ์ฌ๋ด ์ ์ฅ์์ push ํ๋๋ก ํ๋ ๊ณผ์ ๊น์ง๋ ๋ด๊ฐ ๋งก์๋ค. ์ต์ ์ด๋ฏธ์ง ํ๊ทธ๋ฅผ ๊ฐ์ ธ์ ์๋ฒ๋ฅผ ์
๋ฐ์ดํธ ํ๋ ์์
์ ๋ค๋ฅธ ๊ฐ๋ฐ์ ์ ๋ฐฐ๋์ด ์ฐ๋ํ์๊ธฐ๋ก ํ๋ค.
Dockerfile ์์ฑํ๊ธฐ
๋จผ์ , next.js ํ๋ก์ ํธ ROOT์ Dockerfile์ ์ถ๊ฐํ๋ค.
my-nextjs-app/
โโโ Dockerfile โ
ํ๋ก์ ํธ ๋ฃจํธ์ ์์น
โโโ package.json
โโโ yarn.lock
โโโ public/
โโโ pages/ or app/
โโโ ...
์ถ๊ฐํ Dockerfile์ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
# Node.js ํ๊ฒฝ ์ค์
FROM node:20-alpine
# ์์
๋๋ ํ ๋ฆฌ ์ค์
WORKDIR /app
# ํจํค์ง ๋งค๋์ ์ค์ ํ์ผ ๋ณต์ฌ ๋ฐ ์์กด์ฑ ์ค์น
COPY package.json yarn.lock ./
RUN yarn install
# ์ ์ฒด ์์ค ์ฝ๋ ๋ณต์ฌ
COPY . .
# ์ ํ๋ฆฌ์ผ์ด์
๋น๋
RUN yarn build
# ์ปจํ
์ด๋์์ ๋
ธ์ถํ ํฌํธ
EXPOSE 3000
# ์ฑ ์คํ ๋ช
๋ น์ด
CMD ["yarn", "start"]
alpine์ด๋?
Alpine Linux๋ ๋ณด์, ๋จ์์ฑ, ๋ฆฌ์์ค ์ ์ฝ์ ์ด์ ์ ๋ง์ถ ์ด๊ฒฝ๋ ๋ฆฌ๋ ์ค ๋ฐฐํฌํ
์ฅ์
| ์ด๋ฏธ์ง ํฌ๊ธฐ ์์ | Alpine ๊ธฐ๋ฐ Node.js ์ด๋ฏธ์ง๋ ์ฝ 30~40MB๋. ๊ธฐ๋ณธ Debian ๊ธฐ๋ฐ์ 300MB ์ด์. |
| ๋ณด์์ฑ ๋์ | ์ต์ํ์ ํจํค์ง๋ก ๊ตฌ์ฑ๋์ด ๊ณต๊ฒฉ ํ๋ฉด์ด ์์. |
| ๋น ๋ฅธ ๋ฐฐํฌ ๋ฐ ๋น๋ | ์ด๋ฏธ์ง๊ฐ ์์ ๋คํธ์ํฌ ์ ์ก ์๋ ๋ฐ CI/CD ์๋ ํฅ์. |
| ์ปค์คํฐ๋ง์ด์ง ์ ๋ฆฌ | ๋ถํ์ํ ํจํค์ง๊ฐ ์์ด ํ์ํ ๊ฒ๋ง ์ค์นํด์ ์ฌ๋ฆผํ๊ฒ ์ ์ง ๊ฐ๋ฅ. |
์ฃผ์์
| glibc ๋ฏธํฌํจ | Alpine์ musl libc๋ฅผ ์ฌ์ฉํจ. ์ผ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ glibc ํ์ํด์ ์ถฉ๋ ๊ฐ๋ฅ. |
| ๋น๋ ํ๊ฒฝ ๋ฌธ์ | native addon์ ์ฌ์ฉํ๋ npm ํจํค์ง๋ alpine์์ ๋น๋ ์ ์๋ฌ๊ฐ ๋ ์ ์์. ์: sharp, bcrypt |
| ๋๋ฒ๊น ๋๊ตฌ ๋ถ์กฑ | ๊ธฐ๋ณธ ์ด๋ฏธ์ง์ bash, curl, wget, vim ๋ฑ์ด ์์. ํ์ํ ๊ฒฝ์ฐ ์ง์ ์ค์นํด์ผ ํจ. |
๋์ปค ์ด๋ฏธ์ง ๋น๋ํ๊ธฐ
์์์ ์์ฑํ Dockerfile์ ๋ช
๋ น์ด๋ฅผ ํตํด docker ์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๋ค.
๋์ ๊ฒฝ์ฐ ์ด๋ฏธ docker ์ค์น ๋ฐ ํ๊ฒฝ ์ค์ ์ด ๋์ด์๋ ์ํฉ์ด์๊ธฐ ๋๋ฌธ์, docker ์ค์น๊ฐ ๋์ด ์์ง ์๋ค๋ฉด ์ค์น๊ฐ ์ฌ์ ์ ํ์ํ๋ค.
docker ์ค์น ๋ฐ ํ๊ฒฝ ์ค์ ์ด ๋๋๋ฉด ๋ค์ ๋ช
๋ น์ด๋ฅผ ํตํด ์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๋ค.
docker build -t [๋์ปค ์ด๋ฏธ์ง ์ด๋ฆ] .
# ์์
# docker build -t cattower-front .๋น๋ ๋ ์ด๋ฏธ์ง ํ์ธ
docker images | grep [๋์ปค ์ด๋ฏธ์ง ์ด๋ฆ]
# ์์
# docker images | grep cattower-front

๋ด๊ฐ ์์ฑํ ๋น๋ ์ด๋ฏธ์ง์ ๊ฒฝ์ฐ 3.82GB์ ํฌ๊ธฐ๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ๋ช ๋ถ ์ ์์ฑ ๋์์์ ํ์ธํ ์ ์์๋ค.
์ด ๋ช
๋ น์ด ์ธ์๋ images ๋ชฉ๋ก์ ๋ณด๋ ๋ช
๋ น์ด๋ ๋ค์๊ณผ ๊ฐ๋ค.
docker image ls
์์ฑํ ์ด๋ฏธ์ง๋ฅผ ์ปจํ ์ด๋๋ก ์คํ์์ผ๋ณด๊ธฐ
docker run -d -p [์ธ๋ถ์์ ํต์ ํ๊ธฐ ์ํ ํฌํธ]:3000 [๋์ปค ์ด๋ฏธ์ง ์ด๋ฆ]
# ์ฃผ์ ์ฌํญ
# 3000๋ฒ์ ๊ฒฝ์ฐ dockerfile์์ expose ํ port๋ฒํธ๋ฅผ ์ ๋ ๊ฒ!
# ์์
# docker run -d -p 80:3000 cattower-front
# local์์ ํ ๊ฒฝ์ฐ localhost:80์ผ๋ก ์ ์์ ํ์ธ ๊ฐ๋ฅํ๋ค.
์ปจํ ์ด๋๊ฐ ์ ์คํ๋๊ณ ์๋์ง ํ์ธ
docker ps์คํ์ํจ ์ปจํ ์ด๋ ์ค์ง / ์ญ์ ํ๊ธฐ, ์ด๋ฏธ์ง ์ญ์ ํ๊ธฐ
docker stop [์ปจํ
์ด๋ ID]
docker rm [์ปจํ
์ด๋ ID]
docker image rm [์ด๋ฏธ์ง ์ด๋ฆ]
Docker ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ด๋ป๊ฒ ์ค์ผ ์ ์์๊น?
๋์ปค ์ด๋ฏธ์ง ์์ฑ ์ ๋๋ฌด ์ค๋๊ฑธ๋ ค์ ํด๋น ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ค์ผ ์ ์์ผ๋ฉด ์ค์ด๋๊ฒ ์ข์ง ์์๊น ๋ผ๋ ์๊ฐ์ ํ๋ค.
๋์ปค ๊ณต์๋ฌธ์์ ๊ฒฝ๋ํ ๊ด๋ จ ๋ฌธ์๋ฅผ ๋ฐ๊ฒฌํ ์ ์์๋ค.
๋์ปค ์ด๋ฏธ์ง๋ฅผ ์ค์ด๊ณ ์ถ์ผ๋ฉด multi-stage-builds๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ .dockerignore ์ฌ์ฉํ๋ ๋ฒ ๋ฑ์ best practices๋ก ์๊ฐํ๊ณ ์๋ค.
(ํ์ดํผ๋งํฌ๋ฅผ ๋ฐ๋ผ๊ฐ๋ฉด ๊ณต์ ๋ฌธ์๋ฅผ ํ์ธํ ์ ์๋ค.)
๋๋ ๊ณต์๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์ฌ ๋ค์ 2๊ฐ์ง ๋ฐฉ๋ฒ์ ํตํด ๊ฒฝ๋ํ๋ฅผ ์๋ํ์๋ค.
- Multi-stage ๋น๋๋ฅผ ํตํ ์ด๋ฏธ์ง ์ต์ ํ
- .dockerignore๋ก ๋ถํ์ํ ํ์ผ ์ ๊ฑฐ
1. Multi-stage ๋น๋๋ฅผ ํตํ ์ด๋ฏธ์ง ์ต์ ํ
์์์ ์์ฑํ๋ ๋จ์ผ ๋น๋ ์ด๋ฏธ์ง์ ๋จ์ ์ node_modules, ํ ์คํธ ์ฝ๋, ๊ฐ๋ฐ ๋๊ตฌ๊น์ง ํฌํจ๋์ด ์์ด ์ด๋ฏธ์ง ํฌ๊ธฐ๊ฐ ํฌ๋ค๋ ๋จ์ ์ด ์กด์ฌํ๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด multi-stage ๋น๋๋ฅผ ์๋ ์ฝ๋๋ฅผ ํตํด Dockerfile์ ์ ์ฉํ๋ค.
###########################################
# ๐ ๏ธ 1๋จ๊ณ: ๋น๋ ์คํ
์ด์ง (Build Stage)
# - ์ ํ๋ฆฌ์ผ์ด์
์์ค ์ฝ๋๋ฅผ ๋น๋ํ๊ณ ,
# - ๋ฐํ์์ ํ์ํ ์ฐ์ถ๋ฌผ๋ง ์ถ์ถ
###########################################
FROM node:20-alpine AS builder
# ์์
๋๋ ํ ๋ฆฌ ์ค์
WORKDIR /app
# ์์กด์ฑ ์ค์น๋ฅผ ์ํ ํจํค์ง ํ์ผ ๋ณต์ฌ
COPY package.json yarn.lock ./
# lockfile์ ๊ธฐ๋ฐ์ผ๋ก ์์กด์ฑ ์ค์น (์ฌํ ๊ฐ๋ฅํ ๋น๋)
RUN yarn install --frozen-lockfile
# ์ ์ฒด ์์ค ์ฝ๋ ๋ณต์ฌ
COPY . .
# ์ ํ๋ฆฌ์ผ์ด์
๋น๋ (.next, public ๋ฑ ์์ฑ)
RUN yarn build
###########################################
# ๐ 2๋จ๊ณ: ํ๋ก๋์
๋ฐํ์ ์คํ
์ด์ง
# - ์ค์ ์คํ์ ํ์ํ ์ต์ํ์ ํ์ผ๋ง ํฌํจ
# - ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ต์ํํ์ฌ ๋ณด์ ๋ฐ ์ฑ๋ฅ ๊ฐ์
###########################################
FROM node:20-alpine
# ์์
๋๋ ํ ๋ฆฌ ์ค์
WORKDIR /app
# ๋น๋๋ ๊ฒฐ๊ณผ๋ฌผ ๋ฐ ์คํ์ ํ์ํ ํ์ผ๋ง ๋ณต์ฌ
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
# ์ ํ๋ฆฌ์ผ์ด์
์ด ์ฌ์ฉํ๋ ํฌํธ ๊ฐ๋ฐฉ
EXPOSE 3000
# ์ ํ๋ฆฌ์ผ์ด์
์คํ ๋ช
๋ น์ด
CMD ["yarn", "start"]
multi-stage ์ ์ฉ ํ ์ด๋ฏธ์ง ํฌ๊ธฐ ๋น๊ต
์ : single-stage ๋น๋
ํ: multi-stage ๋น๋
ํด๋น ์ฝ๋๋ฅผ ์ ์ฉ ํ ๋ค์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ํ์ธํด ๋ณด์๋ค.


3.82GB์์ 1.34GB๋ก ์ฝ 64.9% ์ด๋ฏธ์ง๊ฐ ๊ฐ์ํ๋ค.
2. .dockerignore ๋ก ๋ถํ์ํ ํ์ผ ์ ๊ฑฐ
๋ค์ ๋ฐฉ๋ฒ์ผ๋ก๋ .dockerignore ํ์ผ์ ์ถ๊ฐํ์ฌ ๋ถํ์ํ ํ์ผ์ ์ ๊ฑฐํ๋ ๋ฐฉ๋ฒ์ด๋ค.
my-nextjs-app/
โโโ Dockerfile โ
ํ๋ก์ ํธ ๋ฃจํธ์ ์์น
โโโ .dockerignore โ
Dockerfile๊ณผ ๊ฐ์ ์์น
โโโ package.json
โโโ yarn.lock
โโโ public/
โโโ pages/ or app/
โโโ ...
Dockerfile๊ณผ ๊ฐ์ด next.js์ ํ๋ก์ ํธ ROOT ๊ฒฝ๋ก์ .dockerignore๋ฅผ ์ถ๊ฐํ๋ค.
## .dockerignore
node_modules
.next
.git
.gitignore
*.log
.vscode
.idea
*.tsbuildinfo
.DS_Store
coverage
__tests__
.dockerignore ์ ์ฉ ํ ์ด๋ฏธ์ง ํฌ๊ธฐ ๋น๊ต
์ : multi-stage๋ง ์ ์ฉ
ํ : multi-stage + .dockerignore ์ ์ฉ


1.34GB์์ 1.08GB๋ก ์ฝ 19.4% ์ด๋ฏธ์ง๊ฐ ๊ฐ์ํ๋ค.
์ต์ ํ ์ /ํ ๋น๊ต
์ต์ ํ ์ ์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ 3.82GB์๊ณ , ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ต์ ํ๋ฅผ ๊ฑฐ์ณ ์ต์ข ์ ์ผ๋ก๋ 1.08GB๊ฐ ๋์ด ์ฝ 72% ๊ฐ์ํ์๋ค.
์ฃผ์ Docker ๋ช ๋ น์ด
๋ง์ง๋ง์ผ๋ก Docker ๋ช ๋ น์ด๋ฅผ ์ ๋ฆฌํด ๋ณด์๋ค.
## ๋์ปค ์ด๋ฏธ์ง ๋น๋
docker build -t [์ด๋ฏธ์ง ์ด๋ฆ] .
## ๋์ปค ์ด๋ฏธ์ง ํฌ๊ธฐ ํ์ธ
docker images | grep [์ด๋ฏธ์ง ์ด๋ฆ]
## ํ์ฌ ์คํ ์ค์ธ ์ปจํ
์ด๋ ์ค์ง
docker stop $(docker ps -q)
## ํ์ฌ ์คํ ์ค์ธ ์ด๋ฏธ์ง ํ์ธ
docker ps
## ํฌํธ ๋งคํ์ ํฌํจํ์ฌ ์๋ก ์คํ
docker run -p 3000:3000 [์ด๋ฏธ์ง ์ด๋ฆ]
## ๋์ปค ์ด๋ฏธ์ง ๋ชฉ๋ก
docker image ls
## ๋ชจ๋ ์ปจํ
์ด๋ ๊ฐ์ ์ญ์
docker rm -f $(docker ps -aq)
## ์ด๋ฏธ์ง ์ญ์
docker rmi [์ด๋ฏธ์ง ์ด๋ฆ]
Reference
https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
https://promisingmoon.tistory.com/229#์์ฝ -1
https://jaeseo0519.tistory.com/264#1. Health check๋ฅผ ์ง์ํ๋ Docker Image ๋น๋-1
https://creboring.net/blog/how-docker-divide-image-layer/
https://medium.com/@hee98.09.14/docker-layer์-cache-574c12a1e9f7
https://velog.io/@gnoeyah/Next.jsํ๋ก์ ํธ๋ฅผ-Docker์-์ฌ๋ฆฌ๋ผ๋-๋ฏธ์
์-๋ฐ์๋ค
https://frorong.tistory.com/entry/Docker-NextJS-๋ฐฐํฌ๋ฅผ-์ํ-๋์ปค-์ปจํ
์ด๋ํ
https://oliveyoung.tech/2022-05-03/How-to-Set-up-Build-Process-with-Teamcity/
https://docs.docker.com/build/building/best-practices/
๋๊ธ