פיתוח קונטיינרים יעילים יותר

בדף הזה נסביר איך ליצור תמונות Docker קטנות יותר.

יצירת קונטיינרים יעילים יותר

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

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

‫Cloud Build מספק סדרה של קונטיינרים של Docker עם כלים נפוצים למפתחים כמו Git,‏ Docker ו-Google Cloud CLI. אפשר להשתמש בכלים האלה כדי להגדיר קובץ תצורת build עם שלב אחד לבניית האפליקציה, ושלב נוסף להרכבת סביבת זמן הריצה הסופית שלה.

לדוגמה, אם אתם מפתחים אפליקציית Java שדורשת קבצים כמו קוד המקור, ספריות האפליקציה, מערכות build, תלות במערכת build ו-JDK, יכול להיות שקובץ ה-Dockerfile שלכם ייראה כך:

FROM java:8

COPY . workdir/

WORKDIR workdir

RUN GRADLE_USER_HOME=cache ./gradlew buildDeb -x test

RUN dpkg -i ./gate-web/build/distributions/*.deb

CMD ["/opt/gate/bin/gate"]

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

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

דרך יעילה יותר לבצע את הבנייה היא להשתמש ב-Cloud Build כדי להפריד בין בניית האפליקציה לבין בניית שכבת זמן הריצה שלה.

בדוגמה הבאה, השלב של בניית אפליקציית Java מופרד מהשלב של הרכבת קונטיינר זמן הריצה:

YAML

  1. מפתחים את האפליקציה: ב-cloudbuild.yaml, מוסיפים שלב לפיתוח האפליקציה.

    הקוד הבא מוסיף שלב שיוצר את תמונת java:8, שמכילה את קוד Java.

    steps:
    
    - name: 'java:8'
      env: ['GRADLE_USER_HOME=cache']
      entrypoint: 'bash'
      args: ['-c', './gradlew gate-web:installDist -x test']
    
    
  2. הרכבת מאגר התגים של זמן הריצה: ב-cloudbuild.yaml, מוסיפים שלב להרכבת מאגר התגים של זמן הריצה.

    הקוד הבא מוסיף שלב בשם gcr.io/cloud-builders/docker שמרכיב את מאגר הזמן הריצה. הוא מגדיר את מאגר זמן הריצה בקובץ נפרד בשם Dockerfile.slim.

    בדוגמה נעשה שימוש בשכבת הבסיס של Alpine Linux‏ openjdk:8u111-jre-alpine, שהיא מאוד רזה. בנוסף, הוא כולל את JRE, במקום JDK מגושם יותר שהיה נחוץ לבניית האפליקציה.

    cloudbuild.yaml
    
    steps:
    - name: 'java:8'
      env: ['GRADLE_USER_HOME=cache']
      entrypoint: 'bash'
      args: ['-c',
             './gradlew gate-web:installDist -x test']
    
    - name: 'gcr.io/cloud-builders/docker'
      args: ['build',
             '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA',
             '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:latest',
             '-f', 'Dockerfile.slim',
             '.'
      ]
    
    
    Dockerfile.slim
    
    FROM openjdk:8-jre-alpine
    
    COPY ./gate-web/build/install/gate /opt/gate
    
    CMD ["/opt/gate/bin/gate"]
    
  3. יוצרים את קובצי האימג' של Docker: ב-cloudbuild.yaml, מוסיפים שלב ליצירת קובצי האימג'.
    steps:
    - name: 'java:8'
      env: ['GRADLE_USER_HOME=cache']
      entrypoint: 'bash'
      args: ['-c', './gradlew gate-web:installDist -x test']
    - name: 'gcr.io/cloud-builders/docker'
      args: ['build',
             '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA',
             '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:latest',
             '-f', 'Dockerfile.slim', '.']
    images:
    - 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'
    - 'gcr.io/$PROJECT_ID/$REPO_NAME:latest'
    

JSON

  1. יצירת גרסת build של האפליקציה: ב-cloudbuild.json, מוסיפים שלב ליצירת גרסת build של האפליקציה.

    הקוד הבא מוסיף שלב בשם java:8 לבניית קוד Java.

    {
        "steps": [
        {
            "name": "java:8",
            "env": [
                "GRADLE_USER_HOME=cache"
            ],
            "entrypoint": "bash",
            "args": [
                "-c",
                "./gradlew gate-web:installDist -x test"
            ]
        },
    }
    
  2. הרכבת מאגר התגים של זמן הריצה: ב-cloudbuild.json, מוסיפים שלב להרכבת מאגר התגים של זמן הריצה.

    הקוד הבא מוסיף שלב בשם gcr.io/cloud-builders/docker שמרכיב את מאגר הזמן הריצה. הוא מגדיר את מאגר זמן הריצה בקובץ נפרד בשם Dockerfile.slim.

    בדוגמה נעשה שימוש בשכבת הבסיס של Alpine Linux‏ openjdk:8u111-jre-alpine, שהיא מאוד רזה. בנוסף, הוא כולל את JRE, במקום JDK מגושם יותר שהיה נחוץ לבניית האפליקציה.

    cloudbuild.json:
    
    {
        "steps": [
        {
            "name": "java:8",
            "env": [
                "GRADLE_USER_HOME=cache"
            ],
            "entrypoint": "bash",
            "args": [
                "-c",
                "./gradlew gate-web:installDist -x test"
            ]
        },
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": [
                "build",
                "-t",
                "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA",
                "-t",
                "gcr.io/$PROJECT_ID/$REPO_NAME:latest",
                "-f",
                "Dockerfile.slim",
                "."
            ]
        }
        ],
    }
    
    Dockerfile.slim:
    
    FROM openjdk:8u111-jre-alpine
    
    COPY ./gate-web/build/install/gate /opt/gate
    
    CMD ["/opt/gate/bin/gate"]
    
  3. יצירת קובצי האימג' של Docker: ב-cloudbuild.json, מוסיפים שלב ליצירת קובצי האימג'
    {
        "steps": [
        {
            "name": "java:8",
            "env": [
                "GRADLE_USER_HOME=cache"
            ],
            "entrypoint": "bash",
            "args": [
                "-c",
                "./gradlew gate-web:installDist -x test"
            ]
        },
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": [
                "build",
                "-t",
                "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA",
                "-t",
                "gcr.io/$PROJECT_ID/$REPO_NAME:latest",
                "-f",
                "Dockerfile.slim",
                "."
            ]
        }
        ],
        "images": [
            "gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA",
            "gcr.io/$PROJECT_ID/$REPO_NAME:latest"
        ]
    }