如何使用 Azure Container Registry 工作來取用和維護公用內容

本文提供 Azure Container Registry 的工作流程樣本,可協助您管理公用內容的取用和維護狀況:

  1. 匯入相依公用映像的本機複本。
  2. 透過安全性掃描和功能測試來驗證公用映像。
  3. 將映像升階至私人登錄以供內部使用。
  4. 針對與公用內容相依的應用程式,觸發基礎映像更新。
  5. 使用 Azure Container Registry 工作將此工作流程自動化。

下圖為此工作流程的摘要說明:

Consuming public content Workflow

閘道匯入工作流程可協助您管理外部受控成品上的組織相依性。例如,來源為公用登錄的映像,包括 Docker HubGCRQuayGitHub Container RegistryMicrosoft Container Registry,甚至是其他 Azure 容器登錄

如需了解公用內容相依性所引發的風險背景資訊,以及如何使用 Azure Container Registry 來降低風險,請參閱 OCI 取用公用內容部落格文章使用 Azure Container Registry 管理公用內容

您可以使用 Azure Cloud Shell 或安裝在本機的 Azure CLI 來完成此逐步解說。 建議使用 Azure CLI 2.10 版或更新版本。 如果您需要安裝或升級,請參閱安裝 Azure CLI

案例概觀

import workflow components

本逐步解說將設定:

  1. 三個容器登錄,代表:
    • 模擬 Docker Hub (publicregistry) 以支援變更基礎映像
    • 小組登錄 (contoso) 以共用私人映像
    • 已匯入公用內容的公司/小組共用登錄 (baseartifacts)
  2. 每個登錄中的 ACR 工作。 工作:
    1. 建置模擬公用 node 映像
    2. node 映像匯入至公司/小組共用登錄並加以驗證
    3. 建置和部署 hello-world 映像
  3. ACR 工作定義,包括下列項目的設定:
  4. 登錄認證集合,即金鑰保存庫的指標
  5. 祕密集合,可在 acr-task.yaml 內取得,且為金鑰保存庫的指標
  6. 已設定值的集合,可在 acr-task.yaml 內使用
  7. 可保護所有祕密的 Azure 金鑰保存庫
  8. 可裝載 hello-world 建置應用程式的 Azure 容器執行個體

必要條件

下列步驟將設定逐步解說中所建立及使用的資源值。

設定環境變數

設定環境專屬的變數。 我們會遵循最佳做法,將含永久性內容的資源放在專屬的資源群組中,以盡可能減少意外刪除的情況。 但若有需要,您可以將這些項目放在單一資源群組中。

本文中的範例會針對 Bash 殼層進行格式化。

# Set the three registry names, must be globally unique:
REGISTRY_PUBLIC=publicregistry
REGISTRY_BASE_ARTIFACTS=contosobaseartifacts
REGISTRY=contoso

# set the location all resources will be created in:
RESOURCE_GROUP_LOCATION=eastus

# default resource groups
REGISTRY_PUBLIC_RG=${REGISTRY_PUBLIC}-rg
REGISTRY_BASE_ARTIFACTS_RG=${REGISTRY_BASE_ARTIFACTS}-rg
REGISTRY_RG=${REGISTRY}-rg

# fully qualified registry urls
REGISTRY_DOCKERHUB_URL=docker.io
REGISTRY_PUBLIC_URL=${REGISTRY_PUBLIC}.azurecr.io
REGISTRY_BASE_ARTIFACTS_URL=${REGISTRY_BASE_ARTIFACTS}.azurecr.io
REGISTRY_URL=${REGISTRY}.azurecr.io

# Azure key vault for storing secrets, name must be globally unique
AKV=acr-task-credentials
AKV_RG=${AKV}-rg

# ACI for hosting the deployed application
ACI=hello-world-aci
ACI_RG=${ACI}-rg

Git 存放庫和權杖

若要模擬您的環境,請將下列每個 Git 存放庫的建立派生至您可以管理的存放庫。

然後,更新派生存放庫的下列變數。

附加至 git URL 結尾的 :main 代表預設存放庫分支。

GIT_BASE_IMAGE_NODE=https://github.com/<your-fork>/base-image-node.git#main
GIT_NODE_IMPORT=https://github.com/<your-fork>/import-baseimage-node.git#main
GIT_HELLO_WORLD=https://github.com/<your-fork>/hello-world.git#main

