• בלוג
  • טיפ דוקר: שימוש ב Multistage Builds

טיפ דוקר: שימוש ב Multistage Builds

06/03/2022

פוסט זה כולל טיפ קצר על Docker. אם אתם רוצים ללמוד יותר לעומק על פיתוח עם Docker, Docker Compose או Kubernetes תשמחו לשמוע שבניתי קורס וידאו מקיף בנושא זה.
למידע נוסף והצטרפות לקורס בקרו בדף קורס Docker כאן באתר.
 

בבניית Docker Image יהיו לנו מצבים שאנחנו צריכים אימג' בסיס מסוים כדי לבצע עבודת "הכנה", אבל אחרי שההכנה הסתיימה אפשר לקחת את התוצרים ולהגיש אותם מאימג' אחר. דוגמה פשוטה היא אפליקציית next.js שיוצרת אתר HTML סטטי. אני צריך את node.js וכל מה שקשור אליו בשביל לבנות את האתר הסטטי, אבל אחרי שבניתי אותו אני יכול להגיש את התוצאה מאימג' של nginx.

בדוקר יש מנגנון שנקרא multi stage builds שנועד לתת מענה למצבים כאלה ולאפשר בניה מאימג' אחד ואריזה באימג' אחר. בואו נראה איך זה עובד.

1. אפליקציית next רגילה באימג' של node

נתחיל עם כתיבת Dockerfile לאפליקציית next רגילה באימג' של node.js. בשביל לבנות את האפליקציה אני צריך להריץ:

$ npm run build
$ npx next export

בהנחה שיש לי בתיקיה תת-תיקיה בשם next-demo-app, בואו נבנה את ה Dockerfile הבא:

FROM node:17
WORKDIR /app

COPY next-demo-app .

RUN npm install
RUN npm run build
RUN npx next export

CMD ["npm", "run", "start"]

אחרי זה אני בונה את האימג' עם:

$ docker build . -t multistage-demo

אני יכול להריץ את האימג' לראות שהכל עובד:

$ docker run -p 8080:3000 --rm multistage-demo

אבל מה שבאמת מעניין זה לראות את הגודל של האימג':

$ docker images | grep multistage-demo

multistage-demo                      latest    e67684b5f7d1   2 minutes ago   1.24GB

כן ראיתם נכון - זה 1.24 ג'יגה.

2. מעבר ל Multistage Builds

אבל אז אני נזכר שאני לא באמת צריך להגיש את האפליקציה משרת של next - כי הפעלתי export וכל האפליקציה שלי זמינה בתור קבצי html סטטיים. לכן מספיק לי להגיש אותה משרת ווב רגיל ופשוט, למשל nginx. נו, אם רק הייתי יכול להעביר את כל הקבצים שבניתי לאימג' nginx ...

ופה נכנס הרעיון של multistage builds. נעדכן את ה Dockerfile לקוד הבא:

FROM node:17 AS builder
WORKDIR /app

COPY next-demo-app .

RUN npm install
RUN npm run build
RUN npx next export

FROM nginx:1.21-alpine
COPY --from=builder /app/out /usr/share/nginx/html/

הוספת שורת FROM נוספת ל Dockerfile מאפשרת לשים בצד את כל מה שיצרנו, ולהתחיל לבנות את האימג' מחדש מתוך אימג' בסיס חדש. בפקודות COPY אני יכול להוסיף --from כדי להעתיק תוצרי בניה מאימג'ים ששמתי בצד. לכן ה Dockerfile המעודכן לוקח את תיקיית out שמכילה את קבצי ה html הסטטיים (אלה שנוצרו ב export), ומעתיק אותה לתיקיה ממנה nginx יגיש את הקבצים הסטטיים שלו.

אפשר לבנות מחדש ולהריץ כמעט עם אותן פקודות (צריך לשנות את מיפוי הפורטים כי nginx מאזין על פורט 80) ואתם תראו שה Dockerfile עדיין עובד, אבל יותר מעניין להסתכל על גודל האימג' עכשיו:

$ docker image ls| grep multistage

multistage-demo                      latest    76259b691276   About a minute ago   23.8MB

וכן ראיתם נכון - גודל האימג' הוא עכשיו 23 מגה בלבד, למרות שהוא עושה בדיוק את אותו דבר שעשה האימג' של הג'יגה. הסוד הוא פשוט להשתמש בדיוק במה שאנחנו צריכים.