Configure GCP OS Config Patch Deployments

The gcp:osconfig/patchDeployment:PatchDeployment resource, part of the Pulumi GCP provider, defines OS Config patch deployments that schedule and configure automated patching for Compute Engine instances. This guide focuses on three capabilities: scheduling (one-time and recurring), instance targeting, and patch configuration with scripts.

Patch deployments target existing Compute Engine instances and may reference GCS buckets for pre/post-patch scripts. The examples are intentionally small. Combine them with your own instance filters, patch policies, and maintenance windows.

Schedule a one-time patch deployment for all instances

Teams often schedule patches across their entire fleet during planned maintenance windows.

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

const patch = new gcp.osconfig.PatchDeployment("patch", {
    patchDeploymentId: "patch-deploy",
    instanceFilter: {
        all: true,
    },
    oneTimeSchedule: {
        executeTime: "2999-10-10T10:10:10.045123456Z",
    },
});
import pulumi
import pulumi_gcp as gcp

patch = gcp.osconfig.PatchDeployment("patch",
    patch_deployment_id="patch-deploy",
    instance_filter={
        "all": True,
    },
    one_time_schedule={
        "execute_time": "2999-10-10T10:10:10.045123456Z",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/osconfig"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := osconfig.NewPatchDeployment(ctx, "patch", &osconfig.PatchDeploymentArgs{
			PatchDeploymentId: pulumi.String("patch-deploy"),
			InstanceFilter: &osconfig.PatchDeploymentInstanceFilterArgs{
				All: pulumi.Bool(true),
			},
			OneTimeSchedule: &osconfig.PatchDeploymentOneTimeScheduleArgs{
				ExecuteTime: pulumi.String("2999-10-10T10:10:10.045123456Z"),
			},
		})
		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 patch = new Gcp.OsConfig.PatchDeployment("patch", new()
    {
        PatchDeploymentId = "patch-deploy",
        InstanceFilter = new Gcp.OsConfig.Inputs.PatchDeploymentInstanceFilterArgs
        {
            All = true,
        },
        OneTimeSchedule = new Gcp.OsConfig.Inputs.PatchDeploymentOneTimeScheduleArgs
        {
            ExecuteTime = "2999-10-10T10:10:10.045123456Z",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.osconfig.PatchDeployment;
import com.pulumi.gcp.osconfig.PatchDeploymentArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentInstanceFilterArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentOneTimeScheduleArgs;
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 patch = new PatchDeployment("patch", PatchDeploymentArgs.builder()
            .patchDeploymentId("patch-deploy")
            .instanceFilter(PatchDeploymentInstanceFilterArgs.builder()
                .all(true)
                .build())
            .oneTimeSchedule(PatchDeploymentOneTimeScheduleArgs.builder()
                .executeTime("2999-10-10T10:10:10.045123456Z")
                .build())
            .build());

    }
}
resources:
  patch:
    type: gcp:osconfig:PatchDeployment
    properties:
      patchDeploymentId: patch-deploy
      instanceFilter:
        all: true
      oneTimeSchedule:
        executeTime: 2999-10-10T10:10:10.045123456Z

The oneTimeSchedule property sets a specific execution time in RFC3339 format. The instanceFilter with all: true targets every VM in the project. After execution, the deployment remains but won’t run again unless you update the schedule.

Run patches daily at a specific time

Production environments automate patching on recurring schedules to maintain security without manual intervention.

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

const patch = new gcp.osconfig.PatchDeployment("patch", {
    patchDeploymentId: "patch-deploy",
    instanceFilter: {
        all: true,
    },
    recurringSchedule: {
        timeZone: {
            id: "America/New_York",
        },
        timeOfDay: {
            hours: 0,
            minutes: 30,
            seconds: 30,
            nanos: 20,
        },
    },
});
import pulumi
import pulumi_gcp as gcp

patch = gcp.osconfig.PatchDeployment("patch",
    patch_deployment_id="patch-deploy",
    instance_filter={
        "all": True,
    },
    recurring_schedule={
        "time_zone": {
            "id": "America/New_York",
        },
        "time_of_day": {
            "hours": 0,
            "minutes": 30,
            "seconds": 30,
            "nanos": 20,
        },
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/osconfig"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := osconfig.NewPatchDeployment(ctx, "patch", &osconfig.PatchDeploymentArgs{
			PatchDeploymentId: pulumi.String("patch-deploy"),
			InstanceFilter: &osconfig.PatchDeploymentInstanceFilterArgs{
				All: pulumi.Bool(true),
			},
			RecurringSchedule: &osconfig.PatchDeploymentRecurringScheduleArgs{
				TimeZone: &osconfig.PatchDeploymentRecurringScheduleTimeZoneArgs{
					Id: pulumi.String("America/New_York"),
				},
				TimeOfDay: &osconfig.PatchDeploymentRecurringScheduleTimeOfDayArgs{
					Hours:   pulumi.Int(0),
					Minutes: pulumi.Int(30),
					Seconds: pulumi.Int(30),
					Nanos:   pulumi.Int(20),
				},
			},
		})
		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 patch = new Gcp.OsConfig.PatchDeployment("patch", new()
    {
        PatchDeploymentId = "patch-deploy",
        InstanceFilter = new Gcp.OsConfig.Inputs.PatchDeploymentInstanceFilterArgs
        {
            All = true,
        },
        RecurringSchedule = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleArgs
        {
            TimeZone = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleTimeZoneArgs
            {
                Id = "America/New_York",
            },
            TimeOfDay = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleTimeOfDayArgs
            {
                Hours = 0,
                Minutes = 30,
                Seconds = 30,
                Nanos = 20,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.osconfig.PatchDeployment;
import com.pulumi.gcp.osconfig.PatchDeploymentArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentInstanceFilterArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleTimeZoneArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleTimeOfDayArgs;
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 patch = new PatchDeployment("patch", PatchDeploymentArgs.builder()
            .patchDeploymentId("patch-deploy")
            .instanceFilter(PatchDeploymentInstanceFilterArgs.builder()
                .all(true)
                .build())
            .recurringSchedule(PatchDeploymentRecurringScheduleArgs.builder()
                .timeZone(PatchDeploymentRecurringScheduleTimeZoneArgs.builder()
                    .id("America/New_York")
                    .build())
                .timeOfDay(PatchDeploymentRecurringScheduleTimeOfDayArgs.builder()
                    .hours(0)
                    .minutes(30)
                    .seconds(30)
                    .nanos(20)
                    .build())
                .build())
            .build());

    }
}
resources:
  patch:
    type: gcp:osconfig:PatchDeployment
    properties:
      patchDeploymentId: patch-deploy
      instanceFilter:
        all: true
      recurringSchedule:
        timeZone:
          id: America/New_York
        timeOfDay:
          hours: 0
          minutes: 30
          seconds: 30
          nanos: 20

The recurringSchedule property defines when patches run repeatedly. The timeZone sets the reference timezone, and timeOfDay specifies the exact hour, minute, second, and nanosecond. This deployment runs daily at 12:30:30.000000020 AM Eastern Time.

Target specific instances with package filters

Some workloads require selective patching, targeting only certain VMs and controlling which packages update.

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

const myImage = gcp.compute.getImage({
    family: "debian-11",
    project: "debian-cloud",
});
const foobar = new gcp.compute.Instance("foobar", {
    name: "patch-deploy-inst",
    machineType: "e2-medium",
    zone: "us-central1-a",
    canIpForward: false,
    tags: [
        "foo",
        "bar",
    ],
    bootDisk: {
        initializeParams: {
            image: myImage.then(myImage => myImage.selfLink),
        },
    },
    networkInterfaces: [{
        network: "default",
    }],
    metadata: {
        foo: "bar",
    },
});
const patch = new gcp.osconfig.PatchDeployment("patch", {
    patchDeploymentId: "patch-deploy",
    instanceFilter: {
        instances: [foobar.id],
    },
    patchConfig: {
        yum: {
            security: true,
            minimal: true,
            excludes: ["bash"],
        },
    },
    recurringSchedule: {
        timeZone: {
            id: "America/New_York",
        },
        timeOfDay: {
            hours: 0,
            minutes: 30,
            seconds: 30,
            nanos: 20,
        },
        monthly: {
            monthDay: 1,
        },
    },
});
import pulumi
import pulumi_gcp as gcp

my_image = gcp.compute.get_image(family="debian-11",
    project="debian-cloud")
foobar = gcp.compute.Instance("foobar",
    name="patch-deploy-inst",
    machine_type="e2-medium",
    zone="us-central1-a",
    can_ip_forward=False,
    tags=[
        "foo",
        "bar",
    ],
    boot_disk={
        "initialize_params": {
            "image": my_image.self_link,
        },
    },
    network_interfaces=[{
        "network": "default",
    }],
    metadata={
        "foo": "bar",
    })
patch = gcp.osconfig.PatchDeployment("patch",
    patch_deployment_id="patch-deploy",
    instance_filter={
        "instances": [foobar.id],
    },
    patch_config={
        "yum": {
            "security": True,
            "minimal": True,
            "excludes": ["bash"],
        },
    },
    recurring_schedule={
        "time_zone": {
            "id": "America/New_York",
        },
        "time_of_day": {
            "hours": 0,
            "minutes": 30,
            "seconds": 30,
            "nanos": 20,
        },
        "monthly": {
            "month_day": 1,
        },
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/osconfig"
	"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
		}
		foobar, err := compute.NewInstance(ctx, "foobar", &compute.InstanceArgs{
			Name:         pulumi.String("patch-deploy-inst"),
			MachineType:  pulumi.String("e2-medium"),
			Zone:         pulumi.String("us-central1-a"),
			CanIpForward: pulumi.Bool(false),
			Tags: pulumi.StringArray{
				pulumi.String("foo"),
				pulumi.String("bar"),
			},
			BootDisk: &compute.InstanceBootDiskArgs{
				InitializeParams: &compute.InstanceBootDiskInitializeParamsArgs{
					Image: pulumi.String(myImage.SelfLink),
				},
			},
			NetworkInterfaces: compute.InstanceNetworkInterfaceArray{
				&compute.InstanceNetworkInterfaceArgs{
					Network: pulumi.String("default"),
				},
			},
			Metadata: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
		})
		if err != nil {
			return err
		}
		_, err = osconfig.NewPatchDeployment(ctx, "patch", &osconfig.PatchDeploymentArgs{
			PatchDeploymentId: pulumi.String("patch-deploy"),
			InstanceFilter: &osconfig.PatchDeploymentInstanceFilterArgs{
				Instances: pulumi.StringArray{
					foobar.ID(),
				},
			},
			PatchConfig: &osconfig.PatchDeploymentPatchConfigArgs{
				Yum: &osconfig.PatchDeploymentPatchConfigYumArgs{
					Security: pulumi.Bool(true),
					Minimal:  pulumi.Bool(true),
					Excludes: pulumi.StringArray{
						pulumi.String("bash"),
					},
				},
			},
			RecurringSchedule: &osconfig.PatchDeploymentRecurringScheduleArgs{
				TimeZone: &osconfig.PatchDeploymentRecurringScheduleTimeZoneArgs{
					Id: pulumi.String("America/New_York"),
				},
				TimeOfDay: &osconfig.PatchDeploymentRecurringScheduleTimeOfDayArgs{
					Hours:   pulumi.Int(0),
					Minutes: pulumi.Int(30),
					Seconds: pulumi.Int(30),
					Nanos:   pulumi.Int(20),
				},
				Monthly: &osconfig.PatchDeploymentRecurringScheduleMonthlyArgs{
					MonthDay: 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 myImage = Gcp.Compute.GetImage.Invoke(new()
    {
        Family = "debian-11",
        Project = "debian-cloud",
    });

    var foobar = new Gcp.Compute.Instance("foobar", new()
    {
        Name = "patch-deploy-inst",
        MachineType = "e2-medium",
        Zone = "us-central1-a",
        CanIpForward = false,
        Tags = new[]
        {
            "foo",
            "bar",
        },
        BootDisk = new Gcp.Compute.Inputs.InstanceBootDiskArgs
        {
            InitializeParams = new Gcp.Compute.Inputs.InstanceBootDiskInitializeParamsArgs
            {
                Image = myImage.Apply(getImageResult => getImageResult.SelfLink),
            },
        },
        NetworkInterfaces = new[]
        {
            new Gcp.Compute.Inputs.InstanceNetworkInterfaceArgs
            {
                Network = "default",
            },
        },
        Metadata = 
        {
            { "foo", "bar" },
        },
    });

    var patch = new Gcp.OsConfig.PatchDeployment("patch", new()
    {
        PatchDeploymentId = "patch-deploy",
        InstanceFilter = new Gcp.OsConfig.Inputs.PatchDeploymentInstanceFilterArgs
        {
            Instances = new[]
            {
                foobar.Id,
            },
        },
        PatchConfig = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigArgs
        {
            Yum = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigYumArgs
            {
                Security = true,
                Minimal = true,
                Excludes = new[]
                {
                    "bash",
                },
            },
        },
        RecurringSchedule = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleArgs
        {
            TimeZone = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleTimeZoneArgs
            {
                Id = "America/New_York",
            },
            TimeOfDay = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleTimeOfDayArgs
            {
                Hours = 0,
                Minutes = 30,
                Seconds = 30,
                Nanos = 20,
            },
            Monthly = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleMonthlyArgs
            {
                MonthDay = 1,
            },
        },
    });

});
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.Instance;
import com.pulumi.gcp.compute.InstanceArgs;
import com.pulumi.gcp.compute.inputs.InstanceBootDiskArgs;
import com.pulumi.gcp.compute.inputs.InstanceBootDiskInitializeParamsArgs;
import com.pulumi.gcp.compute.inputs.InstanceNetworkInterfaceArgs;
import com.pulumi.gcp.osconfig.PatchDeployment;
import com.pulumi.gcp.osconfig.PatchDeploymentArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentInstanceFilterArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigYumArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleTimeZoneArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleTimeOfDayArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleMonthlyArgs;
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 foobar = new Instance("foobar", InstanceArgs.builder()
            .name("patch-deploy-inst")
            .machineType("e2-medium")
            .zone("us-central1-a")
            .canIpForward(false)
            .tags(            
                "foo",
                "bar")
            .bootDisk(InstanceBootDiskArgs.builder()
                .initializeParams(InstanceBootDiskInitializeParamsArgs.builder()
                    .image(myImage.selfLink())
                    .build())
                .build())
            .networkInterfaces(InstanceNetworkInterfaceArgs.builder()
                .network("default")
                .build())
            .metadata(Map.of("foo", "bar"))
            .build());

        var patch = new PatchDeployment("patch", PatchDeploymentArgs.builder()
            .patchDeploymentId("patch-deploy")
            .instanceFilter(PatchDeploymentInstanceFilterArgs.builder()
                .instances(foobar.id())
                .build())
            .patchConfig(PatchDeploymentPatchConfigArgs.builder()
                .yum(PatchDeploymentPatchConfigYumArgs.builder()
                    .security(true)
                    .minimal(true)
                    .excludes("bash")
                    .build())
                .build())
            .recurringSchedule(PatchDeploymentRecurringScheduleArgs.builder()
                .timeZone(PatchDeploymentRecurringScheduleTimeZoneArgs.builder()
                    .id("America/New_York")
                    .build())
                .timeOfDay(PatchDeploymentRecurringScheduleTimeOfDayArgs.builder()
                    .hours(0)
                    .minutes(30)
                    .seconds(30)
                    .nanos(20)
                    .build())
                .monthly(PatchDeploymentRecurringScheduleMonthlyArgs.builder()
                    .monthDay(1)
                    .build())
                .build())
            .build());

    }
}
resources:
  foobar:
    type: gcp:compute:Instance
    properties:
      name: patch-deploy-inst
      machineType: e2-medium
      zone: us-central1-a
      canIpForward: false
      tags:
        - foo
        - bar
      bootDisk:
        initializeParams:
          image: ${myImage.selfLink}
      networkInterfaces:
        - network: default
      metadata:
        foo: bar
  patch:
    type: gcp:osconfig:PatchDeployment
    properties:
      patchDeploymentId: patch-deploy
      instanceFilter:
        instances:
          - ${foobar.id}
      patchConfig:
        yum:
          security: true
          minimal: true
          excludes:
            - bash
      recurringSchedule:
        timeZone:
          id: America/New_York
        timeOfDay:
          hours: 0
          minutes: 30
          seconds: 30
          nanos: 20
        monthly:
          monthDay: 1
variables:
  myImage:
    fn::invoke:
      function: gcp:compute:getImage
      arguments:
        family: debian-11
        project: debian-cloud

The instanceFilter.instances array limits patching to specific VM IDs. The patchConfig.yum block controls package selection: security: true applies only security updates, minimal: true uses minimal update sets, and excludes prevents specific packages from updating. The monthly schedule runs on the first day of each month.

Configure advanced patching with pre/post scripts and rollout

Enterprise deployments need comprehensive control: label-based filtering, validation scripts, and gradual rollout across zones.

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

const patch = new gcp.osconfig.PatchDeployment("patch", {
    patchDeploymentId: "patch-deploy",
    instanceFilter: {
        groupLabels: [{
            labels: {
                env: "dev",
                app: "web",
            },
        }],
        instanceNamePrefixes: ["test-"],
        zones: [
            "us-central1-a",
            "us-central-1c",
        ],
    },
    patchConfig: {
        migInstancesAllowed: true,
        skipUnpatchableVms: true,
        rebootConfig: "ALWAYS",
        apt: {
            type: "DIST",
            excludes: ["python"],
        },
        yum: {
            security: true,
            minimal: true,
            excludes: ["bash"],
        },
        goo: {
            enabled: true,
        },
        zypper: {
            categories: ["security"],
        },
        windowsUpdate: {
            classifications: [
                "CRITICAL",
                "SECURITY",
                "UPDATE",
            ],
            excludes: ["5012170"],
        },
        preStep: {
            linuxExecStepConfig: {
                allowedSuccessCodes: [
                    0,
                    3,
                ],
                localPath: "/tmp/pre_patch_script.sh",
            },
            windowsExecStepConfig: {
                interpreter: "SHELL",
                allowedSuccessCodes: [
                    0,
                    2,
                ],
                localPath: "C:\\Users\\user\\pre-patch-script.cmd",
            },
        },
        postStep: {
            linuxExecStepConfig: {
                gcsObject: {
                    bucket: "my-patch-scripts",
                    generationNumber: "1523477886880",
                    object: "linux/post_patch_script",
                },
            },
            windowsExecStepConfig: {
                interpreter: "POWERSHELL",
                gcsObject: {
                    bucket: "my-patch-scripts",
                    generationNumber: "135920493447",
                    object: "windows/post_patch_script.ps1",
                },
            },
        },
    },
    duration: "10s",
    recurringSchedule: {
        timeZone: {
            id: "America/New_York",
        },
        timeOfDay: {
            hours: 0,
            minutes: 30,
            seconds: 30,
            nanos: 20,
        },
        monthly: {
            weekDayOfMonth: {
                weekOrdinal: -1,
                dayOfWeek: "TUESDAY",
                dayOffset: 3,
            },
        },
    },
    rollout: {
        mode: "ZONE_BY_ZONE",
        disruptionBudget: {
            fixed: 1,
        },
    },
});
import pulumi
import pulumi_gcp as gcp

patch = gcp.osconfig.PatchDeployment("patch",
    patch_deployment_id="patch-deploy",
    instance_filter={
        "group_labels": [{
            "labels": {
                "env": "dev",
                "app": "web",
            },
        }],
        "instance_name_prefixes": ["test-"],
        "zones": [
            "us-central1-a",
            "us-central-1c",
        ],
    },
    patch_config={
        "mig_instances_allowed": True,
        "skip_unpatchable_vms": True,
        "reboot_config": "ALWAYS",
        "apt": {
            "type": "DIST",
            "excludes": ["python"],
        },
        "yum": {
            "security": True,
            "minimal": True,
            "excludes": ["bash"],
        },
        "goo": {
            "enabled": True,
        },
        "zypper": {
            "categories": ["security"],
        },
        "windows_update": {
            "classifications": [
                "CRITICAL",
                "SECURITY",
                "UPDATE",
            ],
            "excludes": ["5012170"],
        },
        "pre_step": {
            "linux_exec_step_config": {
                "allowed_success_codes": [
                    0,
                    3,
                ],
                "local_path": "/tmp/pre_patch_script.sh",
            },
            "windows_exec_step_config": {
                "interpreter": "SHELL",
                "allowed_success_codes": [
                    0,
                    2,
                ],
                "local_path": "C:\\Users\\user\\pre-patch-script.cmd",
            },
        },
        "post_step": {
            "linux_exec_step_config": {
                "gcs_object": {
                    "bucket": "my-patch-scripts",
                    "generation_number": "1523477886880",
                    "object": "linux/post_patch_script",
                },
            },
            "windows_exec_step_config": {
                "interpreter": "POWERSHELL",
                "gcs_object": {
                    "bucket": "my-patch-scripts",
                    "generation_number": "135920493447",
                    "object": "windows/post_patch_script.ps1",
                },
            },
        },
    },
    duration="10s",
    recurring_schedule={
        "time_zone": {
            "id": "America/New_York",
        },
        "time_of_day": {
            "hours": 0,
            "minutes": 30,
            "seconds": 30,
            "nanos": 20,
        },
        "monthly": {
            "week_day_of_month": {
                "week_ordinal": -1,
                "day_of_week": "TUESDAY",
                "day_offset": 3,
            },
        },
    },
    rollout={
        "mode": "ZONE_BY_ZONE",
        "disruption_budget": {
            "fixed": 1,
        },
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/osconfig"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := osconfig.NewPatchDeployment(ctx, "patch", &osconfig.PatchDeploymentArgs{
			PatchDeploymentId: pulumi.String("patch-deploy"),
			InstanceFilter: &osconfig.PatchDeploymentInstanceFilterArgs{
				GroupLabels: osconfig.PatchDeploymentInstanceFilterGroupLabelArray{
					&osconfig.PatchDeploymentInstanceFilterGroupLabelArgs{
						Labels: pulumi.StringMap{
							"env": pulumi.String("dev"),
							"app": pulumi.String("web"),
						},
					},
				},
				InstanceNamePrefixes: pulumi.StringArray{
					pulumi.String("test-"),
				},
				Zones: pulumi.StringArray{
					pulumi.String("us-central1-a"),
					pulumi.String("us-central-1c"),
				},
			},
			PatchConfig: &osconfig.PatchDeploymentPatchConfigArgs{
				MigInstancesAllowed: pulumi.Bool(true),
				SkipUnpatchableVms:  pulumi.Bool(true),
				RebootConfig:        pulumi.String("ALWAYS"),
				Apt: &osconfig.PatchDeploymentPatchConfigAptArgs{
					Type: pulumi.String("DIST"),
					Excludes: pulumi.StringArray{
						pulumi.String("python"),
					},
				},
				Yum: &osconfig.PatchDeploymentPatchConfigYumArgs{
					Security: pulumi.Bool(true),
					Minimal:  pulumi.Bool(true),
					Excludes: pulumi.StringArray{
						pulumi.String("bash"),
					},
				},
				Goo: &osconfig.PatchDeploymentPatchConfigGooArgs{
					Enabled: pulumi.Bool(true),
				},
				Zypper: &osconfig.PatchDeploymentPatchConfigZypperArgs{
					Categories: pulumi.StringArray{
						pulumi.String("security"),
					},
				},
				WindowsUpdate: &osconfig.PatchDeploymentPatchConfigWindowsUpdateArgs{
					Classifications: pulumi.StringArray{
						pulumi.String("CRITICAL"),
						pulumi.String("SECURITY"),
						pulumi.String("UPDATE"),
					},
					Excludes: pulumi.StringArray{
						pulumi.String("5012170"),
					},
				},
				PreStep: &osconfig.PatchDeploymentPatchConfigPreStepArgs{
					LinuxExecStepConfig: &osconfig.PatchDeploymentPatchConfigPreStepLinuxExecStepConfigArgs{
						AllowedSuccessCodes: pulumi.IntArray{
							pulumi.Int(0),
							pulumi.Int(3),
						},
						LocalPath: pulumi.String("/tmp/pre_patch_script.sh"),
					},
					WindowsExecStepConfig: &osconfig.PatchDeploymentPatchConfigPreStepWindowsExecStepConfigArgs{
						Interpreter: pulumi.String("SHELL"),
						AllowedSuccessCodes: pulumi.IntArray{
							pulumi.Int(0),
							pulumi.Int(2),
						},
						LocalPath: pulumi.String("C:\\Users\\user\\pre-patch-script.cmd"),
					},
				},
				PostStep: &osconfig.PatchDeploymentPatchConfigPostStepArgs{
					LinuxExecStepConfig: &osconfig.PatchDeploymentPatchConfigPostStepLinuxExecStepConfigArgs{
						GcsObject: &osconfig.PatchDeploymentPatchConfigPostStepLinuxExecStepConfigGcsObjectArgs{
							Bucket:           pulumi.String("my-patch-scripts"),
							GenerationNumber: pulumi.String("1523477886880"),
							Object:           pulumi.String("linux/post_patch_script"),
						},
					},
					WindowsExecStepConfig: &osconfig.PatchDeploymentPatchConfigPostStepWindowsExecStepConfigArgs{
						Interpreter: pulumi.String("POWERSHELL"),
						GcsObject: &osconfig.PatchDeploymentPatchConfigPostStepWindowsExecStepConfigGcsObjectArgs{
							Bucket:           pulumi.String("my-patch-scripts"),
							GenerationNumber: pulumi.String("135920493447"),
							Object:           pulumi.String("windows/post_patch_script.ps1"),
						},
					},
				},
			},
			Duration: pulumi.String("10s"),
			RecurringSchedule: &osconfig.PatchDeploymentRecurringScheduleArgs{
				TimeZone: &osconfig.PatchDeploymentRecurringScheduleTimeZoneArgs{
					Id: pulumi.String("America/New_York"),
				},
				TimeOfDay: &osconfig.PatchDeploymentRecurringScheduleTimeOfDayArgs{
					Hours:   pulumi.Int(0),
					Minutes: pulumi.Int(30),
					Seconds: pulumi.Int(30),
					Nanos:   pulumi.Int(20),
				},
				Monthly: &osconfig.PatchDeploymentRecurringScheduleMonthlyArgs{
					WeekDayOfMonth: &osconfig.PatchDeploymentRecurringScheduleMonthlyWeekDayOfMonthArgs{
						WeekOrdinal: pulumi.Int(-1),
						DayOfWeek:   pulumi.String("TUESDAY"),
						DayOffset:   pulumi.Int(3),
					},
				},
			},
			Rollout: &osconfig.PatchDeploymentRolloutArgs{
				Mode: pulumi.String("ZONE_BY_ZONE"),
				DisruptionBudget: &osconfig.PatchDeploymentRolloutDisruptionBudgetArgs{
					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 patch = new Gcp.OsConfig.PatchDeployment("patch", new()
    {
        PatchDeploymentId = "patch-deploy",
        InstanceFilter = new Gcp.OsConfig.Inputs.PatchDeploymentInstanceFilterArgs
        {
            GroupLabels = new[]
            {
                new Gcp.OsConfig.Inputs.PatchDeploymentInstanceFilterGroupLabelArgs
                {
                    Labels = 
                    {
                        { "env", "dev" },
                        { "app", "web" },
                    },
                },
            },
            InstanceNamePrefixes = new[]
            {
                "test-",
            },
            Zones = new[]
            {
                "us-central1-a",
                "us-central-1c",
            },
        },
        PatchConfig = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigArgs
        {
            MigInstancesAllowed = true,
            SkipUnpatchableVms = true,
            RebootConfig = "ALWAYS",
            Apt = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigAptArgs
            {
                Type = "DIST",
                Excludes = new[]
                {
                    "python",
                },
            },
            Yum = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigYumArgs
            {
                Security = true,
                Minimal = true,
                Excludes = new[]
                {
                    "bash",
                },
            },
            Goo = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigGooArgs
            {
                Enabled = true,
            },
            Zypper = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigZypperArgs
            {
                Categories = new[]
                {
                    "security",
                },
            },
            WindowsUpdate = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigWindowsUpdateArgs
            {
                Classifications = new[]
                {
                    "CRITICAL",
                    "SECURITY",
                    "UPDATE",
                },
                Excludes = new[]
                {
                    "5012170",
                },
            },
            PreStep = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigPreStepArgs
            {
                LinuxExecStepConfig = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigPreStepLinuxExecStepConfigArgs
                {
                    AllowedSuccessCodes = new[]
                    {
                        0,
                        3,
                    },
                    LocalPath = "/tmp/pre_patch_script.sh",
                },
                WindowsExecStepConfig = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigPreStepWindowsExecStepConfigArgs
                {
                    Interpreter = "SHELL",
                    AllowedSuccessCodes = new[]
                    {
                        0,
                        2,
                    },
                    LocalPath = "C:\\Users\\user\\pre-patch-script.cmd",
                },
            },
            PostStep = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigPostStepArgs
            {
                LinuxExecStepConfig = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigPostStepLinuxExecStepConfigArgs
                {
                    GcsObject = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigPostStepLinuxExecStepConfigGcsObjectArgs
                    {
                        Bucket = "my-patch-scripts",
                        GenerationNumber = "1523477886880",
                        Object = "linux/post_patch_script",
                    },
                },
                WindowsExecStepConfig = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigPostStepWindowsExecStepConfigArgs
                {
                    Interpreter = "POWERSHELL",
                    GcsObject = new Gcp.OsConfig.Inputs.PatchDeploymentPatchConfigPostStepWindowsExecStepConfigGcsObjectArgs
                    {
                        Bucket = "my-patch-scripts",
                        GenerationNumber = "135920493447",
                        Object = "windows/post_patch_script.ps1",
                    },
                },
            },
        },
        Duration = "10s",
        RecurringSchedule = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleArgs
        {
            TimeZone = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleTimeZoneArgs
            {
                Id = "America/New_York",
            },
            TimeOfDay = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleTimeOfDayArgs
            {
                Hours = 0,
                Minutes = 30,
                Seconds = 30,
                Nanos = 20,
            },
            Monthly = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleMonthlyArgs
            {
                WeekDayOfMonth = new Gcp.OsConfig.Inputs.PatchDeploymentRecurringScheduleMonthlyWeekDayOfMonthArgs
                {
                    WeekOrdinal = -1,
                    DayOfWeek = "TUESDAY",
                    DayOffset = 3,
                },
            },
        },
        Rollout = new Gcp.OsConfig.Inputs.PatchDeploymentRolloutArgs
        {
            Mode = "ZONE_BY_ZONE",
            DisruptionBudget = new Gcp.OsConfig.Inputs.PatchDeploymentRolloutDisruptionBudgetArgs
            {
                Fixed = 1,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.osconfig.PatchDeployment;
import com.pulumi.gcp.osconfig.PatchDeploymentArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentInstanceFilterArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigAptArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigYumArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigGooArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigZypperArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigWindowsUpdateArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigPreStepArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigPreStepLinuxExecStepConfigArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigPreStepWindowsExecStepConfigArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigPostStepArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigPostStepLinuxExecStepConfigArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigPostStepLinuxExecStepConfigGcsObjectArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigPostStepWindowsExecStepConfigArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentPatchConfigPostStepWindowsExecStepConfigGcsObjectArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleTimeZoneArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleTimeOfDayArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleMonthlyArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRecurringScheduleMonthlyWeekDayOfMonthArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRolloutArgs;
import com.pulumi.gcp.osconfig.inputs.PatchDeploymentRolloutDisruptionBudgetArgs;
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 patch = new PatchDeployment("patch", PatchDeploymentArgs.builder()
            .patchDeploymentId("patch-deploy")
            .instanceFilter(PatchDeploymentInstanceFilterArgs.builder()
                .groupLabels(PatchDeploymentInstanceFilterGroupLabelArgs.builder()
                    .labels(Map.ofEntries(
                        Map.entry("env", "dev"),
                        Map.entry("app", "web")
                    ))
                    .build())
                .instanceNamePrefixes("test-")
                .zones(                
                    "us-central1-a",
                    "us-central-1c")
                .build())
            .patchConfig(PatchDeploymentPatchConfigArgs.builder()
                .migInstancesAllowed(true)
                .skipUnpatchableVms(true)
                .rebootConfig("ALWAYS")
                .apt(PatchDeploymentPatchConfigAptArgs.builder()
                    .type("DIST")
                    .excludes("python")
                    .build())
                .yum(PatchDeploymentPatchConfigYumArgs.builder()
                    .security(true)
                    .minimal(true)
                    .excludes("bash")
                    .build())
                .goo(PatchDeploymentPatchConfigGooArgs.builder()
                    .enabled(true)
                    .build())
                .zypper(PatchDeploymentPatchConfigZypperArgs.builder()
                    .categories("security")
                    .build())
                .windowsUpdate(PatchDeploymentPatchConfigWindowsUpdateArgs.builder()
                    .classifications(                    
                        "CRITICAL",
                        "SECURITY",
                        "UPDATE")
                    .excludes("5012170")
                    .build())
                .preStep(PatchDeploymentPatchConfigPreStepArgs.builder()
                    .linuxExecStepConfig(PatchDeploymentPatchConfigPreStepLinuxExecStepConfigArgs.builder()
                        .allowedSuccessCodes(                        
                            0,
                            3)
                        .localPath("/tmp/pre_patch_script.sh")
                        .build())
                    .windowsExecStepConfig(PatchDeploymentPatchConfigPreStepWindowsExecStepConfigArgs.builder()
                        .interpreter("SHELL")
                        .allowedSuccessCodes(                        
                            0,
                            2)
                        .localPath("C:\\Users\\user\\pre-patch-script.cmd")
                        .build())
                    .build())
                .postStep(PatchDeploymentPatchConfigPostStepArgs.builder()
                    .linuxExecStepConfig(PatchDeploymentPatchConfigPostStepLinuxExecStepConfigArgs.builder()
                        .gcsObject(PatchDeploymentPatchConfigPostStepLinuxExecStepConfigGcsObjectArgs.builder()
                            .bucket("my-patch-scripts")
                            .generationNumber("1523477886880")
                            .object("linux/post_patch_script")
                            .build())
                        .build())
                    .windowsExecStepConfig(PatchDeploymentPatchConfigPostStepWindowsExecStepConfigArgs.builder()
                        .interpreter("POWERSHELL")
                        .gcsObject(PatchDeploymentPatchConfigPostStepWindowsExecStepConfigGcsObjectArgs.builder()
                            .bucket("my-patch-scripts")
                            .generationNumber("135920493447")
                            .object("windows/post_patch_script.ps1")
                            .build())
                        .build())
                    .build())
                .build())
            .duration("10s")
            .recurringSchedule(PatchDeploymentRecurringScheduleArgs.builder()
                .timeZone(PatchDeploymentRecurringScheduleTimeZoneArgs.builder()
                    .id("America/New_York")
                    .build())
                .timeOfDay(PatchDeploymentRecurringScheduleTimeOfDayArgs.builder()
                    .hours(0)
                    .minutes(30)
                    .seconds(30)
                    .nanos(20)
                    .build())
                .monthly(PatchDeploymentRecurringScheduleMonthlyArgs.builder()
                    .weekDayOfMonth(PatchDeploymentRecurringScheduleMonthlyWeekDayOfMonthArgs.builder()
                        .weekOrdinal(-1)
                        .dayOfWeek("TUESDAY")
                        .dayOffset(3)
                        .build())
                    .build())
                .build())
            .rollout(PatchDeploymentRolloutArgs.builder()
                .mode("ZONE_BY_ZONE")
                .disruptionBudget(PatchDeploymentRolloutDisruptionBudgetArgs.builder()
                    .fixed(1)
                    .build())
                .build())
            .build());

    }
}
resources:
  patch:
    type: gcp:osconfig:PatchDeployment
    properties:
      patchDeploymentId: patch-deploy
      instanceFilter:
        groupLabels:
          - labels:
              env: dev
              app: web
        instanceNamePrefixes:
          - test-
        zones:
          - us-central1-a
          - us-central-1c
      patchConfig:
        migInstancesAllowed: true
        skipUnpatchableVms: true
        rebootConfig: ALWAYS
        apt:
          type: DIST
          excludes:
            - python
        yum:
          security: true
          minimal: true
          excludes:
            - bash
        goo:
          enabled: true
        zypper:
          categories:
            - security
        windowsUpdate:
          classifications:
            - CRITICAL
            - SECURITY
            - UPDATE
          excludes:
            - '5012170'
        preStep:
          linuxExecStepConfig:
            allowedSuccessCodes:
              - 0
              - 3
            localPath: /tmp/pre_patch_script.sh
          windowsExecStepConfig:
            interpreter: SHELL
            allowedSuccessCodes:
              - 0
              - 2
            localPath: C:\Users\user\pre-patch-script.cmd
        postStep:
          linuxExecStepConfig:
            gcsObject:
              bucket: my-patch-scripts
              generationNumber: '1523477886880'
              object: linux/post_patch_script
          windowsExecStepConfig:
            interpreter: POWERSHELL
            gcsObject:
              bucket: my-patch-scripts
              generationNumber: '135920493447'
              object: windows/post_patch_script.ps1
      duration: 10s
      recurringSchedule:
        timeZone:
          id: America/New_York
        timeOfDay:
          hours: 0
          minutes: 30
          seconds: 30
          nanos: 20
        monthly:
          weekDayOfMonth:
            weekOrdinal: -1
            dayOfWeek: TUESDAY
            dayOffset: 3
      rollout:
        mode: ZONE_BY_ZONE
        disruptionBudget:
          fixed: 1

The groupLabels filter targets VMs by label combinations, while zones restricts to specific locations. The preStep and postStep blocks run scripts before and after patching, either from local paths or GCS objects. The rollout.mode controls deployment speed (ZONE_BY_ZONE patches one zone at a time), and disruptionBudget.fixed limits how many VMs can be disrupted simultaneously.

Beyond these examples

These snippets focus on specific patch deployment features: one-time and recurring schedules, instance filtering and package exclusions, and pre/post-patch scripts and rollout strategies. They’re intentionally minimal rather than full patch management solutions.

The examples may reference pre-existing infrastructure such as Compute Engine instances to patch, and GCS buckets for patch scripts in advanced examples. They focus on configuring the deployment rather than provisioning the underlying VMs.

To keep things focused, common patch deployment patterns are omitted, including:

  • Weekly scheduling (weeklySchedule)
  • Apt and Zypper package manager configuration
  • MIG instance handling (migInstancesAllowed)
  • Reboot behavior controls (rebootConfig)

These omissions are intentional: the goal is to illustrate how each patch deployment feature is wired, not provide drop-in patch management modules. See the OS Config PatchDeployment resource reference for all available configuration options.

Let's configure GCP OS Config Patch Deployments

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Immutability
What happens if I need to change my patch deployment configuration?
Most properties are immutable after creation, including instanceFilter, patchConfig, schedules, and rollout. You’ll need to recreate the patch deployment with the new configuration.
What are the naming requirements for patchDeploymentId?
The patchDeploymentId must contain only lowercase letters, numbers, and hyphens; start with a letter; be 1-63 characters long; end with a letter or number; and be unique within the project.
Instance Targeting
How do I target all instances in my project for patching?
Set instanceFilter.all to true in your patch deployment configuration.
How do I target specific instances for patching?
You have several options: use instanceFilter.instances with instance IDs, groupLabels for label-based targeting, zones for zone filtering, or instanceNamePrefixes for name-based matching.
Scheduling
What's the difference between one-time and recurring schedules?
Use oneTimeSchedule with executeTime for a single execution at a specific time. Use recurringSchedule with timeZone, timeOfDay, and frequency (daily, weekly, or monthly) for repeated executions.
What format should I use for the duration field?
Use seconds with up to nine fractional digits, terminated by ’s’ (e.g., 10s or 3.5s). After this duration, the patch times out.
Patch Configuration
How do I configure OS-specific patch settings?
Use patchConfig with OS-specific blocks: apt for Debian/Ubuntu, yum for RHEL/CentOS, windowsUpdate for Windows, goo for Google packages, and zypper for SUSE. Each supports options like excludes, security-only updates, and classifications.
Can I run scripts before or after patching?
Yes, configure preStep and postStep in patchConfig with linuxExecStepConfig or windowsExecStepConfig. Scripts can be local paths or GCS objects.
Rollout & Deployment Strategy
How do I control the rollout of patches across instances?
Configure the rollout property with a mode (e.g., ZONE_BY_ZONE) and disruptionBudget to control how patches are deployed across your instances.
Can I patch instances in Managed Instance Groups?
Yes, set patchConfig.migInstancesAllowed to true to allow patching of instances in Managed Instance Groups.
What happens to instances that can't be patched?
By default, unpatchable VMs will cause the deployment to fail. Set patchConfig.skipUnpatchableVms to true to skip them and continue patching other instances.

Using a different cloud?

Explore compute guides for other cloud providers: