你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

适用于 Python 的Azure 容器注册表客户端库 - 版本 1.2.0

Azure 容器注册表允许在专用注册表中存储和管理所有类型的容器部署的容器映像和项目。

使用 Azure 容器注册表客户端库执行以下操作:

  • 列出注册表中的映像或项目
  • 获取图像和项目、存储库和标记的元数据
  • 设置注册表项的读取/写入/删除属性
  • 删除映像和项目、存储库和标记

源代码 | 包 (Pypi) | 包 (Conda) | API 参考文档 | REST API 文档 | 产品文档

免责声明

对 Python 2.7 的 Azure SDK Python 包支持已于 2022 年 1 月 1 日结束。 有关详细信息和问题,请参阅 https://github.com/Azure/azure-sdk-for-python/issues/20691使用此包需要 Python 3.7 或更高版本。有关更多详细信息,请参阅 Azure SDK for Python 版本支持策略

入门

安装包

使用 pip 安装适用于 Python 的 Azure 容器注册表客户端库:

pip install --pre azure-containerregistry

先决条件

若要创建新的容器注册表,可以使用 Azure 门户Azure PowerShellAzure CLI。 下面是使用 Azure CLI 的示例:

az acr create --name MyContainerRegistry --resource-group MyResourceGroup --location westus --sku Basic

验证客户端

Azure 标识库为身份验证提供简单的 Azure Active Directory 支持。 假设设置了 、 AZURE_TENANT_IDAZURE_CLIENT_SECRET 环境变量,有关详细信息,请参阅 Azure 标识环境变量部分AZURE_CLIENT_IDDefaultAzureCredential

# Create a ContainerRegistryClient that will authenticate through Active Directory
from azure.containerregistry import ContainerRegistryClient
from azure.identity import DefaultAzureCredential

endpoint = "https://mycontainerregistry.azurecr.io"
audience = "https://management.azure.com"
client = ContainerRegistryClient(endpoint, DefaultAzureCredential(), audience=audience)

关键概念

注册表存储 Docker 映像和 OCI 项目。 映像或项目由清单和各层组成 。 映像清单描述构成映像的层,并由其 摘要唯一标识。 还可以对图像进行“标记”,以为其提供可读别名。 图像或项目可以有零个或多个与之关联的 标记 ,并且每个标记唯一标识图像。 共享同名但标记不同的映像集合称为 存储库

有关详细信息,请参阅 容器注册表概念

示例

以下部分提供了几个代码片段,涵盖了一些最常见的 ACR 服务任务,包括:

请注意,每个示例都假定有一个 CONTAINERREGISTRY_ENDPOINT 环境变量设置为包含 https:// 登录服务器前缀和名称的字符串,例如“https://myregistry.azurecr.io"”。 匿名访问示例正在从环境变量CONTAINERREGISTRY_ANONREGISTRY_ENDPOINT获取终结点值。

列出存储库

循环访问注册表中的存储库集合。

with ContainerRegistryClient(self.endpoint, self.credential) as client:
    # Iterate through all the repositories
    for repository_name in client.list_repository_names():
        print(repository_name)

列出具有匿名访问的标记

使用匿名访问权限循环访问存储库中的标记集合。

with ContainerRegistryClient(endpoint) as anon_client:
    manifest = anon_client.get_manifest_properties("library/hello-world", "latest")
    print(f"Tags of {manifest.repository_name}: ")
    # Iterate through all the tags
    for tag in manifest.tags:
        print(tag)

编辑项目属性

设置项目的属性。

with ContainerRegistryClient(self.endpoint, self.credential) as client:
    # Set permissions on image "library/hello-world:v1"
    client.update_manifest_properties(
        "library/hello-world",
        "v1",
        can_write=False,
        can_delete=False
    )

删除映像

删除存储库中早于前三个映像的映像。

with ContainerRegistryClient(self.endpoint, self.credential) as client:
    for repository in client.list_repository_names():
        # Keep the three most recent images, delete everything else
        manifest_count = 0
        for manifest in client.list_manifest_properties(
            repository, order_by=ArtifactManifestOrder.LAST_UPDATED_ON_DESCENDING
        ):
            manifest_count += 1
            if manifest_count > 3:
                # Make sure will have the permission to delete the manifest later
                client.update_manifest_properties(
                    repository,
                    manifest.digest,
                    can_write=True,
                    can_delete=True
                )
                print(f"Deleting {repository}:{manifest.digest}")
                client.delete_manifest(repository, manifest.digest)

上传图像

若要上传完整映像,需要上传各个层和配置。 之后,我们可以上传描述图像或项目的清单,并为其分配标记。

