Como acelerar suas versões

Nesta página, explicamos algumas maneiras de acelerar suas versões usando o Cloud Build.

Como usar uma imagem do Docker em cache

A maneira mais fácil de aumentar a velocidade da versão da imagem do Docker é especificando uma imagem em cache que pode ser usada para versões subsequentes. Você pode especificar a imagem em cache adicionando o argumento --cache-from no seu arquivo de configuração de versão, que instruirá o Docker a criar usando essa imagem como uma fonte de cache.

Cada imagem do Docker é composta de camadas empilhadas. O uso de --cache-from recria todas as camadas da camada alterada até o final da versão. Portanto, usar --cache-from não é vantajoso se você alterar uma camada nas etapas anteriores da versão do Docker.

Recomenda-se que você sempre use --cache-from para suas versões, mas tenha em mente as seguintes ressalvas:

  • Você precisa de uma imagem do Docker criada anteriormente para armazenar em cache.
  • É possível usar --cache-from somente para versões do Docker. Não é possível usá-lo em criações que produzem outros tipos de artefatos.
  • É necessário recuperar a imagem em cache com base em um registro, o que pode aumentar o tempo necessário para a criação.

Nas etapas a seguir, explicamos como criar usando uma imagem previamente armazenada em cache:

YAML

  1. Na configuração da sua versão, adicione instruções para os seguintes objetivos:

    • Enviar a imagem em cache do Container Registry. Observe que a etapa de compilação docker pull abaixo define entrypoint como bash, o que permite executar o comando e ignorar o erro retornado. Isso é necessário quando você cria uma imagem pela primeira vez e docker pull não tem uma imagem existente a ser extraída.
    • Adicionar um argumento --cache-from para usar essa imagem para recriações.

      steps:
       - name: 'gcr.io/cloud-builders/docker'
         entrypoint: 'bash'
         args:
         - '-c'
         - |
           docker pull gcr.io/$PROJECT_ID/[IMAGE_NAME]:latest || exit 0
      - name: 'gcr.io/cloud-builders/docker'
        args: [
                  'build',
                  '-t', 'gcr.io/$PROJECT_ID/[IMAGE_NAME]:latest',
                  '--cache-from', 'gcr.io/$PROJECT_ID/[IMAGE_NAME]:latest',
                  '.'
              ]
      images: ['gcr.io/$PROJECT_ID/[IMAGE_NAME]:latest']
      

      em que [IMAGE_NAME] é o nome da sua imagem.

  2. Crie sua imagem usando a configuração de versão acima:

    gcloud builds submit --config cloudbuild.yaml .
    

JSON

  1. Na configuração da sua versão, adicione instruções para os seguintes objetivos:

    • Enviar a imagem em cache do Container Registry. Observe que a etapa de compilação docker pull abaixo define entrypoint como bash, o que permite executar o comando e ignorar os possíveis erros retornados. Isso é necessário quando você cria uma imagem pela primeira vez e docker pull não tem uma imagem existente a ser extraída.
    • Adicionar um argumento --cache-from para usar essa imagem para recriações.

      {
          "steps": [
          {
              "name": "gcr.io/cloud-builders/docker",
              "entrypoint": "bash",
              "args": ["-c", "docker pull gcr.io/$PROJECT_ID/quickstart-image:latest || exit 0"]
          },
          {
              "name": "gcr.io/cloud-builders/docker",
              "args": [
                  "build",
                  "-t",
                  "gcr.io/$PROJECT_ID/[IMAGE_NAME]:latest",
                  "--cache-from",
                  "gcr.io/$PROJECT_ID/[IMAGE_NAME]:latest",
                  "."
              ]
          }
          ],
          "images": ["gcr.io/$PROJECT_ID/[IMAGE_NAME]:latest"]
      }
      

      em que [IMAGE_NAME] é o nome da sua imagem.

  2. Crie sua imagem usando a configuração de versão acima:

    gcloud builds submit --config cloudbuild.json .
    

Como armazenar diretórios em cache com o Google Cloud Storage

Para aumentar a velocidade de uma versão, reutilize os resultados de uma versão anterior. Você pode copiar os resultados de uma versão anterior para um intervalo do Google Cloud Storage, usar os resultados para um cálculo mais rápido e, em seguida, copiar os novos resultados de volta ao intervalo. Use esse método quando sua versão tomar muito tempo e produzir um pequeno número de arquivos que não leve tempo para copiar do Google Cloud Storage e para ele.

Ao contrário do --cache-from, que é destinado apenas a versões do Docker, o armazenamento em cache do Google Cloud Storage pode ser usado para qualquer criador compatível com Cloud Build.

Use as etapas a seguir para armazenar diretórios em cache usando o Google Cloud Storage:

YAML

  1. No arquivo de configuração de versão, adicione instruções para os seguintes objetivos:

    • Copiar os resultados de uma versão anterior do intervalo do Google Cloud Storage.
    • Usar os resultados para a versão atual.
    • Copiar os novos resultados de volta para o intervalo.

      steps:
      - name: gcr.io/cloud-builders/gsutil
        args: ['cp', 'gs://mybucket/results.zip', 'previous_results.zip']
      # operations that use previous_results.zip and produce new_results.zip
      - name: gcr.io/cloud-builders/gsutil
        args: ['cp', 'new_results.zip', 'gs://mybucket/results.zip']
      
  2. Crie seu código usando a configuração de versão acima:

    gcloud builds submit --config cloudbuild.yaml .
    

