Creazione di container più snelli

Questa pagina descrive come creare immagini Docker più sottili.

Creazione di container più snelli

Quando containerizziamo un'applicazione, i file che non sono necessari in fase di runtime, ad esempio le dipendenze in fase di build e i file intermedi, possono essere inavvertitamente inclusi nell'immagine container. Questi file non necessari possono aumentare le dimensioni dell'immagine del container e, di conseguenza, aumentare il tempo e i costi mentre l'immagine si sposta tra il registro Docker e il runtime del container.

Per ridurre le dimensioni dell'immagine container, separa la creazione dell'applicazione e gli strumenti utilizzati per crearla dall'assemblaggio del container di runtime.

Cloud Build offre una serie di container Docker con strumenti per sviluppatori comuni, come Git, Docker e Google Cloud CLI. Utilizza questi strumenti per definire un file di configurazione della build con un passaggio per creare l'applicazione e un altro per assemblare l'ambiente di runtime finale.

Ad esempio, se stai creando un'applicazione Java, che richiede file come codice sorgente, librerie di applicazioni, sistemi di compilazione, dipendenze sistema di compilazione e JDK, potresti avere un Dockerfile simile al seguente:

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"]

Nell'esempio precedente, Gradle, utilizzato per creare il pacchetto, scarica un numero elevato di librerie per funzionare. Queste librerie sono essenziali per la creazione del pacchetto, ma non sono necessarie in fase di runtime. Tutte le dipendenze di runtime sono raggruppate nel pacchetto.

Ogni comando in Dockerfile crea un nuovo livello nel container. Se i dati vengono generati in quel livello e non vengono eliminati nello stesso comando, quello spazio non può essere recuperato. In questo caso, Gradle scarica centinaia di megabyte di librerie nella directory cache per eseguire la build, ma le librerie non vengono eliminate.

Un modo più efficiente per eseguire la build è utilizzare Cloud Build per separare la creazione dell'applicazione dalla creazione del suo livello di runtime.

L'esempio seguente separa il passaggio di creazione dell'applicazione Java da quello di assemblaggio del container di runtime:

YAML

  1. Crea l'applicazione: in cloudbuild.yaml, aggiungi un passaggio per creare l'applicazione.

    Il codice seguente aggiunge un passaggio che crea l'immagine java:8, che contiene il codice Java.

    steps:
    
    - name: 'java:8'
      env: ['GRADLE_USER_HOME=cache']
      entrypoint: 'bash'
      args: ['-c', './gradlew gate-web:installDist -x test']
    
    
  2. Assemblare il container di runtime: in cloudbuild.yaml, aggiungi un passaggio per assemblare il container di runtime.

    Il codice seguente aggiunge un passaggio denominato gcr.io/cloud-builders/docker che assembla il container di runtime. Definisce il container di runtime in un file separato denominato Dockerfile.slim.

    L'esempio utilizza il livello base di Alpine Linux openjdk:8u111-jre-alpine, che è incredibilmente sottile. Inoltre, include il JRE, invece del più ingombrante JDK necessario per creare l'applicazione.

    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. Crea le immagini Docker: in cloudbuild.yaml, aggiungi un passaggio per creare le immagini.
    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. Crea l'applicazione: in cloudbuild.json, aggiungi un passaggio per creare l'applicazione.

    Il codice seguente aggiunge un passaggio denominato java:8 per la creazione del codice Java.

    {
        "steps": [
        {
            "name": "java:8",
            "env": [
                "GRADLE_USER_HOME=cache"
            ],
            "entrypoint": "bash",
            "args": [
                "-c",
                "./gradlew gate-web:installDist -x test"
            ]
        },
    }
    
  2. Assemblare il container di runtime: in cloudbuild.json, aggiungi un passaggio per assemblare il container di runtime.

    Il codice seguente aggiunge un passaggio denominato gcr.io/cloud-builders/docker che assembla il container di runtime. Definisce il container di runtime in un file separato denominato Dockerfile.slim.

    L'esempio utilizza il livello base di Alpine Linux openjdk:8u111-jre-alpine, che è incredibilmente sottile. Inoltre, include il JRE, invece del più ingombrante JDK necessario per creare l'applicazione.

    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. Crea le immagini Docker: in cloudbuild.json, aggiungi un passaggio per creare le immagini.
    {
        "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"
        ]
    }