self.repository_name = "sample-oci-image"
layer = BytesIO(b"Sample layer")
config = BytesIO(json.dumps(
    {
        "sample config": "content",
    }).encode())
with ContainerRegistryClient(self.endpoint, self.credential) as client:
    # Upload a layer
    layer_digest, layer_size = client.upload_blob(self.repository_name, layer)
    print(f"Uploaded layer: digest - {layer_digest}, size - {layer_size}")
    # Upload a config
    config_digest, config_size = client.upload_blob(self.repository_name, config)
    print(f"Uploaded config: digest - {config_digest}, size - {config_size}")
    # Create an oci image with config and layer info
    oci_manifest = {
        "config": {
            "mediaType": "application/vnd.oci.image.config.v1+json",
            "digest": config_digest,
            "sizeInBytes": config_size,
        },
        "schemaVersion": 2,
        "layers": [
            {
                "mediaType": "application/vnd.oci.image.layer.v1.tar",
                "digest": layer_digest,
                "size": layer_size,
                "annotations": {
                    "org.opencontainers.image.ref.name": "artifact.txt",
                },
            },
        ],
    }
    # Set the image with tag "latest"
    manifest_digest = client.set_manifest(self.repository_name, oci_manifest, tag="latest")
    print(f"Uploaded manifest: digest - {manifest_digest}")

下载映像

若要下载完整映像,需要下载其清单,然后下载各个层和配置。

with ContainerRegistryClient(self.endpoint, self.credential) as client:
    # Get the image
    get_manifest_result = client.get_manifest(self.repository_name, "latest")
    received_manifest = get_manifest_result.manifest
    print(f"Got manifest:\n{received_manifest}")
    
    # Download and write out the layers
    for layer in received_manifest["layers"]:
        # Remove the "sha256:" prefix from digest
        layer_file_name = layer["digest"].split(":")[1]
        try:
            stream = client.download_blob(self.repository_name, layer["digest"])
            with open(layer_file_name, "wb") as layer_file:
                for chunk in stream:
                    layer_file.write(chunk)
        except DigestValidationError:
            print(f"Downloaded layer digest value did not match. Deleting file {layer_file_name}.")
            os.remove(layer_file_name)
        print(f"Got layer: {layer_file_name}")
    # Download and write out the config
    config_file_name = "config.json"
    try:
        stream = client.download_blob(self.repository_name, received_manifest["config"]["digest"])
        with open(config_file_name, "wb") as config_file:
            for chunk in stream:
                config_file.write(chunk)
    except DigestValidationError:
        print(f"Downloaded config digest value did not match. Deleting file {config_file_name}.")
        os.remove(config_file_name)
    print(f"Got config: {config_file_name}")

删除清单

with ContainerRegistryClient(self.endpoint, self.credential) as client:
    get_manifest_result = client.get_manifest(self.repository_name, "latest")
    # Delete the image
    client.delete_manifest(self.repository_name, get_manifest_result.digest)

删除 Blob

with ContainerRegistryClient(self.endpoint, self.credential) as client:
    get_manifest_result = client.get_manifest(self.repository_name, "latest")
    received_manifest = get_manifest_result.manifest
    # Delete the layers
    for layer in received_manifest["layers"]:
        client.delete_blob(self.repository_name, layer["digest"])
    # Delete the config
    client.delete_blob(self.repository_name, received_manifest["config"]["digest"])

疑难解答

有关故障排除的信息,请参阅 故障排除指南

常规

ACR 客户端库将引发 Azure Core 中定义的异常。

Logging

此库使用标准 日志记录 库进行日志记录。

有关 HTTP 会话 (URL、标头等的基本信息,) 是在级别记录的 INFO

可以使用 关键字 (keyword) 参数在客户端上或按操作logging_enable启用详细DEBUG级别日志记录,包括请求/响应正文和未实现的标头。

请参阅此处提供示例的完整 SDK 日志记录文档。

可选配置

可选关键字 (keyword) 参数可以在客户端和按操作级别传入。 azure-core 参考文档 介绍了重试、日志记录、传输协议等的可用配置。

后续步骤

贡献

本项目欢迎贡献和建议。 大多数贡献要求你同意贡献者许可协议 (CLA),并声明你有权(并且确实有权)授予我们使用你的贡献的权利。 有关详细信息,请访问 cla.microsoft.com

此项目采用了 Microsoft 开放源代码行为准则。 有关详细信息,请参阅行为准则常见问题解答,或如果有任何其他问题或意见,请与 联系。

曝光数