教程:在更新另一个专用 Azure 容器注册表中的基础映像时自动化容器映像生成

Azure 任务支持在容器的基础映像更新时(例如在某个基础映像中修补 OS 或应用程序框架时)自动化映像生成。

本教程介绍在将容器的基础映像推送到另一个 Azure 容器注册表时,如何创建在云中触发生成的 ACR 任务。 你还可以尝试在某篇教程中学习如何创建 ACR 任务,以便在将基本映像推送到同一 Azure 容器注册表时触发映像生成。

本教程的内容:

  • 在基础注册表中生成基础映像
  • 在另一注册表中创建应用程序生成任务以跟踪基础映像
  • 更新基础映像以触发应用程序映像任务
  • 显示已触发的任务
  • 验证已更新的应用程序映像

先决条件

完成前一篇教程

本教程假定你已配置环境并完成本系列前两个教程中的步骤,其中包括:

  • 创建 Azure 容器注册表
  • 创建示例存储库分支
  • 克隆示例存储库
  • 创建 GitHub 个人访问令牌

在继续之前,请先完成以下教程(如果尚未完成):

使用 Azure 容器注册表任务在云中生成容器映像

使用 Azure 容器注册表任务自动化容器映像生成

除了为前面的教程创建的容器注册表以外,还需要创建一个注册表来存储基础映像。 如果需要,请在与原始注册表不同的位置创建第二个注册表。

配置环境

使用适用于环境的值填充这些 shell 环境变量。 此步骤并非必须执行的步骤,但它能让在此教程中执行多个 Azure CLI 命令更容易。 如果未填充这些环境变量,则每当示例命令中出现每个值,都必须手动替换该值。

注意

必须使用 az acr build 功能来完成本教程的其余部分,目前只有 China East 2 区域支持 Azure 中国世纪互联上的 az acr build 功能。

请注意,在后续步骤中尝试调用 az acr build 之前,请先提前在 China East 2 区域中创建容器注册表。

BASE_ACR=<base-registry-name>   # The name of your Azure container registry for base images
ACR_NAME=<registry-name>        # The name of your Azure container registry for application images
GIT_USER=<github-username>      # Your GitHub user account name
GIT_PAT=<personal-access-token> # The PAT you generated in the second tutorial

基础映像更新方案

本教程将指导完成基础映像更新方案。 此方案反映了在其他注册表中创建应用程序映像时,在团队共用的专用容器注册表中管理基础映像的开发工作流。 该基础映像可以指定团队共用的操作系统和框架,甚至可以指定共用的服务组件。

例如,在自己注册表中开发应用程序映像的开发人员可以访问共用基础注册表中维护的一组基础映像。 基础注册表可以位于另一区域,甚至可以异地复制。

代码示例包括两个 Dockerfile:一个应用程序映像和一个它指定为其基础的映像。 在以下部分,你将创建一个 ACR 任务,用于在将新版基础映像推送到不同 Azure 容器注册表时自动触发应用程序映像的生成。

  • Dockerfile-app:小型 Node.js Web 应用程序,它呈现一个静态 Web 页面,其中显示该应用程序所基于的 Node.js 版本。 该版本字符串是模拟的:显示基础映像中定义的环境变量和 NODE_VERSION 的内容。

  • Dockerfile-baseDockerfile-app 指定为其基础的映像。 它本身基于节点映像,并且包括 NODE_VERSION 环境变量。

在以下部分,我们将创建一个任务,在基础映像 Dockerfile 中更新 NODE_VERSION 值,并使用 ACR 任务来生成基础映像。 ACR 任务将新基础映像推送到注册表时,它会自动触发应用程序映像的生成。 可选择本地运行应用程序容器映像,在生成的映像中查看不同版本字符串。

在本教程中,ACR 任务会生成并推送在 Dockerfile 中指定的应用程序容器映像。 ACR 任务也可运行多步骤任务,使用 YAML 文件来定义相关步骤,以便生成并推送多个容器,并可选择对其进行测试。

生成基础映像

首先使用 az acr build 通过 ACR 任务“快速任务”来生成基础映像。 如本系列教程的第一篇教程中所述,如果生成成功,则此过程不仅会生成映像,还会将其推送到容器注册表。 在此示例中,映像将推送到基础映像注册表。

