Virtual Machine on Google Cloud
The Google Cloud Virtual Machine template scaffolds a Pulumi project that provisions a Compute Engine instance and the supporting Compute Engine network. The instance boots an HTTP server on port 80 from a small init script, so the project deploys end to end out of the box. Use it as a starting point for a web application, backend service, or database VM.
Before you begin#
For this walkthrough, you'll need:
- The Pulumi CLI
- The gcloud CLI (optional, but recommended and used in this guide)
- Permission to manage Compute Engine
For this walkthrough, you'll need:
- The Pulumi CLI
- The gcloud CLI (optional, but recommended and used in this guide)
- Permission to manage Compute Engine
For this walkthrough, you'll need:
- The Pulumi CLI
- The gcloud CLI (optional, but recommended and used in this guide)
- Permission to manage Compute Engine
- A current version of Go installed locally
For this walkthrough, you'll need:
- The Pulumi CLI
- The gcloud CLI (optional, but recommended and used in this guide)
- Permission to manage Compute Engine
- A current version of .NET installed locally
For this walkthrough, you'll need:
- The Pulumi CLI
- The gcloud CLI (optional, but recommended and used in this guide)
- Permission to manage Compute Engine
For this walkthrough, you'll need:
- A current version of the Pulumi CLI (Pulumi HCL requires no additional runtime)
- The gcloud CLI (optional, but recommended and used in this guide)
- Permission to manage Compute Engine
Create a new project#
Create a new project from the template:
mkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-typescriptmkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-typescriptmkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-pythonmkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-pythonmkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-gomkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-gomkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-csharpmkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-csharpmkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-yamlmkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-yamlmkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-hclmkdir my-virtual-machine; cd my-virtual-machinepulumi new vm-gcp-hclThe pulumi new command walks you through creating and configuring the new project and stack. A stack is an instance of a project, and you can have many of them (dev, staging, prod), each with its own configuration settings. Depending on the language, you may also be asked for your preferred package manager or toolchain.
This template’s settings include:
| Key | Description | Default |
|---|---|---|
| gcp:project | The Google Cloud project to deploy into | — |
| gcp:region | The Google Cloud region to deploy into | us-central1 |
| gcp:zone | The Google Cloud availability zone to deploy into | us-central1-a |
| machineType | The GCP machine type to use for the VM | f1-micro |
| osImage | The OS image type to use for the VM | debian-12 |
| instanceTag | The tag to apply to the VM instance | webserver |
| servicePort | The HTTP service port to expose on the VM | 80 |
pulumi config set
:
pulumi config set gcp:project <value>pulumi config set gcp:region <value>pulumi config set gcp:zone <value>pulumi config set machineType <value>pulumi config set osImage <value>pulumi config set instanceTag <value>pulumi config set servicePort <value>pulumi config set gcp:project "<value>"pulumi config set gcp:region "<value>"pulumi config set gcp:zone "<value>"pulumi config set machineType "<value>"pulumi config set osImage "<value>"pulumi config set instanceTag "<value>"pulumi config set servicePort "<value>"| Key | Description | Default |
|---|---|---|
| gcp:project | The Google Cloud project to deploy into | — |
| gcp:region | The Google Cloud region to deploy into | us-central1 |
| gcp:zone | The Google Cloud availability zone to deploy into | us-central1-a |
| machineType | The GCP machine type to use for the VM | f1-micro |
| osImage | The OS image type to use for the VM | debian-12 |
| instanceTag | The tag to apply to the VM instance | webserver |
| servicePort | The HTTP service port to expose on the VM | 80 |
pulumi config set
:
pulumi config set gcp:project <value>pulumi config set gcp:region <value>pulumi config set gcp:zone <value>pulumi config set machineType <value>pulumi config set osImage <value>pulumi config set instanceTag <value>pulumi config set servicePort <value>pulumi config set gcp:project "<value>"pulumi config set gcp:region "<value>"pulumi config set gcp:zone "<value>"pulumi config set machineType "<value>"pulumi config set osImage "<value>"pulumi config set instanceTag "<value>"pulumi config set servicePort "<value>"| Key | Description | Default |
|---|---|---|
| gcp:project | The Google Cloud project to deploy into | — |
| gcp:region | The Google Cloud region to deploy into | us-central1 |
| gcp:zone | The Google Cloud availability zone to deploy into | us-central1-a |
| machineType | The GCP machine type to use for the VM | f1-micro |
| osImage | The OS image type to use for the VM | debian-12 |
| instanceTag | The tag to apply to the VM instance | webserver |
| servicePort | The HTTP service port to expose on the VM | 80 |
pulumi config set
:
pulumi config set gcp:project <value>pulumi config set gcp:region <value>pulumi config set gcp:zone <value>pulumi config set machineType <value>pulumi config set osImage <value>pulumi config set instanceTag <value>pulumi config set servicePort <value>pulumi config set gcp:project "<value>"pulumi config set gcp:region "<value>"pulumi config set gcp:zone "<value>"pulumi config set machineType "<value>"pulumi config set osImage "<value>"pulumi config set instanceTag "<value>"pulumi config set servicePort "<value>"| Key | Description | Default |
|---|---|---|
| gcp:project | The Google Cloud project to deploy into | — |
| gcp:region | The Google Cloud region to deploy into | us-central1 |
| gcp:zone | The Google Cloud availability zone to deploy into | us-central1-a |
| machineType | The GCP machine type to use for the VM | f1-micro |
| osImage | The OS image type to use for the VM | debian-12 |
| instanceTag | The tag to apply to the VM instance | webserver |
| servicePort | The HTTP service port to expose on the VM | 80 |
pulumi config set
:
pulumi config set gcp:project <value>pulumi config set gcp:region <value>pulumi config set gcp:zone <value>pulumi config set machineType <value>pulumi config set osImage <value>pulumi config set instanceTag <value>pulumi config set servicePort <value>pulumi config set gcp:project "<value>"pulumi config set gcp:region "<value>"pulumi config set gcp:zone "<value>"pulumi config set machineType "<value>"pulumi config set osImage "<value>"pulumi config set instanceTag "<value>"pulumi config set servicePort "<value>"| Key | Description | Default |
|---|---|---|
| gcp:project | The Google Cloud project to deploy into | — |
| gcp:region | The Google Cloud region to deploy into | us-central1 |
| gcp:zone | The Google Cloud availability zone to deploy into | us-central1-a |
| machineType | The GCP machine type to use for the VM | f1-micro |
| osImage | The OS image type to use for the VM | debian-12 |
| instanceTag | The tag to apply to the VM instance | webserver |
| servicePort | The HTTP service port to expose on the VM | 80 |
pulumi config set
:
pulumi config set gcp:project <value>pulumi config set gcp:region <value>pulumi config set gcp:zone <value>pulumi config set machineType <value>pulumi config set osImage <value>pulumi config set instanceTag <value>pulumi config set servicePort <value>pulumi config set gcp:project "<value>"pulumi config set gcp:region "<value>"pulumi config set gcp:zone "<value>"pulumi config set machineType "<value>"pulumi config set osImage "<value>"pulumi config set instanceTag "<value>"pulumi config set servicePort "<value>"| Key | Description | Default |
|---|---|---|
| gcp:project | The Google Cloud project to deploy into | — |
| gcp:region | The Google Cloud region to deploy into | us-central1 |
| gcp:zone | The Google Cloud availability zone to deploy into | us-central1-a |
| machine_type | The GCP machine type to use for the VM | e2-micro |
| os_image | The OS image to use for the VM | debian-12 |
| instance_tag | The network tag to apply to the VM instance | webserver |
| service_port | The HTTP service port to expose on the VM | 80 |
pulumi config set
:
pulumi config set gcp:project <value>pulumi config set gcp:region <value>pulumi config set gcp:zone <value>pulumi config set machine_type <value>pulumi config set os_image <value>pulumi config set instance_tag <value>pulumi config set service_port <value>pulumi config set gcp:project "<value>"pulumi config set gcp:region "<value>"pulumi config set gcp:zone "<value>"pulumi config set machine_type "<value>"pulumi config set os_image "<value>"pulumi config set instance_tag "<value>"pulumi config set service_port "<value>"For gcp:project, enter the ID of an existing Google Cloud project. gcloud config get-value project prints the one gcloud is using. Press Enter at the others to keep the defaults.
Review the code#
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the language it’s written in.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tfcontains the program code that declares your cloud resources.
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the language it’s written in.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tfcontains the program code that declares your cloud resources.
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the language it’s written in.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tfcontains the program code that declares your cloud resources.
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the language it’s written in.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tfcontains the program code that declares your cloud resources.
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the resources it declares.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.
When setup completes, you’ll see a few files:
Pulumi.yamlcontains the project name and the language it’s written in.Pulumi.dev.yamlcontains thedevstack’s settings, including the values you just entered.index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tfcontains the program code that declares your cloud resources.
Take a moment to open them up and have a look. Here’s what’s in index.tsindex.js__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tf:
import * as pulumi from "@pulumi/pulumi";import * as gcp from "@pulumi/gcp";
// Import the program's configuration settings.const config = new pulumi.Config();const machineType = config.get("machineType") || "f1-micro";const osImage = config.get("osImage") || "debian-12";const instanceTag = config.get("instanceTag") || "webserver";const servicePort = config.get("servicePort") || "80";
// Create a new network for the virtual machine.const network = new gcp.compute.Network("network", { autoCreateSubnetworks: false,});
// Create a subnet on the network.const subnet = new gcp.compute.Subnetwork("subnet", { ipCidrRange: "10.0.1.0/24", network: network.id,});
// Create a firewall allowing inbound access over ports 80 (for HTTP) and 22 (for SSH).const firewall = new gcp.compute.Firewall("firewall", { network: network.selfLink, allows: [ { protocol: "tcp", ports: [ "22", servicePort, ], }, ], direction: "INGRESS", sourceRanges: [ "0.0.0.0/0", ], targetTags: [ instanceTag, ],});
// Define a script to be run when the VM starts up.const metadataStartupScript = `#!/bin/bash echo '<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Hello, world!</title> </head> <body> <h1>Hello, world! 👋</h1> <p>Deployed with 💜 by <a href="https://pulumi.com/">Pulumi</a>.</p> </body> </html>' > index.html sudo nohup python3 -m http.server ${servicePort} >/dev/null 2>&1 &`;
// Create the virtual machine.const instance = new gcp.compute.Instance("instance", { machineType, bootDisk: { initializeParams: { image: osImage, }, }, networkInterfaces: [ { network: network.id, subnetwork: subnet.id, accessConfigs: [ {}, ], }, ], serviceAccount: { scopes: [ "https://www.googleapis.com/auth/cloud-platform", ], }, allowStoppingForUpdate: true, metadataStartupScript, tags: [ instanceTag, ],}, { dependsOn: firewall });
const instanceIP = instance.networkInterfaces.apply(interfaces => { return interfaces[0].accessConfigs![0].natIp;});
// Export the instance's name, public IP address, and HTTP URL.export const name = instance.name;export const ip = instanceIP;export const url = pulumi.interpolate`http://${instanceIP}:${servicePort}`;import pulumiimport pulumi_gcp as gcp
# Import the program's configuration settings.config = pulumi.Config()machine_type = config.get("machineType", "f1-micro")os_image = config.get("osImage", "debian-12")instance_tag = config.get("instanceTag", "webserver")service_port = config.get("servicePort", "80")
# Create a new network for the virtual machine.network = gcp.compute.Network( "network", auto_create_subnetworks=False,)
# Create a subnet on the network.subnet = gcp.compute.Subnetwork( "subnet", ip_cidr_range="10.0.1.0/24", network=network.id,)
# Create a firewall allowing inbound access over ports 80 (for HTTP) and 22 (for SSH).firewall = gcp.compute.Firewall( "firewall", network=network.self_link, allows=[ { "protocol": "tcp", "ports": [ "22", service_port, ], }, ], direction="INGRESS", source_ranges=[ "0.0.0.0/0", ], target_tags=[ instance_tag, ],)
# Define a script to be run when the VM starts up.metadata_startup_script = f"""#!/bin/bash echo '<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Hello, world!</title> </head> <body> <h1>Hello, world! 👋</h1> <p>Deployed with 💜 by <a href="https://pulumi.com/">Pulumi</a>.</p> </body> </html>' > index.html sudo nohup python3 -m http.server {service_port} >/dev/null 2>&1 & """
# Create the virtual machine.instance = gcp.compute.Instance( "instance", machine_type=machine_type, boot_disk={ "initialize_params": { "image": os_image, }, }, network_interfaces=[ { "network": network.id, "subnetwork": subnet.id, "access_configs": [ {}, ], }, ], service_account={ "scopes": [ "https://www.googleapis.com/auth/cloud-platform", ], }, allow_stopping_for_update=True, metadata_startup_script=metadata_startup_script, tags=[ instance_tag, ], opts=pulumi.ResourceOptions(depends_on=firewall),)
instance_ip = instance.network_interfaces.apply( lambda interfaces: interfaces[0].access_configs and interfaces[0].access_configs[0].nat_ip)
# Export the instance's name, public IP address, and HTTP URL.pulumi.export("name", instance.name)pulumi.export("ip", instance_ip)pulumi.export("url", instance_ip.apply(lambda ip: f"http://{ip}:{service_port}"))package main
import ( "fmt"
"github.com/pulumi/pulumi-gcp/sdk/v10/go/gcp/compute" "github.com/pulumi/pulumi/sdk/v3/go/pulumi" "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config")
func main() { pulumi.Run(func(ctx *pulumi.Context) error {
// Import the program's configuration settings. cfg := config.New(ctx, "") machineType, err := cfg.Try("machineType") if err != nil { machineType = "f1-micro" }
osImage, err := cfg.Try("osImage") if err != nil { osImage = "debian-12" }
instanceTag, err := cfg.Try("instanceTag") if err != nil { instanceTag = "webserver" }
servicePort, err := cfg.Try("servicePort") if err != nil { servicePort = "80" }
// Create a new network for the virtual machine. network, err := compute.NewNetwork(ctx, "network", &compute.NetworkArgs{ AutoCreateSubnetworks: pulumi.Bool(false), }) if err != nil { return err }
// Create a subnet on the network. subnet, err := compute.NewSubnetwork(ctx, "subnet", &compute.SubnetworkArgs{ IpCidrRange: pulumi.String("10.0.1.0/24"), Network: network.ID(), }) if err != nil { return err }
// Create a firewall allowing inbound access over ports 80 (for HTTP) and 22 (for SSH). firewall, err := compute.NewFirewall(ctx, "firewall", &compute.FirewallArgs{ Network: network.SelfLink, Allows: compute.FirewallAllowArray{ compute.FirewallAllowArgs{ Protocol: pulumi.String("tcp"), Ports: pulumi.ToStringArray([]string{ "22", servicePort, }), }, }, Direction: pulumi.String("INGRESS"), SourceRanges: pulumi.ToStringArray([]string{ "0.0.0.0/0", }), TargetTags: pulumi.ToStringArray([]string{ instanceTag, }), }) if err != nil { return err }
// Define a script to be run when the VM starts up. metadataStartupScript := fmt.Sprintf(`#!/bin/bash echo '<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Hello, world!</title> </head> <body> <h1>Hello, world! 👋</h1> <p>Deployed with 💜 by <a href="https://pulumi.com/">Pulumi</a>.</p> </body> </html>' > index.html sudo nohup python3 -m http.server %s >/dev/null 2>&1 &`, servicePort)
// Create the virtual machine. instance, err := compute.NewInstance(ctx, "instance", &compute.InstanceArgs{ MachineType: pulumi.String(machineType), BootDisk: compute.InstanceBootDiskArgs{ InitializeParams: compute.InstanceBootDiskInitializeParamsArgs{ Image: pulumi.String(osImage), }, }, NetworkInterfaces: compute.InstanceNetworkInterfaceArray{ compute.InstanceNetworkInterfaceArgs{ Network: network.ID(), Subnetwork: subnet.ID(), AccessConfigs: compute.InstanceNetworkInterfaceAccessConfigArray{ compute.InstanceNetworkInterfaceAccessConfigArgs{ // NatIp: nil, // NetworkTier: nil, }, }, }, }, ServiceAccount: compute.InstanceServiceAccountArgs{ Scopes: pulumi.ToStringArray([]string{ "https://www.googleapis.com/auth/cloud-platform", }), }, AllowStoppingForUpdate: pulumi.Bool(true), MetadataStartupScript: pulumi.String(metadataStartupScript), Tags: pulumi.ToStringArray([]string{ instanceTag, }), }, pulumi.DependsOn([]pulumi.Resource{firewall})) if err != nil { return err }
instanceIp := instance.NetworkInterfaces.Index(pulumi.Int(0)).AccessConfigs().Index(pulumi.Int(0)).NatIp()
// Export the instance's name, public IP address, and HTTP URL. ctx.Export("name", instance.Name) ctx.Export("ip", instanceIp) ctx.Export("url", pulumi.Sprintf("http://%s:%s", instanceIp.Elem(), servicePort)) return nil })}using Pulumi;using Gcp = Pulumi.Gcp;using System.Collections.Generic;
return await Deployment.RunAsync(() =>{ // Import the program's configuration settings. var config = new Pulumi.Config(); var machineType = config.Get("machineType") ?? "f1-micro"; var osImage = config.Get("osImage") ?? "debian-12"; var instanceTag = config.Get("instanceTag") ?? "webserver"; var servicePort = config.Get("servicePort") ?? "80";
// Create a new network for the virtual machine. var network = new Gcp.Compute.Network("network", new() { AutoCreateSubnetworks = false, });
// Create a subnet on the network. var subnet = new Gcp.Compute.Subnetwork("subnet", new() { IpCidrRange = "10.0.1.0/24", Network = network.Id, });
// Create a firewall allowing inbound access over ports 80 (for HTTP) and 22 (for SSH). var firewall = new Gcp.Compute.Firewall("firewall", new() { Network = network.SelfLink, Allows = new[] { new Gcp.Compute.Inputs.FirewallAllowArgs { Protocol = "tcp", Ports = new[] { "22", servicePort, }, }, }, Direction = "INGRESS", SourceRanges = new[] { "0.0.0.0/0", }, TargetTags = new[] { instanceTag, }, });
// Define a script to be run when the VM starts up. var metadataStartupScript = $@"#!/bin/bash echo '<!DOCTYPE html> <html lang=""en""> <head> <meta charset=""utf-8""> <title>Hello, world!</title> </head> <body> <h1>Hello, world! 👋</h1> <p>Deployed with 💜 by <a href=""https://pulumi.com/"">Pulumi</a>.</p> </body> </html>' > index.html sudo nohup python3 -m http.server {servicePort} >/dev/null 2>&1 &";
// Create the virtual machine. var instance = new Gcp.Compute.Instance("instance", new() { MachineType = machineType, BootDisk = new Gcp.Compute.Inputs.InstanceBootDiskArgs { InitializeParams = new Gcp.Compute.Inputs.InstanceBootDiskInitializeParamsArgs { Image = osImage, } }, NetworkInterfaces = new[] { new Gcp.Compute.Inputs.InstanceNetworkInterfaceArgs { Network = network.Id, Subnetwork = subnet.Id, AccessConfigs = new[] { new Gcp.Compute.Inputs.InstanceNetworkInterfaceAccessConfigArgs {
}, }, }, }, ServiceAccount = new Gcp.Compute.Inputs.InstanceServiceAccountArgs { Scopes = new[] { "https://www.googleapis.com/auth/cloud-platform", }, }, AllowStoppingForUpdate = true, MetadataStartupScript = metadataStartupScript, Tags = new[] { instanceTag, }, }, new() { DependsOn = firewall });
var instanceIP = instance.NetworkInterfaces.Apply(interfaces => { return interfaces[0].AccessConfigs[0].NatIp; });
// Export the instance's name, public IP address, and HTTP URL. return new Dictionary<string, object?> { ["name"] = instance.Name, ["ip"] = instanceIP, ["url"] = Output.Format($"http://{instanceIP}:{servicePort}"), };});name: my-projectdescription: A Pulumi YAML program to deploy a virtual machine on Google Cloudruntime: yaml
# Import the program's configuration settings.config: machineType: type: string default: f1-micro osImage: type: string default: debian-12 instanceTag: type: string default: webserver servicePort: type: string default: "80"
variables:
# Define a script to be run when the VM starts up. metadataStartupScript: | #!/bin/bash echo '<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Hello, world!</title> </head> <body> <h1>Hello, world! 👋</h1> <p>Deployed with 💜 by <a href="https://pulumi.com/">Pulumi</a>.</p> </body> </html>' > index.html sudo nohup python3 -m http.server ${servicePort} >/dev/null 2>&1 &
resources:
# Create a new network for the virtual machine. network: type: gcp:compute:Network properties: autoCreateSubnetworks: false
# Create a subnet on the network. subnet: type: gcp:compute:Subnetwork properties: ipCidrRange: 10.0.1.0/24 network: ${network.id}
# Create a firewall allowing inbound access over ports 80 (for HTTP) and 22 (for SSH). firewall: type: gcp:compute:Firewall properties: network: ${network.selfLink} allows: - protocol: tcp ports: - "22" - ${servicePort} direction: INGRESS sourceRanges: - 0.0.0.0/0 targetTags: - ${instanceTag}
# Create the virtual machine. instance: type: gcp:compute:Instance properties: machineType: ${machineType} bootDisk: initializeParams: image: ${osImage} networkInterfaces: - network: ${network.id} subnetwork: ${subnet.id} accessConfigs: - {} serviceAccount: scopes: - https://www.googleapis.com/auth/cloud-platform allowStoppingForUpdate: true metadataStartupScript: ${metadataStartupScript} tags: - ${instanceTag} options: dependsOn: - ${firewall}
# Export the instance's name, public IP address, and HTTP URL.outputs: name: ${instance.name} ip: ${instance.networkInterfaces[0].accessConfigs[0].natIp} url: http://${instance.networkInterfaces[0].accessConfigs[0].natIp}:${servicePort}terraform { required_providers { gcp = { source = "pulumi/gcp" } }}
variable "machine_type" { description = "The GCP machine type to use for the VM" type = string default = "e2-micro"}
variable "os_image" { description = "The OS image type to use for the VM" type = string default = "debian-12"}
variable "instance_tag" { description = "The tag to apply to the VM instance" type = string default = "webserver"}
variable "service_port" { description = "The HTTP service port to expose on the VM" type = number default = 80}
locals { startup_script = <<-EOF #!/bin/bash echo '<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Hello, world!</title> </head> <body> <h1>Hello, world! 👋</h1> <p>Deployed with 💜 by <a href="https://pulumi.com/">Pulumi</a>.</p> </body> </html>' > index.html sudo nohup python3 -m http.server ${var.service_port} >/dev/null 2>&1 & EOF}
# Create a new network for the virtual machine.resource "gcp_compute_network" "network" { auto_create_subnetworks = false}
# Create a subnet on the network.resource "gcp_compute_subnetwork" "subnet" { ip_cidr_range = "10.0.1.0/24" network = gcp_compute_network.network.id}
# Create a firewall allowing inbound access over ports 80 (for HTTP) and 22 (for SSH).resource "gcp_compute_firewall" "firewall" { network = gcp_compute_network.network.self_link direction = "INGRESS" source_ranges = ["0.0.0.0/0"] target_tags = [var.instance_tag]
allows { protocol = "tcp" ports = ["22", tostring(var.service_port)] }}
# Create the virtual machine.resource "gcp_compute_instance" "instance" { depends_on = [gcp_compute_firewall.firewall] machine_type = var.machine_type tags = [var.instance_tag] allow_stopping_for_update = true metadata_startup_script = local.startup_script
boot_disk = { initialize_params = { image = var.os_image } }
network_interfaces { network = gcp_compute_network.network.id subnetwork = gcp_compute_subnetwork.subnet.id
access_configs { } }
service_account = { scopes = ["https://www.googleapis.com/auth/cloud-platform"] }}
# Export the instance's name, public IP address, and HTTP URL.output "name" { value = gcp_compute_instance.instance.name}
output "ip" { value = gcp_compute_instance.instance.network_interfaces[0].access_configs[0].nat_ip}
output "url" { value = "http://${gcp_compute_instance.instance.network_interfaces[0].access_configs[0].nat_ip}:${var.service_port}"}Deploy the project#
First, be sure to enable the Compute Engine API in your project:
gcloud services enable compute.googleapis.com --project $(pulumi config get gcp:project)gcloud services enable compute.googleapis.com --project $(pulumi config get gcp:project)Deploy with pulumi up. It starts with a preview of what it’s about to create and asks before it changes anything. Choose yes to deploy.
pulumi uppulumi upPulumi adds a random suffix to most resource names, so the VM instance becomes something like instance-4f8a2c1. This is autonaming. It lets you deploy the same program to more than one stack, and lets Pulumi create a replacement before it deletes the old resource, without names colliding.
When it finishes, Pulumi prints the stack’s outputs, values it only knows once the resources exist:
- name
The name of the virtual machine instance.
- ip
The IP address of the virtual machine.
- url
The fully-qualified HTTP URL of the HTTP server running on the virtual machine.
Read one any time with pulumi stack output <name>, or pass it to another command. This opens the VM’s web page in your browser:
open $(pulumi stack output url)xdg-open $(pulumi stack output url)Start-Process (pulumi stack output url)To check it from the terminal, fetch the page with curl. It prints the template’s placeholder page, which says Hello, world!. The web server starts as the VM boots, so if curl can’t connect, wait a minute and try again:
curl $(pulumi stack output url)curl.exe (pulumi stack output url)Need help?
If pulumi up reports failed to load application credentials, sign in again:
gcloud auth application-default logingcloud auth application-default loginStill stuck? Let us know.
Customize the project#
Projects created with this template expose the following configuration settings:
- machineType
The Compute Engine machine type to use for the VM. Defaults to
f1-micro.- osImage
The OS image type to use for the VM. Defaults to
debian-12.- instanceTag
The tag to apply to the VM instance. Defaults to
webserver.- servicePort
The HTTP service port to expose on the VM. Defaults to
80.
- machineType
The Compute Engine machine type to use for the VM. Defaults to
f1-micro.- osImage
The OS image type to use for the VM. Defaults to
debian-12.- instanceTag
The tag to apply to the VM instance. Defaults to
webserver.- servicePort
The HTTP service port to expose on the VM. Defaults to
80.
- machineType
The Compute Engine machine type to use for the VM. Defaults to
f1-micro.- osImage
The OS image type to use for the VM. Defaults to
debian-12.- instanceTag
The tag to apply to the VM instance. Defaults to
webserver.- servicePort
The HTTP service port to expose on the VM. Defaults to
80.
- machineType
The Compute Engine machine type to use for the VM. Defaults to
f1-micro.- osImage
The OS image type to use for the VM. Defaults to
debian-12.- instanceTag
The tag to apply to the VM instance. Defaults to
webserver.- servicePort
The HTTP service port to expose on the VM. Defaults to
80.
- machineType
The Compute Engine machine type to use for the VM. Defaults to
f1-micro.- osImage
The OS image type to use for the VM. Defaults to
debian-12.- instanceTag
The tag to apply to the VM instance. Defaults to
webserver.- servicePort
The HTTP service port to expose on the VM. Defaults to
80.
- machine_type
The Compute Engine machine type to use for the VM. Defaults to
e2-micro.- os_image
The OS image type to use for the VM. Defaults to
debian-12.- instance_tag
The tag to apply to the VM instance. Defaults to
webserver.- service_port
The HTTP service port to expose on the VM. Defaults to
80.
All of these settings are optional and may be adjusted either by editing the stack configuration file directly (by default, Pulumi.dev.yaml) or by changing their values with pulumi config set.
Changing the machine type#
Move the VM to an e2-small and deploy. Pulumi stops the VM, changes its type and starts it again; the startup script runs on every boot, so the web server comes back. Then list the instance; the MACHINE_TYPE column shows e2-small:
pulumi config set machineType e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machineType e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machineType e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machineType e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machineType e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machineType e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machineType e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machineType e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machineType e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machineType e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machine_type e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"pulumi config set machine_type e2-smallpulumi upgcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"To see what else you can add, browse the Google Cloud provider in the Pulumi Registry.
Cleaning up#
You can cleanly destroy the stack and all of its infrastructure with pulumi destroy:
pulumi destroypulumi destroyLearn more#
- Browse other architecture templates in the Templates gallery.
- Explore the Google Cloud provider API docs in the Pulumi Registry.
- Walk through Pulumi from the ground up in Pulumi Tutorials.
- Read the latest Google Cloud posts on the Pulumi blog.