חבילה פרטית שנפתרת בלי בעיה במכונה שלכם עשויה להיכשל בתוך הבנייה עם 404 או עם פסק זמן, וה-Dockerfile הוא רק לעתים רחוקות הסיבה. שלב הבנייה רץ במרחב שמות רשת אחר, עם תצוגת DNS אחרת ומאגר אישורים אחר מזה של ה-shell שבו בדקתם. עברו על הבדיקות האלה לפי הסדר ועצרו בראשונה שנכשלת, כי כל בדיקה מאוחרת מניחה שהקודמת עברה. כל שלב נוקב בפקודה שמכריעה את העניין.

התחילו בשם ה-builder, לא ב-Dockerfile

BuildKit יכול להיות מקומי, בקונטיינר או על מכונה אחרת, ולכל אחד מהם רשת ברירת מחדל משלו. הריצו docker buildx ls וקראו את הצומת המסומן בכוכבית לפני שתשנו משהו. דרייבר docker-container או builder בענן אינו חולק את המסלול הפרטי במחשב הנייד שלכם רק מפני שהקלדתם שם את הפקודה. אם ה-builder הפעיל מרוחק, כל בדיקה שנותרה חייבת לרוץ מול אותו מארח ולא מול תחנת העבודה שלכם.

ל-builder יש גם תצורת resolver ומשתני proxyמשלו. שניהם נקראים בזמן הבנייה ואינם עוברים בירושה מהמסוף שהתחיל את הבנייה.

הוכיחו את מסלול הרשת מתוך שלב בנייה

כתבו שלב חד-פעמי שמפתח את מארח התלות ופותח אליו חיבור. זו הבדיקה היחידה שעונה על השאלה עבור ה-builder ולא עבור ה-shell שלכם.

FROM alpine:3.20
RUN apk add --no-cache curl bind-tools  && getent hosts registry.example.internal  && curl -sS -o /dev/null -w "%{http_code}
" https://registry.example.internal/simple/

בנו את הקובץ הזה עם אותו builder, אותו מצב רשת ואותן עגינות סוד שהבנייה האמיתית שלכם משתמשת בהן: docker buildx build --builder remote0 -f Dockerfile.probe --progress=plain .. אם getent לא מדפיס דבר, התקלה היא בפתרון שמות ושום אישור לא יתקן אותה. אם השם נפתר אבל curl מדווח על פסק זמן, החסם הוא המסלול או מדיניות היציאה שלפני הרישום.

מחקו את הגלאי ברגע שהוא עונה. זהו שלב אבחוני ואין לתייג או לדחוף אותו לעולם.

עגנו את האישור במקום להעתיק אותו

לאחר שהמסלול עובד, האימות הוא הכשל הבא בתור. עגינת סוד של BuildKit חושפת קובץ לשלב RUN אחד בלי לכתבו לשכבה, וזה מה שכלי התלות צריך ומה שהתמונה לא צריכה לשמור.

RUN --mount=type=secret,id=npmrc,target=/root/.npmrc     npm ci --omit=dev

יש לספק את הסוד מחוץ ל-Dockerfile: docker buildx build --secret id=npmrc,src=/home/me/.npmrc .. הקובץ נשאר אצל הלקוח ולעולם לא נכנס להיסטוריית התמונה. ARG או ENV עם אותו טוקן אינם עושים את העבודה הזו, כי שניהם נרשמים בתצורת התמונה.

תמונה שאינה root זקוקה לנתיב יעד משלה, כגון /home/app/.npmrc או הקובץ המקביל ל-pip, Maven או Cargo. יעד העגינה חייב להתאים למשתמש שמריץ את הפקודה, אחרת הכלי ידווח על קובץ תצורה חסר שלמעשה נמצא שם.

בדקו מה כלי התלות משאיר בתמונה

עגינה זמנית מרחיקה את האישור מהשכבה, אבל היא לא מונעת מהכלי לכתוב משהו אחר. מנהלי חבילות משאירים קבצי lock, תיקיות cache ולפעמים את כתובת הרישום שנפתרה.

קראו את מערכת הקבצים המוגמרת במקום לסמוך על ה-Dockerfile. docker history --no-trunc image:tag מפרט כל פקודת שכבה, ו- docker run --rm image:tag sh -c "ls -a /root" מראה מה שרד אל הקונטיינר שרץ. גם כשהקובץ רק עוגן, טוקן שנכתב לשורת לוג במהלך npm ci נשאר דליפה.

קראו גם את לוג הבנייה, כי --progress=plain מדפיס את פלט הפקודות מילה במילה. אם הטוקן מופיע שם, החליפו אותו לפני כל דבר אחר והעבירו אותו דרך קובץ שהכלי קורא בשקט.

ודאו שתמונת זמן הריצה כבר לא זקוקה למסלול הפרטי

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

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

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

מאמרים קשורים