az acr build --registry $BASE_ACR --image baseimages/node:15-alpine --file Dockerfile-base .

创建一个任务来跟踪专用基础映像

接下来,使用 az acr task create 在应用程序映像注册表中创建一个启用托管标识的任务。 在后续步骤中将使用该托管标识,使任务能够在基础映像注册表中进行身份验证。

此示例使用系统分配的标识,但你可以为特定的方案创建并启用用户分配的托管标识。 有关详细信息,请参阅使用 Azure 托管标识在 ACR 任务中进行跨注册表的身份验证

az acr task create \
    --registry $ACR_NAME \
    --name baseexample2 \
    --image helloworld:{{.Run.ID}} \
    --context https://github.com/$GIT_USER/acr-build-helloworld-node.git#main \
    --file Dockerfile-app \
    --git-access-token $GIT_PAT \
    --arg REGISTRY_NAME=$BASE_ACR.azurecr.cn \
    --assign-identity

此任务类似于上一篇教程中创建的任务。 将提交内容推送到 --context 指定的存储库时,生成任务会指示 ACR 任务触发映像生成。 在前一篇教程用于生成映像的 Dockerfile 指定了公共基础映像 (FROM node:15-alpine),而此任务中的 Dockerfile Dockerfile-app 指定的是基础映像注册表中的基础映像:

FROM ${REGISTRY_NAME}/baseimages/node:15-alpine

使用此配置可以轻松模拟稍后在本教程中对基础映像进行的框架修补。

为标识授予对基础注册表的提取权限

若要为任务的托管标识授予从基础映像注册表提取映像的权限,请先运行 az acr task show 获取标识的服务主体 ID。 然后运行 az acr show 获取基础注册表的资源 ID:

# Get service principal ID of the task
principalID=$(az acr task show --name baseexample2 --registry $ACR_NAME --query identity.principalId --output tsv) 

# Get resource ID of the base registry
baseregID=$(az acr show --name $BASE_ACR --query id --output tsv) 

运行 az role assignment create,为托管标识分配对注册表的提取权限:

az role assignment create \
  --assignee $principalID \
  --scope $baseregID --role acrpull 

将目标注册表凭据添加到任务

运行 az acr task credential add 将凭据添加到任务。 传递 --use-identity [system] 参数,指示任务的系统分配的托管标识可以访问凭据。

az acr task credential add \
  --name baseexample2 \
  --registry $ACR_NAME \
  --login-server $BASE_ACR.azurecr.cn \
  --use-identity [system] 

手动运行任务

使用 az acr task run 手动触发任务并生成应用程序映像。 此步骤是必需的,这样该任务才能跟踪应用程序映像对基础映像的依赖性。

az acr task run --registry $ACR_NAME --name baseexample2

任务完成后,如果还要完成以下可选步骤,请记下“运行 ID”(例如“da6”) 。

可选:本地运行应用程序容器

如果是在本地运行,并且已安装 Docker,请运行容器,以查看 Web 浏览器中呈现的应用程序,然后再重新生成其基础映像。

首先,使用 az acr login 在容器注册表中进行身份验证:

az acr login --name $ACR_NAME

然后,使用 docker run 在本地运行容器。 将 <run-id> 替换为上一步骤的输出中的“运行 ID”(例如“da6”)。 此示例将容器命名为 myapp,并包含 --rm 参数,以便在停止容器后将其删除。

docker run -d -p 8080:80 --name myapp --rm $ACR_NAME.azurecr.cn/helloworld:<run-id>

在浏览器中导航到 http://localhost:8080,应看见呈现在 Web 页面中的 Node.js 版本号,如下所示。 在稍后的步骤中,会通过向版本字符串中添加“a”来提升版本。

Screenshot of sample application in browser

若要停止并删除容器,请运行以下命令:

docker stop myapp

列出生成

接下来,使用 az acr task list-runs 命令列出 ACR 任务对注册表完成的任务运行:

az acr task list-runs --registry $ACR_NAME --output table