您需要 GitHub 存取權杖 (PAT),才能讓 ACR 工作複製及建立 Git Webhook。 如需了解建立含私人存放庫所需權限的權杖步驟,請參閱建立 GitHub 存取權杖

GIT_TOKEN=<set-git-token-here>

Docker Hub 認證

若要迴避從 Docker Hub 提取映像時的節流和身分識別要求,請建立 Docker Hub 權杖。 接下來,請設定下列環境變數:

REGISTRY_DOCKERHUB_USER=<yourusername>
REGISTRY_DOCKERHUB_PASSWORD=<yourtoken>

建立登錄

使用 Azure CLI 命令來建立三個進階層容器登錄,且每個容器登錄都有自己的資源群組:

az group create --name $REGISTRY_PUBLIC_RG --location $RESOURCE_GROUP_LOCATION
az acr create --resource-group $REGISTRY_PUBLIC_RG --name $REGISTRY_PUBLIC --sku Premium

az group create --name $REGISTRY_BASE_ARTIFACTS_RG --location $RESOURCE_GROUP_LOCATION
az acr create --resource-group $REGISTRY_BASE_ARTIFACTS_RG --name $REGISTRY_BASE_ARTIFACTS --sku Premium

az group create --name $REGISTRY_RG --location $RESOURCE_GROUP_LOCATION
az acr create --resource-group $REGISTRY_RG --name $REGISTRY --sku Premium

建立金鑰保存庫並設定祕密

建立金鑰保存庫:

az group create --name $AKV_RG --location $RESOURCE_GROUP_LOCATION
az keyvault create --resource-group $AKV_RG --name $AKV

在金鑰保存庫中設定 Docker Hub 使用者名稱和權杖:

az keyvault secret set \
--vault-name $AKV \
--name registry-dockerhub-user \
--value $REGISTRY_DOCKERHUB_USER

az keyvault secret set \
--vault-name $AKV \
--name registry-dockerhub-password \
--value $REGISTRY_DOCKERHUB_PASSWORD

在金鑰保存庫中設定並驗證 Git PAT:

az keyvault secret set --vault-name $AKV --name github-token --value $GIT_TOKEN

az keyvault secret show --vault-name $AKV --name github-token --query value -o tsv

建立 Azure 容器執行個體的資源群組

部署 hello-world 映像時,此資源群組會在稍後的工作中使用。

az group create --name $ACI_RG --location $RESOURCE_GROUP_LOCATION

建立公用 node 基礎映像

若要模擬 Docker Hub 上的 node 映像,請建立 ACR 工作以建置和維護公用映像。 此設定允許使用 node 映像維護程式來模擬變更。

az acr task create \
  --name node-public \
  -r $REGISTRY_PUBLIC \
  -f acr-task.yaml \
  --context $GIT_BASE_IMAGE_NODE \
  --git-access-token $(az keyvault secret show \
                        --vault-name $AKV \
                        --name github-token \
                        --query value -o tsv) \
  --set REGISTRY_FROM_URL=${REGISTRY_DOCKERHUB_URL}/ \
  --assign-identity

若要迴避 Docker 節流,請將 Docker Hub 認證新增至工作。 acr 工作認證命令可用來將 Docker 認證傳遞至任何登錄,包括 Docker Hub。

az acr task credential add \
  -n node-public \
  -r $REGISTRY_PUBLIC \
  --login-server $REGISTRY_DOCKERHUB_URL \
  -u https://${AKV}.vault.azure.net/secrets/registry-dockerhub-user \
  -p https://${AKV}.vault.azure.net/secrets/registry-dockerhub-password \
  --use-identity [system]

從金鑰保存庫授與工作讀取值的權限:

az keyvault set-policy \
  --name $AKV \
  --resource-group $AKV_RG \
  --object-id $(az acr task show \
                  --name node-public \
                  --registry $REGISTRY_PUBLIC \
                  --query identity.principalId --output tsv) \
  --secret-permissions get

觸發工作的方法包括 Git 認可、基礎映像更新、計時器或手動執行。

手動執行工作以產生 node 映像:

az acr task run -r $REGISTRY_PUBLIC -n node-public

