The aws:lightsail/containerService:ContainerService resource, part of the Pulumi AWS provider, provisions the Lightsail container service platform: compute nodes, networking, and access configuration. This guide focuses on three capabilities: compute capacity configuration, custom domain mapping, and ECR private registry access.
Container services require validated SSL/TLS certificates for custom domains and may reference ECR repositories for private images. The examples are intentionally small. Combine them with your own container deployments, certificates, and image repositories.
Create a container service with compute capacity
Most deployments start by defining compute capacity and naming the service for identification.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.lightsail.ContainerService("example", {
name: "container-service-1",
power: "nano",
scale: 1,
isDisabled: false,
tags: {
foo1: "bar1",
foo2: "",
},
});
import pulumi
import pulumi_aws as aws
example = aws.lightsail.ContainerService("example",
name="container-service-1",
power="nano",
scale=1,
is_disabled=False,
tags={
"foo1": "bar1",
"foo2": "",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lightsail"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := lightsail.NewContainerService(ctx, "example", &lightsail.ContainerServiceArgs{
Name: pulumi.String("container-service-1"),
Power: pulumi.String("nano"),
Scale: pulumi.Int(1),
IsDisabled: pulumi.Bool(false),
Tags: pulumi.StringMap{
"foo1": pulumi.String("bar1"),
"foo2": pulumi.String(""),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.LightSail.ContainerService("example", new()
{
Name = "container-service-1",
Power = "nano",
Scale = 1,
IsDisabled = false,
Tags =
{
{ "foo1", "bar1" },
{ "foo2", "" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lightsail.ContainerService;
import com.pulumi.aws.lightsail.ContainerServiceArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new ContainerService("example", ContainerServiceArgs.builder()
.name("container-service-1")
.power("nano")
.scale(1)
.isDisabled(false)
.tags(Map.ofEntries(
Map.entry("foo1", "bar1"),
Map.entry("foo2", "")
))
.build());
}
}
resources:
example:
type: aws:lightsail:ContainerService
properties:
name: container-service-1
power: nano
scale: 1
isDisabled: false
tags:
foo1: bar1
foo2: ""
The power property sets the node size (nano through xlarge), determining memory, vCPUs, and monthly cost per node. The scale property sets how many nodes run. Together, these define your total compute capacity. The isDisabled property lets you pause the service without deleting it.
Map custom domains to the container service
Applications serving public traffic often need custom domains instead of the default Lightsail URL.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.lightsail.ContainerService("example", {publicDomainNames: {
certificates: [{
certificateName: "example-certificate",
domainNames: ["www.example.com"],
}],
}});
import pulumi
import pulumi_aws as aws
example = aws.lightsail.ContainerService("example", public_domain_names={
"certificates": [{
"certificate_name": "example-certificate",
"domain_names": ["www.example.com"],
}],
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lightsail"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := lightsail.NewContainerService(ctx, "example", &lightsail.ContainerServiceArgs{
PublicDomainNames: &lightsail.ContainerServicePublicDomainNamesArgs{
Certificates: lightsail.ContainerServicePublicDomainNamesCertificateArray{
&lightsail.ContainerServicePublicDomainNamesCertificateArgs{
CertificateName: pulumi.String("example-certificate"),
DomainNames: pulumi.StringArray{
pulumi.String("www.example.com"),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.LightSail.ContainerService("example", new()
{
PublicDomainNames = new Aws.LightSail.Inputs.ContainerServicePublicDomainNamesArgs
{
Certificates = new[]
{
new Aws.LightSail.Inputs.ContainerServicePublicDomainNamesCertificateArgs
{
CertificateName = "example-certificate",
DomainNames = new[]
{
"www.example.com",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lightsail.ContainerService;
import com.pulumi.aws.lightsail.ContainerServiceArgs;
import com.pulumi.aws.lightsail.inputs.ContainerServicePublicDomainNamesArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new ContainerService("example", ContainerServiceArgs.builder()
.publicDomainNames(ContainerServicePublicDomainNamesArgs.builder()
.certificates(ContainerServicePublicDomainNamesCertificateArgs.builder()
.certificateName("example-certificate")
.domainNames("www.example.com")
.build())
.build())
.build());
}
}
resources:
example:
type: aws:lightsail:ContainerService
properties:
publicDomainNames:
certificates:
- certificateName: example-certificate
domainNames:
- www.example.com
The publicDomainNames property maps custom domains to your service. Each certificate can cover multiple domains. You must create and validate an SSL/TLS certificate in Lightsail before using it here; the certificateName references that certificate. DNS records must point to the container service for traffic to reach it.
Pull images from Amazon ECR private repositories
Teams storing images in private ECR repositories need to grant the service permission to pull them.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const exampleContainerService = new aws.lightsail.ContainerService("example", {privateRegistryAccess: {
ecrImagePullerRole: {
isActive: true,
},
}});
const example = exampleContainerService.privateRegistryAccess.apply(privateRegistryAccess => aws.iam.getPolicyDocumentOutput({
statements: [{
effect: "Allow",
principals: [{
type: "AWS",
identifiers: [privateRegistryAccess.ecrImagePullerRole?.principalArn],
}],
actions: [
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer",
],
}],
}));
const exampleRepositoryPolicy = new aws.ecr.RepositoryPolicy("example", {
repository: exampleAwsEcrRepository.name,
policy: example.apply(example => example.json),
});
import pulumi
import pulumi_aws as aws
example_container_service = aws.lightsail.ContainerService("example", private_registry_access={
"ecr_image_puller_role": {
"is_active": True,
},
})
example = example_container_service.private_registry_access.apply(lambda private_registry_access: aws.iam.get_policy_document_output(statements=[{
"effect": "Allow",
"principals": [{
"type": "AWS",
"identifiers": [private_registry_access.ecr_image_puller_role.principal_arn],
}],
"actions": [
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer",
],
}]))
example_repository_policy = aws.ecr.RepositoryPolicy("example",
repository=example_aws_ecr_repository["name"],
policy=example.json)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ecr"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lightsail"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
exampleContainerService, err := lightsail.NewContainerService(ctx, "example", &lightsail.ContainerServiceArgs{
PrivateRegistryAccess: &lightsail.ContainerServicePrivateRegistryAccessArgs{
EcrImagePullerRole: &lightsail.ContainerServicePrivateRegistryAccessEcrImagePullerRoleArgs{
IsActive: pulumi.Bool(true),
},
},
})
if err != nil {
return err
}
example := exampleContainerService.PrivateRegistryAccess.ApplyT(func(privateRegistryAccess lightsail.ContainerServicePrivateRegistryAccess) (iam.GetPolicyDocumentResult, error) {
return iam.GetPolicyDocumentResult(interface{}(iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
Statements: []iam.GetPolicyDocumentStatement([]iam.GetPolicyDocumentStatement{
{
Effect: pulumi.StringRef(pulumi.String(pulumi.StringRef("Allow"))),
Principals: []iam.GetPolicyDocumentStatementPrincipal{
{
Type: "AWS",
Identifiers: interface{}{
privateRegistryAccess.EcrImagePullerRole.PrincipalArn,
},
},
},
Actions: []string{
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer",
},
},
}),
}, nil))), nil
}).(iam.GetPolicyDocumentResultOutput)
_, err = ecr.NewRepositoryPolicy(ctx, "example", &ecr.RepositoryPolicyArgs{
Repository: pulumi.Any(exampleAwsEcrRepository.Name),
Policy: pulumi.String(example.ApplyT(func(example iam.GetPolicyDocumentResult) (*string, error) {
return &example.Json, nil
}).(pulumi.StringPtrOutput)),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var exampleContainerService = new Aws.LightSail.ContainerService("example", new()
{
PrivateRegistryAccess = new Aws.LightSail.Inputs.ContainerServicePrivateRegistryAccessArgs
{
EcrImagePullerRole = new Aws.LightSail.Inputs.ContainerServicePrivateRegistryAccessEcrImagePullerRoleArgs
{
IsActive = true,
},
},
});
var example = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementArgs
{
Effect = "Allow",
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalArgs
{
Type = "AWS",
Identifiers = new[]
{
exampleContainerService.PrivateRegistryAccess.EcrImagePullerRole?.PrincipalArn,
},
},
},
Actions = new[]
{
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer",
},
},
},
});
var exampleRepositoryPolicy = new Aws.Ecr.RepositoryPolicy("example", new()
{
Repository = exampleAwsEcrRepository.Name,
Policy = example.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lightsail.ContainerService;
import com.pulumi.aws.lightsail.ContainerServiceArgs;
import com.pulumi.aws.lightsail.inputs.ContainerServicePrivateRegistryAccessArgs;
import com.pulumi.aws.lightsail.inputs.ContainerServicePrivateRegistryAccessEcrImagePullerRoleArgs;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.ecr.RepositoryPolicy;
import com.pulumi.aws.ecr.RepositoryPolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var exampleContainerService = new ContainerService("exampleContainerService", ContainerServiceArgs.builder()
.privateRegistryAccess(ContainerServicePrivateRegistryAccessArgs.builder()
.ecrImagePullerRole(ContainerServicePrivateRegistryAccessEcrImagePullerRoleArgs.builder()
.isActive(true)
.build())
.build())
.build());
final var example = exampleContainerService.privateRegistryAccess().applyValue(_privateRegistryAccess -> IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.effect("Allow")
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.type("AWS")
.identifiers(_privateRegistryAccess.ecrImagePullerRole().principalArn())
.build())
.actions(
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer")
.build())
.build()));
var exampleRepositoryPolicy = new RepositoryPolicy("exampleRepositoryPolicy", RepositoryPolicyArgs.builder()
.repository(exampleAwsEcrRepository.name())
.policy(example.applyValue(_example -> _example.json()))
.build());
}
}
resources:
exampleContainerService:
type: aws:lightsail:ContainerService
name: example
properties:
privateRegistryAccess:
ecrImagePullerRole:
isActive: true
exampleRepositoryPolicy:
type: aws:ecr:RepositoryPolicy
name: example
properties:
repository: ${exampleAwsEcrRepository.name}
policy: ${example.json}
variables:
example:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- effect: Allow
principals:
- type: AWS
identifiers:
- ${exampleContainerService.privateRegistryAccess.ecrImagePullerRole.principalArn}
actions:
- ecr:BatchGetImage
- ecr:GetDownloadUrlForLayer
The privateRegistryAccess property enables ECR integration. Setting isActive to true creates an IAM role that can pull images. The example shows how to use the service’s principalArn to create an ECR repository policy that grants pull permissions. This lets your container service authenticate to ECR and pull private images during deployment.
Beyond these examples
These snippets focus on specific container service features: compute capacity sizing, custom domain mapping with SSL/TLS, and ECR private registry integration. They’re intentionally minimal rather than full container deployments.
The examples may reference pre-existing infrastructure such as SSL/TLS certificates for custom domains, ECR repositories with container images, and DNS configuration pointing to the service. They focus on configuring the service platform rather than deploying containers.
To keep things focused, common container service patterns are omitted, including:
- Container deployment configuration (images, ports, environment variables)
- Health checks and monitoring
- Scaling policies and auto-scaling
- Network configuration and VPC peering
These omissions are intentional: the goal is to illustrate how each service feature is wired, not provide drop-in container platforms. See the Lightsail ContainerService resource reference for all available configuration options.
Let's deploy AWS Lightsail Container Services
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Setup
nano, micro, small, medium, large, and xlarge. Each power level determines the memory, number of vCPUs, and monthly price per node.name (1-63 characters, unique per region), power (e.g., nano), and scale (number of compute nodes).name property is immutable. Changing it requires destroying and recreating the service, so plan your naming carefully.Custom Domains & SSL
publicDomainNames. Custom domains won’t work without a validated certificate.publicDomainNames. Each domain requires certificate configuration.url output property.Private Registry Access
privateRegistryAccess with ecrImagePullerRole.isActive set to true, then create an ECR repository policy granting access to the principalArn output property.Resource Management
isDisabled to true. This disables the service while preserving its configuration. The default is false.Using a different cloud?
Explore containers guides for other cloud providers: