【问题标题】:How to Enable Docker layer caching in Azure DevOps如何在 Azure DevOps 中启用 Docker 层缓存
【发布时间】:2019-12-10 11:56:21
【问题描述】:

我正在运行以下 yaml 脚本来构建 docker 映像并推送到 kubernetes 集群,但同时我想在构建 yaml 脚本时在 azure DevOps 中启用 docker 层缓存。请您解释一下如何启用或如何启用在 azure devops 中添加任务来执行此操作。

Yaml:

# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml

trigger:
- master

pool:
  vmImage: 'ubuntu-latest'

variables:
  tag: 'web'
  DockerImageName: 'boiyaa/google-cloud-sdk-nodejs'


steps:
- task: Docker@2
  inputs:
    command: 'build'
    Dockerfile: '**/Dockerfile'
    tags: 'web'
  
- script: |
    echo ${GCLOUD_SERVICE_KEY_STAGING} > ${HOME}/gcp-key.json
               gcloud auth activate-service-account --key-file ${HOME}/gcp-key.json --project ${GCLOUD_PROJECT_ID_STAGING}
               gcloud container clusters get-credentials ${GCLOUD_PROJECT_CLUSTER_ID_STAGING} \
        --zone ${GCLOUD_PROJECT_CLUSTER_ZONE_STAGING} \
        --project ${GCLOUD_PROJECT_ID_STAGING}
  displayName: 'Setup-staging_credentials'


- bash: bash ./deploy/deploy-all.sh staging
  displayName: 'Deploy_script_staging'