列出模擬公用登錄中的映像:

az acr repository show-tags -n $REGISTRY_PUBLIC --repository node

建立 hello-world 映像

根據模擬的公用 node 映像來建置 hello-world 映像。

建立權杖以取得模擬公用登錄的提取權

建立模擬公用登錄的存取權杖,範圍則設為 pull。 然後在金鑰保存庫中加以設定:

az keyvault secret set \
  --vault-name $AKV \
  --name "registry-${REGISTRY_PUBLIC}-user" \
  --value "registry-${REGISTRY_PUBLIC}-user"

az keyvault secret set \
  --vault-name $AKV \
  --name "registry-${REGISTRY_PUBLIC}-password" \
  --value $(az acr token create \
              --name "registry-${REGISTRY_PUBLIC}-user" \
              --registry $REGISTRY_PUBLIC \
              --scope-map _repositories_pull \
              -o tsv \
              --query credentials.passwords[0].value)

透過 Azure 容器執行個體建立提取權的權杖

建立裝載 hello-world 映像的登錄存取權杖,範圍則設為提取。 然後在金鑰保存庫中加以設定:

az keyvault secret set \
  --vault-name $AKV \
  --name "registry-${REGISTRY}-user" \
  --value "registry-${REGISTRY}-user"

az keyvault secret set \
  --vault-name $AKV \
  --name "registry-${REGISTRY}-password" \
  --value $(az acr token create \
              --name "registry-${REGISTRY}-user" \
              --registry $REGISTRY \
              --repository hello-world content/read \
              -o tsv \
              --query credentials.passwords[0].value)

建立工作以建置和維護 hello-world 映像

下列命令會透過 hello-world 存放庫 acr-tasks.yaml 中的定義來建立工作。 工作步驟會建置 hello-world 映像,然後將其部署至 Azure 容器執行個體。 Azure 容器執行個體的資源群組已於上一節建立。 藉由在工作中呼叫 az container create,且只有 image:tag 處有差異,工作就可在整個逐步解說流程中部署到相同的執行個體。

az acr task create \
  -n hello-world \
  -r $REGISTRY \
  -f acr-task.yaml \
  --context $GIT_HELLO_WORLD \
  --git-access-token $(az keyvault secret show \
                        --vault-name $AKV \
                        --name github-token \
                        --query value -o tsv) \
  --set REGISTRY_FROM_URL=${REGISTRY_PUBLIC_URL}/ \
  --set KEYVAULT=$AKV \
  --set ACI=$ACI \
  --set ACI_RG=$ACI_RG \
  --assign-identity

將認證新增至模擬公用登錄的工作:

az acr task credential add \
  -n hello-world \
  -r $REGISTRY \
  --login-server $REGISTRY_PUBLIC_URL \
  -u https://${AKV}.vault.azure.net/secrets/registry-${REGISTRY_PUBLIC}-user \
  -p https://${AKV}.vault.azure.net/secrets/registry-${REGISTRY_PUBLIC}-password \
  --use-identity [system]

從金鑰保存庫授與工作讀取值的權限:

az keyvault set-policy \
  --name $AKV \
  --resource-group $AKV_RG \
  --object-id $(az acr task show \
                  --name hello-world \
                  --registry $REGISTRY \
                  --query identity.principalId --output tsv) \
  --secret-permissions get

透過授與資源群組存取權,即可授與工作存取權,以建立和管理 Azure 容器執行個體:

az role assignment create \
  --assignee $(az acr task show \
  --name hello-world \
  --registry $REGISTRY \
  --query identity.principalId --output tsv) \
  --scope $(az group show -n $ACI_RG --query id -o tsv) \
  --role owner

建立並設定工作後,請執行工作以建置和部署 hello-world 映像:

az acr task run -r $REGISTRY -n hello-world

建立後,請取得裝載 hello-world 映像的容器 IP 位址。

az container show \
  --resource-group $ACI_RG \
  --name ${ACI} \
  --query ipAddress.ip \
  --out tsv

請在瀏覽器中前往 IP 位址查看執行中的應用程式。

使用「有問題」變更來更新基礎映像

本節將模擬可能會造成環境問題的基礎映像變更。

  1. 在派生的 base-image-node 存放庫中開啟 Dockerfile
  2. BACKGROUND_COLOR 變更為 Orange 以模擬變更。
