טיפ דוקר: שימוש ב Multistage Builds
פוסט זה כולל טיפ קצר על 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 מגה בלבד, למרות שהוא עושה בדיוק את אותו דבר שעשה האימג' של הג'יגה. הסוד הוא פשוט להשתמש בדיוק במה שאנחנו צריכים.