Creazione di container più snelli

In questa pagina viene descritto come creare immagini Docker più snelle.

Creazione di container più snelli

Quando esegui il containerizzazione di un'applicazione, i file non necessari in fase di esecuzione, come le dipendenze di compilazione e i file intermedi, possono essere inclusi inavvertitamente nell'immagine del contenitore. Questi file non necessari possono aumentare la dimensione dell'immagine container, quindi aggiungere tempo e costi aggiuntivi quando l'immagine si sposta tra Docker Registry e il runtime del container.

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 le funzionalità di questi strumenti per definire un file di configurazione di compilazione con un solo passaggio e un altro passaggio per assemblare l'ambiente di runtime finale.

Ad esempio, se stai creando un'applicazione Java, che richiede file come il codice sorgente, le librerie dell'applicazione, i sistemi di compilazione, le dipendenze del sistema di compilazione e il 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 una 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 creazione dell'applicazione Java il passaggio per assemblare il container del runtime:

YAML

  1. Crea l'applicazione: in cloudbuild.yaml, aggiungi 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. 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 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.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 seguente codice aggiunge un passaggio denominato java:8 per 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. 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"
        ]
    }