Creazione di container più snelli

Questa pagina descrive come creare immagini Docker più snelle.

Creazione di container più snelli

Quando containerizza un'applicazione, i file che non sono necessari in fase di runtime, come dipendenze in fase di build e file intermedi, possono essere inclusi inavvertitamente nell'immagine container. Questi file non necessari possono aumentare le dimensioni dell'immagine del contenitore e, di conseguenza, aggiungere tempo e costi aggiuntivi durante il trasferimento dell'immagine tra il registry Docker e il runtime del contenitore.

Per contribuire a ridurre le dimensioni dell'immagine del container, separa la compilazione dell'applicazione, insieme agli strumenti utilizzati per compilarla, dall'assemblaggio del container di runtime.

Cloud Build fornisce una serie di Docker di grandi dimensioni con come Git, Docker e Google Cloud CLI. Utilizza questi strumenti per definire un file di configurazione della build con un passaggio per compilare l'applicazione e un altro per assemblare il relativo ambiente di runtime finale.

Ad esempio, se stai creando un'applicazione Java che richiede file come il codice sorgente, le librerie delle applicazioni, i sistemi di build, e JDK, potresti avere un Dockerfile simile al seguenti:

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 compilazione del pacchetto, ma non sono necessarie in fase di esecuzione. Tutto il runtime le dipendenze 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, lo spazio non può essere recuperato. In questo caso, Gradle scarica centinaia di megabyte di librerie nella directory cache per eseguire la compilazione, ma le librerie non vengono eliminate.

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

L'esempio seguente separa il passaggio per la compilazione dell'applicazione Java dal passaggio per l'assemblaggio del contenitore del runtime:

YAML

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

    Il codice seguente aggiunge un passaggio che genera 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. Assembla il container di runtime: in cloudbuild.yaml, aggiungi un passaggio per assemblare il container runtime.

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

    L'esempio utilizza il livello di base di Alpine Linux openjdk:8u111-jre-alpine, che è incredibilmente snello. Inoltre, include il JRE, invece del più ingombrante JDK necessario per creare un'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 compilare l'applicazione.

    Il codice seguente aggiunge un passaggio denominato java:8 per compilare il codice Java.

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

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

    L'esempio utilizza il livello di base di Alpine Linux openjdk:8u111-jre-alpine, che è incredibilmente snello. Inoltre, include il JRE, invece del più ingombrante JDK necessario per creare un'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"
        ]
    }