클라우드 메모리의 의존 캐시를 이용하여 클라우드 구축 파이프를 개선하다

소개하다.


지속적인 배치 파이프라인을 구축하는 것은 매우 어려운 일이다. 왜냐하면 당신은 매일 피드백을 수집하기 때문이다.우선 파이프가 매우 빠르고 응용 프로그램을 배치하기도 쉽다.하지만 애플리케이션이 늘어나면 지연 시간이 늘어날 수 있습니다...본고는 클라우드 저장소에 의존항 캐시를 추가함으로써 구축 시간을 단축하는 방법을 보여 줍니다.
이 중점에 대해 cloudbuild.yaml 파일을 사용하여 현재 배포 시간을 살펴보고 Google Storage cache를 사용하여 향상된 기능을 모색할 것입니다.
steps:
 - id: 'build-project'
   name: adoptopenjdk/openjdk11:jdk-11.0.8_10-slim
   dir: gcpcloudrunback
   entrypoint: bash
   args:
     - '-c'
     - |
       ./mvnw package

 - id: 'dockerize-project'
   name: gcr.io/cloud-builders/docker
   dir: gcpcloudrunback
   args: [ 'build',
           '-t', 'gcr.io/$PROJECT_ID/gcp-cloudrun-back:$SHORT_SHA',
           '-t', 'gcr.io/$PROJECT_ID/gcp-cloudrun-back:latest',
           '.' ]

 - id: 'push-to-cloud-registry'
   name: gcr.io/cloud-builders/docker
   args: [ 'push', 'gcr.io/$PROJECT_ID/gcp-cloudrun-back:$SHORT_SHA' ]

 - id: 'deploy-cloud-run'
   name: gcr.io/cloud-builders/gcloud
   dir: gcpcloudrunback
   entrypoint: bash
   args:
     - '-c'
     - |
       apt-get update
       apt-get install -qq -y gettext
       export PROJECT_ID=$PROJECT_ID
       export IMAGE_VERSION=$SHORT_SHA
       export SCALING_INSTANCE_COUNT=${_SCALING_INSTANCE_COUNT}
       envsubst < gcp-cloudrun-back.yaml > gcp-cloudrun-back_with_env.yaml
       gcloud beta run services replace gcp-cloudrun-back_with_env.yaml \
         --platform=managed --region=europe-west1
       gcloud run services add-iam-policy-binding gcp-cloudrun-back \
         --platform=managed --region=europe-west1 \
         --member="allUsers" --role="roles/run.invoker"

images:
 - 'gcr.io/$PROJECT_ID/gcp-cloudrun-back:$SHORT_SHA'
 - 'gcr.io/$PROJECT_ID/gcp-cloudrun-back:latest'
다음은 관련 Dockerfile
# Use AdoptOpenJDK for base image.
FROM adoptopenjdk/openjdk11:jre-11.0.8_10-alpine

