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: core template configuration, confidential computing for encrypted workloads, and image versioning strategies.
Instance templates reference service accounts, VPC networks, and optionally existing disks or resource policies. The examples are intentionally small. Combine them with your own IAM roles, networking, and managed instance groups.
Define a template with disks, scheduling, and service accounts
Most deployments start by defining the core compute configuration: machine type, boot disk, and service account permissions.
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. The disks array defines boot and data disks; sourceImage specifies the OS image, while autoDelete controls whether disks are removed when instances terminate. The scheduling block configures restart behavior and maintenance policies. The serviceAccount property grants the VM permissions to access GCP services; the “cloud-platform” scope provides full API access.
Enable confidential computing for encrypted workloads
Workloads handling sensitive data can use confidential computing to encrypt memory contents during execution.
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. This requires specific machine types (n2d-standard series) and CPU platforms (AMD Milan for SEV). The enableConfidentialCompute property activates the feature, while confidentialInstanceType specifies the encryption technology.
Deploy templates with the latest image at apply time
When you want all instances to use the same image version, determined when Pulumi runs, use a data source to fetch the latest image.
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 data source retrieves the latest image in a family at apply time. Using selfLink as the sourceImage locks all instances to that specific image version, preventing unexpected updates during scaling events.
Let instances fetch the latest image at launch time
Alternatively, you can have each instance automatically use the newest image when it launches.
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
Specifying the family name directly (e.g., “debian-cloud/debian-11”) as sourceImage tells GCP to resolve the latest image at instance creation time. This allows automatic updates during scaling without redeploying the template.
Beyond these examples
These snippets focus on specific template-level features: disk configuration and image selection, confidential computing and security features, and image versioning strategies. They’re intentionally minimal rather than full VM deployment configurations.
The examples may reference pre-existing infrastructure such as service accounts with appropriate IAM permissions, VPC networks and subnets, and existing disks and snapshot policies for some examples. They focus on configuring the template rather than provisioning everything around it.
To keep things focused, common template patterns are omitted, including:
- VPC networking details (subnetworks, IP addressing)
- GPU accelerators and specialized hardware (guestAccelerators)
- Metadata and startup scripts (metadata, metadataStartupScript)
- Reservation affinity and capacity planning
- Network performance tuning (networkPerformanceConfig)
- Shielded VM configuration (shieldedInstanceConfig)
These omissions are intentional: the goal is to illustrate how each template feature is wired, not provide drop-in VM modules. See the 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 data residency and reduce the impact of outages outside your region.subnetwork ties the template to a specific region.Naming & Immutability
name sets an explicit name, while namePrefix auto-generates unique names with timestamps and counters. They conflict with each other, and both are immutable.namePrefix to 37 characters or less for better uniqueness.name, namePrefix, machineType, disks, confidentialInstanceConfig, shieldedInstanceConfig, networkInterfaces, metadata, and region. Changes force resource replacement.Security & Confidential Computing
confidentialInstanceConfig.enableConfidentialCompute to true, use a supported machine type like n2d-standard-2, and specify minCpuPlatform (e.g., AMD Milan).shieldedInstanceConfig only works with boot images that have shielded VM support. Check the list of supported images before enabling.Image Deployment Strategies
You have two options:
- Lock at deployment - Use
gcp.compute.getImagedata source to deploy the latest image available when Pulumi runs (all instances use same image) - Check at instance creation - Use image family directly (e.g.,
debian-cloud/debian-11) so each instance checks for latest at creation time
machineType as custom-VCPUS-MEM_IN_MB. For example, custom-6-20480 creates a machine with 6 vCPUs and 20GB of RAM.Configuration Gotchas
metadataStartupScript replaces the startup-script metadata key, so you can’t use both simultaneously. Choose one approach.labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels present on the resource.machineType must be a supported type, the image must include GVNIC in guest-os-features, and network_interface.0.nic-type must be GVNIC.resourcePolicies list causes instance recreation.