Oven logo

Oven

Published

Microsoft Azure Azure Container Registry Client Library for Python

pip install azure-containerregistry

Package Downloads

Weekly DownloadsMonthly Downloads

Requires Python

>=3.7

Dependencies

    Azure Container Registry client library for Python

    Azure Container Registry allows you to store and manage container images and artifacts in a private registry for all types of container deployments.

    Use the client library for Azure Container Registry to:

    • List images or artifacts in a registry
    • Obtain metadata for images and artifacts, repositories and tags
    • Set read/write/delete properties on registry items
    • Delete images and artifacts, repositories and tags

    Source code | Package (Pypi) | Package (Conda) | API reference documentation | REST API documentation | Product documentation

    Disclaimer

    Azure SDK Python packages support for Python 2.7 has ended 01 January 2022. For more information and questions, please refer to https://github.com/Azure/azure-sdk-for-python/issues/20691 Python 3.7 or later is required to use this package. For more details, please refer to Azure SDK for Python version support policy.

    Getting started

    Install the package

    Install the Azure Container Registry client library for Python with pip:

    pip install --pre azure-containerregistry
    

    Prerequisites

    To create a new Container Registry, you can use the Azure Portal, Azure PowerShell, or the Azure CLI. Here's an example using the Azure CLI:

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

    Authenticate the client

    The Azure Identity library provides easy Azure Active Directory support for authentication. The DefaultAzureCredential assumes the AZURE_CLIENT_ID, AZURE_TENANT_ID, and AZURE_CLIENT_SECRET environment variables are set, for more information refer to the Azure Identity environment variables section

    # 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)
    

    Key concepts

    A registry stores Docker images and OCI Artifacts. An image or artifact consists of a manifest and layers. An image's manifest describes the layers that make up the image, and is uniquely identified by its digest. An image can also be "tagged" to give it a human-readable alias. An image or artifact can have zero or more tags associated with it, and each tag uniquely identifies the image. A collection of images that share the same name but have different tags, is referred to as a repository.

    For more information please see Container Registry Concepts.

    Examples

    The following sections provide several code snippets covering some of the most common ACR Service tasks, including:

    Please note that each sample assumes there is a CONTAINERREGISTRY_ENDPOINT environment variable set to a string containing the https:// prefix and the name of the login server, for example "https://myregistry.azurecr.io". Anonymous access samples are getting endpoint value from environment variableCONTAINERREGISTRY_ANONREGISTRY_ENDPOINT.

    List repositories

    Iterate through the collection of repositories in the registry.

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

    List tags with anonymous access

    Iterate through the collection of tags in the repository with anonymous access.

    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)
    

    Set artifact properties

    Set properties of an artifact.

    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
        )
    

    Delete images

    Delete images older than the first three in the repository.

    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)
    

    Upload images

    To upload a full image, we need to upload individual layers and configuration. After that we can upload a manifest which describes an image or artifact and assign it a tag.

    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}")
    

    Download images

    To download a full image, we need to download its manifest and then download individual layers and configuration.

    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}")
    

    Delete manifest

    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)
    

    Delete 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"])
    

    Troubleshooting

    For infomation about troubleshooting, refer to the troubleshooting guide.

    General

    ACR client library will raise exceptions defined in Azure Core.

    Logging

    This library uses the standard logging library for logging.

    Basic information about HTTP sessions (URLs, headers, etc.) is logged at INFO level.

    Detailed DEBUG level logging, including request/response bodies and unredacted headers, can be enabled on the client or per-operation with the logging_enable keyword argument.

    See full SDK logging documentation with examples here.

    Optional Configuration

    Optional keyword arguments can be passed in at the client and per-operation level. The azure-core reference documentation describes available configurations for retries, logging, transport protocols, and more.

    Next steps

    Contributing

    This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit cla.microsoft.com.

    This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

    Impressions