Configure GCP Instance Group Managers

The gcp:compute/instanceGroupManager:InstanceGroupManager resource, part of the Pulumi GCP provider, manages pools of homogeneous Compute Engine VM instances created from a common instance template. This guide focuses on four capabilities: auto-healing with health checks, canary deployments with multiple versions, standby policies for fast scaling, and resource policies for specialized workloads.

Instance group managers require instance templates and may reference health checks, target pools, or resource policies that must exist separately. The examples are intentionally small. Combine them with your own instance templates, networking, and monitoring infrastructure.

Deploy instances with health checks and auto-healing

Most managed instance groups start with a single instance template and auto-healing to maintain availability.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const autohealing = new gcp.compute.HealthCheck("autohealing", {
    name: "autohealing-health-check",
    checkIntervalSec: 5,
    timeoutSec: 5,
    healthyThreshold: 2,
    unhealthyThreshold: 10,
    httpHealthCheck: {
        requestPath: "/healthz",
        port: 8080,
    },
});
const appserver = new gcp.compute.InstanceGroupManager("appserver", {
    name: "appserver-igm",
    baseInstanceName: "app",
    zone: "us-central1-a",
    versions: [{
        instanceTemplate: appserverGoogleComputeInstanceTemplate.selfLinkUnique,
    }],
    allInstancesConfig: {
        metadata: {
            metadata_key: "metadata_value",
        },
        labels: {
            label_key: "label_value",
        },
    },
    targetPools: [appserverGoogleComputeTargetPool.id],
    targetSize: 2,
    namedPorts: [{
        name: "customhttp",
        port: 8888,
    }],
    autoHealingPolicies: {
        healthCheck: autohealing.id,
        initialDelaySec: 300,
    },
});
import pulumi
import pulumi_gcp as gcp

autohealing = gcp.compute.HealthCheck("autohealing",
    name="autohealing-health-check",
    check_interval_sec=5,
    timeout_sec=5,
    healthy_threshold=2,
    unhealthy_threshold=10,
    http_health_check={
        "request_path": "/healthz",
        "port": 8080,
    })