【问题讨论】:

    标签: azure-devops docker-layer


    【解决方案1】:

    这是我解决此问题的方法。我只是将最新版本的映像从我的注册表(在我的例子中为 Azure 容器注册表)拉到 Azure DevOps 托管代理。然后我将 --cache-from 添加到 Docker 构建参数中,指向它刚刚下载到本地机器/缓存的最新标签。

    - task: Docker@2
      inputs:
        containerRegistry: '$(ContainerRegistryName)'
        command: 'login'
    
    - script: "docker pull $(ACR_ADDRESS)/$(REPOSITORY):latest"
      displayName: Pull latest for layer caching
      continueOnError: true # for first build, no cache
    
    - task: Docker@2
      displayName: build
      inputs:
        containerRegistry: '$(ContainerRegistryName)'
        repository: '$(REPOSITORY)'
        command: 'build'
        Dockerfile: './dockerfile '
        buildContext: '$(BUILDCONTEXT)'
        arguments: '--cache-from=$(ACR_ADDRESS)/$(REPOSITORY):latest' 
        tags: |
          $(Build.BuildNumber)
          latest
    
    - task: Docker@2
      displayName: "push"
      inputs:
        command: push
        containerRegistry: "$(ContainerRegistryName)"
        repository: $(REPOSITORY) 
        tags: |
          $(Build.BuildNumber)
          latest
    

    【讨论】:

    • 这很完美。您也可以使用 docker 任务。
    • 你是个天才!附带说明一下,这也适用于 docker-compose,您只需在 docker-compose.yaml 中的 build 元素下指定 cache_from。
    • 完美!!!我使用的是 cache-from 而没有首先拉出最新的图像。你帮了我很多:D
    • 不幸的是,尽管成功拉取了最新的图像,但它仍然构建了所有应该缓存的阶段。我在这里提出了一个问题:stackoverflow.com/questions/69782647/…
    【解决方案2】:

    Azure DevOps 目前不支持 Docker 层缓存。 reason 声明如下:

    在 Microsoft 托管代理的当前设计中,每个作业都被分派到新配置的虚拟机。这些虚拟机在作业完成后被清理,不会持久化,因此不能重复用于后续作业。虚拟机的短暂性阻止了缓存 Docker 层的重用。

    但是:

    1. 使用自托管代理可以进行 Docker 层缓存。您可以尝试creating your on-premise agents 来运行您的构建管道。

      您可能需要禁用作业的选项“允许脚本访问 OAuth 令牌”。因为 $(System.AccessToken) 是使用 --build-arg ACCESS_TOKEN=$(System.AccessToken) 传递给 docker build 的,每次运行它的值都会变化,这会使缓存失效。

    2. 您也可以使用 Cache taskdocker save/load 命令将保存的 Docker 层上传到 Azure DevOps 服务器,并在以后运行时恢复它。查看此thread 了解更多信息。

    3. blog 中描述的另一种解决方法是在 Dockerfile 中使用 --cache-from 和 --target

    如果上述解决方法不满意,您可以向 Microsoft 开发团队提交 feature request。单击 Suggest a Feature 并选择 Azure DevOps

    【讨论】:

      【解决方案3】:

      编辑:正如 cmets 中所指出的,此功能实际上无需 BuildKit 即可使用。有一个示例 here 在构建期间如何使用 Docker 映像作为缓存源。

      通过将变量DOCKER_BUILDKIT: 1(参见this link)添加到管道作业并安装buildx,我设法通过将缓存存储为单独的图像来实现层缓存。见this link for some basics

      这是 Azure DevOps 中的一个示例步骤

      - script: |
          image="myreg.azurecr.io/myimage"
          tag=$(Build.SourceBranchName)-$(Build.SourceVersion)
          cache_tag=cache-$(Build.SourceBranchName)
      
          docker buildx create --use
          docker buildx build \
            -t "${image}:${tag}"
            --cache-from=type=registry,ref=${image}:${cache_tag}\
            --cache-to=type=registry,ref=${image}:${cache_tag},mode=max \
            --push \
            --progress=plain \
            .
        displayName: Build & push image using remote BuildKit layer cache
      

      这当然需要每次运行都下载映像缓存,但对于在 Docker 构建过程中具有长时间运行安装步骤的映像,这肯定会更快(在我们的例子中从大约 8 分钟到 2 分钟)。

      【讨论】:

      • 不确定为什么 a) buildkit 是必需的,也不是 buildx。您可以简单地从 reg 中提取目标图像。在构建和使用 cache-from 之前。所以如果我们构建fooimg:tag,我们在构建之前执行docker pull fooimg:tag,然后是docker build --cache-from fooimg:tag . -t fooimg:tag
      • 感谢分享。不知道他们将此功能添加到常规 Docker 引擎中。
      • 我真的很惊讶我以前没有听说过这个 - Github 上的原始线程没有提到使用 --cache-from:github.com/microsoft/azure-pipelines-tasks/issues/6439 ACR 层缓存上的线程(@987654325 @) 提到了 buildx,所以在阅读了 buildx 的文档后,我认为缓存机制是我们所需要的。
      • 请务必注意,使用 BUILDKIT:1 将要求您将 --build-arg BUILDKIT_INLINE_CACHE=1 添加到您的构建参数中,以支持将层缓存到远程注册表。
      • --cache-from 本身不适用于多阶段构建。实际上,您需要在最终映像中内联缓存以进行多阶段构建,以从 MS 托管代理上的缓存中受益。
      【解决方案4】:

      看起来微软不久前为 Azure Devops 引入了管道缓存,并且可以缓存 docker 层。 See this link.

      【讨论】:

      • 我认为这只是缓存最终的 docker 镜像,而不是中间层,所以它实际上并没有加速 Docker 构建(Docker 仍然会尝试重建中间层)。
      【解决方案5】:

      如果您不想将缓存推送到容器注册表,还可以在 Pipeline VM 中设置“本地”Docker 层缓存。您需要执行以下步骤:

      - task: Docker@2
        displayName: Login to ACR
        inputs:
          command: login
          containerRegistry: $(SERVICE_NAME)
      - task: Cache@2
        displayName: Cache task
        inputs:
          key: 'docker | "$(Agent.OS)" | "$(Build.SourceVersion)"'
          path: /tmp/.buildx-cache
          restoreKeys: 'docker | "$(Agent.OS)"'
      
      - bash: |
          docker buildx create --driver docker-container --use
          docker buildx build --cache-to type=local,dest=/tmp/.buildx-cache-new --cache-from type=local,src=/tmp/.buildx-cache --push --target cloud --tag $REGISTRY_NAME/$IMAGE_NAME:$TAG_NAME .
        displayName: Build Docker image
      
      # optional: set up deploy steps here
      
      - task: Docker@2
        displayName: Logout of ACR
        inputs:
          command: logout
          containerRegistry: $(SERVICE_NAME)
      

      这里的关键是设置 Docker buildx 并使用 --cache-to--cache-from 标志运行它,而不是使用 Azure Docker 任务。您还需要使用Cache 任务来确保在后续管道运行中重新加载 Docker 缓存,并且您必须设置手动交换步骤,其中新生成的缓存替换旧缓存。

      【讨论】:

        猜你喜欢
        • 2021-02-14
        • 1970-01-01
        • 2021-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-19
        • 1970-01-01
        相关资源
        最近更新 更多