ARG REGISTRY_NAME=
FROM ${REGISTRY_NAME}node:15-alpine
ENV NODE_VERSION 15-alpine
ENV BACKGROUND_COLOR Orange

認可變更並監看 ACR 工作以自動開始建置。

監看開始執行的工作:

watch -n1 az acr task list-runs -r $REGISTRY_PUBLIC -o table

根據觸發程序 Commit,您最終應該會看到狀態 Succeeded

RUN ID    TASK      PLATFORM    STATUS     TRIGGER    STARTED               DURATION
--------  --------  ----------  ---------  ---------  --------------------  ----------
ca4       hub-node  linux       Succeeded  Commit     2020-10-24T05:02:29Z  00:00:22

輸入 Ctrl+C 以結束監看命令,然後檢視最近執行的記錄:

az acr task logs -r $REGISTRY_PUBLIC

node 映像完成後,請針對 ACR 工作執行 watch,系統會自動開始建置 hello-world 映像:

watch -n1 az acr task list-runs -r $REGISTRY -o table

根據觸發程序 Image Update,您最終應該會看到狀態 Succeeded

RUN ID    TASK         PLATFORM    STATUS     TRIGGER       STARTED               DURATION
--------  -----------  ----------  ---------  ------------  --------------------  ----------
dau       hello-world  linux       Succeeded  Image Update  2020-10-24T05:08:45Z  00:00:31

輸入 Ctrl+C 以結束監看命令,然後檢視最近執行的記錄:

az acr task logs -r $REGISTRY

完成後,請取得裝載更新 hello-world 映像的網站 IP 位址:

az container show \
  --resource-group $ACI_RG \
  --name ${ACI} \
  --query ipAddress.ip \
  --out tsv

在您的瀏覽器中前往網站,該網站的背景應該為橘色 (代表有問題)。

簽入

此時,您已建立在 Git 認可上自動建置,且變更為基礎 node 映像的 hello-world 映像。 在此範例中,工作會針對 Azure Container Registry 中的基礎映像加以建置,但任何支援的登錄也可以使用。

基礎映像更新會在 node 映像更新時,自動重新觸發工作執行。 如這裡所示,並非所有的更新都是需要的。

公用內容的閘道匯入

若要防止上游變更中斷重大工作負載,您可以新增安全性掃描和功能測試。

在本節中,您將建立 ACR 工作以達成下列目標:

  • 建置測試映像
  • 針對測試映像執行功能測試指令碼 ./test.sh
  • 如果映像測試成功,請將公用映像匯入 baseimages 登錄

新增自動化測試

實作自動化測試是為了透過閘道控制所有上游內容。 在此範例中,系統會提供 test.sh 以檢查 $BACKGROUND_COLOR。 如果測試失敗,系統就會傳回 1EXIT_CODE,這會造成 ACR 工作步驟失敗並結束工作執行。 測試可以任何工具形式展開,包括記錄結果。 閘道是由指令碼中的傳遞/失敗回應所管理,於此處重現:

if [ ""$(echo $BACKGROUND_COLOR | tr '[:lower:]' '[:upper:]') = 'RED' ]; then
    echo -e "\e[31mERROR: Invalid Color:\e[0m" ${BACKGROUND_COLOR}
    EXIT_CODE=1
else
  echo -e "\e[32mValidation Complete - No Known Errors\e[0m"
fi
exit ${EXIT_CODE}

工作 YAML

檢閱 import-baseimage-node 存放庫中的 acr-task.yaml,其會執行下列步驟:

  1. 使用下列 Dockerfile 建置測試基礎映像:
    ARG REGISTRY_FROM_URL=
    FROM ${REGISTRY_FROM_URL}node:15-alpine
    WORKDIR /test
    COPY ./test.sh .
    CMD ./test.sh
    
  2. 完成後,請執行容器來驗證映像,該容器將執行 ./test.sh
  3. 只有在順利完成時才可執行匯入步驟,其由 when: ['validate-base-image'] 透過閘道控制
