טיפ דוקר: מה עושים עם node_modules

06/07/2022

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

בפיתוח יישומי node.js בתוך דוקר אני בדרך כלל אוהב להריץ npm install בתוך הקונטיינר בתור פקודה ראשונה כשהוא עולה, לפני שמפעיל את היישום האמיתי שלי, וככה אני יודע שתמיד כל החבילות יהיו במקום. ייתרון נוסף של הגישה הזאת הוא שאפשר להשתמש ב image שכבר קיים בדוקרהאב ב docker-compose.yml וזה חוסך לנו את שלב בניית האימג'.

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

במצב כזה האינטואיציה הראשונה היא להריץ npm install מתוך ה Dockerfile, למשל משהו כזה:

FROM node:18
WORKDIR /app

COPY package*.json .
RUN npm install

CMD ["node", "myapp.js"]

ואז אני משתמש בקובץ docker-compose.yml כזה כדי למפות את התיקיה הנוכחית (סביבת הפיתוח) פנימה לקונטיינר:

version: "3.9"
services:
  app:
    build: .
    command: sleep infinity
    volumes:
      - .:/app

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

זה קורה בגלל שמיפוי ה Volume של תיקיית הפיתוח מסתיר את קבצי ה node_modules שהתקנתי בעת בניית האימג'.

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

ב node לצערי זה לא אפשרי ו node_modules ממש חייב להיות בתוך תיקיית קוד המקור שלכם, ולכן הפיתרון דורש קצת יותר יצירתיות: אנחנו מגדירים Volume בתוך ה Dockerfile שיכיל את המודולים המותקנים, ואז בהרצה ממפים את אותו volume על גבי המיפוי של תיקיית המקור - כך יוצא שה volume החדש של ה node_modules מסתיר את המיפוי של node_modules מתיקיית המקור, שהוא בעצמו הסתיר את תיקיית node_modules של האימג' (שעכשיו ריקה כי ההתקנה היתה על ה Volume).

קוד? ברור. זה ה Dockerfile - התוספת היחידה היא פקודת volume:

FROM node:18
WORKDIR /app

COPY package*.json .

VOLUME /app/node_modules
RUN npm install

CMD ["node", "myapp.js"]

כשמפעילים את האימג', פקודת run תעתיק את התוכן של node_modules שנמצא באימג' לתוך ה Volume החדש, והוא ימופה לתוך /app/node_modules במקום התיקיה מהמחשב המארח.

הטריק היחיד לזכור כאן הוא שהתיקיה node_modules חייבת להיות קיימת על המחשב המארח בתיקיית הפיתוח (יכולה להיות ריקה), אחרת המיפוי נכשל והקונטיינר לא יעלה.