JSON

  1. No arquivo de configuração de versão, adicione instruções para os seguintes objetivos:

    • Copiar os resultados de uma versão anterior do intervalo do Google Cloud Storage.
    • Usar os resultados para a versão atual.
    • Copiar os novos resultados de volta para o intervalo.

      {
          "steps": [
          {
              "name": "gcr.io/cloud-builders/gsutil",
              "args": ["cp", "gs://mybucket/results.zip", "previous_results.zip"]
          },
          {
              // operations that use previous_results.zip and produce new_results.zip
          },
          {
              "name": "gcr.io/cloud-builders/gsutil",
              "args": ["cp", "new_results.zip", "gs://mybucket/results.zip"]
          }
          ]
      }
      
  2. Crie seu código usando a configuração de versão acima:

    gcloud builds submit --config cloudbuild.json .
    

Como usar tamanhos personalizados de máquinas virtuais

Além do tipo de máquina padrão, o Cloud Build oferece dois tipos de máquinas virtuais de alta CPU para executar as versões. Para aumentar a velocidade da compilação, selecione uma máquina virtual com uma CPU maior. Solicitar uma máquina com CPU elevada pode aumentar o tempo de inicialização da compilação, uma vez que o Cloud Build inicia essas máquinas somente sob demanda.

Para ver informações sobre como selecionar tamanhos de disco personalizados, consulte diskSize.

Nas etapas a seguir, explicaremos como especificar um tamanho de VM personalizado para uma versão:

gcloud

Para especificar um tamanho de VM personalizado, use o argumento --machine-type:

gcloud builds submit --config=cloudbuild.yaml \
    --machine-type=n1-highcpu-8 .

YAML

  1. Especifique o tamanho da VM no seu arquivo de configuração de versão:

    steps:
    - name: 'gcr.io/cloud-builders/docker'
      args: ['build', '-t', 'gcr.io/my-project/image1', '.']
      # operations that take a long time to build
    - name: 'gcr.io/cloud-builders/docker'
      args: ['build', '-t', 'gcr.io/my-project/image2', '.']
    options:
      machineType: 'N1_HIGHCPU_8'
    
  2. Crie usando a configuração de versão acima:

    gcloud builds submit --config cloudbuild.yaml .
    

JSON

  1. Especifique o tamanho da VM no seu arquivo de configuração de versão:

    {
        "steps": [
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": ["build", "-t", "gcr.io/my-project/image1", "."]
        },
        // operations that take a long time to build
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": ["build", "-t", "gcr.io/my-project/image2", "."]
        }
        ],
        "options": {
            "machineType": "N1_HIGHCPU_8"
        }
    }
    
  2. Crie usando a configuração de versão acima:

    gcloud builds submit --config cloudbuild.json .
    

Como criar contêineres mais enxutos

Muitas vezes, criar um aplicativo requer muitos arquivos, como dependências de tempo de criação e arquivos intermediários, que não são necessários no momento da execução. Mas quando você insere o aplicativo em um contêiner, esses arquivos são incluídos nele, resultando em cargas desnecessárias. Ao longo do tempo, essa sobrecarga custa tanto tempo quanto dinheiro, por armazenar e mover bits entre o registro do Docker e o tempo de execução do seu contêiner.

Para garantir que seu contêiner seja o menor possível, separe a criação do aplicativo (e as ferramentas necessárias para criá-lo) da montagem do contêiner de tempo de execução.

O Cloud Build oferece uma série de contêineres do Docker com ferramentas para desenvolvedores comuns, como Git, Docker e a interface de linha de comando gcloud. 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 versão, as dependências do sistema de versão e o JDK, é possível ter um Dockerfile como o mostrado abaixo:

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. Neste caso, o Gradle está fazendo o download de centenas de megabytes de bibliotecas para o diretório de cache, a fim de executar a versão, 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. Crie o aplicativo: no cloudbuild.yaml, 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. Monte o contêiner de ambiente de execução: no cloudbuild.yaml, adicione uma etapa para montar o contêiner de ambiente de execução.

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

    O exemplo usa a camada de base Alpine Linux openjdk:8u111-jre-alpine, que é incrivelmente enxuta. 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:8u111-jre-alpine
    
    COPY ./gate-web/build/install/gate /opt/gate
    
    CMD ["/opt/gate/bin/gate"]
    
  3. Crie as imagens do Docker: no 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. Crie o aplicativo: no 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. Monte o contêiner de ambiente de execução: no cloudbuild.json, adicione uma etapa para montar o contêiner de ambiente de execução.

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

    O exemplo usa a camada de base Alpine Linux openjdk:8u111-jre-alpine, que é incrivelmente enxuta. 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. Crie as imagens do Docker: no 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"
        ]
    }
    

Não fazer upload de arquivos desnecessários

Quando uma versão é acionada, é feito upload do diretório do seu código para uso pelo Cloud Build.

É possível excluir arquivos não necessários para sua compilação com um arquivo .gcloudignore para otimizar o tempo de upload.

Exemplos de arquivos comumente excluídos incluem:

  • documentação e código de amostra para desenvolvedores de projetos
  • código de scaffolding gerado, binários, arquivos *.jar ou recursos da Web compilados usados para desenvolvimento
  • dependências de terceiros fornecidas para desenvolvimento local

Para preparar um arquivo .gcloudignore para resolver esses casos, crie um arquivo na raiz do projeto com o conteúdo, como:

.git
dist
node_modules
vendor
*.jar

A exclusão do código compilado e de dependências de terceiros também resulta em um processo de criação mais consistente e em um risco reduzido de implantação acidental de código que ainda está em desenvolvimento ativo.

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…