๐Ÿš€ Node.js Docker ์ด๋ฏธ์ง€, 1.2GB โ†’ 57MB! ํฌ๊ธฐ 95% ์ ˆ๊ฐ ์„ฑ๊ณต๊ธฐ

[์ถœ์ฒ˜] https://medium.com/@prateekjain.dev/a-step-by-step-guide-to-docker-image-optimisation-reduce-size-by-over-95-d90bcab3819d

์ถœ์ฒ˜์˜ ๋‚ด์šฉ์„ ๋ฒˆ์—ญํ•ด์„œ ๊ณต์œ ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๋น„๋Œ€ํ•œ ์ด๋ฏธ์ง€์˜ ์‹ค์ œ ์˜ํ–ฅ

์ด๋ฏธ์ง€ ํฌ๊ธฐ๋Š” ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋™์ž‘์— ์ง์ ‘์ ์ธ ์˜ํ–ฅ์„ ์ค๋‹ˆ๋‹ค. 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 ์ €์žฅ์†Œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

:backhand_index_pointing_right: https://github.com/prateekjaindev/docker-shrink

4 Likes