Before you begin
- Labs create a Google Cloud project and resources for a fixed time
- Labs have a time limit and no pause feature. If you restart it, you'll have to start from the beginning.
- Click Start lab to begin
Provision infrastructure
/ 50
Upload files to the bucket
/ 50
This lab was developed with our partner, Hashicorp. Your personal information may be shared with Hashicorp, the lab sponsor, if you have opted in to receive product updates, announcements, and offers in your Account Profile.
As you manage your infrastructure with Terraform, increasingly complex configurations will be created. There is no intrinsic limit to the complexity of a single Terraform configuration file or directory, so it is possible to continue writing and updating your configuration files in a single directory. However, if you do, you may encounter one or more of the following problems:
In this lab, you will learn how modules can address these problems, the structure of a Terraform module, and best practices when using and creating modules.
Here are some of the ways that modules help solve the problems listed above:
Organize configuration: Modules make it easier to navigate, understand, and update your configuration by keeping related parts of your configuration together. Even moderately complex infrastructure can require hundreds or thousands of lines of configuration to implement. By using modules, you can organize your configuration into logical components.
Encapsulate configuration: Another benefit of using modules is to encapsulate configuration into distinct logical components. Encapsulation can help prevent unintended consequences—such as a change to one part of your configuration accidentally causing changes to other infrastructure—and reduce the chances of simple errors like using the same name for two different resources.
Re-use configuration: Writing all of your configuration without using existing code can be time-consuming and error-prone. Using modules can save time and reduce costly errors by re-using configuration written either by yourself, other members of your team, or other Terraform practitioners who have published modules for you to use. You can also share modules that you have written with your team or the general public, giving them the benefit of your hard work.
Provide consistency and ensure best practices: Modules also help to provide consistency in your configurations. Consistency makes complex configurations easier to understand, and it also helps to ensure that best practices are applied across all of your configuration. For example, cloud providers offer many options for configuring object storage services, such as Amazon S3 (Simple Storage Service) or Google's Cloud Storage buckets. Many high-profile security incidents have involved incorrectly secured object storage, and because of the number of complex configuration options involved, it's easy to accidentally misconfigure these services.
Using modules can help reduce these errors. For example, you might create a module to describe how all of your organization's public website buckets will be configured, and another module for private buckets used for logging applications. Also, if a configuration for a type of resource needs to be updated, using modules allows you to make that update in a single place and have it be applied to all cases where you use that module.
In this lab, you will learn how to perform the following tasks:
Read these instructions. Labs are timed and you cannot pause them. The timer, which starts when you click Start Lab, shows how long Google Cloud resources are made available to you.
This hands-on lab lets you do the lab activities in a real cloud environment, not in a simulation or demo environment. It does so by giving you new, temporary credentials you use to sign in and access Google Cloud for the duration of the lab.
To complete this lab, you need:
Click the Start Lab button. If you need to pay for the lab, a dialog opens for you to select your payment method. On the left is the Lab Details pane with the following:
Click Open Google Cloud console (or right-click and select Open Link in Incognito Window if you are running the Chrome browser).
The lab spins up resources, and then opens another tab that shows the Sign in page.
Tip: Arrange the tabs in separate windows, side-by-side.
If necessary, copy the Username below and paste it into the Sign in dialog.
You can also find the Username in the Lab Details pane.
Click Next.
Copy the Password below and paste it into the Welcome dialog.
You can also find the Password in the Lab Details pane.
Click Next.
Click through the subsequent pages:
After a few moments, the Google Cloud console opens in this tab.
Cloud Shell is a virtual machine that is loaded with development tools. It offers a persistent 5GB home directory and runs on the Google Cloud. Cloud Shell provides command-line access to your Google Cloud resources.
Click Activate Cloud Shell at the top of the Google Cloud console.
Click through the following windows:
When you are connected, you are already authenticated, and the project is set to your Project_ID,
gcloud
is the command-line tool for Google Cloud. It comes pre-installed on Cloud Shell and supports tab-completion.
Output:
Output:
gcloud
, in Google Cloud, refer to the gcloud CLI overview guide.
A Terraform module is a set of Terraform configuration files in a single directory. Even a simple configuration consisting of a single directory with one or more .tf
files is a module. When you run Terraform commands directly from such a directory, it is considered the root module. So in this sense, every Terraform configuration is part of a module. You may have a simple set of Terraform configuration files like this:
In this case, when you run Terraform commands from within the minimal-module
directory, the contents of that directory are considered the root module.
Terraform commands will only directly use the configuration files in one directory, which is usually the current working directory. However, your configuration can use module blocks to call modules in other directories. When Terraform encounters a module block, it loads and processes that module's configuration files.
A module that is called by another configuration is sometimes referred to as a "child module" of that configuration.
Modules can be loaded from either the local filesystem or a remote source. Terraform supports a variety of remote sources, including the Terraform Registry, most version control systems, HTTP URLs, and Terraform Cloud or Terraform Enterprise private module registries.
In many ways, Terraform modules are similar to the concepts of libraries, packages, or modules found in most programming languages, and they provide many of the same benefits. Just like almost any non-trivial computer program, real-world Terraform configurations should almost always use modules to provide the benefits mentioned above.
It is recommended that every Terraform practitioner use modules by following these best practices:
Start writing your configuration with a plan for modules. Even for slightly complex Terraform configurations managed by a single person, the benefits of using modules outweigh the time it takes to use them properly.
Use local modules to organize and encapsulate your code. Even if you aren't using or publishing remote modules, organizing your configuration in terms of modules from the beginning will significantly reduce the burden of maintaining and updating your configuration as your infrastructure grows in complexity.
Use the public Terraform Registry to find useful modules. This way you can quickly and confidently implement your configuration by relying on the work of others.
Publish and share modules with your team. Most infrastructure is managed by a team of people, and modules are an important tool that teams can use to create and maintain infrastructure. As mentioned earlier, you can publish modules either publicly or privately. You will see how to do this in a later lab in this series.
In this section, you use modules from the Terraform Registry to provision an example environment in Google Cloud. The concepts you use here will apply to any modules from any source.
The page includes information about the module and a link to the source repository. The right side of the page includes a dropdown interface to select the module version and instructions for using the module to provision infrastructure.
When you call a module, the source
argument is required. In this example, Terraform will search for a module in the Terraform Registry that matches the given string. You could also use a URL or local file path for the source of your modules. See the Terraform documentation for a list of possible module sources.
The other argument shown here is the version
. For supported sources, the version will let you define what version or versions of the module will be loaded. In this lab, you will specify an exact version number for the modules you use. You can read about more ways to specify versions in the module documentation.
Other arguments to module blocks are treated as input variables to the modules.
v6.0.1
branch:This ensures that you're using the correct version number.
On the Cloud Shell toolbar, click Open Editor. To switch between Cloud Shell and the code editor, click Open Editor or Open Terminal as required, or click Open in a new window to leave the Editor open in a separate tab.
In the editor, navigate to terraform-google-network/examples/simple_project
, and open the main.tf
file. Your main.tf
configuration will look like this:
This configuration includes one important block:
module "test-vpc-module"
defines a Virtual Private Cloud (VPC), which will provide networking services for the rest of your infrastructure.Some input variables are required, which means that the module doesn't provide a default value; an explicit value must be provided in order for Terraform to run correctly.
Within the module "test-vpc-module"
block, review the input variables you are setting. Each of these input variables is documented in the Terraform Registry. The required inputs for this module are:
network_name
: The name of the network being createdproject_id
: The ID of the project where this VPC will be createdsubnets
: The list of subnets being createdIn order to use most modules, you will need to pass input variables to the module configuration. The configuration that calls a module is responsible for setting its input values, which are passed as arguments to the module block. Aside from source
and version
, most of the arguments to a module block will set variable values.
On the Terraform Registry page for the Google Cloud network module, an Inputs tab describes all of the input variables that module supports.
Using input variables with modules is very similar to how you use variables in any Terraform configuration. A common pattern is to identify which module input variables you might want to change in the future, and then create matching variables in your configuration's variables.tf
file with sensible default values. Those variables can then be passed to the module block as arguments.
In the Editor, still in the same directory, navigate to variables.tf
.
Fill in the variable project_id
with the output of the previous command. You must follow the format below and set the default
value for the variable:
variables.tf
, add in the variable network_name
. You can use the name example-vpc
or any other name you'd like. You must follow the format below and set the default
value for the variable:main.tf
file, update the network_name
parameter to use the variable you just defined by setting the value to var.network_name
.main.tf
file, update the subnet regions on lines 35, 40, and 47 from us-west1
to Modules also have output values, which are defined within the module with the output
keyword. You can access them by referring to module.<MODULE NAME>.<OUTPUT NAME>
. Like input variables, module outputs are listed under the outputs
tab in the Terraform Registry.
Module outputs are usually either passed to other parts of your configuration or defined as outputs in your root module. You will see both uses in this lab.
outputs.tf
file inside of your configuration's directory. Verify that the file contains the following:simple_project
directory:Great! You've just used your first module. Your configuration's output should look like this:
When using a new module for the first time, you must run either terraform init
or terraform get
to install the module. When either of these commands is run, Terraform will install any new modules in the .terraform/modules
directory within your configuration's working directory. For local modules, Terraform will create a symlink to the module's directory. Because of this, any changes to local modules will be effective immediately, without your having to re-run terraform get
.
Now you have seen how to use modules from the Terraform Registry, how to configure those modules with input variables, and how to get output values from those modules.
Respond to the prompt with yes
.
Terraform will destroy the infrastructure you created.
Once you've destroyed your resourced, delete the terraform-google-network
folder.
Click Check my progress to verify the objective.
In the last task, you used a module from the Terraform Registry to create a VPC network in Google Cloud. Although using existing Terraform modules correctly is an important skill, every Terraform practitioner will also benefit from learning how to create modules. We recommend that you create every Terraform configuration with the assumption that it may be used as a module, because this will help you design your configurations to be flexible, reusable, and composable.
As you may already know, Terraform treats every configuration as a module. When you run terraform
commands, or use Terraform Cloud or Terraform Enterprise to remotely run Terraform, the target directory containing Terraform configuration is treated as the root module.
In this task, you create a module to manage Compute Storage buckets used to host static websites.
Terraform treats any local directory referenced in the source
argument of a module
block as a module. A typical file structure for a new module is:
.tf
file or use any other file structure you like.
Each of these files serves a purpose:
LICENSE
contains the license under which your module will be distributed. When you share your module, the LICENSE file will let people using it know the terms under which it has been made available. Terraform itself does not use this file.README.md
contains documentation in markdown format that describes how to use your module. Terraform does not use this file, but services like the Terraform Registry and GitHub will display the contents of this file to visitors to your module's Terraform Registry or GitHub page.main.tf
contains the main set of configurations for your module. You can also create other configuration files and organize them in a way that makes sense for your project.variables.tf
contains the variable definitions for your module. When your module is used by others, the variables will be configured as arguments in the module block. Because all Terraform values must be defined, any variables that don't have a default value will become required arguments. A variable with a default value can also be provided as a module argument, thus overriding the default value.outputs.tf
contains the output definitions for your module. Module outputs are made available to the configuration using the module, so they are often used to pass information about the parts of your infrastructure defined by the module to other parts of your configuration.Be aware of these files and ensure that you don't distribute them as part of your module:
terraform.tfstate
and terraform.tfstate.backup
files contain your Terraform state and are how Terraform keeps track of the relationship between your configuration and the infrastructure provisioned by it..terraform
directory contains the modules and plugins used to provision your infrastructure. These files are specific to an individual instance of Terraform when provisioning infrastructure, not the configuration of the infrastructure defined in .tf
files.*.tfvars
files don't need to be distributed with your module unless you are also using it as a standalone Terraform configuration because module input variables are set via arguments to the module block in your configuration.Navigate to your home directory and create your root module by constructing a new main.tf
configuration file. Then create a directory called modules that contains another folder called gcs-static-website-bucket
. You will work with three Terraform configuration files inside the gcs-static-website-bucket
directory: website.tf
, variables.tf
, and outputs.tf
.
gcs-static-website-bucket
directory, run the following command to create a file called README.md
with the following content:LICENSE
with the following content:Your current module directory structure should now look like this:
website.tf
file inside the modules/gcs-static-website-bucket
directory:The provider documentation is GitHub.
variables.tf
file in your module and add the following code:outputs.tf
file inside your module:Like variables, outputs in modules perform the same function as they do in the root module but are accessed in a different way. A module's outputs can be accessed as read-only attributes on the module object, which is available within the configuration that calls the module.
main.tf
in your root directory and add a reference to the new module:outputs.tf
file for your root module:outputs.tf
file:variables.tf
file:variables.tf
file. Set the variables project_id
and name
to default to your Project ID: Whenever you add a new module to a configuration, Terraform must install the module before it can be used. Both the terraform get
and terraform init
commands will install and update modules. The terraform init
command will also initialize backends and install plugins.
You have now configured and used your own module to create a static website. You may want to visit this static website. Right now there is nothing inside your bucket, so there is nothing to see at the website. In order to see any content, you will need to upload objects to your bucket. You can upload the contents of the www
directory in the GitHub repository.
YOUR-BUCKET-NAME
with the name of your storage bucket:https://storage.cloud.google.com/YOUR-BUCKET-NAME/index.html
, replacing YOUR-BUCKET-NAME
with the name of your storage bucket.You should see a basic HTML web page that says Nothing to see here.
Click Check my progress to verify the objective.
Lastly, you will clean up your project by destroying the infrastructure you just created.
After you respond to the prompt with yes
, Terraform will destroy all of the resources you created by following this lab.
In this lab, you learned the foundations of Terraform modules and how to use a pre-existing module from the Registry. You then built your own module to create a static website hosted on a Cloud Storage bucket. In doing so, you defined inputs, outputs, and variables for your configuration files and learned the best-practices for building modules.
These links provide more hands-on practice with Terraform:
...helps you make the most of Google Cloud technologies. Our classes include technical skills and best practices to help you get up to speed quickly and continue your learning journey. We offer fundamental to advanced level training, with on-demand, live, and virtual options to suit your busy schedule. Certifications help you validate and prove your skill and expertise in Google Cloud technologies.
Manual Last Updated September 19, 2024
Lab Last Tested December 11, 2023
Copyright 2025 Google LLC All rights reserved. Google and the Google logo are trademarks of Google LLC. All other company and product names may be trademarks of the respective companies with which they are associated.