Skip to main content

Search the Dev Center

Search tutorials, templates, examples, and more.

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.

Architecture diagram of the Google Cloud Virtual Machine template Google Cloud Compute Network (VPC) VPC Subnet Firewall Rules Compute Instance

Before you begin#

For this walkthrough, you'll need:

Create a new project#

Create a new project from the template:

Terminal window
mkdir my-virtual-machine; cd my-virtual-machine
pulumi new vm-gcp-typescript

The 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:

KeyDescriptionDefault
gcp:projectThe Google Cloud project to deploy into—
gcp:regionThe Google Cloud region to deploy intous-central1
gcp:zoneThe Google Cloud availability zone to deploy intous-central1-a
machineTypeThe GCP machine type to use for the VMf1-micro
osImageThe OS image type to use for the VMdebian-12
instanceTagThe tag to apply to the VM instancewebserver
servicePortThe HTTP service port to expose on the VM80
You can change values like these later with pulumi config set :
Terminal window
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>

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.yaml contains the project name and the language it’s written in.
  • Pulumi.dev.yaml contains the dev stack’s settings, including the values you just entered.
  • index.ts contains 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.ts:

index.ts
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}`;

Deploy the project#

First, be sure to enable the Compute Engine API in your project:

Terminal window
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.

Terminal window
pulumi up

Pulumi 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:

Terminal window
open $(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:

Terminal window
curl $(pulumi stack output url)
Need help?

If pulumi up reports failed to load application credentials, sign in again:

Terminal window
gcloud auth application-default login

Still 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.

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:

Terminal window
pulumi config set machineType e2-small
pulumi up
gcloud compute instances list --project $(pulumi config get gcp:project) --filter "name=$(pulumi stack output name)"

Cleaning up#

You can cleanly destroy the stack and all of its infrastructure with pulumi destroy:

Terminal window
pulumi destroy

Learn more#

Related

The infrastructure as code platform for any cloud.