version: v1.1.0
steps:
  - id: build-test-base-image
    # Build off the base image we'll track
    # Add a test script to do unit test validations
    # Note: the test validation image isn't saved to the registry
    # but the task logs captures log validation results
    build: >
      --build-arg REGISTRY_FROM_URL={{.Values.REGISTRY_FROM_URL}}
      -f ./Dockerfile
      -t {{.Run.Registry}}/node-import:test
      .
  - id: validate-base-image
    # only continues if node-import:test returns a non-zero code
    when: ['build-test-base-image']
    cmd: "{{.Run.Registry}}/node-import:test"
  - id: pull-base-image
    # import the public image to base-artifacts
    # Override the stable tag,
    # and create a unique tag to enable rollback
    # to a previously working image
    when: ['validate-base-image']
    cmd: >
        docker pull {{.Values.REGISTRY_FROM_URL}}node:15-alpine
  - id: retag-base-image
    when: ['pull-base-image']
    cmd: docker tag {{.Values.REGISTRY_FROM_URL}}node:15-alpine {{.Run.Registry}}/node:15-alpine
  - id: retag-base-image-unique-tag
    when: ['pull-base-image']
    cmd: docker tag {{.Values.REGISTRY_FROM_URL}}node:15-alpine {{.Run.Registry}}/node:15-alpine-{{.Run.ID}}
  - id: push-base-image
    when: ['retag-base-image', 'retag-base-image-unique-tag']
    push:
    - "{{.Run.Registry}}/node:15-alpine"
    - "{{.Run.Registry}}/node:15-alpine-{{.Run.ID}}"

建立工作以匯入和測試基礎映像

  az acr task create \
  --name base-import-node \
  -f acr-task.yaml \
  -r $REGISTRY_BASE_ARTIFACTS \
  --context $GIT_NODE_IMPORT \
  --git-access-token $(az keyvault secret show \
                        --vault-name $AKV \
                        --name github-token \
                        --query value -o tsv) \
  --set REGISTRY_FROM_URL=${REGISTRY_PUBLIC_URL}/ \
  --assign-identity

將認證新增至模擬公用登錄的工作:

az acr task credential add \
  -n base-import-node \
  -r $REGISTRY_BASE_ARTIFACTS \
  --login-server $REGISTRY_PUBLIC_URL \
  -u https://${AKV}.vault.azure.net/secrets/registry-${REGISTRY_PUBLIC}-user \
  -p https://${AKV}.vault.azure.net/secrets/registry-${REGISTRY_PUBLIC}-password \
  --use-identity [system]

從金鑰保存庫授與工作讀取值的權限:

az keyvault set-policy \
  --name $AKV \
  --resource-group $AKV_RG \
  --object-id $(az acr task show \
                  --name base-import-node \
                  --registry $REGISTRY_BASE_ARTIFACTS \
                  --query identity.principalId --output tsv) \
  --secret-permissions get

執行匯入工作:

az acr task run -n base-import-node -r $REGISTRY_BASE_ARTIFACTS

注意

如果工作因為 ./test.sh: Permission denied 而失敗,請確定指令碼具有執行權限,並認可回 Git 存放庫:

chmod +x ./test.sh

更新 hello-world 映像即可從閘道 node 映像建置

建立存取權杖即可存取基礎成品登錄,請透過 node 存放庫將範圍設為 read。 然後,在金鑰保存庫中設定下列內容:

az keyvault secret set \
  --vault-name $AKV \
  --name "registry-${REGISTRY_BASE_ARTIFACTS}-user" \
  --value "registry-${REGISTRY_BASE_ARTIFACTS}-user"

az keyvault secret set \
  --vault-name $AKV \
  --name "registry-${REGISTRY_BASE_ARTIFACTS}-password" \
  --value $(az acr token create \
              --name "registry-${REGISTRY_BASE_ARTIFACTS}-user" \
              --registry $REGISTRY_BASE_ARTIFACTS \
              --repository node content/read \
              -o tsv \
              --query credentials.passwords[0].value)

將認證新增至基礎成品登錄的 hello-world 工作:

az acr task credential add \
  -n hello-world \
  -r $REGISTRY \
  --login-server $REGISTRY_BASE_ARTIFACTS_URL \
  -u https://${AKV}.vault.azure.net/secrets/registry-${REGISTRY_BASE_ARTIFACTS}-user \
  -p https://${AKV}.vault.azure.net/secrets/registry-${REGISTRY_BASE_ARTIFACTS}-password \
  --use-identity [system]

