Como criar contêineres mais enxutos

Nesta página, você vê como criar imagens mais enxutas do Docker.

Como criar contêineres mais enxutos

Quando você coloca um aplicativo em contêineres, os arquivos que não são necessários no ambiente de execução, como dependências de tempo de compilação e arquivos intermediários, são incluídos inadvertidamente na imagem do contêiner. Esses arquivos desnecessários aumentam o tamanho da imagem e geram mais tempo e custo à medida que ela é transferida entre o registro do Docker e o ambiente de execução do contêiner.

Para reduzir o tamanho da imagem do contêiner, separe a compilação do aplicativo, além das ferramentas usadas para criá-lo, a partir da montagem do contêiner do ambiente de execução.

O Cloud Build oferece uma série de contêineres do Docker com ferramentas para desenvolvedores comuns, como Git, Docker e Google Cloud CLI. Use essas ferramentas para definir um arquivo de configuração de versão com uma etapa para criar o aplicativo e outra para montar o ambiente de tempo de execução final.

Por exemplo, se você estiver criando um aplicativo Java, que exige arquivos como o código-fonte, as bibliotecas de aplicativos, os sistemas de build, as dependências do sistema de build e o JDK, é possível ter um Dockerfile como este:

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

No exemplo acima, o Gradle, que é usado para criar o pacote, faz o download de um grande número de bibliotecas para fins de funcionamento. Essas bibliotecas são essenciais para a criação do pacote, mas não são necessárias no momento da execução. Todas as dependências de tempo de execução são agrupadas no pacote.

Cada comando no Dockerfile cria uma nova camada no contêiner. Se os dados forem gerados nessa camada e não forem excluídos no mesmo comando, esse espaço não poderá ser recuperado. Nesse caso, o Gradle está fazendo download de centenas de megabytes de bibliotecas para o diretório cache para executar o build, mas as bibliotecas não são excluídas.

Uma maneira mais eficiente de executar a versão é usar o Cloud Build para separar a criação do aplicativo da criação da camada de tempo de execução dele.

No exemplo a seguir, separamos a etapa de criação do aplicativo Java da etapa de montagem do contêiner de tempo de execução:

YAML

  1. Criar o aplicativo: em cloudbuild.yaml, adicione uma etapa para criar o aplicativo.

    O código a seguir adiciona uma etapa que cria a imagem java:8, que contém o código Java.

    steps:
    
    - name: 'java:8'
      env: ['GRADLE_USER_HOME=cache']
      entrypoint: 'bash'
      args: ['-c', './gradlew gate-web:installDist -x test']
    
    
  2. Montar o contêiner do ambiente de execução: em cloudbuild.yaml, adicione uma etapa para montar o contêiner do ambiente de execução.

    O código a seguir adiciona uma etapa chamada gcr.io/cloud-builders/docker, que monta o contêiner do ambiente de execução. Ele define o contêiner do ambiente de execução em um arquivo separado chamado Dockerfile.slim.

    O exemplo usa a camada de base do Alpine Linux openjdk:8u111-jre-alpine, que é incrivelmente leve. Além disso, ele inclui o JRE em vez do JDK mais volumoso, que foi necessário para criar o aplicativo.

    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. Crie as imagens do Docker: em cloudbuild.yaml, adicione uma etapa para criar as imagens.
    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. Criar o aplicativo: em cloudbuild.json, adicione uma etapa para criar o aplicativo.

    O código a seguir adiciona uma etapa chamada java:8 para criar o código Java.

    {
        "steps": [
        {
            "name": "java:8",
            "env": [
                "GRADLE_USER_HOME=cache"
            ],
            "entrypoint": "bash",
            "args": [
                "-c",
                "./gradlew gate-web:installDist -x test"
            ]
        },
    }
    
  2. Montar o contêiner do ambiente de execução: em cloudbuild.json, adicione uma etapa para montar o contêiner do ambiente de execução.

    O código a seguir adiciona uma etapa chamada gcr.io/cloud-builders/docker, que monta o contêiner do ambiente de execução. Ele define o contêiner do ambiente de execução em um arquivo separado chamado Dockerfile.slim.

    O exemplo usa a camada de base do Alpine Linux openjdk:8u111-jre-alpine, que é incrivelmente leve. Além disso, ele inclui o JRE em vez do JDK mais volumoso, que foi necessário para criar o aplicativo.

    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. Criar as imagens do Docker: em cloudbuild.json, adicione uma etapa para criar as imagens.
    {
        "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"
        ]
    }