appserver = gcp.compute.InstanceGroupManager("appserver",
    name="appserver-igm",
    base_instance_name="app",
    zone="us-central1-a",
    versions=[{
        "instance_template": appserver_google_compute_instance_template["selfLinkUnique"],
    }],
    all_instances_config={
        "metadata": {
            "metadata_key": "metadata_value",
        },
        "labels": {
            "label_key": "label_value",
        },
    },
    target_pools=[appserver_google_compute_target_pool["id"]],
    target_size=2,
    named_ports=[{
        "name": "customhttp",
        "port": 8888,
    }],
    auto_healing_policies={
        "health_check": autohealing.id,
        "initial_delay_sec": 300,
    })
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 {
		autohealing, err := compute.NewHealthCheck(ctx, "autohealing", &compute.HealthCheckArgs{
			Name:               pulumi.String("autohealing-health-check"),
			CheckIntervalSec:   pulumi.Int(5),
			TimeoutSec:         pulumi.Int(5),
			HealthyThreshold:   pulumi.Int(2),
			UnhealthyThreshold: pulumi.Int(10),
			HttpHealthCheck: &compute.HealthCheckHttpHealthCheckArgs{
				RequestPath: pulumi.String("/healthz"),
				Port:        pulumi.Int(8080),
			},
		})
		if err != nil {
			return err
		}
		_, err = compute.NewInstanceGroupManager(ctx, "appserver", &compute.InstanceGroupManagerArgs{
			Name:             pulumi.String("appserver-igm"),
			BaseInstanceName: pulumi.String("app"),
			Zone:             pulumi.String("us-central1-a"),
			Versions: compute.InstanceGroupManagerVersionArray{
				&compute.InstanceGroupManagerVersionArgs{
					InstanceTemplate: pulumi.Any(appserverGoogleComputeInstanceTemplate.SelfLinkUnique),
				},
			},
			AllInstancesConfig: &compute.InstanceGroupManagerAllInstancesConfigArgs{
				Metadata: pulumi.StringMap{
					"metadata_key": pulumi.String("metadata_value"),
				},
				Labels: pulumi.StringMap{
					"label_key": pulumi.String("label_value"),
				},
			},
			TargetPools: pulumi.StringArray{
				appserverGoogleComputeTargetPool.Id,
			},
			TargetSize: pulumi.Int(2),
			NamedPorts: compute.InstanceGroupManagerNamedPortArray{
				&compute.InstanceGroupManagerNamedPortArgs{
					Name: pulumi.String("customhttp"),
					Port: pulumi.Int(8888),
				},
			},
			AutoHealingPolicies: &compute.InstanceGroupManagerAutoHealingPoliciesArgs{
				HealthCheck:     autohealing.ID(),
				InitialDelaySec: pulumi.Int(300),
			},
		})
		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 autohealing = new Gcp.Compute.HealthCheck("autohealing", new()
    {
        Name = "autohealing-health-check",
        CheckIntervalSec = 5,
        TimeoutSec = 5,
        HealthyThreshold = 2,
        UnhealthyThreshold = 10,
        HttpHealthCheck = new Gcp.Compute.Inputs.HealthCheckHttpHealthCheckArgs
        {
            RequestPath = "/healthz",
            Port = 8080,
        },
    });

    var appserver = new Gcp.Compute.InstanceGroupManager("appserver", new()
    {
        Name = "appserver-igm",
        BaseInstanceName = "app",
        Zone = "us-central1-a",
        Versions = new[]
        {
            new Gcp.Compute.Inputs.InstanceGroupManagerVersionArgs
            {
                InstanceTemplate = appserverGoogleComputeInstanceTemplate.SelfLinkUnique,
            },
        },
        AllInstancesConfig = new Gcp.Compute.Inputs.InstanceGroupManagerAllInstancesConfigArgs
        {
            Metadata = 
            {
                { "metadata_key", "metadata_value" },
            },
            Labels = 
            {
                { "label_key", "label_value" },
            },
        },
        TargetPools = new[]
        {
            appserverGoogleComputeTargetPool.Id,
        },
        TargetSize = 2,
        NamedPorts = new[]
        {
            new Gcp.Compute.Inputs.InstanceGroupManagerNamedPortArgs
            {
                Name = "customhttp",
                Port = 8888,
            },
        },
        AutoHealingPolicies = new Gcp.Compute.Inputs.InstanceGroupManagerAutoHealingPoliciesArgs
        {
            HealthCheck = autohealing.Id,
            InitialDelaySec = 300,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckHttpHealthCheckArgs;
import com.pulumi.gcp.compute.InstanceGroupManager;
import com.pulumi.gcp.compute.InstanceGroupManagerArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerVersionArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerAllInstancesConfigArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerNamedPortArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerAutoHealingPoliciesArgs;
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 autohealing = new HealthCheck("autohealing", HealthCheckArgs.builder()
            .name("autohealing-health-check")
            .checkIntervalSec(5)
            .timeoutSec(5)
            .healthyThreshold(2)
            .unhealthyThreshold(10)
            .httpHealthCheck(HealthCheckHttpHealthCheckArgs.builder()
                .requestPath("/healthz")
                .port(8080)
                .build())
            .build());

        var appserver = new InstanceGroupManager("appserver", InstanceGroupManagerArgs.builder()
            .name("appserver-igm")
            .baseInstanceName("app")
            .zone("us-central1-a")
            .versions(InstanceGroupManagerVersionArgs.builder()
                .instanceTemplate(appserverGoogleComputeInstanceTemplate.selfLinkUnique())
                .build())
            .allInstancesConfig(InstanceGroupManagerAllInstancesConfigArgs.builder()
                .metadata(Map.of("metadata_key", "metadata_value"))
                .labels(Map.of("label_key", "label_value"))
                .build())
            .targetPools(appserverGoogleComputeTargetPool.id())
            .targetSize(2)
            .namedPorts(InstanceGroupManagerNamedPortArgs.builder()
                .name("customhttp")
                .port(8888)
                .build())
            .autoHealingPolicies(InstanceGroupManagerAutoHealingPoliciesArgs.builder()
                .healthCheck(autohealing.id())
                .initialDelaySec(300)
                .build())
            .build());

    }
}
resources:
  autohealing:
    type: gcp:compute:HealthCheck
    properties:
      name: autohealing-health-check
      checkIntervalSec: 5
      timeoutSec: 5
      healthyThreshold: 2
      unhealthyThreshold: 10 # 50 seconds
      httpHealthCheck:
        requestPath: /healthz
        port: '8080'
  appserver:
    type: gcp:compute:InstanceGroupManager
    properties:
      name: appserver-igm
      baseInstanceName: app
      zone: us-central1-a
      versions:
        - instanceTemplate: ${appserverGoogleComputeInstanceTemplate.selfLinkUnique}
      allInstancesConfig:
        metadata:
          metadata_key: metadata_value
        labels:
          label_key: label_value
      targetPools:
        - ${appserverGoogleComputeTargetPool.id}
      targetSize: 2
      namedPorts:
        - name: customhttp
          port: 8888
      autoHealingPolicies:
        healthCheck: ${autohealing.id}
        initialDelaySec: 300

When health checks detect unhealthy instances, the group automatically replaces them. The autoHealingPolicies property connects to a health check and sets initialDelaySec to allow instances time to start before monitoring begins. The versions array specifies which instance template to use, and targetSize controls the number of running instances.

Run canary deployments with multiple instance versions

Teams rolling out new application versions often run a small canary deployment alongside the stable version to validate changes.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const appserver = new gcp.compute.InstanceGroupManager("appserver", {
    name: "appserver-igm",
    baseInstanceName: "app",
    zone: "us-central1-a",
    targetSize: 5,
    versions: [
        {
            name: "appserver",
            instanceTemplate: appserverGoogleComputeInstanceTemplate.selfLinkUnique,
        },
        {
            name: "appserver-canary",
            instanceTemplate: appserver_canary.selfLinkUnique,
            targetSize: {
                fixed: 1,
            },
        },
    ],
});
import pulumi
import pulumi_gcp as gcp

appserver = gcp.compute.InstanceGroupManager("appserver",
    name="appserver-igm",
    base_instance_name="app",
    zone="us-central1-a",
    target_size=5,
    versions=[
        {
            "name": "appserver",
            "instance_template": appserver_google_compute_instance_template["selfLinkUnique"],
        },
        {
            "name": "appserver-canary",
            "instance_template": appserver_canary["selfLinkUnique"],
            "target_size": {
                "fixed": 1,
            },
        },
    ])
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.NewInstanceGroupManager(ctx, "appserver", &compute.InstanceGroupManagerArgs{
			Name:             pulumi.String("appserver-igm"),
			BaseInstanceName: pulumi.String("app"),
			Zone:             pulumi.String("us-central1-a"),
			TargetSize:       pulumi.Int(5),
			Versions: compute.InstanceGroupManagerVersionArray{
				&compute.InstanceGroupManagerVersionArgs{
					Name:             pulumi.String("appserver"),
					InstanceTemplate: pulumi.Any(appserverGoogleComputeInstanceTemplate.SelfLinkUnique),
				},
				&compute.InstanceGroupManagerVersionArgs{
					Name:             pulumi.String("appserver-canary"),
					InstanceTemplate: pulumi.Any(appserver_canary.SelfLinkUnique),
					TargetSize: &compute.InstanceGroupManagerVersionTargetSizeArgs{
						Fixed: pulumi.Int(1),
					},
				},
			},
		})
		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 appserver = new Gcp.Compute.InstanceGroupManager("appserver", new()
    {
        Name = "appserver-igm",
        BaseInstanceName = "app",
        Zone = "us-central1-a",
        TargetSize = 5,
        Versions = new[]
        {
            new Gcp.Compute.Inputs.InstanceGroupManagerVersionArgs
            {
                Name = "appserver",
                InstanceTemplate = appserverGoogleComputeInstanceTemplate.SelfLinkUnique,
            },
            new Gcp.Compute.Inputs.InstanceGroupManagerVersionArgs
            {
                Name = "appserver-canary",
                InstanceTemplate = appserver_canary.SelfLinkUnique,
                TargetSize = new Gcp.Compute.Inputs.InstanceGroupManagerVersionTargetSizeArgs
                {
                    Fixed = 1,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.InstanceGroupManager;
import com.pulumi.gcp.compute.InstanceGroupManagerArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerVersionArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerVersionTargetSizeArgs;
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 appserver = new InstanceGroupManager("appserver", InstanceGroupManagerArgs.builder()
            .name("appserver-igm")
            .baseInstanceName("app")
            .zone("us-central1-a")
            .targetSize(5)
            .versions(            
                InstanceGroupManagerVersionArgs.builder()
                    .name("appserver")
                    .instanceTemplate(appserverGoogleComputeInstanceTemplate.selfLinkUnique())
                    .build(),
                InstanceGroupManagerVersionArgs.builder()
                    .name("appserver-canary")
                    .instanceTemplate(appserver_canary.selfLinkUnique())
                    .targetSize(InstanceGroupManagerVersionTargetSizeArgs.builder()
                        .fixed(1)
                        .build())
                    .build())
            .build());

    }
}
resources:
  appserver:
    type: gcp:compute:InstanceGroupManager
    properties:
      name: appserver-igm
      baseInstanceName: app
      zone: us-central1-a
      targetSize: 5
      versions:
        - name: appserver
          instanceTemplate: ${appserverGoogleComputeInstanceTemplate.selfLinkUnique}
        - name: appserver-canary
          instanceTemplate: ${["appserver-canary"].selfLinkUnique}
          targetSize:
            fixed: 1

The versions array can include multiple entries, each with its own instance template. Setting targetSize with a fixed value on the canary version limits how many instances run the new code. The remaining instances use the primary version, allowing you to test changes with a subset of traffic before full rollout.

Maintain stopped and suspended instances for fast scaling

Applications with predictable traffic spikes can pre-provision stopped or suspended instances that start faster than creating new instances from scratch.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const igm_sr = new gcp.compute.InstanceGroupManager("igm-sr", {
    name: "tf-sr-igm",
    baseInstanceName: "tf-sr-igm-instance",
    zone: "us-central1-a",
    targetSize: 5,
    versions: [{
        instanceTemplate: sr_igm.selfLink,
        name: "primary",
    }],
    standbyPolicy: {
        initialDelaySec: 30,
        mode: "MANUAL",
    },
    targetSuspendedSize: 2,
    targetStoppedSize: 1,
});
import pulumi
import pulumi_gcp as gcp

igm_sr = gcp.compute.InstanceGroupManager("igm-sr",
    name="tf-sr-igm",
    base_instance_name="tf-sr-igm-instance",
    zone="us-central1-a",
    target_size=5,
    versions=[{
        "instance_template": sr_igm["selfLink"],
        "name": "primary",
    }],
    standby_policy={
        "initial_delay_sec": 30,
        "mode": "MANUAL",
    },
    target_suspended_size=2,
    target_stopped_size=1)
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.NewInstanceGroupManager(ctx, "igm-sr", &compute.InstanceGroupManagerArgs{
			Name:             pulumi.String("tf-sr-igm"),
			BaseInstanceName: pulumi.String("tf-sr-igm-instance"),
			Zone:             pulumi.String("us-central1-a"),
			TargetSize:       pulumi.Int(5),
			Versions: compute.InstanceGroupManagerVersionArray{
				&compute.InstanceGroupManagerVersionArgs{
					InstanceTemplate: pulumi.Any(sr_igm.SelfLink),
					Name:             pulumi.String("primary"),
				},
			},
			StandbyPolicy: &compute.InstanceGroupManagerStandbyPolicyArgs{
				InitialDelaySec: pulumi.Int(30),
				Mode:            pulumi.String("MANUAL"),
			},
			TargetSuspendedSize: pulumi.Int(2),
			TargetStoppedSize:   pulumi.Int(1),
		})
		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 igm_sr = new Gcp.Compute.InstanceGroupManager("igm-sr", new()
    {
        Name = "tf-sr-igm",
        BaseInstanceName = "tf-sr-igm-instance",
        Zone = "us-central1-a",
        TargetSize = 5,
        Versions = new[]
        {
            new Gcp.Compute.Inputs.InstanceGroupManagerVersionArgs
            {
                InstanceTemplate = sr_igm.SelfLink,
                Name = "primary",
            },
        },
        StandbyPolicy = new Gcp.Compute.Inputs.InstanceGroupManagerStandbyPolicyArgs
        {
            InitialDelaySec = 30,
            Mode = "MANUAL",
        },
        TargetSuspendedSize = 2,
        TargetStoppedSize = 1,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.InstanceGroupManager;
import com.pulumi.gcp.compute.InstanceGroupManagerArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerVersionArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerStandbyPolicyArgs;
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 igm_sr = new InstanceGroupManager("igm-sr", InstanceGroupManagerArgs.builder()
            .name("tf-sr-igm")
            .baseInstanceName("tf-sr-igm-instance")
            .zone("us-central1-a")
            .targetSize(5)
            .versions(InstanceGroupManagerVersionArgs.builder()
                .instanceTemplate(sr_igm.selfLink())
                .name("primary")
                .build())
            .standbyPolicy(InstanceGroupManagerStandbyPolicyArgs.builder()
                .initialDelaySec(30)
                .mode("MANUAL")
                .build())
            .targetSuspendedSize(2)
            .targetStoppedSize(1)
            .build());

    }
}
resources:
  igm-sr:
    type: gcp:compute:InstanceGroupManager
    properties:
      name: tf-sr-igm
      baseInstanceName: tf-sr-igm-instance
      zone: us-central1-a
      targetSize: 5
      versions:
        - instanceTemplate: ${["sr-igm"].selfLink}
          name: primary
      standbyPolicy:
        initialDelaySec: 30
        mode: MANUAL
      targetSuspendedSize: 2
      targetStoppedSize: 1

The standbyPolicy property controls how the group manages stopped and suspended instances. Setting mode to MANUAL prevents automatic transitions, while targetSuspendedSize and targetStoppedSize specify how many instances to keep in each state. These instances start faster than provisioning new ones, reducing scaling latency during traffic spikes.

Apply workload policies for specialized hardware

High-performance workloads on specialized hardware benefit from resource policies that optimize instance placement.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const myImage = gcp.compute.getImage({
    family: "debian-11",
    project: "debian-cloud",
});
const workloadPolicy = new gcp.compute.ResourcePolicy("workload_policy", {
    name: "tf-test-gce-policy",
    region: "us-central1",
    workloadPolicy: {
        type: "HIGH_THROUGHPUT",
    },
});
const igm_basic = new gcp.compute.InstanceTemplate("igm-basic", {
    name: "igm-instance-template",
    machineType: "a4-highgpu-8g",
    canIpForward: false,
    tags: [
        "foo",
        "bar",
    ],
    disks: [{
        sourceImage: myImage.then(myImage => myImage.selfLink),
        autoDelete: true,
        boot: true,
        diskType: "hyperdisk-balanced",
    }],
    networkInterfaces: [{
        network: "default",
    }],
    serviceAccount: {
        scopes: [
            "userinfo-email",
            "compute-ro",
            "storage-ro",
        ],
    },
});
const igm_workload_policy = new gcp.compute.InstanceGroupManager("igm-workload-policy", {
    description: "Terraform test instance group manager",
    name: "igm-basic-workload-policy",
    versions: [{
        name: "prod",
        instanceTemplate: igm_basic.selfLink,
    }],
    baseInstanceName: "tf-test-igm-no-tp",
    zone: "us-central1-b",
    targetSize: 0,
    resourcePolicies: {
        workloadPolicy: workloadPolicy.selfLink,
    },
});
import pulumi
import pulumi_gcp as gcp

my_image = gcp.compute.get_image(family="debian-11",
    project="debian-cloud")
workload_policy = gcp.compute.ResourcePolicy("workload_policy",
    name="tf-test-gce-policy",
    region="us-central1",
    workload_policy={
        "type": "HIGH_THROUGHPUT",
    })
igm_basic = gcp.compute.InstanceTemplate("igm-basic",
    name="igm-instance-template",
    machine_type="a4-highgpu-8g",
    can_ip_forward=False,
    tags=[
        "foo",
        "bar",
    ],
    disks=[{
        "source_image": my_image.self_link,
        "auto_delete": True,
        "boot": True,
        "disk_type": "hyperdisk-balanced",
    }],
    network_interfaces=[{
        "network": "default",
    }],
    service_account={
        "scopes": [
            "userinfo-email",
            "compute-ro",
            "storage-ro",
        ],
    })
igm_workload_policy = gcp.compute.InstanceGroupManager("igm-workload-policy",
    description="Terraform test instance group manager",
    name="igm-basic-workload-policy",
    versions=[{
        "name": "prod",
        "instance_template": igm_basic.self_link,
    }],
    base_instance_name="tf-test-igm-no-tp",
    zone="us-central1-b",
    target_size=0,
    resource_policies={
        "workload_policy": workload_policy.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
		}
		workloadPolicy, err := compute.NewResourcePolicy(ctx, "workload_policy", &compute.ResourcePolicyArgs{
			Name:   pulumi.String("tf-test-gce-policy"),
			Region: pulumi.String("us-central1"),
			WorkloadPolicy: &compute.ResourcePolicyWorkloadPolicyArgs{
				Type: pulumi.String("HIGH_THROUGHPUT"),
			},
		})
		if err != nil {
			return err
		}
		igm_basic, err := compute.NewInstanceTemplate(ctx, "igm-basic", &compute.InstanceTemplateArgs{
			Name:         pulumi.String("igm-instance-template"),
			MachineType:  pulumi.String("a4-highgpu-8g"),
			CanIpForward: pulumi.Bool(false),
			Tags: pulumi.StringArray{
				pulumi.String("foo"),
				pulumi.String("bar"),
			},
			Disks: compute.InstanceTemplateDiskArray{
				&compute.InstanceTemplateDiskArgs{
					SourceImage: pulumi.String(myImage.SelfLink),
					AutoDelete:  pulumi.Bool(true),
					Boot:        pulumi.Bool(true),
					DiskType:    pulumi.String("hyperdisk-balanced"),
				},
			},
			NetworkInterfaces: compute.InstanceTemplateNetworkInterfaceArray{
				&compute.InstanceTemplateNetworkInterfaceArgs{
					Network: pulumi.String("default"),
				},
			},
			ServiceAccount: &compute.InstanceTemplateServiceAccountArgs{
				Scopes: pulumi.StringArray{
					pulumi.String("userinfo-email"),
					pulumi.String("compute-ro"),
					pulumi.String("storage-ro"),
				},
			},
		})
		if err != nil {
			return err
		}
		_, err = compute.NewInstanceGroupManager(ctx, "igm-workload-policy", &compute.InstanceGroupManagerArgs{
			Description: pulumi.String("Terraform test instance group manager"),
			Name:        pulumi.String("igm-basic-workload-policy"),
			Versions: compute.InstanceGroupManagerVersionArray{
				&compute.InstanceGroupManagerVersionArgs{
					Name:             pulumi.String("prod"),
					InstanceTemplate: igm_basic.SelfLink,
				},
			},
			BaseInstanceName: pulumi.String("tf-test-igm-no-tp"),
			Zone:             pulumi.String("us-central1-b"),
			TargetSize:       pulumi.Int(0),
			ResourcePolicies: &compute.InstanceGroupManagerResourcePoliciesArgs{
				WorkloadPolicy: workloadPolicy.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 workloadPolicy = new Gcp.Compute.ResourcePolicy("workload_policy", new()
    {
        Name = "tf-test-gce-policy",
        Region = "us-central1",
        WorkloadPolicy = new Gcp.Compute.Inputs.ResourcePolicyWorkloadPolicyArgs
        {
            Type = "HIGH_THROUGHPUT",
        },
    });

    var igm_basic = new Gcp.Compute.InstanceTemplate("igm-basic", new()
    {
        Name = "igm-instance-template",
        MachineType = "a4-highgpu-8g",
        CanIpForward = false,
        Tags = new[]
        {
            "foo",
            "bar",
        },
        Disks = new[]
        {
            new Gcp.Compute.Inputs.InstanceTemplateDiskArgs
            {
                SourceImage = myImage.Apply(getImageResult => getImageResult.SelfLink),
                AutoDelete = true,
                Boot = true,
                DiskType = "hyperdisk-balanced",
            },
        },
        NetworkInterfaces = new[]
        {
            new Gcp.Compute.Inputs.InstanceTemplateNetworkInterfaceArgs
            {
                Network = "default",
            },
        },
        ServiceAccount = new Gcp.Compute.Inputs.InstanceTemplateServiceAccountArgs
        {
            Scopes = new[]
            {
                "userinfo-email",
                "compute-ro",
                "storage-ro",
            },
        },
    });

    var igm_workload_policy = new Gcp.Compute.InstanceGroupManager("igm-workload-policy", new()
    {
        Description = "Terraform test instance group manager",
        Name = "igm-basic-workload-policy",
        Versions = new[]
        {
            new Gcp.Compute.Inputs.InstanceGroupManagerVersionArgs
            {
                Name = "prod",
                InstanceTemplate = igm_basic.SelfLink,
            },
        },
        BaseInstanceName = "tf-test-igm-no-tp",
        Zone = "us-central1-b",
        TargetSize = 0,
        ResourcePolicies = new Gcp.Compute.Inputs.InstanceGroupManagerResourcePoliciesArgs
        {
            WorkloadPolicy = workloadPolicy.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.ResourcePolicy;
import com.pulumi.gcp.compute.ResourcePolicyArgs;
import com.pulumi.gcp.compute.inputs.ResourcePolicyWorkloadPolicyArgs;
import com.pulumi.gcp.compute.InstanceTemplate;
import com.pulumi.gcp.compute.InstanceTemplateArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateDiskArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateNetworkInterfaceArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateServiceAccountArgs;
import com.pulumi.gcp.compute.InstanceGroupManager;
import com.pulumi.gcp.compute.InstanceGroupManagerArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerVersionArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerResourcePoliciesArgs;
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 workloadPolicy = new ResourcePolicy("workloadPolicy", ResourcePolicyArgs.builder()
            .name("tf-test-gce-policy")
            .region("us-central1")
            .workloadPolicy(ResourcePolicyWorkloadPolicyArgs.builder()
                .type("HIGH_THROUGHPUT")
                .build())
            .build());

        var igm_basic = new InstanceTemplate("igm-basic", InstanceTemplateArgs.builder()
            .name("igm-instance-template")
            .machineType("a4-highgpu-8g")
            .canIpForward(false)
            .tags(            
                "foo",
                "bar")
            .disks(InstanceTemplateDiskArgs.builder()
                .sourceImage(myImage.selfLink())
                .autoDelete(true)
                .boot(true)
                .diskType("hyperdisk-balanced")
                .build())
            .networkInterfaces(InstanceTemplateNetworkInterfaceArgs.builder()
                .network("default")
                .build())
            .serviceAccount(InstanceTemplateServiceAccountArgs.builder()
                .scopes(                
                    "userinfo-email",
                    "compute-ro",
                    "storage-ro")
                .build())
            .build());

        var igm_workload_policy = new InstanceGroupManager("igm-workload-policy", InstanceGroupManagerArgs.builder()
            .description("Terraform test instance group manager")
            .name("igm-basic-workload-policy")
            .versions(InstanceGroupManagerVersionArgs.builder()
                .name("prod")
                .instanceTemplate(igm_basic.selfLink())
                .build())
            .baseInstanceName("tf-test-igm-no-tp")
            .zone("us-central1-b")
            .targetSize(0)
            .resourcePolicies(InstanceGroupManagerResourcePoliciesArgs.builder()
                .workloadPolicy(workloadPolicy.selfLink())
                .build())
            .build());

    }
}
resources:
  workloadPolicy:
    type: gcp:compute:ResourcePolicy
    name: workload_policy
    properties:
      name: tf-test-gce-policy
      region: us-central1
      workloadPolicy:
        type: HIGH_THROUGHPUT
  igm-basic:
    type: gcp:compute:InstanceTemplate
    properties:
      name: igm-instance-template
      machineType: a4-highgpu-8g
      canIpForward: false
      tags:
        - foo
        - bar
      disks:
        - sourceImage: ${myImage.selfLink}
          autoDelete: true
          boot: true
          diskType: hyperdisk-balanced
      networkInterfaces:
        - network: default
      serviceAccount:
        scopes:
          - userinfo-email
          - compute-ro
          - storage-ro
  igm-workload-policy:
    type: gcp:compute:InstanceGroupManager
    properties:
      description: Terraform test instance group manager
      name: igm-basic-workload-policy
      versions:
        - name: prod
          instanceTemplate: ${["igm-basic"].selfLink}
      baseInstanceName: tf-test-igm-no-tp
      zone: us-central1-b
      targetSize: 0
      resourcePolicies:
        workloadPolicy: ${workloadPolicy.selfLink}
variables:
  myImage:
    fn::invoke:
      function: gcp:compute:getImage
      arguments:
        family: debian-11
        project: debian-cloud

The resourcePolicies property attaches a workload policy that optimizes instance configuration for specific hardware. In this example, the HIGH_THROUGHPUT policy optimizes networking for GPU workloads on a4-highgpu-8g machine types. The policy must be created separately and referenced by self-link.

Beyond these examples

These snippets focus on specific instance group manager features: auto-healing and health monitoring, canary deployments and version management, and standby policies and resource optimization. They’re intentionally minimal rather than full VM deployment solutions.

The examples rely on pre-existing infrastructure such as instance templates with application configuration, health checks, target pools, and load balancers, and VPC networks and subnets referenced in templates. They focus on configuring the instance group manager rather than provisioning everything around it.

To keep things focused, common instance group patterns are omitted, including:

  • Update policies for rolling updates (updatePolicy)
  • Stateful disk and IP preservation (statefulDisks, statefulExternalIps)
  • Named ports for service discovery
  • Wait conditions for deployment synchronization (waitForInstances)

These omissions are intentional: the goal is to illustrate how each instance group manager feature is wired, not provide drop-in VM management modules. See the Instance Group Manager resource reference for all available configuration options.

Let's configure GCP Instance Group Managers

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Regional vs Zonal Deployment
When should I use RegionInstanceGroupManager instead of InstanceGroupManager?
Use gcp.compute.RegionInstanceGroupManager to create a regional (multi-zone) instance group manager for higher availability across multiple zones.
Instance Configuration & Immutability
What properties can't I change after creating an instance group manager?
The following properties are immutable: baseInstanceName, name, zone, project, and params. Changing these requires recreating the resource.
How are instance names generated from baseInstanceName?
Instances are named by appending a hyphen and a random 4-character string to the baseInstanceName. The base name must be RFC1035-compliant (lowercase letters, numbers, hyphens).
Scaling & Target Sizes
Why shouldn't I set targetSize when using an autoscaler?
When the instance group is attached to an autoscaler, targetSize should never be set because the autoscaler manages the size automatically. Set targetSize explicitly only when not using an autoscaler.
What's the difference between targetSize, targetStoppedSize, and targetSuspendedSize?
targetSize controls running instances, targetStoppedSize controls stopped instances, and targetSuspendedSize controls suspended instances. Use standbyPolicy to manage stopped and suspended instances.
Updates & Rollouts
How do I set up canary deployments with multiple versions?
Define multiple entries in the versions array, each with a name and instanceTemplate. Use targetSize.fixed to control how many instances run each version (e.g., fixed: 1 for a single canary instance).
What's the difference between STABLE and UPDATED for waitForInstancesStatus?
STABLE waits until instances are stable before returning. UPDATED waits for the version target to be reached, per-instance configs to be effective, and all instances to be stable.
What happens if waitForInstances times out?
If waitForInstances is true and the operation doesn’t succeed, Pulumi will continue trying until it times out. Use this setting with caution and consider appropriate timeout values.
Why aren't my allInstancesConfig changes applying to existing instances?
After setting allInstancesConfig (metadata or labels), you must manually update the group’s instances to apply the configuration. The changes don’t automatically propagate to existing instances.
Health & Auto-healing
What should I set for initialDelaySec in auto-healing policies?
The initialDelaySec parameter delays health checks after instance creation. The example shows 300 seconds (5 minutes), which gives instances time to start up before health checks begin.
Networking & Load Balancing
How do I configure named ports for load balancing?
Use the namedPorts array with name and port fields. For example, name: "customhttp" with port: 8888 creates a named port for load balancer backends.
Why don't my target pool changes affect existing instances?
Updating the targetPools attribute only affects new instances added to the group. Existing instances remain in their original target pools.
How do I preserve disks and IPs when instances are recreated?
Use statefulDisks for disks, statefulExternalIps for external IPs, and statefulInternalIps for internal IPs. These resources are preserved on instance delete, update, and other operations.

Using a different cloud?

Explore compute guides for other cloud providers: