Getting Started - Google Cloud Platform

Build Infrastructure

With Terraform installed, let's dive right into it and start creating some infrastructure.

We'll build infrastructure on GCP for this getting started guide, but Terraform can manage many other things using providers. Some examples of this are in the use cases section.

Setting up GCP

In addition to a GCP account, you'll need two things to use Terraform to provision your infrastructure:

  • A GCP Project: GCP organizes resources into projects. You can create one in the GCP console. You'll need the Project ID later. You can see a list of your projects in the cloud resource manager.

  • Google Compute Engine: You'll need to enable Google Compute Engine for your project. You can do so in the console. Make sure the project you're using to follow this guide is selected and click the "Enable" button.

  • A GCP service account key: Terraform will access your GCP account by using a service account key. You can create one in the console. When creating the key, use the following settings:

    • Select the project you created in the previous step.
    • Under "Service account", select "New service account".
    • Give it any name you like.
    • For the Role, choose "Project -> Editor".
    • Leave the "Key Type" as JSON.
    • Click "Create" to create the key and save the key file to your system.

You can read more about service account keys in Google's documentation.

Configuration

The set of files used to describe infrastructure in Terraform is known as a Terraform configuration. We're going to write our first configuration now to launch a single GCP instance.

The format of the configuration files is documented here. Configuration files can also be JSON, but we recommend only using JSON when the configuration is generated by a machine.

The entire configuration is shown below. We'll go over each part soon.

When run, Terraform will load all configuration files from the current directory. So it's a good idea to organize your configurations into separate directories based on your needs (e.g. departments, production vs development, etc). To set things up for

Create a directory for the examples in this guide, and inside of it save the example configuration below to a file named main.tf. Terraform recognizes files ending in .tf or .tf.json as configuration files and will load them when it runs.

provider "google" {
  credentials = file("<NAME>.json")

  project = "<PROJECT_ID>"
  region  = "us-central1"
  zone    = "us-central1-c"
}

resource "google_compute_network" "vpc_network" {
  name = "terraform-network"
}

You'll also need to copy the service account key file that you downloaded earlier into this directory and reference it in the "credentials" line.

There are other ways to supply your account credentials, see the provider reference for more details.

The provider block is used to configure the named provider, in our case google. A provider is responsible for creating and managing resources. Multiple provider blocks can exist if a Terraform configuration manages resources from different providers.

The resource block defines a resource that exists within the infrastructure. A resource might be a physical component such as a server, or it can be a logical resource such as a Heroku application. In this example, we're creating a network for the resources we'll created later in this tutorial.

The resource block has two strings before opening the block: the resource type and the resource name. In our example, the resource type is "google_compute_network" and the name is "vpc_network." The prefix of the type maps to the provider. In our case "google_compute_network" automatically tells Terraform that it is managed by the "google" provider. The resource type and name together form the resource ID, in this case "google_compute_network.vpc_network". The resource can be referenced by this ID in other parts of your configuration.

Within the resource block itself is configuration for that resource. This is dependent on each resource provider and is fully documented within our providers reference.

The GCP provider documents supported resources resources, including google_compute_network.

There are a number of optional arguments, but for our network, we just specify the name, which will be how the network is identified in GCP.

Initialization

The first command to run for a new configuration -- or after checking out an existing configuration from version control -- is terraform init, which initializes various local settings and data that will be used by subsequent commands.

Run the command terraform init in the same directory as your main.tf file now:

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "google" (terraform-providers/google) 2.10.0...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.google: version = "~> 2.10"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

The google provider plugin has been downloaded and installed in a subdirectory of the current working directory, along with various other book-keeping files.

The output specifies which version of the plugin was installed, and suggests specifying that version in configuration to ensure that running terraform init in future will install a compatible version. This step is not necessary to follow this getting started guide, since we'll discard this configuration at the end.

Creating Resources

In the same directory as the main.tf file you created, now run terraform apply. You should see output similar to below:

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # google_compute_network.vpc_network will be created
  + resource "google_compute_network" "vpc_network" {
      + auto_create_subnetworks         = true
      + delete_default_routes_on_create = false
      + gateway_ipv4                    = (known after apply)
      + id                              = (known after apply)
      + name                            = "terraform-network"
      + project                         = (known after apply)
      + routing_mode                    = (known after apply)
      + self_link                       = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:

This output shows the execution plan, describing which actions Terraform will take in order to create infrastructure to match the configuration. The output format is similar to the diff format generated by tools such as Git. The output has a + next to resource "google_compute_network" "vpc_network", meaning that Terraform will create this resource. Beneath that, it shows the attributes that will be set. When the value displayed is (known after apply), it means that the value won't be known until the resource is created.

If the plan was created successfully, Terraform will now pause and wait for approval before proceeding. If anything in the plan seems incorrect or dangerous, it is safe to abort here with no changes made to your infrastructure.

In this case the plan looks acceptable, so type yes at the confirmation prompt to proceed.

If terraform apply failed with an error, read the error message and fix the error that occurred.

Executing the plan will take a few minutes since Terraform waits for the network to be created successfully:

# ...
  Enter a value: yes

google_compute_network.vpc_network: Creating...
google_compute_network.vpc_network: Still creating... [10s elapsed]
google_compute_network.vpc_network: Still creating... [20s elapsed]
google_compute_network.vpc_network: Still creating... [30s elapsed]
google_compute_network.vpc_network: Still creating... [40s elapsed]
google_compute_network.vpc_network: Still creating... [50s elapsed]
google_compute_network.vpc_network: Creation complete after 58s [id=terraform-network]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

After this, Terraform is all done! You can go to the GCP console to see the created network. Make sure you're looking at the same region and project that was configured in the provider configuration.

If you look in your current working directory, you'll see that Terraform also wrote some data into the terraform.tfstate file. This state file is extremely important; it keeps track of Terraform's understanding of the resources it created. We recommended that you use source control for the configuration files, but the state should not be stored in source control. You can setup remote state to store and share the state with your teams. You'll see how to do so later on in this guide.

You can inspect the current state by running terraform show:

$ terraform show
# google_compute_network.vpc_network:
resource "google_compute_network" "vpc_network" {
    auto_create_subnetworks         = true
    delete_default_routes_on_create = false
    id                              = "terraform-network"
    name                            = "terraform-network"
    project                         = "hc-training-test"
    routing_mode                    = "REGIONAL"
    self_link                       = "https://www.googleapis.com/compute/v1/projects/example-project/global/networks/terraform-network"
}

You can see that by creating our resource, we've also gathered a lot of information about it. These values can be referenced to configure other resources or outputs, which will be covered later in this guide.