如果已完成之前的教程(并且没有删除注册表),应看到如下所示的输出。 记下任务运行的数目以及最新的运行 ID,以便在后续部分中更新基础映像后对比输出。

az acr task list-runs --registry $ACR_NAME --output table
RUN ID    TASK            PLATFORM    STATUS     TRIGGER       STARTED               DURATION
--------  --------------  ----------  ---------  ----------    --------------------  ----------
ca12      baseexample2    linux       Succeeded  Manual        2020-11-21T00:00:56Z  00:00:36
ca11      baseexample1    linux       Succeeded  Image Update  2020-11-20T23:38:24Z  00:00:34
ca10      taskhelloworld  linux       Succeeded  Image Update  2020-11-20T23:38:24Z  00:00:24
cay                       linux       Succeeded  Manual        2020-11-20T23:38:08Z  00:00:22
cax       baseexample1    linux       Succeeded  Manual        2020-11-20T23:33:12Z  00:00:30
caw       taskhelloworld  linux       Succeeded  Commit        2020-11-20T23:16:07Z  00:00:29

更新基础映像

在这里模拟基础映像中的框架补丁。 编辑“Dockerfile-base”,并在 NODE_VERSION 中定义的版本号后面添加一个“a” :

ENV NODE_VERSION 15.2.1a

运行快速任务来生成修改后的基础映像。 记下输出中的“运行 ID” 。

az acr build --registry $BASE_ACR --image baseimages/node:15-alpine --file Dockerfile-base .

生成完成并且 ACR 任务将新基础映像推送到注册表后,它会触发应用程序映像的生成。 之前创建的任务触发应用程序映像生成可能需要一些时间,因为它必须检测新生成和推送的基础映像。

列出已更新的生成

更新基础映像后,请再次列出任务运行,以便与之前的列表进行比较。 如果开始时输出没有区别,可定期运行该命令以查看出现在列表中的新任务运行。

az acr task list-runs --registry $ACR_NAME --output table

输出如下所示。 最后执行的生成的触发器应为“映像更新”,指示任务是通过基础映像的快速任务启动的。

az acr task list-runs --registry $ACR_NAME --output table
Run ID    TASK            PLATFORM    STATUS     TRIGGER       STARTED               DURATION
--------  --------------  ----------  ---------  ------------  --------------------  ----------
ca13      baseexample2    linux       Succeeded  Image Update  2020-11-21T00:06:00Z  00:00:43
ca12      baseexample2    linux       Succeeded  Manual        2020-11-21T00:00:56Z  00:00:36
ca11      baseexample1    linux       Succeeded  Image Update  2020-11-20T23:38:24Z  00:00:34
ca10      taskhelloworld  linux       Succeeded  Image Update  2020-11-20T23:38:24Z  00:00:24
cay                       linux       Succeeded  Manual        2020-11-20T23:38:08Z  00:00:22
cax       baseexample1    linux       Succeeded  Manual        2020-11-20T23:33:12Z  00:00:30
caw       taskhelloworld  linux       Succeeded  Commit        2020-11-20T23:16:07Z  00:00:29

如果想要执行以下可选步骤运行新生成的容器,以查看更新的版本号,请记下映像更新触发的生成的“运行 ID”值(在之前的输出中为“ca13”)。

可选:运行新生成的映像

如果正在本地运行并且已安装 Docker,请在新应用程序映像的生成完成后运行它。 将 <run-id> 替换为上一步骤中获取的“运行 ID”。

docker run -d -p 8081:80 --name updatedapp --rm $ACR_NAME.azurecr.cn/helloworld:<run-id>

在浏览器中导航到 http://localhost:8081 ,应看见网页上显示有更新后的 Node.js 版本编号(带有“a”):

Screenshot of updated sample application in browser

请务必注意,使用新版本号更新“基础”映像,但是最后生成的“应用程序”映像显示新版本 。 ACR 任务选取了对基础映像的更改,并自动重新生成了应用程序映像。

若要停止并删除容器,请运行以下命令:

docker stop updatedapp

后续步骤

在本教程中,我们已了解在更新映像的基础映像后,如何使用任务来自动触发容器映像生成。 现在,请转到下一个教程学习如何按照定义的计划触发任务。