The gcp:compute/instanceTemplate:InstanceTemplate resource, part of the Pulumi GCP provider, defines reusable VM configurations for managed instance groups: machine type, disks, networking, and security settings. This guide focuses on three capabilities: disk and backup policy configuration, image selection strategies, and Confidential Computing setup.
Instance templates reference service accounts, networks, and optionally existing disks or resource policies that must exist separately. The examples are intentionally small. Combine them with your own IAM, networking, and storage infrastructure.
Define a template with disks, scheduling, and service accounts
Most deployments start by specifying the machine type, boot disk image, and service account that instances will use.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.serviceaccount.Account("default", {
accountId: "service-account-id",
displayName: "Service Account",
});
const myImage = gcp.compute.getImage({
family: "debian-11",
project: "debian-cloud",
});
const foobar = new gcp.compute.Disk("foobar", {
name: "existing-disk",
image: myImage.then(myImage => myImage.selfLink),
size: 10,
type: "pd-ssd",
zone: "us-central1-a",
});
const dailyBackup = new gcp.compute.ResourcePolicy("daily_backup", {
name: "every-day-4am",
region: "us-central1",
snapshotSchedulePolicy: {
schedule: {
dailySchedule: {
daysInCycle: 1,
startTime: "04:00",
},
},
},
});
const defaultInstanceTemplate = new gcp.compute.InstanceTemplate("default", {
name: "appserver-template",
description: "This template is used to create app server instances.",
tags: [
"foo",
"bar",
],
labels: {
environment: "dev",
},
instanceDescription: "description assigned to instances",
machineType: "e2-medium",
canIpForward: false,
scheduling: {
automaticRestart: true,
onHostMaintenance: "MIGRATE",
},
disks: [
{
sourceImage: "debian-cloud/debian-11",
autoDelete: true,
boot: true,
resourcePolicies: dailyBackup.id,
},
{
source: foobar.name,
autoDelete: false,
boot: false,
},
],
networkInterfaces: [{
network: "default",
}],
metadata: {
foo: "bar",
},
serviceAccount: {
email: _default.email,
scopes: ["cloud-platform"],
},
});
import pulumi
import pulumi_gcp as gcp
default = gcp.serviceaccount.Account("default",
account_id="service-account-id",
display_name="Service Account")
my_image = gcp.compute.get_image(family="debian-11",
project="debian-cloud")
foobar = gcp.compute.Disk("foobar",
name="existing-disk",
image=my_image.self_link,
size=10,
type="pd-ssd",
zone="us-central1-a")
daily_backup = gcp.compute.ResourcePolicy("daily_backup",
name="every-day-4am",
region="us-central1",
snapshot_schedule_policy={
"schedule": {
"daily_schedule": {
"days_in_cycle": 1,
"start_time": "04:00",
},
},
})
default_instance_template = gcp.compute.InstanceTemplate("default",
name="appserver-template",
description="This template is used to create app server instances.",
tags=[
"foo",
"bar",
],
labels={
"environment": "dev",
},
instance_description="description assigned to instances",
machine_type="e2-medium",
can_ip_forward=False,
scheduling={
"automatic_restart": True,
"on_host_maintenance": "MIGRATE",
},
disks=[
{
"source_image": "debian-cloud/debian-11",
"auto_delete": True,
"boot": True,
"resource_policies": daily_backup.id,
},
{
"source": foobar.name,
"auto_delete": False,
"boot": False,
},
],
network_interfaces=[{
"network": "default",
}],
metadata={
"foo": "bar",
},
service_account={
"email": default.email,
"scopes": ["cloud-platform"],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/serviceaccount"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := serviceaccount.NewAccount(ctx, "default", &serviceaccount.AccountArgs{
AccountId: pulumi.String("service-account-id"),
DisplayName: pulumi.String("Service Account"),
})
if err != nil {
return err
}
myImage, err := compute.LookupImage(ctx, &compute.LookupImageArgs{
Family: pulumi.StringRef("debian-11"),
Project: pulumi.StringRef("debian-cloud"),
}, nil)
if err != nil {
return err
}
foobar, err := compute.NewDisk(ctx, "foobar", &compute.DiskArgs{
Name: pulumi.String("existing-disk"),
Image: pulumi.String(myImage.SelfLink),
Size: pulumi.Int(10),
Type: pulumi.String("pd-ssd"),
Zone: pulumi.String("us-central1-a"),
})
if err != nil {
return err
}
dailyBackup, err := compute.NewResourcePolicy(ctx, "daily_backup", &compute.ResourcePolicyArgs{
Name: pulumi.String("every-day-4am"),
Region: pulumi.String("us-central1"),
SnapshotSchedulePolicy: &compute.ResourcePolicySnapshotSchedulePolicyArgs{
Schedule: &compute.ResourcePolicySnapshotSchedulePolicyScheduleArgs{
DailySchedule: &compute.ResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleArgs{
DaysInCycle: pulumi.Int(1),
StartTime: pulumi.String("04:00"),
},
},
},
})
if err != nil {
return err
}
_, err = compute.NewInstanceTemplate(ctx, "default", &compute.InstanceTemplateArgs{
Name: pulumi.String("appserver-template"),
Description: pulumi.String("This template is used to create app server instances."),
Tags: pulumi.StringArray{
pulumi.String("foo"),
pulumi.String("bar"),
},
Labels: pulumi.StringMap{
"environment": pulumi.String("dev"),
},
InstanceDescription: pulumi.String("description assigned to instances"),
MachineType: pulumi.String("e2-medium"),
CanIpForward: pulumi.Bool(false),
Scheduling: &compute.InstanceTemplateSchedulingArgs{
AutomaticRestart: pulumi.Bool(true),
OnHostMaintenance: pulumi.String("MIGRATE"),
},
Disks: compute.InstanceTemplateDiskArray{
&compute.InstanceTemplateDiskArgs{
SourceImage: pulumi.String("debian-cloud/debian-11"),
AutoDelete: pulumi.Bool(true),
Boot: pulumi.Bool(true),
ResourcePolicies: dailyBackup.ID(),
},
&compute.InstanceTemplateDiskArgs{
Source: foobar.Name,
AutoDelete: pulumi.Bool(false),
Boot: pulumi.Bool(false),
},
},
NetworkInterfaces: compute.InstanceTemplateNetworkInterfaceArray{
&compute.InstanceTemplateNetworkInterfaceArgs{
Network: pulumi.String("default"),
},
},
Metadata: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
ServiceAccount: &compute.InstanceTemplateServiceAccountArgs{
Email: _default.Email,
Scopes: pulumi.StringArray{
pulumi.String("cloud-platform"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.ServiceAccount.Account("default", new()
{
AccountId = "service-account-id",
DisplayName = "Service Account",
});
var myImage = Gcp.Compute.GetImage.Invoke(new()
{
Family = "debian-11",
Project = "debian-cloud",
});
var foobar = new Gcp.Compute.Disk("foobar", new()
{
Name = "existing-disk",
Image = myImage.Apply(getImageResult => getImageResult.SelfLink),
Size = 10,
Type = "pd-ssd",
Zone = "us-central1-a",
});
var dailyBackup = new Gcp.Compute.ResourcePolicy("daily_backup", new()
{
Name = "every-day-4am",
Region = "us-central1",
SnapshotSchedulePolicy = new Gcp.Compute.Inputs.ResourcePolicySnapshotSchedulePolicyArgs
{
Schedule = new Gcp.Compute.Inputs.ResourcePolicySnapshotSchedulePolicyScheduleArgs
{
DailySchedule = new Gcp.Compute.Inputs.ResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleArgs
{
DaysInCycle = 1,
StartTime = "04:00",
},
},
},
});
var defaultInstanceTemplate = new Gcp.Compute.InstanceTemplate("default", new()
{
Name = "appserver-template",
Description = "This template is used to create app server instances.",
Tags = new[]
{
"foo",
"bar",
},
Labels =
{
{ "environment", "dev" },
},
InstanceDescription = "description assigned to instances",
MachineType = "e2-medium",
CanIpForward = false,
Scheduling = new Gcp.Compute.Inputs.InstanceTemplateSchedulingArgs
{
AutomaticRestart = true,
OnHostMaintenance = "MIGRATE",
},
Disks = new[]
{
new Gcp.Compute.Inputs.InstanceTemplateDiskArgs
{
SourceImage = "debian-cloud/debian-11",
AutoDelete = true,
Boot = true,
ResourcePolicies = dailyBackup.Id,
},
new Gcp.Compute.Inputs.InstanceTemplateDiskArgs
{
Source = foobar.Name,
AutoDelete = false,
Boot = false,
},
},
NetworkInterfaces = new[]
{
new Gcp.Compute.Inputs.InstanceTemplateNetworkInterfaceArgs
{
Network = "default",
},
},
Metadata =
{
{ "foo", "bar" },
},
ServiceAccount = new Gcp.Compute.Inputs.InstanceTemplateServiceAccountArgs
{
Email = @default.Email,
Scopes = new[]
{
"cloud-platform",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.serviceaccount.Account;
import com.pulumi.gcp.serviceaccount.AccountArgs;
import com.pulumi.gcp.compute.ComputeFunctions;
import com.pulumi.gcp.compute.inputs.GetImageArgs;
import com.pulumi.gcp.compute.Disk;
import com.pulumi.gcp.compute.DiskArgs;
import com.pulumi.gcp.compute.ResourcePolicy;
import com.pulumi.gcp.compute.ResourcePolicyArgs;
import com.pulumi.gcp.compute.inputs.ResourcePolicySnapshotSchedulePolicyArgs;
import com.pulumi.gcp.compute.inputs.ResourcePolicySnapshotSchedulePolicyScheduleArgs;
import com.pulumi.gcp.compute.inputs.ResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleArgs;
import com.pulumi.gcp.compute.InstanceTemplate;
import com.pulumi.gcp.compute.InstanceTemplateArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateSchedulingArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateDiskArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateNetworkInterfaceArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateServiceAccountArgs;
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 default_ = new Account("default", AccountArgs.builder()
.accountId("service-account-id")
.displayName("Service Account")
.build());
final var myImage = ComputeFunctions.getImage(GetImageArgs.builder()
.family("debian-11")
.project("debian-cloud")
.build());
var foobar = new Disk("foobar", DiskArgs.builder()
.name("existing-disk")
.image(myImage.selfLink())
.size(10)
.type("pd-ssd")
.zone("us-central1-a")
.build());
var dailyBackup = new ResourcePolicy("dailyBackup", ResourcePolicyArgs.builder()
.name("every-day-4am")
.region("us-central1")
.snapshotSchedulePolicy(ResourcePolicySnapshotSchedulePolicyArgs.builder()
.schedule(ResourcePolicySnapshotSchedulePolicyScheduleArgs.builder()
.dailySchedule(ResourcePolicySnapshotSchedulePolicyScheduleDailyScheduleArgs.builder()
.daysInCycle(1)
.startTime("04:00")
.build())
.build())
.build())
.build());
var defaultInstanceTemplate = new InstanceTemplate("defaultInstanceTemplate", InstanceTemplateArgs.builder()
.name("appserver-template")
.description("This template is used to create app server instances.")
.tags(
"foo",
"bar")
.labels(Map.of("environment", "dev"))
.instanceDescription("description assigned to instances")
.machineType("e2-medium")
.canIpForward(false)
.scheduling(InstanceTemplateSchedulingArgs.builder()
.automaticRestart(true)
.onHostMaintenance("MIGRATE")
.build())
.disks(
InstanceTemplateDiskArgs.builder()
.sourceImage("debian-cloud/debian-11")
.autoDelete(true)
.boot(true)
.resourcePolicies(dailyBackup.id())
.build(),
InstanceTemplateDiskArgs.builder()
.source(foobar.name())
.autoDelete(false)
.boot(false)
.build())
.networkInterfaces(InstanceTemplateNetworkInterfaceArgs.builder()
.network("default")
.build())
.metadata(Map.of("foo", "bar"))
.serviceAccount(InstanceTemplateServiceAccountArgs.builder()
.email(default_.email())
.scopes("cloud-platform")
.build())
.build());
}
}
resources:
default:
type: gcp:serviceaccount:Account
properties:
accountId: service-account-id
displayName: Service Account
defaultInstanceTemplate:
type: gcp:compute:InstanceTemplate
name: default
properties:
name: appserver-template
description: This template is used to create app server instances.
tags:
- foo
- bar
labels:
environment: dev
instanceDescription: description assigned to instances
machineType: e2-medium
canIpForward: false
scheduling:
automaticRestart: true
onHostMaintenance: MIGRATE
disks:
- sourceImage: debian-cloud/debian-11
autoDelete: true
boot: true
resourcePolicies: ${dailyBackup.id}
- source: ${foobar.name}
autoDelete: false
boot: false
networkInterfaces:
- network: default
metadata:
foo: bar
serviceAccount:
email: ${default.email}
scopes:
- cloud-platform
foobar:
type: gcp:compute:Disk
properties:
name: existing-disk
image: ${myImage.selfLink}
size: 10
type: pd-ssd
zone: us-central1-a
dailyBackup:
type: gcp:compute:ResourcePolicy
name: daily_backup
properties:
name: every-day-4am
region: us-central1
snapshotSchedulePolicy:
schedule:
dailySchedule:
daysInCycle: 1
startTime: 04:00
variables:
myImage:
fn::invoke:
function: gcp:compute:getImage
arguments:
family: debian-11
project: debian-cloud
The machineType property sets the VM size (e.g., “e2-medium”). The disks array defines boot and data disks; sourceImage specifies the OS, and resourcePolicies attaches backup schedules. The scheduling block controls restart behavior during maintenance. The serviceAccount property grants instances permissions via scopes like “cloud-platform”.
Deploy the latest image using dynamic lookup
Teams often want all instances to use the same image version, determined when Pulumi runs.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const myImage = gcp.compute.getImage({
family: "debian-11",
project: "debian-cloud",
});
const instanceTemplate = new gcp.compute.InstanceTemplate("instance_template", {
namePrefix: "instance-template-",
machineType: "e2-medium",
region: "us-central1",
disks: [{
sourceImage: myImage.then(myImage => myImage.selfLink),
}],
});
import pulumi
import pulumi_gcp as gcp
my_image = gcp.compute.get_image(family="debian-11",
project="debian-cloud")
instance_template = gcp.compute.InstanceTemplate("instance_template",
name_prefix="instance-template-",
machine_type="e2-medium",
region="us-central1",
disks=[{
"source_image": my_image.self_link,
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
myImage, err := compute.LookupImage(ctx, &compute.LookupImageArgs{
Family: pulumi.StringRef("debian-11"),
Project: pulumi.StringRef("debian-cloud"),
}, nil)
if err != nil {
return err
}
_, err = compute.NewInstanceTemplate(ctx, "instance_template", &compute.InstanceTemplateArgs{
NamePrefix: pulumi.String("instance-template-"),
MachineType: pulumi.String("e2-medium"),
Region: pulumi.String("us-central1"),
Disks: compute.InstanceTemplateDiskArray{
&compute.InstanceTemplateDiskArgs{
SourceImage: pulumi.String(myImage.SelfLink),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var myImage = Gcp.Compute.GetImage.Invoke(new()
{
Family = "debian-11",
Project = "debian-cloud",
});
var instanceTemplate = new Gcp.Compute.InstanceTemplate("instance_template", new()
{
NamePrefix = "instance-template-",
MachineType = "e2-medium",
Region = "us-central1",
Disks = new[]
{
new Gcp.Compute.Inputs.InstanceTemplateDiskArgs
{
SourceImage = myImage.Apply(getImageResult => getImageResult.SelfLink),
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.ComputeFunctions;
import com.pulumi.gcp.compute.inputs.GetImageArgs;
import com.pulumi.gcp.compute.InstanceTemplate;
import com.pulumi.gcp.compute.InstanceTemplateArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateDiskArgs;
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) {
final var myImage = ComputeFunctions.getImage(GetImageArgs.builder()
.family("debian-11")
.project("debian-cloud")
.build());
var instanceTemplate = new InstanceTemplate("instanceTemplate", InstanceTemplateArgs.builder()
.namePrefix("instance-template-")
.machineType("e2-medium")
.region("us-central1")
.disks(InstanceTemplateDiskArgs.builder()
.sourceImage(myImage.selfLink())
.build())
.build());
}
}
resources:
instanceTemplate:
type: gcp:compute:InstanceTemplate
name: instance_template
properties:
namePrefix: instance-template-
machineType: e2-medium
region: us-central1
disks:
- sourceImage: ${myImage.selfLink}
variables:
myImage:
fn::invoke:
function: gcp:compute:getImage
arguments:
family: debian-11
project: debian-cloud
The getImage function retrieves the latest image from a family at deployment time. Using selfLink in sourceImage locks all instances to that specific image version, ensuring consistency across the instance group. New deployments require a Pulumi update to pick up newer images.
Let instances fetch the latest image at creation
Some deployments prefer instances to check for the latest image when they’re created during scaling or rebuilds.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const instanceTemplate = new gcp.compute.InstanceTemplate("instance_template", {
namePrefix: "instance-template-",
machineType: "e2-medium",
region: "us-central1",
disks: [{
sourceImage: "debian-cloud/debian-11",
}],
});
import pulumi
import pulumi_gcp as gcp
instance_template = gcp.compute.InstanceTemplate("instance_template",
name_prefix="instance-template-",
machine_type="e2-medium",
region="us-central1",
disks=[{
"source_image": "debian-cloud/debian-11",
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := compute.NewInstanceTemplate(ctx, "instance_template", &compute.InstanceTemplateArgs{
NamePrefix: pulumi.String("instance-template-"),
MachineType: pulumi.String("e2-medium"),
Region: pulumi.String("us-central1"),
Disks: compute.InstanceTemplateDiskArray{
&compute.InstanceTemplateDiskArgs{
SourceImage: pulumi.String("debian-cloud/debian-11"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var instanceTemplate = new Gcp.Compute.InstanceTemplate("instance_template", new()
{
NamePrefix = "instance-template-",
MachineType = "e2-medium",
Region = "us-central1",
Disks = new[]
{
new Gcp.Compute.Inputs.InstanceTemplateDiskArgs
{
SourceImage = "debian-cloud/debian-11",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.InstanceTemplate;
import com.pulumi.gcp.compute.InstanceTemplateArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateDiskArgs;
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 instanceTemplate = new InstanceTemplate("instanceTemplate", InstanceTemplateArgs.builder()
.namePrefix("instance-template-")
.machineType("e2-medium")
.region("us-central1")
.disks(InstanceTemplateDiskArgs.builder()
.sourceImage("debian-cloud/debian-11")
.build())
.build());
}
}
resources:
instanceTemplate:
type: gcp:compute:InstanceTemplate
name: instance_template
properties:
namePrefix: instance-template-
machineType: e2-medium
region: us-central1
disks:
- sourceImage: debian-cloud/debian-11
Setting sourceImage to the family name (e.g., “debian-cloud/debian-11”) delegates image lookup to GCP. Each new instance checks for the latest image in that family at creation time, allowing automatic updates without Pulumi changes. This differs from EX4, where the image version is fixed at deployment.
Enable Confidential Computing for encrypted workloads
Workloads handling sensitive data can use Confidential Computing to encrypt data in memory.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.serviceaccount.Account("default", {
accountId: "my-custom-sa",
displayName: "Custom SA for VM Instance",
});
const confidentialInstanceTemplate = new gcp.compute.InstanceTemplate("confidential_instance_template", {
networkInterfaces: [{
accessConfigs: [{}],
network: "default",
}],
name: "my-confidential-instance-template",
region: "us-central1",
machineType: "n2d-standard-2",
minCpuPlatform: "AMD Milan",
confidentialInstanceConfig: {
enableConfidentialCompute: true,
confidentialInstanceType: "SEV",
},
disks: [{
sourceImage: "ubuntu-os-cloud/ubuntu-2204-lts",
}],
serviceAccount: {
email: _default.email,
scopes: ["cloud-platform"],
},
});
import pulumi
import pulumi_gcp as gcp
default = gcp.serviceaccount.Account("default",
account_id="my-custom-sa",
display_name="Custom SA for VM Instance")
confidential_instance_template = gcp.compute.InstanceTemplate("confidential_instance_template",
network_interfaces=[{
"access_configs": [{}],
"network": "default",
}],
name="my-confidential-instance-template",
region="us-central1",
machine_type="n2d-standard-2",
min_cpu_platform="AMD Milan",
confidential_instance_config={
"enable_confidential_compute": True,
"confidential_instance_type": "SEV",
},
disks=[{
"source_image": "ubuntu-os-cloud/ubuntu-2204-lts",
}],
service_account={
"email": default.email,
"scopes": ["cloud-platform"],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/serviceaccount"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := serviceaccount.NewAccount(ctx, "default", &serviceaccount.AccountArgs{
AccountId: pulumi.String("my-custom-sa"),
DisplayName: pulumi.String("Custom SA for VM Instance"),
})
if err != nil {
return err
}
_, err = compute.NewInstanceTemplate(ctx, "confidential_instance_template", &compute.InstanceTemplateArgs{
NetworkInterfaces: compute.InstanceTemplateNetworkInterfaceArray{
&compute.InstanceTemplateNetworkInterfaceArgs{
AccessConfigs: compute.InstanceTemplateNetworkInterfaceAccessConfigArray{
&compute.InstanceTemplateNetworkInterfaceAccessConfigArgs{},
},
Network: pulumi.String("default"),
},
},
Name: pulumi.String("my-confidential-instance-template"),
Region: pulumi.String("us-central1"),
MachineType: pulumi.String("n2d-standard-2"),
MinCpuPlatform: pulumi.String("AMD Milan"),
ConfidentialInstanceConfig: &compute.InstanceTemplateConfidentialInstanceConfigArgs{
EnableConfidentialCompute: pulumi.Bool(true),
ConfidentialInstanceType: pulumi.String("SEV"),
},
Disks: compute.InstanceTemplateDiskArray{
&compute.InstanceTemplateDiskArgs{
SourceImage: pulumi.String("ubuntu-os-cloud/ubuntu-2204-lts"),
},
},
ServiceAccount: &compute.InstanceTemplateServiceAccountArgs{
Email: _default.Email,
Scopes: pulumi.StringArray{
pulumi.String("cloud-platform"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.ServiceAccount.Account("default", new()
{
AccountId = "my-custom-sa",
DisplayName = "Custom SA for VM Instance",
});
var confidentialInstanceTemplate = new Gcp.Compute.InstanceTemplate("confidential_instance_template", new()
{
NetworkInterfaces = new[]
{
new Gcp.Compute.Inputs.InstanceTemplateNetworkInterfaceArgs
{
AccessConfigs = new[]
{
null,
},
Network = "default",
},
},
Name = "my-confidential-instance-template",
Region = "us-central1",
MachineType = "n2d-standard-2",
MinCpuPlatform = "AMD Milan",
ConfidentialInstanceConfig = new Gcp.Compute.Inputs.InstanceTemplateConfidentialInstanceConfigArgs
{
EnableConfidentialCompute = true,
ConfidentialInstanceType = "SEV",
},
Disks = new[]
{
new Gcp.Compute.Inputs.InstanceTemplateDiskArgs
{
SourceImage = "ubuntu-os-cloud/ubuntu-2204-lts",
},
},
ServiceAccount = new Gcp.Compute.Inputs.InstanceTemplateServiceAccountArgs
{
Email = @default.Email,
Scopes = new[]
{
"cloud-platform",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.serviceaccount.Account;
import com.pulumi.gcp.serviceaccount.AccountArgs;
import com.pulumi.gcp.compute.InstanceTemplate;
import com.pulumi.gcp.compute.InstanceTemplateArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateNetworkInterfaceArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateConfidentialInstanceConfigArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateDiskArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateServiceAccountArgs;
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 default_ = new Account("default", AccountArgs.builder()
.accountId("my-custom-sa")
.displayName("Custom SA for VM Instance")
.build());
var confidentialInstanceTemplate = new InstanceTemplate("confidentialInstanceTemplate", InstanceTemplateArgs.builder()
.networkInterfaces(InstanceTemplateNetworkInterfaceArgs.builder()
.accessConfigs(InstanceTemplateNetworkInterfaceAccessConfigArgs.builder()
.build())
.network("default")
.build())
.name("my-confidential-instance-template")
.region("us-central1")
.machineType("n2d-standard-2")
.minCpuPlatform("AMD Milan")
.confidentialInstanceConfig(InstanceTemplateConfidentialInstanceConfigArgs.builder()
.enableConfidentialCompute(true)
.confidentialInstanceType("SEV")
.build())
.disks(InstanceTemplateDiskArgs.builder()
.sourceImage("ubuntu-os-cloud/ubuntu-2204-lts")
.build())
.serviceAccount(InstanceTemplateServiceAccountArgs.builder()
.email(default_.email())
.scopes("cloud-platform")
.build())
.build());
}
}
resources:
default:
type: gcp:serviceaccount:Account
properties:
accountId: my-custom-sa
displayName: Custom SA for VM Instance
confidentialInstanceTemplate:
type: gcp:compute:InstanceTemplate
name: confidential_instance_template
properties:
networkInterfaces:
- accessConfigs:
- {}
network: default
name: my-confidential-instance-template
region: us-central1
machineType: n2d-standard-2
minCpuPlatform: AMD Milan
confidentialInstanceConfig:
enableConfidentialCompute: true
confidentialInstanceType: SEV
disks:
- sourceImage: ubuntu-os-cloud/ubuntu-2204-lts
serviceAccount:
email: ${default.email}
scopes:
- cloud-platform
The confidentialInstanceConfig block enables memory encryption via enableConfidentialCompute. This requires specific machine types (n2d-standard-2) and CPU platforms (AMD Milan) that support SEV (Secure Encrypted Virtualization). Confidential Computing protects against memory inspection and unauthorized access to data in use.
Beyond these examples
These snippets focus on specific instance template features: disk configuration and backup policies, image selection strategies, and Confidential Computing with memory encryption. They’re intentionally minimal rather than full VM deployment configurations.
The examples reference pre-existing infrastructure such as service accounts with appropriate scopes, VPC networks (default network in examples), and existing disks and resource policies. They focus on template configuration rather than provisioning the surrounding infrastructure.
To keep things focused, common template patterns are omitted, including:
- VPC and subnet configuration (networkInterfaces details)
- GPU accelerators (guestAccelerators)
- Shielded VM settings (shieldedInstanceConfig)
- Metadata and startup scripts
- Network performance tuning (networkPerformanceConfig)
- Reservation affinity and resource manager tags
These omissions are intentional: the goal is to illustrate how each template feature is wired, not provide drop-in instance group modules. See the Compute Instance Template resource reference for all available configuration options.
Let's create GCP Instance Templates
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Resource Scope & Regional Considerations
google_compute_region_instance_template) provide better isolation from outages outside your region and ensure data residency within your region.Immutability & Resource Lifecycle
machineType, disks, networkInterfaces, scheduling, etc.) are immutable and require recreating the template to change. Only labels and partnerMetadata can be updated in place.Naming & Identification
name and namePrefix are mutually exclusive. Use name for explicit naming or namePrefix for auto-generated names with timestamps. Keep namePrefix to 37 characters or less to avoid collision-prone shortened UUIDs.Machine Types & Custom Configurations
custom-VCPUS-MEM_IN_MB for machineType. For example, custom-6-20480 creates a machine with 6 vCPUs and 20GB of RAM.lifecycle.ignore_changes or explicitly add these disks to your configuration.Security Features
n2d-standard-2, (2) minCpuPlatform set to AMD Milan, and (3) confidentialInstanceConfig with enableConfidentialCompute: true.shieldedInstanceConfig only works with boot images that have shielded VM support. Check the shielded images list before enabling this feature.Image Deployment Strategies
You have two options:
- Data source approach - Use
gcp.compute.getImageto lock to the latest image atpulumi uptime - Family string approach - Use the family directly (e.g.,
debian-cloud/debian-11) to get the latest at instance creation time
pulumi up. The family string approach lets each instance check for the latest image at creation or scaling time, which can result in different instances running different images.Networking & Performance
networkPerformanceConfig requires three things: (1) machineType must be a supported type, (2) the image must include GVNIC in guest-os-features, and (3) network_interface.0.nic-type must be GVNIC.Metadata & Startup Configuration
metadataStartupScript replaces the startup-script metadata key, so the two mechanisms cannot be used simultaneously. Choose one approach.labels is non-authoritative and only manages labels in your configuration. effectiveLabels shows all labels on the resource, including those added by other clients and services.