# Copy the jar to the production image from the previous step
COPY target/*.jar /app.jar

# Run the web service on container startup.
CMD ["java", "-jar", "/app.jar"]
  • In this pipeline, we build our application using the maven wrapper from our project. Besides, we use a simple Dockerfile, not a multi-staged one.
  • Also note you need to grant Cloud Build service account the Cloud Run and Service Accounts roles.

캐시를 사용하여 구축 시간 단축


현재 이 파이프(based on this Github project)를 배치할 때 나의 구축은 평균 1분 45초가 걸려야 완성할 수 있다.우선 이 구축 시간을 이해하고 무엇을 개선할 수 있는지 봅시다.
  • The longest step is the one where the dependencies need to be installed build-project, where we see all the dependencies are downloaded. If you think that those dependencies will not change so often, it clearly needs some optimization to avoid unnecessary resources to be used.

maven 캐시 추가


구글 Cloud build optimizations documentation을 읽으면 수동으로 구글 메모리 캐시를 추가해 구축 시간을 줄일 수 있다.

Note that some Cloud Build competitors offer easily managed caching solutions... such a shame Cloud Build is not and we have to do everything manually.


스토리지 통 생성


우리는 캐시에 의존하여 특정한 메모리 통에 저장할 것이다.다음을 만듭니다.
gsutil mb gs://${PROJECT_ID}-cache-dependencies

Creating gs://${PROJECT_ID}-cache-dependencies/...

Replace ${PROJECT_ID} with your actual project Id. Cloud storage needs a unique name among all the buckets in the system. By prefixing your bucket with your project Id, there is a low chance to collide with another bucket name.


캐시를 가져오고 저장하려면


Maven 다운로드 캐시를 가져오고 저장하려면:
  • 은 Cloud Build의 볼륨 기능을 사용합니다.기본적으로 Cloud Build는 폴더 /workspace을 전체 빌드 단계에 저장합니다.우리는 지속될 다른 볼륨을 지정할 수 있다.
  • Cloud Build 는 버전 간의 의존 관계를 캐시하는 간단한 방법을 제공하지 않았습니다.
  • 은 파이프를 멈추지 않는 상황에서 소리 없이 실패할 가능성도 제공하지 않는다.
  • 이를 통해 캐시에 의존하는 최종 cloudbuild.yaml의 모습은 다음과 같습니다.
    steps:
     - id: 'download-cached-maven-dependencies'
       name: gcr.io/cloud-builders/gsutil
       entrypoint: bash
       volumes:
         - name: 'maven-repository'
           path: '/root/.m2'
       args:
         - '-c'
         - |
           gsutil cp gs://${PROJECT_ID}-cache-dependencies/cache/maven-dependencies.tgz maven-dependencies.tgz || exit 0
           tar -zxf maven-dependencies.tgz --directory / || exit 0
    
     - id: 'build-project'
       name: adoptopenjdk/openjdk11:jdk-11.0.8_10
       dir: mavencachecloudbuild/gcpcloudrunback
       entrypoint: bash
       volumes:
         - name: 'maven-repository'
           path: '/root/.m2'
       args:
         - '-c'
         - |
           ./mvnw package
    
     - id: 'dockerize-project'
       name: gcr.io/cloud-builders/docker
       dir: mavencachecloudbuild/gcpcloudrunback
       args: [ 'build',
               '-t', 'gcr.io/$PROJECT_ID/gcp-cloudrun-back:$SHORT_SHA',
               '-t', 'gcr.io/$PROJECT_ID/gcp-cloudrun-back:latest',
               '.' ]
    
     - id: 'push-to-cloud-registry'
       name: gcr.io/cloud-builders/docker
       args: [ 'push', 'gcr.io/$PROJECT_ID/gcp-cloudrun-back:$SHORT_SHA' ]
    
     - id: 'deploy-cloud-run'
       name: gcr.io/cloud-builders/gcloud
       dir: mavencachecloudbuild/gcpcloudrunback
       entrypoint: bash
       args:
         - '-c'
         - |
           apt-get update
           apt-get install -qq -y gettext
           export PROJECT_ID=$PROJECT_ID
           export IMAGE_VERSION=$SHORT_SHA
           export SCALING_INSTANCE_COUNT=${_SCALING_INSTANCE_COUNT}
           envsubst < gcp-cloudrun-back.yaml > gcp-cloudrun-back_with_env.yaml
           gcloud beta run services replace gcp-cloudrun-back_with_env.yaml \
             --platform=managed --region=europe-west1
           gcloud run services add-iam-policy-binding gcp-cloudrun-back \
             --platform=managed --region=europe-west1 \
             --member="allUsers" --role="roles/run.invoker"
    
     - id: 'upload-cached-maven-dependencies'
       waitFor: [ 'build-project']
       name: gcr.io/cloud-builders/gsutil
       entrypoint: bash
       volumes:
         - name: 'maven-repository'
           path: '/root/.m2'
       args:
         - '-c'
         - |
           tar -zcf maven-dependencies.tgz /root/.m2
           gsutil cp maven-dependencies.tgz gs://${PROJECT_ID}-cache-dependencies/cache/maven-dependencies.tgz
    
    images:
     - 'gcr.io/$PROJECT_ID/gcp-cloudrun-back:$SHORT_SHA'
     - 'gcr.io/$PROJECT_ID/gcp-cloudrun-back:latest'
    
    우리 중요한 부분을 되돌아봅시다.
  • 첫 번째는 클라우드 메모리통에서 마븐을 다운로드하는 것입니다.
  •  - id: 'download-cached-maven-dependencies'
       name: gcr.io/cloud-builders/gsutil
       entrypoint: bash
       volumes:
         - name: 'maven-repository'
           path: '/root/.m2'
       args:
         - '-c'
         - |
           gsutil cp gs://${PROJECT_ID}-cache-dependencies/cache/maven-dependencies.tgz maven-dependencies.tgz || exit 0
           tar -zxf maven-dependencies.tgz --directory / || exit 0
    
    
    • name: gcr.io/cloud-builders/gsutil: use a provided Google image with gsutil to manage buckets.
    • volumes:: persist a volume across build steps. With maven, the default volume is /${USER_HOME}/.m2, which is /root/.m2 in our different images.
    • gsutil cp && tar -xzf: downloading the files from the bucket (in .tgz to reduce dependencies size).
    • || exit 0: As mentioned earlier, there is no easy way to ignore steps on error. Just add exit 0 to make sure if the folder does not exist on the bucket your build does not fail. I know it is not a perfect solution, but the step is small enough not to damage the entire pipeline. Besides, if you don’t have cache, you can still build the application.
  • 이전 단계에서 보존한 볼륨을 사용하여 ./mvnw 명령 향상
  •  - id: 'build-project'
       name: adoptopenjdk/openjdk11:jdk-11.0.8_10-slim
       dir: mavencachecloudbuild/gcpcloudrunback
       entrypoint: bash
       volumes:
         - name: 'maven-repository'
           path: '/root/.m2'
       args:
         - '-c'
         - |
           ./mvnw package
    

    Thanks to the shared volume, when the step will execute ./mvnw package it will rely on the dependencies provided by Cloud Storage.

  • 업로드 의존항.pom.xml을 변경하고 새로운 의존항을 사용하여 캐시를 업데이트해야 한다면 매우 유용할 것입니다
  •  - id: 'upload-cached-maven-dependencies'
       waitFor: [ 'build-project']
       name: gcr.io/cloud-builders/gsutil
       entrypoint: bash
       volumes:
         - name: 'maven-repository'
           path: '/root/.m2'
       args:
         - '-c'
         - |
           tar -zcf maven-dependencies.tgz /root/.m2
           gsutil cp maven-dependencies.tgz gs://${PROJECT_ID}-cache-dependencies/cache/maven-dependencies.tgz
    
    • In this step, we expect it not to fail, so we don't use exit 0.
    • We reuse the volume created by download-cached-maven-dependencies and potentially modified by build-project.
    • We use the waitFor to start this step right after the build-project, as this volume will no longer be modified later.

    결실


    첫 번째 구축은 두 단계를 추가했고 캐시가 없기 때문에 조금 길어집니다.그런데 다음 게 더 빨라요!
    캐시가 생성되기 전에 처음 생성된 결과입니다.
    다음은 캐시 생성 후 두 번째로 생성된 결과입니다.
    지금 우리가 몇 초 (30초) 를 절약했으니, 너는 이것이 가치가 없다고 말할 수도 있다.그러나 당신의 구축은 점점 커질 것이다. 만약 당신이 그것을 최적화하지 않는다면, 그것은 몇 분이 걸려야 완성될 것이다.오늘날 우리는 하나의 단일한 클라우드 운행 서비스만 배치할 수 있지만 2개나 3개의 클라우드 기능도 배치할 수 있다.마벤트 의존항을 다운로드할 때마다 많은 시간과 자원을 낭비합니다.그러니까 그걸 기억해.

    보상: 사선이 있는 전단 종목에도 적용


    다음은 cloudbuild.yaml 파일로 yarn 의존항을 보존하는 데 사용됩니다.
    steps:
     - id: 'download-cached-yarn-dependencies'
       name: gcr.io/cloud-builders/gsutil
       dir: gcpfirebasefront
       entrypoint: bash
       args:
         - '-c'
         - |
           gsutil cp gs://${PROJECT_ID}-cache-dependencies/cache/yarn-dependencies.tgz yarn-dependencies.tgz || exit 0
           tar -zxf yarn-dependencies.tgz || exit 0
    
     - id: 'install-yarn'
       name: node
       entrypoint: yarn
       dir: gcpfirebasefront
       args: ['install', '--silent']
    
     - id: 'build-front'
       name: node
       entrypoint: yarn
       dir: gcpfirebasefront
       args: [ 'build' ]
    
     - id: 'deploy-firebase'
       name: gcr.io/$PROJECT_ID/firebase
       dir: gcpfirebasefront
       args: [ 'deploy', '--project=$PROJECT_ID', '--only', 'hosting' ]
    
     - id: 'upload-cached-yarn-dependencies'
       waitFor: ['build-front']
       name: gcr.io/cloud-builders/gsutil
       entrypoint: bash
       dir: cloudcmr-front
       args:
         - '-c'
         - |
           tar -zcf yarn-dependencies.tgz ./node_modules
           gsutil cp yarn-dependencies.tgz gs://${PROJECT_ID}-cache-dependencies/cache/yarn-dependencies.tgz
    

    Note for yarn the dependencies are located under /workspace folder hierarchies. Therefore, there is no need to add a custom volume to be persisted by Cloud Build


    요약


    이 문서에서 Maven 및 Thread 구축 절차를 사용하여 클라우드 구축을 최적화하는 데 중점을 두었습니다.
  • 캐시 의존 항목을 사용하지 않을 때 자주 발생하는 문제, 자원 및 시간 낭비
  • gsutil을 사용하여 스토리지 종속성
  • 은 잘못된 단계를 무시합니다. 이것은 클라우드 구축이 이때 제공하는 기존 단계가 아닙니다.
  • 크로스 생성
  • 기타 폴더
  • 클라우드 스토리지 통에서 파일 다운로드 및 가져오기
  • 클라우드 저장소를 캐시 저장소로 사용하면 저장된 천메가바이트를 지불해야 하기 때문에 소량의 비용이 발생할 수 있음을 주의하십시오.하지만 걱정하지 마십시오. 캐시된 마븐 폴더는 61MB입니다. 무료로 사용할 수 있습니다.

    한층 더


    원하는 경우 다음과 같은 방법으로 빌드의 일부를 개선할 수 있습니다.
  • 과 버킷에서 파일을 다운로드하는 것보다 왜 모든 의존 항목을 포함하는 이미지를 구축하지 않습니까?
  • 은 의존항이
  • 을 마지막으로 생성한 이래 변경되었을 때만 해시를 사용하여 업로드합니다
  • 또한 한 통에 docker 이미지를 저장하여 더욱 빠르게 구축할 수 있습니다(Google Jib 사용)
  • 캐시 폴더
  • 에서 파일을 다운로드하는 동안 오류가 발생하지 않도록 개선
  • 은 2주 이상 된 파일을 삭제하도록 스토리지 통을 구성하여 더 이상 사용하지 않는 캐시에 대한 비용을 절감합니다.
  • 리소스

  • Best practices for speeding up builds
  • Cloud Build global configuration file
  • GSutil command to manage buckets
  • 좋은 웹페이지 즐겨찾기