更新工作即可變更 REGISTRY_FROM_URL 以使用 BASE_ARTIFACTS 登錄

az acr task update \
  -n hello-world \
  -r $REGISTRY \
  --set KEYVAULT=$AKV \
  --set REGISTRY_FROM_URL=${REGISTRY_BASE_ARTIFACTS_URL}/ \
  --set ACI=$ACI \
  --set ACI_RG=$ACI_RG

執行 hello-world 工作來變更其基礎映像相依性:

az acr task run -r $REGISTRY -n hello-world

使用「有效」變更更新基礎映像

  1. 開啟 base-image-node 存放庫中的 Dockerfile
  2. BACKGROUND_COLOR 變更為 Green 以模擬有效的變更。
ARG REGISTRY_NAME=
FROM ${REGISTRY_NAME}node:15-alpine
ENV NODE_VERSION 15-alpine
ENV BACKGROUND_COLOR Green

認可變更並監視更新序列:

watch -n1 az acr task list-runs -r $REGISTRY_PUBLIC -o table

執行後,請輸入 Ctrl+C 並監視記錄:

az acr task logs -r $REGISTRY_PUBLIC

完成後,請監視 base-image-import 工作:

watch -n1 az acr task list-runs -r $REGISTRY_BASE_ARTIFACTS -o table

執行後,請輸入 Ctrl+C 並監視記錄:

az acr task logs -r $REGISTRY_BASE_ARTIFACTS

完成後,請監視 hello-world 工作:

watch -n1 az acr task list-runs -r $REGISTRY -o table

執行後,請輸入 Ctrl+C 並監視記錄:

az acr task logs -r $REGISTRY

完成後,請取得裝載更新 hello-world 映像的網站 IP 位址:

az container show \
  --resource-group $ACI_RG \
  --name ${ACI} \
  --query ipAddress.ip \
  --out tsv

在您的瀏覽器中前往網站,該網站的背景應該為綠色 (代表有效)。

檢視閘道工作流程

再次執行上一節的步驟,背景為紅色。

  1. 在存放庫 base-image-node 中開啟 Dockerfile
  2. BACKGROUND_COLOR 變更為 Red 以模擬無效的變更。
ARG REGISTRY_NAME=
FROM ${REGISTRY_NAME}node:15-alpine
ENV NODE_VERSION 15-alpine
ENV BACKGROUND_COLOR Red

認可變更並監視更新序列:

watch -n1 az acr task list-runs -r $REGISTRY_PUBLIC -o table

執行後,請輸入 Ctrl+C 並監視記錄:

az acr task logs -r $REGISTRY_PUBLIC

完成後,請監視 base-image-import 工作:

watch -n1 az acr task list-runs -r $REGISTRY_BASE_ARTIFACTS -o table

執行後,請輸入 Ctrl+C 並監視記錄:

az acr task logs -r $REGISTRY_BASE_ARTIFACTS

此時,您應該會看到 base-import-node 工作驗證失敗,並停止序列以發佈 hello-world 更新。 輸出會類似:

[...]
2020/10/30 03:57:39 Launching container with name: validate-base-image
Validating Image
NODE_VERSION: 15-alpine
BACKGROUND_COLOR: Red
ERROR: Invalid Color: Red
2020/10/30 03:57:40 Container failed during run: validate-base-image. No retries remaining.
failed to run step ID: validate-base-image: exit status 1

發佈更新至 hello-world

hello-world 映像的變更將繼續使用最後一個已驗證的 node 映像。

任何通過閘道驗證的基礎 node 映像額外變更,都會觸發 hello-world 映像的基礎映像更新。

清除

如果不再需要本文中使用的資源,請予以刪除。

az group delete -n $REGISTRY_RG --no-wait -y
az group delete -n $REGISTRY_PUBLIC_RG --no-wait -y
az group delete -n $REGISTRY_BASE_ARTIFACTS_RG --no-wait -y
az group delete -n $AKV_RG --no-wait -y
az group delete -n $ACI_RG --no-wait -y

下一步

本文內容: 您使用了 ACR 工作來建立自動化閘道工作流程,以將更新的基礎映像引入您的環境。 請參閱相關資訊,了解如何在 Azure Container Registry 中管理映像。