Automating Docker image deployments using Azure Container Instances
From my archive - originally published on 3 December 2017
Azure’s Container Instances service provides an easy and quick way to run containers without having to operate an orchestration platform or manage a cluster of virtual machines.It's similar to Amazon's Elastic Container Service except that it provides full support for Windows Containers without any caveats or limitations. You only pay for what you use by the second and there are no overhead charges or need to pre-provision capacity. This makes it ideal for short-lived workloads such as batch processed where you need to spin up capacity for a relatively short period of time. Note that all this service provides is a means of spinning up container instances easily. There’s nothing to help you stand up complicated arrangements of containers or manage their lifecycle. The Azure Management Libraries can help you to automate deployment and management, but the documentation does not give a lot away. Once you unravel their mysteries then they can be paired with something like Azure Functions to provide an automated means of standing up, monitoring and tearing down container instances, all with negligible cost.
Creating a registryBefore you start you will need to publish your Docker images in a registry that Azure can access. You can use Docker’s public registry for this, but you will probably feel more comfortable running your own using an instance of the Azure Container Registry service. When creating this it will make life easier in the short term by enabling the Admin user – this allows easier, though less secure, login to the registry. Once this has been deployed you can access the login details in the Azure portal by visiting the “Access Keys” section of the resource.
Pushing containers to the registryOnce you have a registry you will need to push your compiled Docker images to them. Ideally this should be done as part of your build and deploy pipeline along with the actual image creation. Pushing the container can be done using three separate Docker commands. The examples below assume you have an registry called "my-registry" and an image called "my-image". The login command authenticates with the registry you have just created with a username and password:
docker login --username [username] --password [passowrd] my-registry.azurecr.io
docker tag my-image my-registry.azurecr.io/my-image:latest
docker push my-registry.azurecr.io/my-image
Deploying the containerOnce you have the containers published to the registry you can deploy them using the Azure management SDK. This provides a fluent SDK that allows you to stand up, query and tear down Azure Container Instances. Before you start you’ll need to create a service principal. This is a way of creating an account that is associated with your identity to which you can grant the minimum privileges required to run. To create a service principal you’ll need to install Azure Powershell and follow Microsoft’s guide which will give you a client id and secret along with a tenant identifier. These details should let you login to Azure using the fluent SDK as shown below. This will need a reference to the Microsoft.Azure.Management.Fluent package and the resulting IAzure object can be used for all your subsequent requests:
AzureCredentials credentials = SdkContext.AzureCredentialsFactory.FromServicePrincipal( clientId: "[Client ID]", clientSecret: "[Client secret]", tenantId: "[Tenant ID]", environment: AzureEnvironment.AzureGlobalCloud); IAzure azure = Azure .Configure() .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic) .Authenticate(credentials) .WithDefaultSubscription();
IContainerGroup containerGroup = azure.ContainerGroups.Define(instanceName) // This is the data centre .WithRegion(Region.EuropeWest) // Select a resource group - you can also create a new one .WithExistingResourceGroup("[A resource group]") // Use Windows-based containers .WithWindows() // Specify the private image registry .WithPrivateImageRegistry("[Registry address]", "[Username]", "[Password]") // To attach a disc use DefineVolume() or WithNewAzureFileShareVolume() .WithoutVolume() // Set out the container instance, i.e. the image, ports, CPUs, memory and environment variables .DefineContainerInstance(instanceName) .WithImage("[Docker Image ID]") .WithoutPorts() .WithEnvironmentVariable("[Name]", "[Value]") .WithCpuCoreCount(1) .WithMemorySizeInGB(1) .Attach() // Create the instance .Create();
Querying and killing container instancesYou can use the ContainerGroups collection to retrieve the details of your running containers, query the logs and delete them as shown below:
// List the available groups var groups = azure.ContainerGroups.ListByResourceGroup("[Resource Group]"); // Get the logs for an individual container var logs = azure.ContainerGroups.GetLogContent("[Resource Group]", "[Container Group]", "[Container]"); // Delete a container azure.ContainerGroups.DeleteById("[Container Group]");