Use HCP Packer and Terraform to manage cloud container registries
Author: Bruce Harrison
This guide will help you with creating and managing Docker containers via HCP Packer and interface them with cloud service providers (CSP) container registries. This guide will demonstrate how to push images to AWS, Azure, and GCP container registries.
This guide uses both Packer CE and the HCP Packer platform. You will use Packer CE to build containers and VM images. You will use HCP Packer to store container and VM metadata generated by Packer CE.
By using Packer CE and HCP Packer, you gain the following benefits:
- Capturing of container metadata by the HCP platform
- Visibility into container lineage
- Notification when a derived image is outdated due to a new version of the parent being released
- Leverage HCP Packer webhooks for more advanced cloud providers registry management
- VM images and containers can share a common declarative file format (Packer HCL) that is used to describe and build both.
Target audience
This guide references the following roles:
- Platform operator: Someone responsible for setting up the image repositories, building the containers, and pushing them to the respective cloud provider container registries.
Validated architecture
The following diagram shows the process of pushing a container to a cloud provider's container registry using HCP Packer.
This document focuses on running this process from a local machine, but the same concepts could easily be applied to a CI/CD mechanism such as Github Actions or Gitlab Runners.
We recommend using Terraform to provision the underlying infrastructure.
Due to the way Packer post-processors and docker login works, if you plan on pushing images to multiple cloud providers, you should run each build in an isolated context. Attempting to push multiple images in parallel from a single context can cause transient failures since they all compete for
docker login
access.Packer offers a
docker-push
post processor, but this guide does not cover this post-processor. The post-processor is inherently inflexible, and causes wide divergence in container push processes across cloud providers. Instead, you will be manually logging into registries and pushing the containers. This method is broadly applicable to CI/CD scenarios as well.Every cloud provider has unique constraints on how credentials are handled. This guide uses long-lived credentials for brevity, but this may not work for all organizations.
Platform operators should consult with their internal security teams to ensure that the cloud providers authentication method aligns with company policies and practices.
Prerequisites
- An active HCP service principal.
- An existing HCP Packer Account (HCP Platform).
- Packer OSS CLI >=v1.11.0 installed.
- Have a working Packer HCL file configured for building a Docker container.
- Git CLI installed.
For your desired cloud provider, ensure you have the following:
- Necessary permissions to create resources within your chosen cloud provider.
- Azure CLI installed locally and configured with your Azure credentials
Create image repository
You can create an container registry using either Terraform or the Azure CLI.
Use the following Terraform configuration to deploy an Azure container registry. This configuration uses the azurerm_resource_group
, azurerm_container_registry
, azuread_service_principal
, and azurerm_role_assignment
resources.
Update the <repository-name>
with the name of the repository you want to create.
data "azuread_client_config" "current" {}
resource "azurerm_resource_group" "demo" {
name = "demo-resources"
location = "West Europe"
}
resource "azurerm_container_registry" "demo" {
name = "<repository-name>"
resource_group_name = azurerm_resource_group.demo.name
location = azurerm_resource_group.demo.location
sku = "Premium"
admin_enabled = false
georeplications {
location = "East US"
zone_redundancy_enabled = true
tags = {}
}
georeplications {
location = "North Europe"
zone_redundancy_enabled = true
tags = {}
}
}
resource "azuread_application" "demo" {
display_name = "packer-push"
owners = [data.azuread_client_config.current.object_id]
password {
display_name = "client_secret"
start_date = time_rotating.example.id
end_date = timeadd(time_rotating.example.id, "4320h")
}
}
resource "azuread_service_principal" "demo" {
client_id = azuread_application.demo.client_id
app_role_assignment_required = false
owners = [data.azuread_client_config.current.object_id]
}
resource "azurerm_role_assignment" "example" {
scope = azurerm_container_registry.demo.id
role_definition_name = "AcrPush"
principal_id = azuread_service_principal.demo.object_id
}
output "app_id" {
value = azuread_application.demo.client_id
}
output "app_password" {
value = azuread_application.demo.password[0].value
}
output "login_server" {
value = azurerm_container_registry.demo.login_server
}
After you create the Azure container registry, store the app_id
, app_password
, login_server
values from the output. You will use these values to login to the container registry.
Push container to registry
Locate your HCP service principal credentials and export them as environment variables.
$ export HCP_CLIENT_ID=
$ export HCP_CLIENT_SECRET=
In your Packer template, update the following fields: app_id
, app_password
, login_server
, and repository_name
.
Build the container
$ packer build docker-debian-azure.pkr.hcl
Login to the AZ CLI via Service Principal credentials. Update <app-id>
with the app_id
value you captured from the Terraform output. Update <password>
with the app_password
value you captured from the Terraform output. Update <tenant>
with the tenant ID you want to use.
$ az login --service-principal -u <app-id> -p <password> --tenant <tenant>
Login to the Azure Container Registry via AZ CLI. Update <repository-name>
with the name of the container registry you created.
$ az acr login --name <repository-name>
Push the container to the Azure Container Registry. Update <repository-name>
with the name of the container registry you created.
$ docker push <repository-name>.azurecr.io/packer-demo-image/packer-demo-image:latest
You have pushed your image to the Azure Container Registry. It is now available to be consumed by services with permission to pull it.
Conclusion
In this guide, you learned how to push containers to cloud provider container registries using Packer CE and HCP Packer. To learn more, check out the following resources: