Container Service on Azure
The Azure Container Service template scaffolds a Pulumi project that deploys a containerized service to Azure. The architecture includes an Azure Container Registry for the container image and Azure Container Instances (ACI) for serverless container execution. The template ships with placeholder app content so the project deploys end to end out of the box.
Before you begin#
For this walkthrough, you'll need:
- The Pulumi CLI
- The Azure CLI (optional, but recommended and used in this guide)
- Permission to manage Container Registry and Container Instances
- Docker installed and running
For this walkthrough, you'll need:
- The Pulumi CLI
- The Azure CLI (optional, but recommended and used in this guide)
- Permission to manage Container Registry and Container Instances
- Docker installed and running
For this walkthrough, you'll need:
- The Pulumi CLI
- The Azure CLI (optional, but recommended and used in this guide)
- Permission to manage Container Registry and Container Instances
- A current version of Go installed locally
- Docker installed and running
For this walkthrough, you'll need:
- The Pulumi CLI
- The Azure CLI (optional, but recommended and used in this guide)
- Permission to manage Container Registry and Container Instances
- A current version of .NET installed locally
- Docker installed and running
For this walkthrough, you'll need:
- A current version of the Pulumi CLI (Pulumi HCL requires no additional runtime)
- The Azure CLI (optional, but recommended and used in this guide)
- Permission to manage Container Registry and Container Instances
- Docker installed and running
Create a new project#
Create a new project from the template:
mkdir my-container-service; cd my-container-servicepulumi new container-azure-typescriptmkdir my-container-service; cd my-container-servicepulumi new container-azure-typescriptmkdir my-container-service; cd my-container-servicepulumi new container-azure-pythonmkdir my-container-service; cd my-container-servicepulumi new container-azure-pythonmkdir my-container-service; cd my-container-servicepulumi new container-azure-gomkdir my-container-service; cd my-container-servicepulumi new container-azure-gomkdir my-container-service; cd my-container-servicepulumi new container-azure-csharpmkdir my-container-service; cd my-container-servicepulumi new container-azure-csharpmkdir my-container-service; cd my-container-servicepulumi new container-azure-hclmkdir my-container-service; cd my-container-servicepulumi new container-azure-hclThe pulumi new command walks you through creating and configuring the new project and stack. A stack is an instance of a project, and you can have many of them (dev, staging, prod), each with its own configuration settings. Depending on the language, you may also be asked for your preferred package manager or toolchain.
This template’s settings include:
| Key | Description | Default |
|---|---|---|
| azure-native:location | The Azure region to deploy into | WestUS |
| appPath | The path to the container application to deploy | app |
| imageName | The name to give the container image | my-app |
| imageTag | The tag to give the container image | latest |
| containerPort | The port to expose on the container | 80 |
| cpu | The number of CPU cores to allocate on the container | 1 |
| memory | The amount of memory, in GB, to allocate on the container | 2 |
pulumi config set
:
pulumi config set azure-native:location <value>pulumi config set appPath <value>pulumi config set imageName <value>pulumi config set imageTag <value>pulumi config set containerPort <value>pulumi config set cpu <value>pulumi config set memory <value>pulumi config set azure-native:location "<value>"pulumi config set appPath "<value>"pulumi config set imageName "<value>"pulumi config set imageTag "<value>"pulumi config set containerPort "<value>"pulumi config set cpu "<value>"pulumi config set memory "<value>"| Key | Description | Default |
|---|---|---|
| azure-native:location | The Azure region to deploy into | WestUS |
| appPath | The path to the container application to deploy | app |
| imageName | The name to give the container image | my-app |
| imageTag | The tag to give the container image | latest |
| containerPort | The port to expose on the container | 80 |
| cpu | The number of CPU cores to allocate on the container | 1 |
| memory | The amount of memory, in GB, to allocate on the container | 2 |
pulumi config set
:
pulumi config set azure-native:location <value>pulumi config set appPath <value>pulumi config set imageName <value>pulumi config set imageTag <value>pulumi config set containerPort <value>pulumi config set cpu <value>pulumi config set memory <value>pulumi config set azure-native:location "<value>"pulumi config set appPath "<value>"pulumi config set imageName "<value>"pulumi config set imageTag "<value>"pulumi config set containerPort "<value>"pulumi config set cpu "<value>"pulumi config set memory "<value>"| Key | Description | Default |
|---|---|---|
| azure-native:location | The Azure region to deploy into | WestUS |
| appPath | The path to the container application to deploy | app |
| imageName | The name to give the container image | my-app |
| imageTag | The tag to give the container image | latest |
| containerPort | The port to expose on the container | 80 |
| cpu | The number of CPU cores to allocate on the container | 1 |
| memory | The amount of memory, in GB, to allocate on the container | 2 |
pulumi config set
:
pulumi config set azure-native:location <value>pulumi config set appPath <value>pulumi config set imageName <value>pulumi config set imageTag <value>pulumi config set containerPort <value>pulumi config set cpu <value>pulumi config set memory <value>pulumi config set azure-native:location "<value>"pulumi config set appPath "<value>"pulumi config set imageName "<value>"pulumi config set imageTag "<value>"pulumi config set containerPort "<value>"pulumi config set cpu "<value>"pulumi config set memory "<value>"| Key | Description | Default |
|---|---|---|
| azure-native:location | The Azure region to deploy into | WestUS |
| appPath | The path to the container application to deploy | app |
| imageName | The name to give the container image | my-app |
| imageTag | The tag to give the container image | latest |
| containerPort | The port to expose on the container | 80 |
| cpu | The number of CPU cores to allocate on the container | 1 |
| memory | The amount of memory, in GB, to allocate on the container | 2 |
pulumi config set
:
pulumi config set azure-native:location <value>pulumi config set appPath <value>pulumi config set imageName <value>pulumi config set imageTag <value>pulumi config set containerPort <value>pulumi config set cpu <value>pulumi config set memory <value>pulumi config set azure-native:location "<value>"pulumi config set appPath "<value>"pulumi config set imageName "<value>"pulumi config set imageTag "<value>"pulumi config set containerPort "<value>"pulumi config set cpu "<value>"pulumi config set memory "<value>"| Key | Description | Default |
|---|---|---|
| azure-native:location | The Azure region to deploy into | WestUS |
| app_path | The path to the container application to deploy | ./app |
| image_name | The name to give the container image | my-app |
| image_tag | The tag to give the container image | latest |
| container_port | The port to expose on the container | 80 |
| cpu | The number of CPU cores to allocate for the container | 1 |
| memory | The amount of memory, in GB, to allocate for the container | 2 |
pulumi config set
:
pulumi config set azure-native:location <value>pulumi config set app_path <value>pulumi config set image_name <value>pulumi config set image_tag <value>pulumi config set container_port <value>pulumi config set cpu <value>pulumi config set memory <value>pulumi config set azure-native:location "<value>"pulumi config set app_path "<value>"pulumi config set image_name "<value>"pulumi config set image_tag "<value>"pulumi config set container_port "<value>"pulumi config set cpu "<value>"pulumi config set memory "<value>"Review the code#
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the language it’s written in.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tfcontains the program code that declares your cloud resources.appholds a small web app that answers with a “Hello, world!” message, and the Dockerfile that builds it.
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the language it’s written in.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tfcontains the program code that declares your cloud resources.appholds a small web app that answers with a “Hello, world!” message, and the Dockerfile that builds it.
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the language it’s written in.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tfcontains the program code that declares your cloud resources.appholds a small web app that answers with a “Hello, world!” message, and the Dockerfile that builds it.
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the language it’s written in.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tfcontains the program code that declares your cloud resources.appholds a small web app that answers with a “Hello, world!” message, and the Dockerfile that builds it.
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the language it’s written in.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tfcontains the program code that declares your cloud resources.appholds a small web app that answers with a “Hello, world!” message, and the Dockerfile that builds it.
Take a moment to open them up and have a look. Here’s what’s in index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tf:
import * as pulumi from "@pulumi/pulumi";import * as resources from "@pulumi/azure-native/resources";import * as containerregistry from "@pulumi/azure-native/containerregistry";import * as containerinstance from "@pulumi/azure-native/containerinstance";import * as random from "@pulumi/random";import * as dockerbuild from "@pulumi/docker-build";
// Import the program's configuration settings.const config = new pulumi.Config();const appPath = config.get("appPath") || "./app";const imageName = config.get("imageName") || "my-app";const imageTag = config.get("imageTag") || "latest";const containerPort = config.getNumber("containerPort") || 80;const cpu = config.getNumber("cpu") || 1;const memory = config.getNumber("memory") || 2;
// Create a resource group for the container registry.const resourceGroup = new resources.ResourceGroup("resource-group");
// Create a container registry.const registry = new containerregistry.Registry("registry", { resourceGroupName: resourceGroup.name, adminUserEnabled: true, sku: { name: containerregistry.SkuName.Basic, },});
// Fetch login credentials for the registry.const credentials = containerregistry.listRegistryCredentialsOutput({ resourceGroupName: resourceGroup.name, registryName: registry.name,}).apply(creds => { return { username: creds.username!, password: creds.passwords![0].value!, };});
// Create a container image for the service.const image = new dockerbuild.Image("image", { tags: [pulumi.interpolate`${registry.loginServer}/${imageName}:${imageTag}`], context: { location: appPath, }, platforms: ["linux/amd64"], push: true, registries: [{ address: registry.loginServer, username: credentials.username, password: credentials.password, }],});
// Use a random string to give the service a unique DNS name.const dnsName = new random.RandomString("dns-name", { length: 8, special: false,}).result.apply(result => `${imageName}-${result.toLowerCase()}`);
// Create a container group for the service that makes it publicly accessible.const containerGroup = new containerinstance.ContainerGroup("container-group", { resourceGroupName: resourceGroup.name, osType: "linux", restartPolicy: "always", imageRegistryCredentials: [ { server: registry.loginServer, username: credentials.username, password: credentials.password, }, ], containers: [ { name: imageName, image: image.ref, ports: [ { port: containerPort, protocol: "tcp", }, ], environmentVariables: [ { name: "PORT", value: containerPort.toString(), }, ], resources: { requests: { cpu: cpu, memoryInGB: memory, }, }, }, ], ipAddress: { type: containerinstance.ContainerGroupIpAddressType.Public, dnsNameLabel: dnsName, ports: [ { port: containerPort, protocol: "tcp", }, ], },});
// Export the service's IP address, hostname, and fully-qualified URL.export const hostname = containerGroup.ipAddress.apply(addr => addr!.fqdn!);export const ip = containerGroup.ipAddress.apply(addr => addr!.ip!);export const url = containerGroup.ipAddress.apply(addr => `http://${addr!.fqdn!}:${containerPort}`);import pulumiimport pulumi_docker_build as docker_buildimport pulumi_random as randomfrom pulumi_azure_native import resources, containerregistry, containerinstance
# Import the program's configuration settings.config = pulumi.Config()app_path = config.get("appPath", "./app")image_name = config.get("imageName", "my-app")image_tag = config.get("imageTag", "latest")container_port = config.get_int("containerPort", 80)cpu = config.get_int("cpu", 1)memory = config.get_int("memory", 2)
# Create a resource group for the container registry.resource_group = resources.ResourceGroup("resource-group")
# Create a container registry.registry = containerregistry.Registry( "registry", containerregistry.RegistryArgs( resource_group_name=resource_group.name, admin_user_enabled=True, sku=containerregistry.SkuArgs( name=containerregistry.SkuName.BASIC, ), ),)
# Fetch login credentials for the registry.credentials = containerregistry.list_registry_credentials_output( resource_group_name=resource_group.name, registry_name=registry.name,)
registry_username = credentials.apply(lambda creds: creds.username)registry_password = credentials.apply(lambda creds: creds.passwords[0].value)
# Create a container image for the service.image = docker_build.Image( "image", tags=[pulumi.Output.concat(registry.login_server, f"/{image_name}:{image_tag}")], context=docker_build.BuildContextArgs( location=app_path, ), platforms=[docker_build.Platform.LINUX_AMD64], push=True, registries=[{ "address": registry.login_server, "username": registry_username, "password": registry_password, }],)
# Use a random string to give the service a unique DNS name.dns_name = random.RandomString( "dns-name", random.RandomStringArgs( length=8, special=False, ),).result.apply(lambda result: f"{image_name}-{result.lower()}")
# Create a container group for the service that makes it publicly accessible.container_group = containerinstance.ContainerGroup( "container-group", resource_group_name=resource_group.name, os_type="linux", restart_policy="always", image_registry_credentials=[ { "server": registry.login_server, "username": registry_username, "password": registry_password, }, ], containers=[ { "name": image_name, "image": image.ref, "ports": [ { "port": container_port, "protocol": "tcp", }, ], "environment_variables": [ { "name": "FLASK_RUN_PORT", "value": str(container_port), }, { "name": "FLASK_RUN_HOST", "value": "0.0.0.0", }, ], "resources": { "requests": { "cpu": cpu, "memory_in_gb": memory, }, }, }, ], ip_address={ "type": containerinstance.ContainerGroupIpAddressType.PUBLIC, "dns_name_label": dns_name, "ports": [ { "port": container_port, "protocol":"tcp", }, ], })
# Export the service's IP address, hostname, and fully-qualified URL.pulumi.export("hostname", container_group.ip_address.apply(lambda addr: addr.fqdn))pulumi.export("ip", container_group.ip_address.apply(lambda addr: addr.ip))pulumi.export( "url", container_group.ip_address.apply( lambda addr: f"http://{addr.fqdn}:{container_port}" ),)package main
import ( "fmt" "strings"
"github.com/pulumi/pulumi-azure-native-sdk/containerinstance/v3" "github.com/pulumi/pulumi-azure-native-sdk/containerregistry/v3" "github.com/pulumi/pulumi-azure-native-sdk/resources/v3" "github.com/pulumi/pulumi-docker-build/sdk/go/dockerbuild" "github.com/pulumi/pulumi-random/sdk/v4/go/random" "github.com/pulumi/pulumi/sdk/v3/go/pulumi" "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config")
func main() { pulumi.Run(func(ctx *pulumi.Context) error {
// Import the program's configuration settings. cfg := config.New(ctx, "") appPath := "./app" if param := cfg.Get("appPath"); param != "" { appPath = param } imageName := "my-app" if param := cfg.Get("imageName"); param != "" { imageName = param } imageTag := "latest" if param := cfg.Get("imageTag"); param != "" { imageTag = param } containerPort := 80 if param := cfg.GetInt("containerPort"); param != 0 { containerPort = param } cpu := 1 if param := cfg.GetInt("cpu"); param != 0 { cpu = param } memory := 2 if param := cfg.GetInt("memory"); param != 0 { memory = param }
// Create a resource group for the container registry. resourceGroup, err := resources.NewResourceGroup(ctx, "resource-group", nil) if err != nil { return err }
// Create a container registry. registry, err := containerregistry.NewRegistry(ctx, "registry", &containerregistry.RegistryArgs{ ResourceGroupName: resourceGroup.Name, AdminUserEnabled: pulumi.Bool(true), Sku: &containerregistry.SkuArgs{ Name: pulumi.String(containerregistry.SkuNameBasic), }, }) if err != nil { return err }
// Fetch login credentials for the registry. credentials := containerregistry.ListRegistryCredentialsOutput(ctx, containerregistry.ListRegistryCredentialsOutputArgs{ ResourceGroupName: resourceGroup.Name, RegistryName: registry.Name, }) registryUsername := credentials.Username().Elem() registryPassword := credentials.Passwords().Index(pulumi.Int(0)).Value().Elem()
// Create a container image for the service. image, err := dockerbuild.NewImage(ctx, "image", &dockerbuild.ImageArgs{ Tags: pulumi.StringArray{pulumi.Sprintf("%s/%s:%s", registry.LoginServer, imageName, imageTag)}, Context: &dockerbuild.BuildContextArgs{ Location: pulumi.String(appPath), }, Platforms: dockerbuild.PlatformArray{dockerbuild.Platform_Linux_amd64}, Push: pulumi.Bool(true), Registries: dockerbuild.RegistryArray{ &dockerbuild.RegistryArgs{ Address: registry.LoginServer, Username: registryUsername, Password: registryPassword, }, }, }) if err != nil { return err }
// Use a random string to give the service a unique DNS name. dnsNameSuffix, err := random.NewRandomString(ctx, "dns-name-suffix", &random.RandomStringArgs{ Length: pulumi.Int(8), Special: pulumi.Bool(false), }) if err != nil { return err } dnsName := dnsNameSuffix.Result.ApplyT(func(result string) string { return fmt.Sprintf("%s-%s", imageName, strings.ToLower(result)) }).(pulumi.StringOutput)
// Create a container group for the service that makes it publicly accessible. containerGroup, err := containerinstance.NewContainerGroup(ctx, "container-group", &containerinstance.ContainerGroupArgs{ ResourceGroupName: resourceGroup.Name, OsType: pulumi.String("linux"), RestartPolicy: pulumi.String("always"), ImageRegistryCredentials: containerinstance.ImageRegistryCredentialArray{ containerinstance.ImageRegistryCredentialArgs{ Server: registry.LoginServer, Username: registryUsername, Password: registryPassword, }, }, Containers: containerinstance.ContainerArray{ containerinstance.ContainerArgs{ Name: pulumi.String(imageName), Image: image.Ref, Ports: containerinstance.ContainerPortArray{ containerinstance.ContainerPortArgs{ Port: pulumi.Int(containerPort), Protocol: pulumi.String("tcp"), }, }, EnvironmentVariables: containerinstance.EnvironmentVariableArray{ containerinstance.EnvironmentVariableArgs{ Name: pulumi.String("PORT"), Value: pulumi.Sprintf("%d", containerPort), }, }, Resources: containerinstance.ResourceRequirementsArgs{ Requests: containerinstance.ResourceRequestsArgs{ Cpu: pulumi.Float64(cpu), MemoryInGB: pulumi.Float64(memory), }, }, }, }, IpAddress: containerinstance.IpAddressArgs{ Type: pulumi.String("public"), DnsNameLabel: dnsName, Ports: containerinstance.PortArray{ containerinstance.PortArgs{ Port: pulumi.Int(containerPort), Protocol: pulumi.String("tcp"), }, }, }, }) if err != nil { return err }
// Export the service's IP address, hostname, and fully-qualified URL. ctx.Export("ip", containerGroup.IpAddress.Elem().Ip()) ctx.Export("hostname", containerGroup.IpAddress.Elem().Fqdn()) ctx.Export("url", pulumi.Sprintf("http://%s:%d", containerGroup.IpAddress.Elem().Fqdn(), containerPort))
return nil })}using System;using System.Collections.Generic;using Pulumi;using AzureNative = Pulumi.AzureNative;using DockerBuild = Pulumi.DockerBuild;using Random = Pulumi.Random;
return await Pulumi.Deployment.RunAsync(() =>{ // Import the program's configuration settings. var config = new Config(); var appPath = config.Get("appPath") ?? "./app"; var imageName = config.Get("imageName") ?? "my-app"; var imageTag = config.Get("imageTag") ?? "latest"; var containerPort = config.GetInt32("containerPort") ?? 80; var cpu = config.GetInt32("cpu") ?? 1; var memory = config.GetInt32("memory") ?? 2;
// Create a resource group for the container registry. var resourceGroup = new AzureNative.Resources.ResourceGroup("resource-group");
// Create a container registry. var registry = new AzureNative.ContainerRegistry.Registry("registry", new() { ResourceGroupName = resourceGroup.Name, AdminUserEnabled = true, Sku = new AzureNative.ContainerRegistry.Inputs.SkuArgs { Name = AzureNative.ContainerRegistry.SkuName.Basic, }, });
// Fetch login credentials for the registry. var credentials = AzureNative.ContainerRegistry.ListRegistryCredentials.Invoke(new() { ResourceGroupName = resourceGroup.Name, RegistryName = registry.Name, }); var registryUsername = credentials.Apply(result => result.Username!); var registryPassword = credentials.Apply(result => result.Passwords[0]!.Value!);
// Create a container image for the service. var image = new DockerBuild.Image("image", new() { Tags = new[] { Pulumi.Output.Format($"{registry.LoginServer}/{imageName}:{imageTag}"), }, Context = new DockerBuild.Inputs.BuildContextArgs { Location = appPath, }, Platforms = new[] { DockerBuild.Platform.Linux_amd64,
}, Push = true, Registries = new[] { new DockerBuild.Inputs.RegistryArgs { Address = registry.LoginServer, Password = registryPassword, Username = registryUsername, }, }, });
// Use a random string to give the service a unique DNS name. var dnsName = new Random.RandomString("dns-name", new() { Length = 8, Special = false, }).Result.Apply(result => $"{imageName}-{result.ToLower()}");
// Create a container group for the service that makes it publicly accessible. var containerGroup = new AzureNative.ContainerInstance.ContainerGroup("container-group", new() { ResourceGroupName = resourceGroup.Name, OsType = "linux", RestartPolicy = "always", ImageRegistryCredentials = new AzureNative.ContainerInstance.Inputs.ImageRegistryCredentialArgs { Server = registry.LoginServer, Username = registryUsername, Password = registryPassword, }, Containers = new[] { new AzureNative.ContainerInstance.Inputs.ContainerArgs { Name = imageName, Image = image.Ref, Ports = new[] { new AzureNative.ContainerInstance.Inputs.ContainerPortArgs { Port = containerPort, Protocol = "tcp", }, }, EnvironmentVariables = new[] { new AzureNative.ContainerInstance.Inputs.EnvironmentVariableArgs { Name = "ASPNETCORE_URLS", Value = $"http://0.0.0.0:{containerPort}", }, }, Resources = new AzureNative.ContainerInstance.Inputs.ResourceRequirementsArgs { Requests = new AzureNative.ContainerInstance.Inputs.ResourceRequestsArgs { Cpu = cpu, MemoryInGB = memory, }, }, }, }, IpAddress = new AzureNative.ContainerInstance.Inputs.IpAddressArgs { Type = AzureNative.ContainerInstance.ContainerGroupIpAddressType.Public, DnsNameLabel = dnsName, Ports = new[] { new AzureNative.ContainerInstance.Inputs.PortArgs { Port = containerPort, Protocol = "tcp", }, }, } });
// Export the service's IP address, hostname, and fully-qualified URL. return new Dictionary<string, object?> { ["hostname"] = containerGroup.IpAddress.Apply(addr => addr!.Fqdn), ["ip"] = containerGroup.IpAddress.Apply(addr => addr!.Ip), ["url"] = containerGroup.IpAddress.Apply(addr => $"http://{addr!.Fqdn}:{containerPort}"), };});terraform { required_providers { azure-native = { source = "pulumi/azure-native" } docker-build = { source = "pulumi/docker-build" } random = { source = "pulumi/random" } }}
variable "app_path" { description = "The path to the container application to deploy" type = string default = "./app"}
variable "image_name" { description = "The name to give the container image" type = string default = "my-app"}
variable "image_tag" { description = "The tag to give the container image" type = string default = "latest"}
variable "container_port" { description = "The port to expose on the container" type = number default = 80}
variable "cpu" { description = "The number of CPU cores to allocate for the container" type = number default = 1}
variable "memory" { description = "The amount of memory, in GB, to allocate for the container" type = number default = 2}
# Use a random string to give the service a unique DNS name.resource "random_random_string" "dns-name" { length = 8 upper = false special = false}
# Create a resource group for the container registry.resource "azure-native_resources_resource_group" "resource-group" {}
# Create a container registry.resource "azure-native_containerregistry_registry" "registry" { resource_group_name = azure-native_resources_resource_group.resource-group.name admin_user_enabled = true sku = { name = "Basic" }}
# Fetch login credentials for the registry.data "azure-native_containerregistry_list_registry_credentials" "credentials" { resource_group_name = azure-native_resources_resource_group.resource-group.name registry_name = azure-native_containerregistry_registry.registry.name}
# Create a container image for the service.resource "docker-build_image" "image" { tags = ["${azure-native_containerregistry_registry.registry.login_server}/${var.image_name}:${var.image_tag}"] platforms = ["linux/amd64"] push = true
context = { location = var.app_path }
registries { address = azure-native_containerregistry_registry.registry.login_server username = data.azure-native_containerregistry_list_registry_credentials.credentials.username password = data.azure-native_containerregistry_list_registry_credentials.credentials.passwords[0].value }}
# Create a container group for the service that makes it publicly accessible.resource "azure-native_containerinstance_container_group" "container-group" { resource_group_name = azure-native_resources_resource_group.resource-group.name os_type = "Linux" restart_policy = "Always"
image_registry_credentials { server = azure-native_containerregistry_registry.registry.login_server username = data.azure-native_containerregistry_list_registry_credentials.credentials.username password = data.azure-native_containerregistry_list_registry_credentials.credentials.passwords[0].value }
containers { name = var.image_name image = docker-build_image.image.ref
ports { port = var.container_port protocol = "TCP" }
environment_variables { name = "PORT" value = tostring(var.container_port) }
resources = { requests = { cpu = var.cpu memory_in_gb = var.memory } } }
ip_address = { type = "Public" dns_name_label = "${var.image_name}-${random_random_string.dns-name.result}" ports = [{ port = var.container_port protocol = "TCP" }] }}
# Export the service's IP address, hostname, and fully-qualified URL.output "hostname" { value = azure-native_containerinstance_container_group.container-group.ip_address.fqdn}
output "ip" { value = azure-native_containerinstance_container_group.container-group.ip_address.ip}
output "url" { value = "http://${azure-native_containerinstance_container_group.container-group.ip_address.fqdn}:${var.container_port}"}Deploy the project#
Deploy with pulumi up. It starts with a preview of what it’s about to create and asks before it changes anything. Choose yes to deploy.
Pulumi builds the container image with Docker on your machine, so Docker needs to be running.
pulumi uppulumi upPulumi adds a random suffix to most resource names, so the resource group resource-group becomes something like resource-group3f8a2c1d. This is autonaming. It lets you deploy the same program to more than one stack, and lets Pulumi create a replacement before it deletes the old resource, without names colliding.
When it finishes, Pulumi prints the stack’s outputs, values it only knows once the resources exist:
- hostname
The hostname of the container group.
- ip
The public IP address of the container group.
- url
The HTTP URL of the container group.
Read one any time with pulumi stack output <name>, or pass it to another command. This opens the app in your browser:
open $(pulumi stack output url)xdg-open $(pulumi stack output url)Start-Process $(pulumi stack output url)To check it from the terminal, call the app with curl:
curl $(pulumi stack output url){"message":"Hello, world!"}curl.exe $(pulumi stack output url){"message":"Hello, world!"}Need help?
If pulumi up asks you to run az login, or says your sign-in has expired, sign in again:
az loginaz loginStill stuck? Let us know.
Customize the project#
Projects created with this template expose the following configuration settings:
- appPath
The path to the folder containing the application and Dockerfile. Defaults to
app, which contains a “Hello world” example.- containerPort
The port to expose on the container. Defaults to
80.- cpu
The number of CPU cores to allocate on the container. Defaults to
1.- memory
The amount of memory, in GB, to allocate on the container. Defaults to
2.- imageName
The name of the container image to be published to Azure Container Registry. Defaults to
my-app.- imageTag
The tag applied to published container images. Defaults to
latest.
- appPath
The path to the folder containing the application and Dockerfile. Defaults to
app, which contains a “Hello world” example.- containerPort
The port to expose on the container. Defaults to
80.- cpu
The number of CPU cores to allocate on the container. Defaults to
1.- memory
The amount of memory, in GB, to allocate on the container. Defaults to
2.- imageName
The name of the container image to be published to Azure Container Registry. Defaults to
my-app.- imageTag
The tag applied to published container images. Defaults to
latest.
- appPath
The path to the folder containing the application and Dockerfile. Defaults to
app, which contains a “Hello world” example.- containerPort
The port to expose on the container. Defaults to
80.- cpu
The number of CPU cores to allocate on the container. Defaults to
1.- memory
The amount of memory, in GB, to allocate on the container. Defaults to
2.- imageName
The name of the container image to be published to Azure Container Registry. Defaults to
my-app.- imageTag
The tag applied to published container images. Defaults to
latest.
- appPath
The path to the folder containing the application and Dockerfile. Defaults to
app, which contains a “Hello world” example.- containerPort
The port to expose on the container. Defaults to
80.- cpu
The number of CPU cores to allocate on the container. Defaults to
1.- memory
The amount of memory, in GB, to allocate on the container. Defaults to
2.- imageName
The name of the container image to be published to Azure Container Registry. Defaults to
my-app.- imageTag
The tag applied to published container images. Defaults to
latest.
- app_path
The path to the folder containing the application and Dockerfile. Defaults to
./app, which contains a “Hello world” example.- image_name
The name of the container image to be published to Azure Container Registry. Defaults to
my-app.- image_tag
The tag applied to published container images. Defaults to
latest.- container_port
The port to expose on the container. Defaults to
80.- cpu
The number of CPU cores to allocate on the container. Defaults to
1.- memory
The amount of memory, in GB, to allocate on the container. Defaults to
2.
All of these settings are optional and may be adjusted either by editing the stack configuration file directly (by default, Pulumi.dev.yaml) or by changing their values with pulumi config set.
For example, move the app to port 8080:
pulumi config set containerPort 8080pulumi uppulumi config set containerPort 8080pulumi uppulumi config set containerPort 8080pulumi uppulumi config set containerPort 8080pulumi uppulumi config set containerPort 8080pulumi uppulumi config set containerPort 8080pulumi uppulumi config set containerPort 8080pulumi uppulumi config set containerPort 8080pulumi uppulumi config set container_port 8080pulumi uppulumi config set container_port 8080pulumi upThe program passes the port to the app and opens it on the container group, so the url output now ends in :8080. Call it again to check:
curl $(pulumi stack output url){"message":"Hello, world!"}curl.exe $(pulumi stack output url){"message":"Hello, world!"}To see what else you can add, browse the Azure Native provider in the Pulumi Registry.
Cleaning up#
You can cleanly destroy the stack and all of its infrastructure with pulumi destroy:
pulumi destroypulumi destroyLearn more#
- Browse other architecture templates in the Templates gallery.
- Explore the Azure Native provider API docs in the Pulumi Registry.
- Walk through Pulumi from the ground up in Pulumi Tutorials.
- Read the latest container posts on the Pulumi blog.