์ถ์ฒ์ ๋ด์ฉ์ ๋ฒ์ญํด์ ๊ณต์ ๋๋ฆฝ๋๋ค.
๋น๋ํ ์ด๋ฏธ์ง์ ์ค์ ์ํฅ
์ด๋ฏธ์ง ํฌ๊ธฐ๋ ํ๋ก๋์ ํ๊ฒฝ์์ ์ ํ๋ฆฌ์ผ์ด์ ๋์์ ์ง์ ์ ์ธ ์ํฅ์ ์ค๋๋ค. 1GB์ง๋ฆฌ ์ด๋ฏธ์ง์ 50MB์ง๋ฆฌ ์ด๋ฏธ์ง์ ์ฐจ์ด๋ ์์ ์๋์์ ์ธํ๋ผ ๋น์ฉ๊น์ง ๋ค์ํ ์์์ ์ํฅ์ ์ค๋๋ค.
- ๋น ๋ฅธ ๋ฐฐํฌ: ์์ ์ด๋ฏธ์ง๋ CI/CD ํ์ดํ๋ผ์ธ์ ๋ ๋น ๋ฅด๊ฒ ํต๊ณผํฉ๋๋ค. ํ๋ฃจ์๋ ์์ญ ๊ฐ ์๋น์ค๋ฅผ ๋ฐฐํฌํ๋ ํ๊ฒฝ์์๋, ๋ฐฐํฌ๋ง๋ค ๋ช ๋ถ์ฉ ์ค์ด๋ ๊ฒ์ด ๊ณง ํฐ ์ฐจ์ด๊ฐ ๋ฉ๋๋ค.
- ๋น์ฉ ์ ๊ฐ: ๊ฐ๋ฒผ์ด ์ด๋ฏธ์ง๋ ์ ์ฅ ๊ณต๊ฐ์ ๋ ์ฐจ์งํฉ๋๋ค. ์ค์ ๋ก ํ์์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ค์ธ ํ ์ปจํ ์ด๋ ๋ ์ง์คํธ๋ฆฌ ๋น์ฉ์ ์ต๋ 60%๊น์ง ์ ๊ฐํ ์ฌ๋ก๊ฐ ์์ต๋๋ค.
- ๋ณด์ ๊ฐํ: ํจํค์ง๊ฐ ์ค์ด๋ค๋ฉด ๊ณต๊ฒฉ ๋ฒกํฐ๋ ์ค์ด๋ญ๋๋ค. ํ ์ฌ๋ก์์๋ ๋ถํ์ํ ์์กด์ฑ ๋๋ฌธ์ ๋ณด๊ณ ๋ ์ทจ์ฝ์ ์ 3๋ถ์ 2 ์ด์์ด ๋ฐ์ํ ๊ฒ์ผ๋ก ๋๋ฌ๋ฌ์ต๋๋ค.
Docker ์ด๋ฏธ์ง ํฌ๊ธฐ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์๊ฐ์ ์ง์ ์ ์ธ ์ํฅ์ ์ฃผ๋ฉฐ, ์ด๋ ์คํ ์ค์ผ์ผ๋ง ์๋, ์ฅ์ ๋ณต๊ตฌ ์๊ฐ, ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์ ๊ฒฝํ ์ ๋ฐ์๊น์ง ์ํฅ์ ์ค๋๋ค.
์์ ์ ํ๋ฆฌ์ผ์ด์
์ด์ ์ค์ ํ๋ก๋์ ์์ ๋ฐฐํฌํ ์ ์๋ ์ ํ์ ์ธ Node.js ๋ง์ดํฌ๋ก์๋น์ค๋ฅผ ํํํ๋ Express ์ ํ๋ฆฌ์ผ์ด์ ์ ์์๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ผ์ฐํ ์ ์ํ express, ์๊ฐ ํฌ๋งท์ ์ํ moment, MongoDB ์ฐ๋์ ์ํ mongoose, ๊ทธ๋ฆฌ๊ณ cors์ helmet ๊ฐ์ ๋ฏธ๋ค์จ์ด๋ฅผ ํฌํจํฉ๋๋ค. ์ค์ ๋ง์ดํฌ๋ก์๋น์ค๋ผ๋ฉด ๋ก๊น , ๋ฉํธ๋ฆญ, ์ธ์ฆ ๋ฏธ๋ค์จ์ด๋ ์์ ์ ์์ง๋ง, ์ฌ๊ธฐ์๋ ๋จ์ํ๋ฅผ ์ํด ๊ธฐ๋ณธ์ ์ธ ์์๋ง ๋ค๋ฃน๋๋ค.
๋จผ์ , ์๋ก์ด Node.js ํ๋ก์ ํธ๋ฅผ ์ด๊ธฐํํฉ๋๋ค:
mkdir docker-shrink
cd docker-shrink
npm init -y
dependencies ์ค์นํฉ๋๋ค:
npm install express moment mongoose cors helmet
npm install --save-dev nodemon jest supertest
์ด์ index.js ํ์ผ์ ์์ฑํฉ๋๋ค:
const express = require("express");
const moment = require("moment");
const cors = require("cors");
const helmet = require("helmet");
// Initialize express
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(cors());
app.use(helmet());
app.use(express.json());
// Routes
app.get("/", (req, res) => {
res.json({
message: "Hello from a slim Docker container!",
timestamp: moment().format("MMMM Do YYYY, h:mm:ss a"),
uptime: process.uptime(),
});
});
app.get("/health", (req, res) => {
res.json({ status: "UP", memory: process.memoryUsage() });
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: "Something went wrong!" });
});
// Start server
if (process.env.NODE_ENV !== "test") {
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
}
module.exports = app; // For testing
์ด์ ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ Docker๋ก ์ปจํ ์ด๋ํํ๊ธฐ ์์ํฉ๋๋ค.
1๋จ๊ณ: ํ์ค ๋ฒ ์ด์ค๋ผ์ธ ์ ๊ทผ
๋๋ถ๋ถ์ ๊ฐ๋ฐ์์ ๋ง์ฐฌ๊ฐ์ง๋ก, ์ ๋ ํํ ๋ฆฌ์ผ์ด๋ Stack Overflow ๊ธ์์ ๊ทธ๋๋ก ๊ฐ์ ธ์จ ๋จ์ํ Dockerfile๋ก ์์ํ์ต๋๋ค. ์๋ฌด ์๊ฐ ์์ด node:latest๋ฅผ ๋ฒ ์ด์ค ์ด๋ฏธ์ง๋ก ์ฌ์ฉํ ๋ฐฉ์์ด์์ฃ .
FROM node:latest
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
์ด ์ด๋ฏธ์ง๋ฅผ ๋น๋ํฉ๋๋ค:
docker build -t node-app:phase1 .
docker images | grep node-app
์ด๋ฏธ์ง ํฌ๊ธฐ๊ฐ 1.22GB์ ๋ฌํด ๋งค์ฐ ํฝ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋๋ ๋ช ๋ฉ๊ฐ๋ฐ์ดํธ์ ๋ถ๊ณผํ ์ ์์ง๋ง, ์ด๋ฏธ์ง์๋ ์ ์ฒด Linux ๋ฐฐํฌํ๊ณผ Node.js ๋ฐํ์, ๊ทธ๋ฆฌ๊ณ ๋ถํ์ํ ์๋ง์ ์์กด์ฑ์ด ํฌํจ๋์ด ์์์ต๋๋ค.
๋ฒ ์ด์ค๋ผ์ธ ์ด๋ฏธ์ง ํ ์คํธ
์ต์ ํ๋ฅผ ์งํํ๊ธฐ ์ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ์ ๋์ํ๋์ง ๋จผ์ ํ์ธํด ๋ด ๋๋ค:
docker run -d -p 3000:3000 node-app:phase1
curl http://localhost:3000
์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ์์ ์ผ๋ก ๋์ํ๊ณ ์์ต๋๋ค. ์ด์ ์ต์ ํ๋ฅผ ์์ํด ๋ณด๊ฒ ์ต๋๋ค.
2๋จ๊ณ: ์ฌ๋ฐ๋ฅธ ๋ฒ ์ด์ค ์ด๋ฏธ์ง ์ ํ
์ฒซ ๋ฒ์งธ ์ต์ ํ๋ ๋ ์ฌ๋ฆผํ ๋ฒ ์ด์ค ์ด๋ฏธ์ง๋ก ์ ํํ๋ ๊ฒ์ด์๊ณ , ์ด๋ ์ฆ์ ์ฌ๋ฌ ๊ฐ์ง ์ด์ ์ ๊ฐ์ ธ์์ต๋๋ค:
๋ฐํ์์ ํ์ํ์ง ์์ ๋ถํ์ํ ํจํค์ง์ ์ ํธ๋ฆฌํฐ๋ฅผ ์ ๊ฑฐํ์ต๋๋ค.
์ปจํ
์ด๋์ ๊ณต๊ฒฉ ํ๋ฉด์ ์ค์์ต๋๋ค.
๋ฐฐํฌ ๊ณผ์ ์์ ๋น๋ ๋ฐ pull ์๋๋ฅผ ํฌ๊ฒ ๊ฐ์ ํ์ต๋๋ค.
์ ๋ฐ์ดํธ๋ Dockerfile์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
FROM node:slim
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
์ธก์ ํด ๋ณด๊ฒ ์ต๋๋ค:
docker build -t node-app:phase2 . -f Dockerfile.phase2
docker images | grep node-app
์ด๋ฏธ์ง๊ฐ 345MB๋ก ์ค์ด๋ค์์ผ๋ฉฐ, ๋จ ํ ๋จ์ด์ ๋ณ๊ฒฝ๋ง์ผ๋ก ๋ฌด๋ ค 71% ํฌ๊ธฐ ๊ฐ์๋ฅผ ๋ฌ์ฑํ์ต๋๋ค! ๋ฒ ์ด์ค ์ด๋ฏธ์ง๋ฅผ ์ ํํ๋ ๊ฒ์ ์ปจํ ์ด๋ ํฌ๊ธฐ์ ์์ด ๊ฐ์ฅ ํฐ ์ํฅ์ ์ฃผ๋ ๊ฒฐ์ ์ ๋๋ค.
์ฌ๋ฆผ ์ด๋ฏธ์ง ํ ์คํธ
๋ ๊ฐ๋ฒผ์์ง ์ด๋ฏธ์ง์์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ์์ ์ผ๋ก ๋์ํ๋์ง ํ์ธํด ๋ด ๋๋ค:
docker run -d -p 3000:3000 node-app:phase2
curl http://localhost:3000
์ ํ๋ฆฌ์ผ์ด์ ์ ๋์ผํ๊ฒ ์ ๋์ํ์ง๋ง, ์ด๋ฏธ์ง ํฌ๊ธฐ๋ ๋์ ๋๊ฒ ์ค์ด๋ค์์ต๋๋ค.
3๋จ๊ณ: Alpine ๋ฒ ์ด์ค ์ด๋ฏธ์ง ์ฌ์ฉ
๋ค์์ผ๋ก๋ Alpine์ ์ฌ์ฉํด ํ ๋จ๊ณ ๋ ์ต์ ํํ์ต๋๋ค. Alpine์ ์ด์ํ ํฌ๊ธฐ์ ๋ณด์์ฑ์ผ๋ก ์ ๋ช ํ ๋ฏธ๋๋ฉ๋ฆฌ์คํธ Linux ๋ฐฐํฌํ์ ๋๋ค. Alpine์ ์ฌ์ฉํ๋ฉด ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ํฌ๊ฒ ์ค์ผ ์ ์์ ๋ฟ ์๋๋ผ, ๊ณต๊ฒฉ ํ๋ฉด๊น์ง ๋ํญ ์ถ์ํ ์ ์์ต๋๋ค.
FROM node:alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๊ณ ํฌ๊ธฐ๋ฅผ ํ์ธํด ๋ด ๋๋ค:
docker build -t node-app:phase3 . -f Dockerfile.phase3
docker images | grep node-app
์ด์ ์ด๋ฏธ์ง ํฌ๊ธฐ๊ฐ 258MB๋ก ์ค์ด๋ค์์ผ๋ฉฐ, ์ด๊ธฐ 1.22GB ๋๋น ๋ฌด๋ ค 78% ๊ฐ์๋ฅผ ๋ฌ์ฑํ์ต๋๋ค.
Alpine ๊ธฐ๋ฐ ์ด๋ฏธ์ง ํ ์คํธ
Alpine ๊ธฐ๋ฐ ์ด๋ฏธ์ง๊ฐ ์ ์์ ์ผ๋ก ๋์ํ๋์ง ํ์ธํด ๋ด ๋๋ค:
docker run -d -p 3000:3000 node-app:phase3
curl http://localhost:3000
Alpine์ด ํจ๊ณผ์ ์ธ ์ด์ ๋ ํ์์ ์ผ๋ก ๊ฐ๋ณ๊ฒ ์ค๊ณ๋์๊ธฐ ๋๋ฌธ์ ๋๋ค. glibc ๋์ musl libc๋ฅผ ์ฌ์ฉํ๊ณ , GNU Core Utilities ๋์ BusyBox๋ฅผ ์ฌ์ฉํ๋ฉฐ, ํจ์ฌ ๋ ์์ ํจํค์ง ์ ์ฅ์๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ ์ฒด ๋ฐฐํฌํ์ ํฌ๊ธฐ๋ ๊ณ ์ 5MB์ ๋ถ๊ณผํฉ๋๋ค.
ํ์ง๋ง ํด๋ผ์ด์ธํธ ํ๋ก์ ํธ์์ ์ด๋ ค์ด ๊ตํ์ ์ป์์ต๋๋ค. Alpine์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ์ ๋ ๊ฐ๋ฐ ๋ฐ ํ ์คํธ ํ๊ฒฝ์์๋ ๋ชจ๋ ๊ฒ์ด ์ ๋์ํ์ง๋ง, ํ๋ก๋์ ์์๋ ๋ฌด์์๋ก ํฌ๋์๊ฐ ๋ฐ์ํ๊ธฐ ์์ํ์ต๋๋ค. ์์ธ์ ์ถ์ ํ ๋์, ๋ค์ดํฐ๋ธ ์์กด์ฑ์ด glibc์ ๋ฌ๋ฆฌ musl libc์์ ๋ค๋ฅด๊ฒ ๋์ํ๋ค๋ ์ฌ์ค์ ๋ฐ๊ฒฌํ์ต๋๋ค.
๊ทธ ์ดํ๋ก๋ ํนํ ์ปดํ์ผ๋ ๋ค์ดํฐ๋ธ ๋ชจ๋์ ์์กดํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฃฐ ๋, Alpine ๋น๋๋ฅผ ์ฒ ์ ํ ๊ฒ์ฆํ๋ ๊ฒ์ ์ต์ ์ ๊ดํ์ผ๋ก ์ผ๊ณ ์์ต๋๋ค.
4๋จ๊ณ: ๋ฉํฐ ์คํ ์ด์ง ๋น๋์ .dockerignore ํ์ผ
์ ๊ฐ ๊ฐ์ฅ ๋ง์ด ํ์ฉํ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฒ ์ค ํ๋๋ ๋ฉํฐ ์คํ ์ด์ง ๋น๋์ ๋๋ค. ์ด๋ ๋น๋ ํ๊ฒฝ๊ณผ ๋ฐํ์ ํ๊ฒฝ์ ๋ถ๋ฆฌํ์ฌ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ค์ด๋ ๋์์ ๊ฐ๋ฐ ์ ํ์ํ ํด์ ์ด์ ์ ๋ชจ๋ ์ ์งํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋๋ค.
๋ฉํฐ ์คํ ์ด์ง ๋น๋๋ฅผ ์ฌ์ฉํ๋ฉด ๊ธฐ๋ฅ์ด ์๋น๋ Node ์ด๋ฏธ์ง๋ฅผ ํ์ฉํด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ปดํ์ผยทํ ์คํธยท๋ฒ๋ค๋งํ ํ, ํ์ ์ํฐํฉํธ๋ง ๊นจ๋ํ๊ณ ์ต์ํ๋ ๋ฐํ์ ์ด๋ฏธ์ง(์ข ์ข Alpine ๊ธฐ๋ฐ)๋ก ๋ณต์ฌํ ์ ์์ต๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ถํ์ํ ํ์ผ๊ณผ ๊ฐ๋ฐ ์์กด์ฑ์ ์ ๊ฑฐํ ๋ฟ ์๋๋ผ, ์ต์ข ์ปจํ ์ด๋๋ฅผ ๊ฐ๋ณ๊ณ ์์ ํ๋ฉฐ ํ๋ก๋์ ์ ์ ํฉํ ์ํ๋ก ์ ์งํฉ๋๋ค.
.dockerignore ํ์ผ์ Docker ๋น๋๋ฅผ ์ํ .gitignore๋ผ๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค. ์ปจํ
์ด๋์ ๋ฌด์์ด ํฌํจ๋ ์ง๋ฅผ ์๊ฒฉํ ๊ด๋ฆฌํด์ฃผ๋ฉฐ, ๋น๋๋ฅผ ๋ ๊น๋ํ๊ณ ์์ ํ๊ฒ ๋ง๋๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ ์ค ํ๋์
๋๋ค.
๋น๋๋ฅผ ์์ํ๊ธฐ ์ ์, ์ด๋ฏธ์ง์ ๋ณต์ฌ๋๋ฉด ์ ๋๋ ํ์ผ๊ณผ ํด๋๋ฅผ ์ ์ธํ๋๋ก .dockerignore ํ์ผ์ ์ถ๊ฐํ๋ ๊ฒ์ด ๋งค์ฐ ์ค์ํฉ๋๋ค:
node_modules
npm-debug.log
tests
coverage
Dockerfile
.dockerignore
.env
*.md
๋ฉํฐ ์คํ ์ด์ง ๋น๋๋ฅผ ์ ์ฉํ Dockerfile์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
# Build stage
FROM node:alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# Runtime stage
FROM node:alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
COPY --from=builder /app/*.js ./
EXPOSE 3000
CMD ["node", "index.js"]
์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๊ณ ํฌ๊ธฐ๋ฅผ ํ์ธํด ๋ด ๋๋ค:
docker build -t node-app:phase4 . -f Do4kerfile.phase4
docker images | grep node-app
๋ฉํฐ ์คํ ์ด์ง ๋น๋๋ฅผ ํ ์คํธํฉ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฌ์ ํ ์ ์์ ์ผ๋ก ๋์ํ๋์ง ํ์ธํด ๋ด ๋๋ค:
๋ชจ๋ ๊ฒ์ด ์ฌ์ ํ ๊ธฐ๋ํ ๋๋ก ์ ๋์ํฉ๋๋ค!
์ด์ ์ด๋ฏธ์ง๋ 178MB๋ก ์ค์์ผ๋ฉฐ, ์ด๋ ์ฒ์ ํฌ๊ธฐ์์ ๊ฑฐ์ 85% ๊ฐ์ํ ์์น์ ๋๋ค. ๋ฉํฐ ์คํ ์ด์ง ๋น๋๋ ๋น๋ ๋๊ตฌ์ ์ค๊ฐ ํ์ผ๋ค์ ์ต์ข ์ด๋ฏธ์ง์์ ์ ์ธ์์ผ ์ค๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ํ๋์ ์ปจํ ์ด๋๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น๋ํ๊ณ , ๋ค๋ฅธ ๋ ์์ ์ปจํ ์ด๋๋ก ์คํํ ์ ์๊ฒ ํด์ค๋๋ค.
์ด ํจํด์ ํนํ TypeScript ํ๋ก์ ํธ์์ ๋งค์ฐ ํจ๊ณผ์ ์ ๋๋ค. ์ค์ ํฌ์ค์ผ์ด ํ๋ก์ ํธ์์๋ TypeScript ์ปดํ์ผ๊ณผ ํ ์คํธ ๋จ๊ณ์์ 300MB๊ฐ ๋๋ ์ํฐํฉํธ๊ฐ ์์ฑ๋์๋๋ฐ, ๋จ์ผ ์คํ ์ด์ง ๋น๋๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ต์ข ์ด๋ฏธ์ง์ ํฌํจ๋์์ ๊ฒ์ ๋๋ค. ๋ฉํฐ ์คํ ์ด์ง ๋น๋๋ ์ต์ข ์ด๋ฏธ์ง์ ์ปดํ์ผ๋ JavaScript๋ง ๋จ๊ฒจ๋ ์ผ๋ก์จ ์ด๋ฅผ ๋ฐฉ์งํ์ต๋๋ค.
5๋จ๊ณ: Distroless ์ฌ์ฉํ๊ธฐ
Google์ Distroless ์ด๋ฏธ์ง๋ ๋ฏธ๋๋ฉ๋ฆฌ์ฆ์ ํ ๋จ๊ณ ๋ ๋์ด์ฌ๋ฆฐ ๊ฒ์ผ๋ก, ์ด์์ฒด์ ์ ํจํค์ง ๊ด๋ฆฌ์์ ์๊น์ง ์ ๊ฑฐํฉ๋๋ค. ์ด ์ด๋ฏธ์ง์๋ ์ ํ๋ฆฌ์ผ์ด์ ์คํ์ ํ์ํ ๋ฐํ์ ์์กด์ฑ๋ง ํฌํจ๋ฉ๋๋ค.
Distroless์ ํน์ง์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ํจํค์ง ๊ด๋ฆฌ์ ์์ (apk, apt ๋ฑ) โ ๊ณต๊ฒฉ์๊ฐ ์นจ์ ํ ์ ์ฑ ์ํํธ์จ์ด๋ฅผ ์ค์นํ ์ ์์ต๋๋ค.
- ์ ์์ (/bin/sh ์์) โ ๊ณต๊ฒฉ ํ๋ฉด์ด ์ค์ด๋ญ๋๋ค.
- ๋ถ๋ณ(Immutable)ํ๊ณ ์ต์ํ๋จ โ ๋ณดํต Alpine ๊ธฐ๋ฐ ์ด๋ฏธ์ง๋ณด๋ค ๋ ์์ต๋๋ค.
- ํ๋ก๋์ ํ๊ฒฝ์ ์ต์ โ ์ฌํ์ฑ, ํฌ๊ธฐ, ๋ณด์์ ์ฐ์ ์ํ๋ ํ๊ฒฝ์ ์๋ฒฝํฉ๋๋ค.
์๋๋ Distroless ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ๋ Dockerfile ์์์ ๋๋ค:
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install --only=production
COPY . .
# Step 2: Use distroless image
FROM gcr.io/distroless/nodejs22
WORKDIR /app
COPY --from=builder /app /app
CMD ["index.js"]
์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๊ณ ํฌ๊ธฐ๋ฅผ ํ์ธํด ๋ด ๋๋ค:
docker build -t node-app:phase5 . -f Dockerfile.phase5
docker images | grep node-app
Distroless ์ด๋ฏธ์ง๋ฅผ ํ ์คํธํฉ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์ด Distroless ์ด๋ฏธ์ง์์๋ ์ ์์ ์ผ๋ก ๋์ํ๋์ง ํ์ธํด ๋ด ๋๋ค:
์ปจํ ์ด๋์ ์์ ์ ๊ทผ์ ์๋ํด ๋ณด๋ฉด, ์กด์ฌํ์ง ์๋๋ค๋ ๊ฒ์ ์๊ฒ ๋ฉ๋๋ค:
docker exec -it <CONTAINER_ID> sh
์ด๊ฒ์ Distroless ์ด๋ฏธ์ง์ ๋ณด์ ๊ธฐ๋ฅ์ ๋๋ค. ์์ด๋ ์ ์ฉ๋ ์ ์๋ ์ ํธ๋ฆฌํฐ๊ฐ ์ ํ ํฌํจ๋์ด ์์ง ์์ต๋๋ค.
Distroless ์ด๋ฏธ์ง๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๊ทธ ์คํ์ ํ์ํ ๋ฐํ์ ์์กด์ฑ๋ง์ ๋ด๊ณ ์์ต๋๋ค. ํจํค์ง ๊ด๋ฆฌ์๋, ์๋, ๊ทธ ์ธ์ ๊ฒ๋ค๋ ์์ต๋๋ค. ์ด๋ ๋จ์ํ ๊ณต๊ฐ์ ์ ์ฝํ๋ ๊ฒ์ ๋์ด, ๋ณด์์ ๊ทน์ ์ผ๋ก ๊ฐํํฉ๋๋ค.
Distroless๋ฅผ ์ ์ฉํ ํ ์ต์ข ์ด๋ฏธ์ง๋ 143MB๊ฐ ๋์์ผ๋ฉฐ, ์ด๋ ์๋ 1.22GB ๋๋น 88.2% ๊ฐ์ํ ์์น์ ๋๋ค. ๊ธฐ๋ฅ์ด๋ ๋ณด์์ ํฌ์ํ์ง ์๊ณ ์ด ์ ๋์ ์ฑ๊ณผ๋ฅผ ์ป์ ๊ฒ์ ๋๋ผ์ด ์ฑ์ทจ์ ๋๋ค.
6๋จ๊ณ: ์ ์ ๋ฐ์ด๋๋ฆฌ (Static Binaries)
๊ถ๊ทน์ ์ธ ํฌ๊ธฐ ์ต์ ํ๋ฅผ ์ํด Node.js ์ ํ๋ฆฌ์ผ์ด์
์ ๋
๋ฆฝ ์คํํ ๋ฐ์ด๋๋ฆฌ๋ก ์ปดํ์ผํฉ๋๋ค. pkg๋ nexe ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํด Node.js ๋ฐํ์์ ํฌํจํ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์
์ ๋จ์ผ ์คํ ํ์ผ๋ก ๋ฌถ์ ์ ์์ต๋๋ค.
์ด ๋ฐฉ์์ ๊ณต๊ฒฉ ํ๋ฉด๊ณผ ์์กด์ฑ ๋ณต์ก์ฑ์ ์ค์ฌ์ค ๋ฟ ์๋๋ผ, scratch๋ distroless ๊ฐ์ ์ต์ ๋ฒ ์ด์ค ์ด๋ฏธ์ง ์์์ ์คํํ ์ ์์ด ์ต์ข ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ 20MB ์ดํ๋ก ์ค์ด๋ ๊ฒ๋ ๊ฐ๋ฅํฉ๋๋ค. ๋ํ Node.js ๋ฐํ์์ด ํ์ ์์ด์ ธ, ํจ์ฌ ๋ ์์ ์ด๋ฏธ์ง์ ๋น ๋ฅธ ์ฝ๋ ์คํํธ๋ฅผ ๋ณด์ฅํฉ๋๋ค.
์๋๋ ์ด๋ฅผ ์ํ Dockerfile ์์์ ๋๋ค:
FROM node:alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
RUN npm install -g pkg
COPY . .
RUN pkg --targets node16-alpine-x64 index.js -o app
# Minimal runtime
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/app .
EXPOSE 3000
CMD ["./app"]
์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๊ณ ํฌ๊ธฐ๋ฅผ ํ์ธํด ๋ด ๋๋ค:
docker build --platform=linux/amd64 -t node-app:phase6 . -f Dockerfile.phase6
docker run --platform=linux/amd64 -d -p 3000:3000 node-app:phase6
์ต์ข ์ด๋ฏธ์ง๋ 57MB๋ก ํฌ๊ฒ ์ค์์ผ๋ฉฐ, ์ด๋ ์๋ ํฌ๊ธฐ์ ๋จ 4.7%์ ๋ถ๊ณผํฉ๋๋ค! ๋ถํ์ํ ๋ ์ด์ด, ํจํค์ง, ์์กด์ฑ์ ๋ชจ๋ ์ ๊ฑฐํ๋ฉด์ ์์ฒญ๋ ๊ฐ์ ์ ์ด๋ค๋ธ ๊ฒ์ ๋๋ค.
์คํ ๋ฐ์ด๋๋ฆฌ๊ฐ x86_64 ์ํคํ
์ฒ์์ ๋ฌธ์ ์์ด ๋์ํ๋๋ก, --platform=linux/amd64 ์ต์
์ ์ถ๊ฐํด ARM ๊ธฐ๋ฐ Mac์์์ ํธํ์ฑ ๋ฌธ์ ๋ฅผ ํผํ์ต๋๋ค.
์ ์ ๋ฐ์ด๋๋ฆฌ ์ด๋ฏธ์ง ํ ์คํธ
์ปดํ์ผ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ์์ ์ผ๋ก ๋์ํ๋์ง ํ์ธํด ๋ด ๋๋ค:
docker run --platform=linux/amd64 -d -p 3000:3000 node-app:phase6
curl http://localhost:3000
์ด ์ ๊ทผ ๋ฐฉ์์ด ๋ชจ๋ ๊ฒฝ์ฐ์ ์ ํฉํ ๊ฒ์ ์๋๋๋ค. ์ ์ ์ปดํ์ผ์ ๋จ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ ๋์ํ์ง๋ง, ๋ณต์กํ ์์กด์ฑ์ด ์๋ ๊ฒฝ์ฐ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์์ต๋๋ค. ์ค์ ๋ก ๊ฐ๋ฐ ํ๊ฒฝ์์๋ ์ ์์ ์ผ๋ก ๋์ํ์ง๋ง, ๋์ ๋ชจ๋ ๋ก๋ฉ ํจํด ๋๋ฌธ์ ํ๋ก๋์ ์์๋ ์คํจํ ๊ฒฝํ๋ ์์์ต๋๋ค.
Node.js ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์ํ ๊ธฐ๋ฒ์ผ๋ก ์ปจํ ์ด๋ํํ ๊ฒฐ๊ณผ, ๊ธฐ๋ณธ ๋ฒ ์ด์ค ์ด๋ฏธ์ง์์ ์์ํด scratch, distroless, ๊ทธ๋ฆฌ๊ณ ์ ์ ๋ฐ์ด๋๋ฆฌ๊น์ง ๊ฑฐ์ณ ์ต์ข ์ ์ผ๋ก 57MB๋ผ๋ ๋๋ผ์ธ ์ ๋๋ก ์ฌ๋ฆผํ ์ด๋ฏธ์ง๋ฅผ ์ป์ ์ ์์์ต๋๋ค.
Slim ์ฌ์ฉํ๊ธฐ (์ด์ ์ด๋ฆ: Dockerslim)
์ต์ ํ ์ํฌํ๋ก์ฐ๋ฅผ ๊ฐ์ํํ ๋ฐฉ๋ฒ์ ์ฐพ๋ ์ค, Slim์ด๋ผ๋ ๊ฐ๋ ฅํ ์คํ์์ค ๋๊ตฌ๋ฅผ ๋ฐ๊ฒฌํ์ต๋๋ค. ์ด ํด์ ์ปจํ ์ด๋ ์ด๋ฏธ์ง ์ต์ํ๋ฅผ ์๋ํํฉ๋๋ค. ์ด๋ฏธ์ง๋ฅผ ๊ฒ์ฌํ๊ณ ๋ฐํ์์ ์ค์ ๋ก ์ฌ์ฉ๋๋ ๊ฒ๋ง ์๋ณํ ๋ค, ๋๋จธ์ง๋ ๋ชจ๋ ์ ๊ฑฐํฉ๋๋ค.
์ด ๋ฐฉ์์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ต๋ 30๋ฐฐ ์ด์ ์ค์ฌ์ค ๋ฟ ์๋๋ผ, ๋ถํ์ํ ํจํค์ง๋ฅผ ์ ๊ฑฐํด ๊ณต๊ฒฉ ํ๋ฉด์ ์ค์ฌ ๋ณด์์ ๊ฐํํฉ๋๋ค. ๋์ฑ ์ธ์์ ์ธ ์ ์ Dockerfile์ ๋ค์ ์์ฑํ๊ฑฐ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋๋ฅผ ์ฌ๊ตฌ์ฑํ ํ์ ์์ด ์ด๋ฅผ ๋ฌ์ฑํ๋ค๋ ๊ฒ์ ๋๋ค.
๋์ ๋ฐฉ์
Slim์ ์ปจํ ์ด๋๋ฅผ ์๋๋ฐ์ค ํ๊ฒฝ์์ ์คํ์ํค๊ณ , ์์คํ ํธ์ถ์ ์ถ์ ํ์ฌ ์ต์ ํ๋ ์ด๋ฏธ์ง๋ฅผ ์๋ก ๋น๋ํฉ๋๋ค. ์ด ๊ณผ์ ์์ ๋ฐํ์์ ๊ผญ ํ์ํ ๊ตฌ์ฑ ์์๋ง ํฌํจํ๋ฉฐ, ๋ค์๊ณผ ๊ฐ์ ์ํฐํฉํธ๋ฅผ ์์ฑํฉ๋๋ค:
- ์ต์ํ๋ ์ด๋ฏธ์ง (
slim.<original-image-name>) - ์ปจํ ์ด๋ ๋ณด์์ ๊ฐํํ๋ Seccomp ํ๋กํ
- ํ์ผ, ํจํค์ง, ๋คํธ์ํฌ ์ฌ์ฉ ๋ด์ญ์ ๋ด์ ๋ฆฌํฌํธ ๋๋ ํฐ๋ฆฌ
์ค์น ๋ฐ ์ฌ์ฉํ๊ธฐ
Slim์ ๋ก์ปฌ์ ์ค์นํ๊ณ , 1๋จ๊ณ์์ ๋ง๋ Docker ์ด๋ฏธ์ง(์ต์ด์ ์ต์ ํ๋์ง ์์ Node.js ์ฑ)๋ฅผ ๋์์ผ๋ก ์ต์ ํ๋ฅผ ์งํํด ๋ณด๊ฒ ์ต๋๋ค.
macOS์์๋ Homebrew๋ฅผ ํตํด ๊ฐ์ฅ ์ฝ๊ฒ ์ค์นํ ์ ์์ต๋๋ค:
brew install docker-slim
slim --version
์ด์ node-app:phase1 ์ด๋ฏธ์ง์ ๋ํด ์ต์ ํ ๋ช
๋ น์ ์คํํฉ๋๋ค:
slim build node-app:phase1
docker images | grep slim
Slim์ ์ฌ์ฉํ๋ ๋จ ํ ๋ฒ์ ๋ช ๋ น์ผ๋ก 1.22GB์๋ ์ด๋ฏธ์ง๊ฐ ๋ถ๊ณผ 123MB๋ก ์ค์ด๋ค์์ต๋๋ค!
Slim์ผ๋ก ์ต์ ํํ ์ปจํ ์ด๋๊ฐ ์ ์์ ์ผ๋ก ๋์ํ๋์ง ํ์ธํด ๋ด ๋๋ค:
docker run -d -p 3000:3000 node-app.slim
curl http://localhost:3000
Slim์ ๋ถ๋ช ์ธ์์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ์ฃผ์ง๋ง, ์ ์คํ๊ฒ ์ฌ์ฉํ ํ์๊ฐ ์์ต๋๋ค. ์ค์ ๋ก ํ ํ๋ก์ ํธ์์๋ Slim์ด ๋๋ฌผ๊ฒ๋ง ์ฌ์ฉ๋๋ ์ค๋ฅ ์ฒ๋ฆฌ ๊ฒฝ๋ก์์ ํ์ํ ํ์ผ๊น์ง ์ ๊ฑฐํด ๋ฒ๋ ค, ํน์ ์กฐ๊ฑด์์๋ง ๋ํ๋๋ ํ๋ก๋์ ์ฅ์ ๊ฐ ๋ฐ์ํ ์ ์ด ์์ต๋๋ค.
์ฆ, Slim์ ๋ง๋ฅ ํด๊ฒฐ์ฑ ์ด ์๋๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐํ์ ๋์์ ์ถฉ๋ถํ ์ดํดํ๊ณ ๊ทธ์ ๋ง๊ฒ ์ต์ ํ ๊ณผ์ ์ ์กฐ์จํ ์ ์์ ๋ ๊ฐ์ฅ ํจ๊ณผ์ ์ ๋๋ค.
์ Slim๋ง์ผ๋ก ์์ํ์ง ์์๊น?
Slim์ ๋๋ผ์ด ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด, ์ฒ์๋ถํฐ ์๋ ์ต์ ํ๋ฅผ ํ ํ์๊ฐ ์๋ ํ๋ ์๋ฌธ์ด ์๊ธธ ์ ์์ต๋๋ค. ์ ์ญ์ ์ด ์ ๊ทผ ๋ฐฉ์์ ํ์ ์๊ฐํ๋ฉด์ ๊ฐ์ ์ง๋ฌธ์ ๋์ก์ต๋๋ค.
์๋ํ๋ ๋๊ตฌ๋ ์ต์ ํ์ ํ๋ฅญํ์ง๋ง, ๊ธฐ๋ณธ ์๋ฆฌ๋ฅผ ์ดํดํ๋ ๊ณผ์ ์ ๋์ฒดํ ์๋ ์์ต๋๋ค. ์๋ ์ต์ ํ๋ฅผ ๋จผ์ ๋ฐฐ์์ผ ํ๋ ๋ช ๊ฐ์ง ์ค๋๋ ฅ ์๋ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๋ฌธ์ ํด๊ฒฐ ๋ฅ๋ ฅ: Slim์ด ์ค์ํ ํ์ผ์ ์ ๊ฑฐํ์ ๋, Docker ์ต์ ํ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ ์์ด์ผ ๋ฌธ์ ๋ฅผ ๋น ๋ฅด๊ฒ ์ง๋จํ๊ณ ์์ ํ ์ ์์ต๋๋ค. ์๋ํ ๋๊ตฌ๋ง์ผ๋ก๋ ํญ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
- ์ ์ด์ ์์ธก ๊ฐ๋ฅ์ฑ: ์๋ ์ต์ ํ๋ ์ด๋ฏธ์ง์ ๋ด์ฉ์ ์ ๋ฐํ๊ฒ ์ ์ดํ ์ ์์ด, ๊ผญ ํ์ํ ๊ตฌ์ฑ ์์๋ง ๋จ๊ธฐ๊ณ ๋ ์์ธก ๊ฐ๋ฅํ ๋น๋๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
- ๋ณด์ ๊ฒ์ฆ: ๋ณด์ ํ์ ์ปจํ ์ด๋ ๋ด์ฉ์ ๋ํ ์์ ํ ๊ฐ์์ฑ์ ์๊ตฌํฉ๋๋ค. ์๋ ์ต์ ํ ์ด๋ฏธ์ง๋ ์ด๋ฅผ ๋ฌธ์ํํ๊ณ ๊ฒ์ฆํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์ด ๋ณด์ ์ ์ฑ ์ค์๋ฅผ ๋์ต๋๋ค.
- ์ง์ ์ ์ด: ์ปจํ ์ด๋ ์ต์ ํ ์๋ฆฌ๋ ์ธ์ด์ ํ๋ ์์ํฌ๋ฅผ ๊ฐ๋ฆฌ์ง ์๊ณ ์ ์ฉ๋๋ฏ๋ก, ์๋ ์ต์ ํ๋ ๋ค์ํ ํ๋ก์ ํธ์ ํ์ฉํ ์ ์๋ ์ ์ฉํ ๊ธฐ์ ์ ๋๋ค.
- ๋ง์ถคํ์ ์ ์ฐ์ฑ: ํน์ ์๊ตฌ์ ๋ง์ถฐ ์ด๋ฏธ์ง๋ฅผ ์กฐ์ ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๋น๋ ํ์ดํ๋ผ์ธ์ ์์ ํ๊ฑฐ๋ ์ ์ฅ์ ์ ์ฝ ์กฐ๊ฑด์ ๋์ํ ์ ์์ต๋๋ค.
- ๋น๋ ํ๋ก์ธ์ค ์ดํด: ์๋ ์ต์ ํ๋ Docker ๋ ์ด์ด๊ฐ ์ด๋ป๊ฒ ์ํธ์์ฉํ๋์ง, Dockerfile์ ์ด๋ป๊ฒ ๊ตฌ์ฑํด์ผ ํจ์จ์ ์ธ์ง ๋ ๊น์ด ์ดํดํ๊ฒ ํฉ๋๋ค.
์ต์ ํ์ ์ ์ฌ์ ๋ฌธ์
์ต์ ํ๋ ํฐ ๊ฐ์ ์ ๊ฐ์ ธ์ค์ง๋ง, ๋์์ ํด๊ฒฐํด์ผ ํ ๋ช ๊ฐ์ง ๊ณผ์ ๋ฅผ ๋๋ฐํฉ๋๋ค:
- Alpine ํธํ์ฑ ๋ฌธ์ : ๋ค์ดํฐ๋ธ ์์กด์ฑ์ด Alpine์์ ๋ค๋ฅด๊ฒ ๋์ํ ์ ์์ด ํธํ์ฑ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ผ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํด์ด ๊ธฐ๋๋๋ก ์๋ํ์ง ์์ ์ถ๊ฐ์ ์ธ ์์ ์ด๋ ์ฐํ ๋ฐฉ๋ฒ์ด ํ์ํฉ๋๋ค.
- ๋๋ฒ๊น ์ด๋ ค์: Distroless ์ปจํ ์ด๋๋ ์ต์ํ๋์ด ํจ์จ์ ์ด์ง๋ง, ๋๋ฒ๊น ๋๊ตฌ๊ฐ ๊ฑฐ์ ์์ด ๋ฌธ์ ์๋ณ๊ณผ ํด๊ฒฐ์ด ๋ ๋ณต์กํ๊ณ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆด ์ ์์ต๋๋ค.
- ๋น๋ ๋ณต์ก์ฑ ์ฆ๊ฐ: ๋ฉํฐ ์คํ ์ด์ง ๋น๋๋ฅผ ๊ด๋ฆฌํ๋ฉด์ Dockerfile์ด ๋ณต์กํด์ก์ต๋๋ค. ํน์ ํ์๋ค์๊ฒ๋ ๋น๋ ๋จ๊ณ๋ฅผ ์ดํดํ๊ณ ์ฌ๋ฐ๋ฅธ ๋ ์ด์ด๋ฅผ ํฌํจยท์ ์ธํ๋ ๊ฒ์ด ์ด๋ ค์์ผ๋ก ๋ค๊ฐ์์ต๋๋ค.
- ํ ๋์ : ํ ์ ์ฒด๊ฐ ์ต์ ํ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋์ ํ๋๋ก ์ฅ๋ คํ๋ ๋ฐ ์๊ฐ๊ณผ ๊ต์ก์ด ํ์ํ์ต๋๋ค. ๋ชจ๋ ํ์์ด ์ฒ์๋ถํฐ ์ต์ํ์ง ์์๊ธฐ ๋๋ฌธ์, ํ๋ จ๊ณผ ์ง์์ ์ธ ํ์ต์ ํตํด ํฉ์๋ฅผ ์ด๋์ด๋ด์ผ ํ์ต๋๋ค.
ํต์ฌ ๊ตํ์ ์ต์ ํ๊ฐ ๋ชจ๋์๊ฒ ๋๊ฐ์ด ์ ์ฉ๋๋ ํด๋ฒ์ด ์๋๋ผ๋ ๊ฒ์ ๋๋ค. ํฌ๊ธฐ, ๊ธฐ๋ฅ, ๋ณด์ ๊ฐ์ ์ ์ ํ ๊ท ํ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํน์ฑ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค.
์ถ๊ฐ ์ต์ ํ ๊ธฐ๋ฒ
์ ์๊ฒ ํจ๊ณผ์ ์ด์๋ ๋ค๋ฅธ ๊ธฐ๋ฒ๋ ์์ต๋๋ค:
1. ๋ ์ด์ด ์ต์ ํ
Docker ์ด๋ฏธ์ง๋ ์ฌ๋ฌ ๊ฐ์ ๋ ์ด์ด๋ก ๊ตฌ์ฑ๋๋ฉฐ, Dockerfile์ ๊ฐ ๋ช ๋ น์ด๊ฐ ์๋ก์ด ๋ ์ด์ด๋ฅผ ๋ง๋ญ๋๋ค. ๊ด๋ จ๋ ๋ช ๋ น์ ๊ฒฐํฉํ๋ฉด ๋ ์ด์ด ์๋ฅผ ์ค์ผ ์ ์๊ณ , ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ํฌ๊ฒ ์ค์ผ ์ ์์ต๋๋ค.
์๋ชป๋ ์ ๊ทผ ๋ฐฉ์:
RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2
์ฌ๋ฐ๋ฅธ ์ ๊ทผ ๋ฐฉ์:
RUN apt-get update && \
apt-get install -y package1 package2 && \
rm -rf /var/lib/apt/lists/*
2. BuildKit Cache Mounts ํ์ฉ
Node.js ์ ํ๋ฆฌ์ผ์ด์ ์์๋ npm ์บ์ฑ์ ํ์ฉํ๋ฉด ๋น๋ ์๋๋ฅผ ํฌ๊ฒ ๋์ผ ์ ์์ต๋๋ค:
# syntax=docker/dockerfile:1.4
FROM node:alpine
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
3. ๋์ฒด ๋๊ตฌ ๊ณ ๋ คํ๊ธฐ
์๋ ์ต์ ํ์ Slim ๊ฐ์ ์๋ํ ์ธ์๋, ์ปจํ ์ด๋ ์ด๋ฏธ์ง๋ฅผ ์ ๊ฒยท๋ถ์ยท์ถ๊ฐ ์ต์ ํํ๋ ๋ฐ ๋์์ ์ค ์ ์๋ ๊ฐ๋ ฅํ ๋๊ตฌ๋ค์ด ์์ต๋๋ค:
- dive: Docker ์ด๋ฏธ์ง ๋ ์ด์ด๋ฅผ ์๊ฐ์ ์ผ๋ก ํ์ํ ์ ์๋ CLI ๋๊ตฌ์ ๋๋ค. ์ด๋ฏธ์ง ํฌ๊ธฐ์ ์ด๋ค ์์๊ฐ ๊ธฐ์ฌํ๊ณ ์๋์ง, ๋ถํ์ํ ํ์ผ์ด๋ ๋นํจ์จ์ ์ธ ๋ ์ด์ด ๊ตฌ์ฑ์ผ๋ก ์ธํ ๋น๋ํ๋ฅผ ์๋ณํ ์ ์์ต๋๋ค.
- Docker Scout: Docker์ ๊ณต์ ์ด๋ฏธ์ง ๋ถ์ ๋ฐ ๋ณด์ ๋๊ตฌ์ ๋๋ค. ์ด๋ฏธ์ง ๋ฉํ๋ฐ์ดํฐ์ SBOM(Software Bill of Materials)์ ๊ธฐ๋ฐ์ผ๋ก ์ทจ์ฝ์ , ์ค๋๋ ์์กด์ฑ, ํฌ๊ธฐ ์ต์ ํ ๊ธฐํ๋ฅผ ์๋ ค์ค๋๋ค.
- Buildpacks: CNCF ํ๋ก์ ํธ๋ก, Dockerfile ์์ด ์์ค ์ฝ๋์์ ๋ฐ๋ก ์ปจํ ์ด๋ ์ด๋ฏธ์ง๋ฅผ ๋น๋ํ ์ ์์ต๋๋ค. ๋ฒ ์คํธ ํ๋ํฐ์ค๋ฅผ ๊ฐ์ ํ๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์ ๋ฐํ์์ ๋ง์ถ ์ต์ํ๋ ํ๋ก๋์ ์ค๋น ์ด๋ฏธ์ง๋ฅผ ์์ฑํฉ๋๋ค.
์ด๋ฌํ ๋๊ตฌ๋ค์ ๊ธฐ๋ณธ์ ์ธ Dockerfile ์ต์ ํ๋ฅผ ๋์ด, ์ปจํ ์ด๋ ๋ด๋ถ๋ฅผ ๊น์ด ์ดํดํ๊ณ ํจ์จ์ฑ์ ๊ทน๋ํํ๋ ๋ฐ ์ข์ ์กฐ๋ ฅ์๊ฐ ๋ฉ๋๋ค.
๋ง๋ฌด๋ฆฌ ์๊ฐ
1.22GB์์ 57MB๋ก ์ค์ฌ์จ ๊ณผ์ ์ ๋จ์ํ ๋์คํฌ ๊ณต๊ฐ ์ ์ฝ์ ๋์ด, ํจ์จ์ฑยท๋ณด์ยท์์ง๋์ด๋ง ํ์ง์ ๋ํ ์ฒ ํ์ ๋ณด์ฌ์ค๋๋ค.
์ด๋ฌํ ๊ธฐ๋ฒ๋ค์ ๋์ ํ๋ฉด ์๊ฐ์ด ์ง๋ ์๋ก ๋ณตํฉ์ ์ธ ์ด์ ์ ์ป๊ฒ ๋ฉ๋๋ค. ์์ ์ปจํ ์ด๋๋ ๊ณง:
- ๋ ๋น ๋ฅธ ๋ฐฐํฌ
- ๋ฎ์ ์ธํ๋ผ ๋น์ฉ
- ๊ฐํ๋ ๋ณด์ ํ์ธ
- ํฅ์๋ ๋ฆฌ์์ค ํ์ฉ
- ๋ ๋น ๋ฅธ ์ํ ํ์ฅ
์ต์ ํ๋ ์ด๋ถ๋ฒ์ ๋ชฉํ๊ฐ ์๋๋ผ ์คํํธ๋ผ์์ ๊ธฐ์ตํด์ผ ํฉ๋๋ค. ๋ชจ๋ ๊ธฐ๋ฒ์ ๋ค ์ ์ฉํ์ง ๋ชปํ๋๋ผ๋, ํ ๋จ๊ณ์ฉ ์ ์ฉํ ๋๋ง๋ค ์ถฉ๋ถํ ํจ๊ณผ๊ฐ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด 1GB์์ 200MB๋ก๋ง ์ค์ฌ๋ ํฐ ์ฑ๊ณผ์ ๋๋ค.
์์ ์ ํ๋ก์ ํธ์ ๋ง๋ ๊ธฐ๋ฒ๋ถํฐ ์์ํด, ์ ์ฐจ ๋ ๊ณ ๊ธ ์ต์ ํ๋ฅผ ์ตํ๋ฉฐ ์ ์ฉํด ๋ณด์ธ์. ์ปจํ ์ด๋ ํจ์จ์ฑ์ผ๋ก ๊ฐ๋ ์ฌ์ ์ ๋ฐ๋ณต์ ์ด์ง๋ง, ๋ ธ๋ ฅํ ๋งํผ ๋ณด์์ด ๋ฐ๋ฆ ๋๋ค.
์ด ๊ฐ์ด๋์์ ์ฌ์ฉํ ๋ชจ๋ Dockerfile์ ๊ณต๊ฐ GitHub ์ ์ฅ์์์ ํ์ธํ ์ ์์ต๋๋ค:














