{"id":2641,"date":"2023-05-12T07:59:01","date_gmt":"2023-05-12T14:59:01","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sdk\/?p=2641"},"modified":"2023-05-12T07:59:01","modified_gmt":"2023-05-12T14:59:01","slug":"announcing-the-new-azure-container-registry-libraries","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sdk\/announcing-the-new-azure-container-registry-libraries\/","title":{"rendered":"Announcing the new Azure Container Registry libraries"},"content":{"rendered":"<p>We&#8217;re pleased to announce that version 1.1.0 of the Azure Container Registry (ACR) libraries for .NET, Java, JavaScript\/TypeScript, and Python are now generally available. A Go library is currently available as a <a href=\"https:\/\/pkg.go.dev\/github.com\/Azure\/azure-sdk-for-go\/sdk\/containers\/azcontainerregistry\">preview<\/a>; the stable release is expected later this year.<\/p>\n<p>Our new libraries follow our modern <a href=\"https:\/\/azure.github.io\/azure-sdk\/general_introduction.html\">Azure SDK Guidelines<\/a>, meaning that you can expect an idiomatic, consistent, approachable, diagnosable, and dependable library experience. These libraries use the language-specific Azure Core packages, which handle requests, errors, and credentials.<\/p>\n<p><a href=\"https:\/\/azure.microsoft.com\/products\/container-registry\/\">ACR<\/a> is a private registry service that allows you to create, store, and manage container images and related artifacts. It&#8217;s compatible with Docker and Open Container Initiative (OCI) images and artifacts, which means you can use it with your existing container development and deployment pipelines. If you need to build container images on demand, you can use ACR Tasks.<\/p>\n<h2>New features<\/h2>\n<p>One of the most significant improvements in this version of the ACR library is the ability to upload and download images to ACR. Previously, version 1.0 only allowed developers to list repositories and images, get and update metadata, and delete them.<\/p>\n<h2>Library availability<\/h2>\n<p>The new ACR libraries can be downloaded from each language&#8217;s preferred package manager.<\/p>\n<table>\n<thead>\n<tr>\n<th>Language<\/th>\n<th>Package<\/th>\n<th>Command<\/th>\n<th>Project<\/th>\n<th>Get started<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>.NET<\/td>\n<td><a href=\"https:\/\/www.nuget.org\/packages\/Azure.Containers.ContainerRegistry\">NuGet<\/a><\/td>\n<td><code>dotnet add package Azure.Containers.ContainerRegistry<\/code><\/td>\n<td><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/tree\/master\/sdk\/containerregistry\/Azure.ContainerRegistry\">link<\/a><\/td>\n<td><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/tree\/main\/sdk\/containerregistry\/Azure.Containers.ContainerRegistry#getting-started\">link<\/a><\/td>\n<\/tr>\n<tr>\n<td>Java<\/td>\n<td><a href=\"https:\/\/search.maven.org\/artifact\/com.azure\/azure-containers-containerregistry\">Java<\/a><\/td>\n<td><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/tree\/main\/sdk\/containerregistry\/azure-containers-containerregistry#include-the-package\">Add to POM.xml file<\/a><\/td>\n<td><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/tree\/main\/sdk\/containerregistry\/azure-containers-containerregistry\">link<\/a><\/td>\n<td><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/tree\/main\/sdk\/containerregistry\/azure-containers-containerregistry#getting-started\">link<\/a><\/td>\n<\/tr>\n<tr>\n<td>JavaScript\/TypeScript<\/td>\n<td><a href=\"https:\/\/www.npmjs.com\/package\/@azure\/container-registry\">npm<\/a><\/td>\n<td><code>npm install @azure\/container-registry<\/code><\/td>\n<td><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-js\/tree\/main\/sdk\/containerregistry\/container-registry\">link<\/a><\/td>\n<td><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-js\/tree\/main\/sdk\/containerregistry\/container-registry#getting-started\">link<\/a><\/td>\n<\/tr>\n<tr>\n<td>Python<\/td>\n<td><a href=\"https:\/\/pypi.org\/project\/azure-containerregistry\/\">PyPI<\/a><\/td>\n<td><code>pip install azure-containerregistry<\/code><\/td>\n<td><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-python\/tree\/main\/sdk\/containerregistry\/azure-containerregistry\">link<\/a><\/td>\n<td><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-python\/tree\/main\/sdk\/containerregistry\/azure-containerregistry#getting-started\">link<\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Code samples<\/h2>\n<p>The following samples illustrate how to upload and download OCI and Docker images to an ACR instance using the ACR library for .NET.<\/p>\n<p>Samples are also available for <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/tree\/main\/sdk\/containerregistry\/azure-containers-containerregistry#blob-and-manifest-operations\">Java<\/a>, <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-js\/tree\/main\/sdk\/containerregistry\/container-registry\/samples\/v1\/typescript\">TypeScript<\/a>\/<a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-js\/tree\/main\/sdk\/containerregistry\/container-registry\/samples\/v1\/javascript\">JavaScript<\/a>, and <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-python\/blob\/main\/sdk\/containerregistry\/azure-containerregistry\/samples\/sample_set_get_image.py\">Python<\/a>.<\/p>\n<h3>Create a client<\/h3>\n<p>Create a <code>ContainerRegistryContentClient<\/code> for the registry, passing the repository, credentials, and client options.<\/p>\n<pre><code class=\"language-csharp\">\/\/ Get the service endpoint from the environment\r\nUri endpoint = new(Environment.GetEnvironmentVariable(\"REGISTRY_ENDPOINT\"));\r\n\r\nstring repository = \"sample-oci-image\";\r\nstring tag = \"demo\";\r\n\r\n\/\/ Create a new ContainerRegistryContentClient\r\nContainerRegistryContentClient client = new(endpoint, repository, new DefaultAzureCredential());<\/code><\/pre>\n<h3>Upload an OCI image<\/h3>\n<p>To upload an OCI image, upload its config file, layers, and manifest. In this sample, the manifest is updated with information about each file associated with the image, and then uploaded as a final step.<\/p>\n<pre><code class=\"language-csharp\">\/\/ Create a manifest to list files in this image\r\nOciImageManifest manifest = new(schemaVersion: 2);\r\n\r\n\/\/ Upload a config file\r\nBinaryData config = BinaryData.FromString(\"Sample config\");\r\nUploadRegistryBlobResult uploadConfigResult = await client.UploadBlobAsync(config);\r\n\r\n\/\/ Update manifest with config info\r\nmanifest.Configuration = new OciDescriptor()\r\n{\r\n  Digest = uploadConfigResult.Digest,\r\n  SizeInBytes = uploadConfigResult.SizeInBytes,\r\n  MediaType = \"application\/vnd.oci.image.config.v1+json\"\r\n};\r\n\r\n\/\/ Upload a layer file\r\nBinaryData layer = BinaryData.FromString(\"Sample layer\");\r\nUploadRegistryBlobResult uploadLayerResult = await client.UploadBlobAsync(layer);\r\n\r\n\/\/ Update manifest with layer info\r\nmanifest.Layers.Add(new OciDescriptor()\r\n{\r\n  Digest = uploadLayerResult.Digest,\r\n  SizeInBytes = uploadLayerResult.SizeInBytes,\r\n  MediaType = \"application\/vnd.oci.image.layer.v1.tar\"\r\n});\r\n\r\n\/\/ Finally, upload the manifest file\r\nawait client.SetManifestAsync(manifest, tag);<\/code><\/pre>\n<h3>Download an OCI image<\/h3>\n<p>To download an OCI image, first download its manifest. The manifest describes the files that need to be downloaded to pull the full image.<\/p>\n<pre><code class=\"language-csharp\">\/\/ Download the manifest to obtain the list of files in the image\r\nGetManifestResult result = await client.GetManifestAsync(tag);\r\nOciImageManifest manifest = result.Manifest.ToObjectFromJson&lt;OciImageManifest&gt;();\r\n\r\nstring manifestFile = Path.Combine(path, \"manifest.json\");\r\n\r\nusing (FileStream stream = File.Create(manifestFile))\r\n{\r\n  await result.Manifest.ToStream().CopyToAsync(stream);\r\n}\r\n\r\n\/\/ Download and write out the config\r\nDownloadRegistryBlobResult configBlob = await client.DownloadBlobContentAsync(manifest.Configuration.Digest);\r\nstring configFile = Path.Combine(path, \"config.json\");\r\n\r\nusing (FileStream stream = File.Create(configFile))\r\n{\r\n  await configBlob.Content.ToStream().CopyToAsync(stream);\r\n}\r\n\r\n\/\/ Download and write out the layers\r\nforeach (OciDescriptor layerInfo in manifest.Layers)\r\n{\r\n  string layerFile = Path.Combine(path, TrimSha(layerInfo.Digest));\r\n  using (FileStream stream = File.Create(layerFile))\r\n  {\r\n    await client.DownloadBlobToAsync(layerInfo.Digest, stream);\r\n  }\r\n}\r\n\r\nstatic string TrimSha(string digest)\r\n{\r\n  int index = digest.IndexOf(':');\r\n  if (index &gt; -1)\r\n  {\r\n    return digest.Substring(index + 1);\r\n  }\r\n  return digest;\r\n}<\/code><\/pre>\n<h3>Upload a custom manifest type<\/h3>\n<p>To upload an image with a custom manifest type, pass the <code>ManifestMediaType<\/code> to the <code>UploadManifest<\/code> method.<\/p>\n<pre><code class=\"language-csharp\">\/\/ Create a manifest file in the Docker v2 Manifest List format\r\ndynamic manifestList = new\r\n{\r\n  schemaVersion = 2,\r\n  mediaType = \"application\/vnd.docker.distribution.manifest.list.v2+json\",\r\n  manifests = new[]\r\n  {\r\n    new\r\n    {\r\n      digest = \"sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4\",\r\n      mediaType = ManifestMediaType.DockerManifest.ToString(),\r\n      platform = new {\r\n        architecture = ArtifactArchitecture.Amd64.ToString(),\r\n        os = ArtifactOperatingSystem.Linux.ToString()\r\n      }\r\n    }\r\n  }\r\n};\r\n\r\n\/\/ Finally, upload the manifest file\r\nBinaryData content = BinaryData.FromObjectAsJson(manifestList);\r\nawait client.SetManifestAsync(content, tag: \"sample\", ManifestMediaType.DockerManifestList);<\/code><\/pre>\n<h3>Download a manifest of an unknown type<\/h3>\n<p>If you&#8217;re downloading a manifest where the media type isn&#8217;t known ahead of time, check the <code>MediaType<\/code> property returned on the <code>DownloadManifestResult<\/code> to determine the type.<\/p>\n<pre><code class=\"language-csharp\">GetManifestResult result = await client.GetManifestAsync(\"sample\");\r\nif (result.MediaType == \"application\/vnd.docker.distribution.manifest.list.v2+json\")\r\n{\r\n  Console.WriteLine(\"Manifest is a Docker manifest list.\");\r\n}\r\nelse if (result.MediaType == \"application\/vnd.oci.image.index.v1+json\")\r\n{\r\n  Console.WriteLine(\"Manifest is an OCI index.\");\r\n}<\/code><\/pre>\n<h3>Delete a manifest<\/h3>\n<p>A manifest can be deleted as shown in the following example. It&#8217;s also possible to delete a full image using the <code>ContainerRegistryClient<\/code> as shown in <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/blob\/main\/sdk\/containerregistry\/Azure.Containers.ContainerRegistry\/samples\/Sample02b_DeleteImagesAsync.md\">a separate example<\/a>.<\/p>\n<pre><code class=\"language-csharp\">GetManifestResult manifestResult = await client.GetManifestAsync(tag);\r\nawait client.DeleteManifestAsync(manifestResult.Digest);<\/code><\/pre>\n<h3>Delete a blob<\/h3>\n<p>A blob can be deleted as shown in the following example. It&#8217;s also possible to delete a full image using the <code>ContainerRegistryClient<\/code> as shown in <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/blob\/main\/sdk\/containerregistry\/Azure.Containers.ContainerRegistry\/samples\/Sample02b_DeleteImagesAsync.md\">a separate example<\/a>.<\/p>\n<pre><code class=\"language-csharp\">GetManifestResult result = await client.GetManifestAsync(tag);\r\nOciImageManifest manifest = result.Manifest.ToObjectFromJson&lt;OciImageManifest&gt;();\r\n\r\nforeach (OciDescriptor layerInfo in manifest.Layers)\r\n{\r\n  await client.DeleteBlobAsync(layerInfo.Digest);\r\n}<\/code><\/pre>\n<h2>Learn more<\/h2>\n<p>We hope this article was a useful introduction to the new and improved ACR libraries and how you can use them today to build and ship rich experiences.<\/p>\n<p>To learn more and to get started, see these links to our official documentation:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/tree\/main\/sdk\/containerregistry\/Azure.Containers.ContainerRegistry\">.NET<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/tree\/main\/sdk\/containerregistry\/azure-containers-containerregistry\">Java<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-js\/tree\/main\/sdk\/containerregistry\/container-registry\">JavaScript\/TypeScript<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-python\/tree\/main\/sdk\/containerregistry\/azure-containerregistry\">Python<\/a><\/li>\n<\/ul>\n<h2>Give us your feedback<\/h2>\n<p>We appreciate your feedback and encourage you to share your thoughts with us. We thrive on improvement and would welcome any suggestions you may have. Let&#8217;s work together to make our experience even better!<\/p>\n<p>You can reach out to us by filing issues in the GitHub repo of the language you&#8217;re interested in:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/issues\">.NET<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/issues\">Java<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-js\/issues\">JavaScript\/TypeScript<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-python\/issues\">Python<\/a><\/li>\n<\/ul>\n<p>Include the &#8220;[Container Registry]&#8221; string in the issue title so it gets routed to the right people.<\/p>\n<h2>References<\/h2>\n<ul>\n<li><a href=\"https:\/\/learn.microsoft.com\/azure\/container-registry\/\">Official ACR documentation<\/a><\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/azure\/container-registry\/quickstart-client-libraries\">Create Container Registry resources Quickstart<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Announcing release of the new Azure Container Registry libraries with support for uploading and downloading of images.<\/p>\n","protected":false},"author":63526,"featured_media":2655,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[701,903,750,905,160,159,904,162],"class_list":["post-2641","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sdk","tag-net","tag-azure-container-registry","tag-azure-sdk","tag-docker-images","tag-java","tag-javascript","tag-oci","tag-python"],"acf":[],"blog_post_summary":"<p>Announcing release of the new Azure Container Registry libraries with support for uploading and downloading of images.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/2641","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/users\/63526"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/comments?post=2641"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/2641\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media\/2655"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media?parent=2641"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/categories?post=2641"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/tags?post=2641"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}