The gcp:compute/instance:Instance resource, part of the Pulumi GCP provider, defines a GCE VM instance: its machine type, boot disk, network placement, and security configuration. This guide focuses on three capabilities: boot disk and image selection, service account attachment, and confidential computing with AMD SEV.
Instances run in a VPC network and zone, use service accounts for API access, and boot from disk images. The examples are intentionally small. Combine them with your own VPC configuration, IAM roles, and security policies.
Launch an instance with boot disk and service account
Most deployments create an instance with a boot disk image, machine type, and service account for API access.
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 defaultInstance = new gcp.compute.Instance("default", {
networkInterfaces: [{
accessConfigs: [{}],
network: "default",
}],
name: "my-instance",
machineType: "n2-standard-2",
zone: "us-central1-a",
tags: [
"foo",
"bar",
],
bootDisk: {
initializeParams: {
image: "debian-cloud/debian-11",
labels: {
my_label: "value",
},
},
},
scratchDisks: [{
"interface": "NVME",
}],
metadata: {
foo: "bar",
},
metadataStartupScript: "echo hi > /test.txt",
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")
default_instance = gcp.compute.Instance("default",
network_interfaces=[{
"access_configs": [{}],
"network": "default",
}],
name="my-instance",
machine_type="n2-standard-2",
zone="us-central1-a",
tags=[
"foo",
"bar",
],
boot_disk={
"initialize_params": {
"image": "debian-cloud/debian-11",
"labels": {
"my_label": "value",
},
},
},
scratch_disks=[{
"interface": "NVME",
}],
metadata={
"foo": "bar",
},
metadata_startup_script="echo hi > /test.txt",
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.NewInstance(ctx, "default", &compute.InstanceArgs{
NetworkInterfaces: compute.InstanceNetworkInterfaceArray{
&compute.InstanceNetworkInterfaceArgs{
AccessConfigs: compute.InstanceNetworkInterfaceAccessConfigArray{
&compute.InstanceNetworkInterfaceAccessConfigArgs{},
},
Network: pulumi.String("default"),
},
},
Name: pulumi.String("my-instance"),
MachineType: pulumi.String("n2-standard-2"),
Zone: pulumi.String("us-central1-a"),
Tags: pulumi.StringArray{
pulumi.String("foo"),
pulumi.String("bar"),
},
BootDisk: &compute.InstanceBootDiskArgs{
InitializeParams: &compute.InstanceBootDiskInitializeParamsArgs{
Image: pulumi.String("debian-cloud/debian-11"),
Labels: pulumi.StringMap{
"my_label": pulumi.String("value"),
},
},
},
ScratchDisks: compute.InstanceScratchDiskArray{
&compute.InstanceScratchDiskArgs{
Interface: pulumi.String("NVME"),
},
},
Metadata: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
MetadataStartupScript: pulumi.String("echo hi > /test.txt"),
ServiceAccount: &compute.InstanceServiceAccountArgs{
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 defaultInstance = new Gcp.Compute.Instance("default", new()
{
NetworkInterfaces = new[]
{
new Gcp.Compute.Inputs.InstanceNetworkInterfaceArgs
{
AccessConfigs = new[]
{
null,
},
Network = "default",
},
},
Name = "my-instance",
MachineType = "n2-standard-2",
Zone = "us-central1-a",
Tags = new[]
{
"foo",
"bar",
},
BootDisk = new Gcp.Compute.Inputs.InstanceBootDiskArgs
{
InitializeParams = new Gcp.Compute.Inputs.InstanceBootDiskInitializeParamsArgs
{
Image = "debian-cloud/debian-11",
Labels =
{
{ "my_label", "value" },
},
},
},
ScratchDisks = new[]
{
new Gcp.Compute.Inputs.InstanceScratchDiskArgs
{
Interface = "NVME",
},
},
Metadata =
{
{ "foo", "bar" },
},
MetadataStartupScript = "echo hi > /test.txt",
ServiceAccount = new Gcp.Compute.Inputs.InstanceServiceAccountArgs
{
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.Instance;
import com.pulumi.gcp.compute.InstanceArgs;
import com.pulumi.gcp.compute.inputs.InstanceNetworkInterfaceArgs;
import com.pulumi.gcp.compute.inputs.InstanceBootDiskArgs;
import com.pulumi.gcp.compute.inputs.InstanceBootDiskInitializeParamsArgs;
import com.pulumi.gcp.compute.inputs.InstanceScratchDiskArgs;
import com.pulumi.gcp.compute.inputs.InstanceServiceAccountArgs;
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 defaultInstance = new Instance("defaultInstance", InstanceArgs.builder()
.networkInterfaces(InstanceNetworkInterfaceArgs.builder()
.accessConfigs(InstanceNetworkInterfaceAccessConfigArgs.builder()
.build())
.network("default")
.build())
.name("my-instance")
.machineType("n2-standard-2")
.zone("us-central1-a")
.tags(
"foo",
"bar")
.bootDisk(InstanceBootDiskArgs.builder()
.initializeParams(InstanceBootDiskInitializeParamsArgs.builder()
.image("debian-cloud/debian-11")
.labels(Map.of("my_label", "value"))
.build())
.build())
.scratchDisks(InstanceScratchDiskArgs.builder()
.interface_("NVME")
.build())
.metadata(Map.of("foo", "bar"))
.metadataStartupScript("echo hi > /test.txt")
.serviceAccount(InstanceServiceAccountArgs.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
defaultInstance:
type: gcp:compute:Instance
name: default
properties:
networkInterfaces:
- accessConfigs:
- {}
network: default
name: my-instance
machineType: n2-standard-2
zone: us-central1-a
tags:
- foo
- bar
bootDisk:
initializeParams:
image: debian-cloud/debian-11
labels:
my_label: value
scratchDisks:
- interface: NVME
metadata:
foo: bar
metadataStartupScript: echo hi > /test.txt
serviceAccount:
email: ${default.email}
scopes:
- cloud-platform
The machineType and zone determine compute capacity and location. The bootDisk.initializeParams.image specifies the OS image (here, Debian 11). The networkInterfaces array attaches the instance to a network; accessConfigs grants a public IP. The serviceAccount block attaches an identity for API calls, with scopes controlling permissions. The metadataStartupScript runs on boot, useful for initialization tasks.
Enable confidential computing with AMD SEV
Workloads handling sensitive data can encrypt memory contents during processing using Confidential VM.
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 confidentialInstance = new gcp.compute.Instance("confidential_instance", {
networkInterfaces: [{
accessConfigs: [{}],
network: "default",
}],
name: "my-confidential-instance",
zone: "us-central1-a",
machineType: "n2d-standard-2",
minCpuPlatform: "AMD Milan",
confidentialInstanceConfig: {
enableConfidentialCompute: true,
confidentialInstanceType: "SEV",
},
bootDisk: {
initializeParams: {
image: "ubuntu-os-cloud/ubuntu-2204-lts",
labels: {
my_label: "value",
},
},
},
scratchDisks: [{
"interface": "NVME",
}],
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 = gcp.compute.Instance("confidential_instance",
network_interfaces=[{
"access_configs": [{}],
"network": "default",
}],
name="my-confidential-instance",
zone="us-central1-a",
machine_type="n2d-standard-2",
min_cpu_platform="AMD Milan",
confidential_instance_config={
"enable_confidential_compute": True,
"confidential_instance_type": "SEV",
},
boot_disk={
"initialize_params": {
"image": "ubuntu-os-cloud/ubuntu-2204-lts",
"labels": {
"my_label": "value",
},
},
},
scratch_disks=[{
"interface": "NVME",
}],
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.NewInstance(ctx, "confidential_instance", &compute.InstanceArgs{
NetworkInterfaces: compute.InstanceNetworkInterfaceArray{
&compute.InstanceNetworkInterfaceArgs{
AccessConfigs: compute.InstanceNetworkInterfaceAccessConfigArray{
&compute.InstanceNetworkInterfaceAccessConfigArgs{},
},
Network: pulumi.String("default"),
},
},
Name: pulumi.String("my-confidential-instance"),
Zone: pulumi.String("us-central1-a"),
MachineType: pulumi.String("n2d-standard-2"),
MinCpuPlatform: pulumi.String("AMD Milan"),
ConfidentialInstanceConfig: &compute.InstanceConfidentialInstanceConfigArgs{
EnableConfidentialCompute: pulumi.Bool(true),
ConfidentialInstanceType: pulumi.String("SEV"),
},
BootDisk: &compute.InstanceBootDiskArgs{
InitializeParams: &compute.InstanceBootDiskInitializeParamsArgs{
Image: pulumi.String("ubuntu-os-cloud/ubuntu-2204-lts"),
Labels: pulumi.StringMap{
"my_label": pulumi.String("value"),
},
},
},
ScratchDisks: compute.InstanceScratchDiskArray{
&compute.InstanceScratchDiskArgs{
Interface: pulumi.String("NVME"),
},
},
ServiceAccount: &compute.InstanceServiceAccountArgs{
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 confidentialInstance = new Gcp.Compute.Instance("confidential_instance", new()
{
NetworkInterfaces = new[]
{
new Gcp.Compute.Inputs.InstanceNetworkInterfaceArgs
{
AccessConfigs = new[]
{
null,
},
Network = "default",
},
},
Name = "my-confidential-instance",
Zone = "us-central1-a",
MachineType = "n2d-standard-2",
MinCpuPlatform = "AMD Milan",
ConfidentialInstanceConfig = new Gcp.Compute.Inputs.InstanceConfidentialInstanceConfigArgs
{
EnableConfidentialCompute = true,
ConfidentialInstanceType = "SEV",
},
BootDisk = new Gcp.Compute.Inputs.InstanceBootDiskArgs
{
InitializeParams = new Gcp.Compute.Inputs.InstanceBootDiskInitializeParamsArgs
{
Image = "ubuntu-os-cloud/ubuntu-2204-lts",
Labels =
{
{ "my_label", "value" },
},
},
},
ScratchDisks = new[]
{
new Gcp.Compute.Inputs.InstanceScratchDiskArgs
{
Interface = "NVME",
},
},
ServiceAccount = new Gcp.Compute.Inputs.InstanceServiceAccountArgs
{
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.Instance;
import com.pulumi.gcp.compute.InstanceArgs;
import com.pulumi.gcp.compute.inputs.InstanceNetworkInterfaceArgs;
import com.pulumi.gcp.compute.inputs.InstanceConfidentialInstanceConfigArgs;
import com.pulumi.gcp.compute.inputs.InstanceBootDiskArgs;
import com.pulumi.gcp.compute.inputs.InstanceBootDiskInitializeParamsArgs;
import com.pulumi.gcp.compute.inputs.InstanceScratchDiskArgs;
import com.pulumi.gcp.compute.inputs.InstanceServiceAccountArgs;
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 confidentialInstance = new Instance("confidentialInstance", InstanceArgs.builder()
.networkInterfaces(InstanceNetworkInterfaceArgs.builder()
.accessConfigs(InstanceNetworkInterfaceAccessConfigArgs.builder()
.build())
.network("default")
.build())
.name("my-confidential-instance")
.zone("us-central1-a")
.machineType("n2d-standard-2")
.minCpuPlatform("AMD Milan")
.confidentialInstanceConfig(InstanceConfidentialInstanceConfigArgs.builder()
.enableConfidentialCompute(true)
.confidentialInstanceType("SEV")
.build())
.bootDisk(InstanceBootDiskArgs.builder()
.initializeParams(InstanceBootDiskInitializeParamsArgs.builder()
.image("ubuntu-os-cloud/ubuntu-2204-lts")
.labels(Map.of("my_label", "value"))
.build())
.build())
.scratchDisks(InstanceScratchDiskArgs.builder()
.interface_("NVME")
.build())
.serviceAccount(InstanceServiceAccountArgs.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
confidentialInstance:
type: gcp:compute:Instance
name: confidential_instance
properties:
networkInterfaces:
- accessConfigs:
- {}
network: default
name: my-confidential-instance
zone: us-central1-a
machineType: n2d-standard-2
minCpuPlatform: AMD Milan
confidentialInstanceConfig:
enableConfidentialCompute: true
confidentialInstanceType: SEV
bootDisk:
initializeParams:
image: ubuntu-os-cloud/ubuntu-2204-lts
labels:
my_label: value
scratchDisks:
- interface: NVME
serviceAccount:
email: ${default.email}
scopes:
- cloud-platform
The confidentialInstanceConfig.enableConfidentialCompute activates memory encryption. This requires an N2D machine type (machineType: “n2d-standard-2”) and AMD Milan CPU platform (minCpuPlatform: “AMD Milan”). The confidentialInstanceType specifies the encryption technology; SEV (Secure Encrypted Virtualization) protects against hypervisor-level access to memory.
Beyond these examples
These snippets focus on specific instance-level features: boot disk and image selection, service account attachment, and confidential computing with AMD SEV. They’re intentionally minimal rather than full VM deployments.
The examples rely on pre-existing infrastructure such as the default VPC network and service accounts with appropriate IAM roles. They focus on configuring the instance rather than provisioning the surrounding infrastructure.
To keep things focused, common instance patterns are omitted, including:
- Custom VPC and subnet configuration
- GPU accelerators (guestAccelerators)
- Shielded VM integrity monitoring
- Attached persistent disks and scratch disks
- Instance scheduling and maintenance policies
- Custom metadata and SSH key management
These omissions are intentional: the goal is to illustrate how each instance feature is wired, not provide drop-in VM modules. See the Compute Instance resource reference for all available configuration options.
Let's create and Configure Compute Engine Instances
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Updates & Lifecycle
machineType, minCpuPlatform, shieldedInstanceConfig, enableDisplay, or serviceAccount require stopping the instance. Set allowStoppingForUpdate to true, or set desiredStatus to TERMINATED before updating these fields.deletionProtection is enabled, the instance cannot be deleted and pulumi destroy will not complete successfully. Disable deletion protection before removing the resource.bootDisk, confidentialInstanceConfig, guestAccelerators, name, networkInterfaces, zone, hostname, project, reservationAffinity, scratchDisks, instanceEncryptionKey, keyRevocationActionType, networkPerformanceConfig, and params.metadataStartupScript forces instance recreation when changed, while metadata.startup-script does not. Use metadataStartupScript only if you want the instance recreated when the script changes.Machine Types & Resources
custom-NUMBER_OF_CPUS-AMOUNT_OF_MEMORY_MB, such as custom-6-20480 for 6 vCPU and 20GB RAM. For extended memory (over 6.5 GB per CPU), add the -ext suffix, like custom-2-15360-ext for 2 vCPU and 15 GB of memory.lifecycle.ignore_changes on machineType to suppress these diffs.onHostMaintenance set to TERMINATE in the scheduling configuration.n2d-standard-2), set minCpuPlatform to AMD Milan, and configure confidentialInstanceConfig with enableConfidentialCompute: true and confidentialInstanceType: SEV.Import & State Management
boot_disk.0.disk_encryption_raw and attached_disk.*.disk_encryption_key_raw) cannot be imported automatically and must be manually added to state. The desiredStatus field will not be set on import; if you configure it, expect a diff on the first pulumi up. If you specify metadataStartupScript on import, you’ll see a destroy/recreate diff unless you modify your state file.Networking & Performance
networkPerformanceConfig, your machineType must be a supported type, the boot image must include GVNIC in guest-os-features, and network_interface.0.nic-type must be set to GVNIC. All three requirements must be met.Security & Configuration
shieldedInstanceConfig can only be used with boot images that have shielded VM support. Additionally, you must set allowStoppingForUpdate to true or desiredStatus to TERMINATED to update this field.metadata via Pulumi. Add them to your configuration to keep them attached to your instance.metadata.startup-script in a shell on every boot. Windows instances require different keys depending on script format and timing.