One place for hosting & domains

      December 2018

      Deploy a WordPress Site Using Terraform and Linode StackScripts


      Updated by Linode Contributed by Linode

      Linode’s Terraform provider supports StackScripts. StackScripts allow you to automate the deployment of custom software on top of Linode’s default Linux images, or on any of your saved custom images. You can create your own StackScripts, use a StackScript created by Linode, or use a Community StackScript.

      In this guide you will learn how to use a Community StackScript to deploy WordPress on a Linode using Terraform.

      Caution

      Following this guide will result in the creation of billable Linode resources on your account. To prevent continued billing for these resources, remove them from your account when you have completed the guide, if desired.

      Before You Begin

      1. Install Terraform on your computer by following the Install Terraform section of our Use Terraform to Provision Linode Environments guide.

      2. Terraform requires an API access token. Follow the Getting Started with the Linode API guide to obtain one.

      3. If you have not already, assign Linode’s name servers to your domain at your domain name’s registrar.

      4. Browse the existing StackScripts Library to familiarize yourself with common tasks you can complete with existing StackScripts.

      Create a Terraform Configuration

      Terraform defines the elements of your Linode infrastructure inside of configuration files. Terraform refers to these infrastructure elements as resources. Once you declare your Terraform configuration, you then apply it, which results in the creation of those resources on the Linode platform.

      Create the Terraform Configuration File

      1. Ensure that you are in the terraform directory.

        cd ~/terraform
        
      2. Using your preferred text editor, create a Terraform configuration file named main.tf to hold your resource definitions:

        ~/terraform/main.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        
        provider "linode" {
            token = "${var.token}"
        }
        
        resource "linode_sshkey" "my_wordpress_linode_ssh_key" {
            label = "my_ssh_key"
            ssh_key = "${chomp(file("~/.ssh/id_rsa.pub"))}"
        }
        
        resource "random_string" "my_wordpress_linode_root_password" {
            length  = 32
            special = true
        }
        
        resource "linode_instance" "my_wordpress_linode" {
            image = "${var.image}"
            label = "${var.label}"
            region = "${var.region}"
            type = "${var.type}"
            authorized_keys = [ "${linode_sshkey.my_wordpress_linode_ssh_key.ssh_key}" ]
            root_pass = "${random_string.my_wordpress_linode_root_password.result}"
            stackscript_id = "${var.stackscript_id}"
            stackscript_data = "${var.stackscript_data}"
        }
        
        resource "linode_domain" "my_wordpress_domain" {
            domain = "${var.domain}"
            soa_email = "${var.soa_email}"
            type = "master"
         }
        
        resource "linode_domain_record" "my_wordpress_domain_www_record" {
            domain_id = "${linode_domain.my_wordpress_domain.id}"
            name = "www"
            record_type = "${var.a_record}"
            target = "${linode_instance.my_wordpress_linode.ipv4[0]}"
        }
        
        resource "linode_domain_record" "my_wordpress_domain_apex_record" {
            domain_id = "${linode_domain.my_wordpress_domain.id}"
            name = ""
            record_type = "${var.a_record}"
            target = "${linode_instance.my_wordpress_linode.ipv4[0]}"
        }

        The Terraform configuration file uses an interpolation syntax to reference Terraform input variables, call Terraform’s built-in functions, and reference attributes of other resources.

        Variables and their values will be created in separate files later on in this guide. Using separate files for variable declaration allows you to avoid hard-coding values into your resources. This strategy can help you reuse, share, and version control your Terraform configurations.

      Examining the Terraform Configuration

      Let’s take a closer look at each block in the configuration file:

      1. The first stanza declares Linode as the Terraform provider that will manage the life cycle of any resources declared throughout the configuration file. The Linode provider requires your Linode APIv4 token for authentication:

        1
        2
        3
        
        provider "linode" {
            token = "${var.token}"
        }
      2. The next resource configures an SSH Key that will be uploaded to your Linode instance later in the configuration file:

        1
        2
        3
        4
        
        resource "linode_sshkey" "my_wordpress_linode_ssh_key" {
            label = "my_ssh_key"
            ssh_key = "${chomp(file("~/.ssh/id_rsa.pub"))}"
        }

        ssh_key = "${chomp(file("~/.ssh/id_rsa.pub"))}" uses Terraform’s built-in file() function to provide a local file path to the public SSH key’s location. The chomp() built-in function removes trailing new lines from the SSH key.

        Note

        If you do not already have SSH keys, follow the steps in the Create an Authentication Key-pair section of the Securing Your Server Guide.
      3. The random_string resource can be used to create a random string of 32 characters. The linode_instance resource will use it to create a root user password:

        1
        2
        3
        4
        
        resource "random_string" "my_wordpress_linode_root_password" {
            length  = 32
            special = true
        }
      4. The linode_instance resource creates a Linode with the declared configurations:

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        
        resource "linode_instance" "my_wordpress_linode" {
            image = "${var.image}"
            label = "${var.label}"
            region = "${var.region}"
            type = "${var.type}"
            authorized_keys = [ "${linode_sshkey.my_wordpress_linode_ssh_key.ssh_key}" ]
            root_pass = "${random_string.my_wordpress_linode_root_password.result}"
            stackscript_id = "${var.stackscript_id}"
            stackscript_data = "${var.stackscript_data}"
        }
        • The authorized_keys argument uses the SSH public key provided by the linode_sshkey resource in the previous stanza. This argument expects a value of type list, so the value must be wrapped in brackets.

        • The root_pass argument is assigned to the value of the random_string resource previously declared.

        • To use an existing StackScript you must use the stackscript_id argument and provide a valid ID as a value. Every StackScript is assigned a unique ID upon creation. This guide uses the WordPress on Ubuntu 16.04 StackScript provided by Linode user hmorris. This StackScript’s ID will be assigned to a Terraform variable later in this guide.

          StackScripts support user defined data. A StackScript can use the UDF tag to create a variable whose value must be provided by the user of the script. This allows users to customize the behavior of a StackScript on a per-deployment basis. Any required UDF variable can be defined using the stackscript_data argument.

          The StackScript will be responsible for installing WordPress on your Linode, along with all other requirements, like installing and configuring the Apache Web Server, configuring the Virtual Hosts file, and installing MySQL.

        • Other arguments are given values by the Terraform variables that will be declared later in this guide.

      5. In order to complete your WordPress site’s configuration, you need to create a domain and corresponding domain records for your site. The linode_domain and linode_domain_record resources handle these configurations:

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        
        resource "linode_domain" "my_wordpress_domain" {
            domain = "${var.domain}"
            soa_email = "${var.soa_email}"
            type = "master"
         }
        
        resource "linode_domain_record" "my_wordpress_domain_www_record" {
            domain_id = "${linode_domain.my_wordpress_domain.id}"
            name = "www"
            record_type = "${var.a_record}"
            target = "${linode_instance.linode_id.ipv4[0]}"
        }
        
        resource "linode_domain_record" "my_wordpress_domain_apex_record" {
            domain_id = "${linode_domain.my_wordpress_domain.id}"
            name = ""
            record_type = "${var.a_record}"
            target = "${linode_instance.my_wordpress_linode.ipv4[0]}"
        }

        Note

        The linode_domain resource creates a domain zone for your domain.

        Each linode_domain_record resource retrieves the linode_domain resource’s ID and assigns it to that record’s domain_id argument. Each record’s target argument retrieves the IP address from the Linode instance. Every linode_instance resource exposes several attributes, including a Linode’s IPv4 address.

      Define the Input Variables

      In the terraform directory, create a file named variables.tf. This will define all the variables that were used in the main.tf file in the previous section. The values for these variables (aside from their default values) will be assigned in another file:

      ~/terraform/variables.tf
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      
      variable "token" {
        description = "Linode API Personal Access Token"
      }
      
      variable "image" {
        description = "Image to use for Linode instance"
        default = "linode/ubuntu16.04lts"
      }
      
      variable "label" {
        description = "The Linode's label is for display purposes only."
        default = "default-linode"
      }
      
      variable "region" {
        description = "The region where your Linode will be located."
        default = "us-east"
      }
      
      variable "type" {
        description = "Your Linode's plan type."
        default = "g6-standard-1"
      }
      
      variable "stackscript_id" {
        description = "Stackscript ID"
      }
      
      variable "stackscript_data" {
        description = "Map of required StackScript UDF data."
        type = "map"
      }
      
      variable "domain" {
        description = "The domain this domain represents."
      }
      
      variable "soa_email" {
        description = "Start of Authority email address. This is required for master domains."
      }
      
      variable "a_record" {
        description = "The type of DNS record. For example, `A` records associate a domain name with an IPv4 address."
        default = "A"
      }
          

      Note

      It is recommended to include a description attribute for each input variable to help document your configuration’s usage. This will make it easier for anyone else to use this Terraform configuration.

      Every variable can contain a default value. The default value is only used if no other value is provided. You can also declare a type for each variable. If no type is provided, the variable will default to type = "string".

      The stackscript_data variable is of type map. This will allow you to provide values for as many UDF variables as your StackScript requires.

      Assign Values to the Input Variables

      Terraform allows you to assign variables in many ways. For example, you can assign a variable value via the command line when running terraform apply. In order to persist variable values, you can also create files to hold all your values.

      Note

      Terraform will automatically load any file named terraform.tfvars and use its contents to populate variables. However, you should separate out any sensitive values, like passwords and tokens, into their own file. Keep this sensitive file out of version control.

      1. Create a file named terraform.tfvars in your terraform directory to hold all non-sensitive values:

        ~/terraform/terraform.tfvars
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        
        label = "wp-linode"
        stackscript_id = "81736"
        stackscript_data = {
          ssuser = "username"
          hostname = "wordpress"
          website = "example.com"
          dbuser = "wpuser"
        }
        domain = "example.com"
        soa_email = "[email protected]"
      2. Create a file name secrets.tfvars in your terraform directory to hold any sensitive values:

        ~/terraform/secrets.tfvars
        1
        2
        3
        4
        5
        6
        
        token = "my-linode-api4-token"
        stackscript_data = {
          sspassword = "my-secure-password"
          db_password = "another-secure-password"
          dbuser_password = "a-third-secure-password"
        }

        Note

      3. Replace the following values in your new .tfvars files:

        • token should be replaced with your own Linode account’s APIv4 token.

        • For security purposes, the StackScript will create a limited Linux user on your Linode. ssuser should be replaced with your desired username for this user.

        • sspassword, db_password, and dbuser_password should be replaced with secure passwords of your own.

        • domain should be replaced with your WordPress site’s domain address.

        • soa_email should be the email address you would like to use for your Start of Authority email address.

      Initialize, Plan, and Apply the Terraform Configuration

      Your Terraform configuration has been recorded, but you have not told Terraform to create the resources yet. To do this, you will invoke commands from Terraform’s CLI.

      Initialize

      Whenever a new provider is used in a Terraform configuration, it must be initialized before you can create resources with it. The initialization process downloads and installs the provider’s plugin and performs any other steps needed to prepare for its use.

      Navigate to your terraform directory in your terminal and run:

      terraform init
      

      You will see a message that confirms that the Linode provider plugins have been successfully initialized.

      Plan

      It can be useful to view your configuration’s execution plan before actually committing those changes to your infrastructure. Terraform includes a plan command for this purpose. Run this command from the terraform directory:

      terraform plan 
      -var-file="secrets.tfvars" 
      -var-file="terraform.tfvars"
      

      plan won’t take any actions or make any changes on your Linode account. Instead, an analysis is done to determine which actions (i.e. Linode resource creations, deletions, or modifications) are required to achieve the state described in your configuration.

      Apply

      You are now ready to create the infrastructure defined in your main.tf configuration file:

      1. Run Terraform’s apply command from the terraform directory:

        terraform apply 
        -var-file="secrets.tfvars" 
        -var-file="terraform.tfvars"
        

        Since you are using multiple variable value files, you must include each file individually using the var-file argument. You will be prompted to confirm the apply action. Type yes and press enter.

      2. Terraform will begin to create the resources you’ve defined throughout this guide. This process will take several minutes to complete. Once the infrastructure has been successfully built you will see a similar output:

          
        Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
        
        
      3. Navigate to your WordPress site’s domain and verify that the site loads. You may have to wait a few minutes more after the terraform apply command returns, as the StackScript takes time to install WordPress. Additionally, it make take some time for your domain name changes to propagate:

        Install WordPress

      4. Complete the remaining WordPress configuration steps provided by the prompts.

      (Optional) Destroy the Linode Resources

      If you do not want to keep using the resources created by Terraform in this guide, run the destroy command from the terraform directory:

      terraform destroy 
      -var-file="secrets.tfvars" 
      -var-file="terraform.tfvars"
      

      Terraform will prompt you to confirm this action. Enter yes to proceed.

      More Information

      You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

      Find answers, ask questions, and help others.

      This guide is published under a CC BY-ND 4.0 license.



      Source link

      Create a Terraform Module


      Updated by Linode Contributed by Linode

      Terraform modules allow you to better organize your configuration code and make the code reusable. You can host your Terraform modules on remote version control services, like GitHub, for others to use. The Terraform Module Registry hosts community modules that you can reuse for your own Terraform configurations, or you can publish your own modules for consumption by the Terraform community.

      In this guide you will create a Linode StackScripts module. This module will deploy a Linode instance from a StackScript you will create. This module will include nested modules that split up the required resources between the root module, a linode_instance module, and a stackscripts module.

      Before You Begin

      1. Install Terraform on your local computer using the steps found in the Install Terraform section of the Use Terraform to Provision Linode Environments guide. Your Terraform project directory should be named linode_stackscripts.

      2. Terraform requires an API access token. Follow the Getting Started with the Linode API guide to obtain a token.

      3. Complete the steps in the Configure Git section of the Getting Started with Git guide.

      4. Review Deploy a WordPress Site using Terraform and StackScripts to familiarize yourself with the Linode provider’s StackScript resource.

      Standard Module Structure

      Terraform’s standard module structure provides guidance on file and directory layouts for reusable modules. If you would like to make your module public to the Terraform community, the recommended layout allows Terraform to generate documentation and index modules for the Terraform Module Registry.

      • The primary module structure requirement is that a root module must exist. The root module is the directory that holds the Terraform configuration files that are applied to build your desired infrastructure. These files provide an entry point into any nested modules you might utilize.

      • Any module should include, at minimum, a main.tf, a variables.tf, and an outputs.tf file. This naming convention is recommended, but not enforced.

        • If using nested modules to split up your infrastructure’s required resources, the main.tf file holds all your module blocks and any needed resources not contained within your nested modules. A simple module’s main.tf file, without any nested modules, declares all resources within this file.

        • The variables.tf and outputs.tf files contain input variable and output variable declarations. All variables and outputs should include descriptions.

      • If using nested modules, they should be located in a root module’s subdirectory named modules/.

      • If your modules will be hosted on Terraform’s Module Registry, root modules and any nested modules should contain a README.MD file with a description that explains the module’s intended use.

      • You can provide examples in a root module’s subdirectory named examples.

      Create the Linode StackScripts Module

      The Linode Stackscripts module will included two nested modules that split up the required resources between the root module, a linodes module, and a stackscripts module. When you are done creating all required Terraform files your directory structure will look as follows:

        
      linode_stackscripts/
      ├── main.tf
      ├── outputs.tf
      ├── secrets.tfvars
      ├── terraform
      ├── terraform.tfvars
      ├── variables.tf
      └── modules/
          ├── linodes/
          │   ├── main.tf
          │   ├── variables.tf
          │   └── outputs.tf
          └── stackscripts/
              ├── main.tf
              ├── variables.tf
              └── outputs.tf
      
      

      Note

      Your linode_stackscripts directory will likely contain other files related to the Terraform installation you completed prior to beginning the steps in this guide.

      Create the Linodes Module

      In this section, you will create the linodes module which will be in charge of creating your Linode instance. This module contains a main.tf file and corresponding variables.tf and outputs.tf files.

      1. If your Terraform project directory is not named linode_stackscripts, rename it before beginning and move into that directory:

        mv terraform linode_stackscripts
        cd linode_stackscripts
        
      2. Create the modules and linodes subdirectories:

        mkdir -p modules/linodes
        
      3. Using your preferred text editor, create a main.tf file in modules/linodes/ with the following resources:

        linode_stackscripts/modules/linodes/main.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        
        locals {
            key ="${var.key}"
        }
        
        resource "linode_sshkey" "main_key" {
            label = "${var.key_label}"
            ssh_key = "${chomp(file(local.key))}"
        }
        
        resource "linode_instance" "linode_id" {
            image = "${var.image}"
            label = "${var.label}"
            region = "${var.region}"
            type = "${var.type}"
            authorized_keys = [ "${linode_sshkey.main_key.ssh_key}" ]
            root_pass = "${var.root_pass}"
            stackscript_id = "${var.stackscript_id}"
            stackscript_data = "${var.stackscript_data}"
        }

        The main.tf file declares a linode_instance resource that deploys a Linode using a StackScript. Notice that all argument values use interpolation syntax to access variable values. You will declare the variables next and provide the variable values in the root module’s terraform.tfvars file. Using separate files for variable declaration and assignment parameterizes your configurations and allows them to be reused as modules.

        Let’s take a closer look at each block in the main.tf configuration file.

        1
        2
        3
        4
        5
        6
        7
        8
        
        locals {
            key ="${var.key}"
        }
        
        resource "linode_sshkey" "main_key" {
            label = "${var.key_label}"
            ssh_key = "${chomp(file(local.key))}"
        }
        • The locals stanza declares a local variable key whose value will be provided by an input variable.

        • The linode_sshkey resource will create Linode SSH Keys tied to your Linode account. These keys can be reused for future Linode deployments once the resource has been created. ssh_key = "${chomp(file(local.key))}" uses Terraform’s built-in function file() to provide a local file path to the public SSH key’s location. The location of the file path is the value of the local variable key. The chomp() built-in function removes trailing new lines from the SSH key.

          Note

          If you do not already have SSH keys, follow the steps in the Create an Authentication Key-pair section of the Securing Your Server Guide.
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        
        resource "linode_instance" "linode_id" {
            image = "${var.image}"
            label = "${var.label}"
            region = "${var.region}"
            type = "${var.type}"
            authorized_keys = [ "${linode_sshkey.main_key.ssh_key}" ]
            root_pass = "${var.root_pass}"
            stackscript_id = "${var.stackscript_id}"
            stackscript_data = "${var.stackscript_data}"
        }

        The linode_instance resource creates a Linode instance with the listed arguments. Please note the following information:

        • The authorized_keys argument uses the SSH public key provided by the linode_sshkey resource in the previous stanza. This argument expects a value of type list, so the value must be wrapped in brackets.

        • To use an existing Linode StackScript you must use the stackscript_id argument and provide a valid ID as a value. Every StackScript is assigned a unique ID upon creation. Later on in the guide, you will create your own StackScript and expose its ID as an output variable in order to use its ID to deploy your Linode instance.

        • StackScripts support user defined data. This means a StackScript can use the UDF tag to create a variable whose value must be provided by the user of the script. This allows users to customize the behavior of a StackScript on a per-deployment basis. Any required UDF variable can be defined using the stackscript_data argument.

      4. Create the variables.tf file to define your resource’s required variables:

        linode_stackscripts/modules/linodes/variables.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        
        variable "key" {
          description = "Public SSH Key's path."
        }
        
        variable "key_label" {
          description = "new SSH key label"
        }
        
        variable "image" {
          description = "Image to use for Linode instance"
          default = "linode/ubuntu18.04"
        }
        
        variable "label" {
          description = "The Linode's label is for display purposes only, but must be unique."
          default = "default-linode"
        }
        
        variable "region" {
          description = "The region where your Linode will be located."
          default = "us-east"
        }
        
        variable "type" {
          description = "Your Linode's plan type."
          default = "g6-standard-1"
        }
        
        variable "authorized_keys" {
          description = "SSH Keys to use for the Linode."
          type = "list"
        }
        
        variable "root_pass" {
          description = "Your Linode's root user's password."
        }
        
        variable "stackscript_id" {
          description = "Stackscript ID."
        }
        
        variable "stackscript_data" {
          description = "Map of required StackScript UDF data."
          type = "map"
        }
        • Modules must include a description for each input variable to help document your configuration’s usage. This will make it easier for anyone else to use this module.

        • Every variable can contain a default value. The default value is only used if no other value is provided. For example, if you have a favorite Linux distribution, you may want to provide it as your image variable’s default value. In this case, linode/ubuntu18.04 is set as the default value.

        • You can declare a type for each variable. If no type is provided, the variable will default to type = "string".

        • Notice that the stackscript_data variable is of type = "map". This will allow you to provide values for as many UDF variables as your StackScript requires.

      5. Create the outputs.tf file:

        ~/linode_stackscripts/modules/linodes/outputs.tf
        1
        2
        3
        
        output "sshkey_linode" {
          value = "${linode_sshkey.main_key.ssh_key}"
        }

        The outputs.tf file exposes any values from the resources you declared in the main.tf file. Any exposed values can be used by any other module within the root module. The sshkey_linode output variable exposes the linode_sshkey resource’s public key.

      Now that the linodes module is complete, in the next section, you will create the stackscripts module.

      Create the StackScripts Module

      In this section you will create the StackScripts module. This module creates a linode_stackscripts resource which you can use to create and modify your own Linode StackScript.

      1. Ensure you are in the linode_stackscripts directory and create the stackscripts subdirectory:

        mkdir modules/stackscripts
        
      2. Using your preferred text editor, create a main.tf file in modules/stackscripts/ with the following resource:

        ~/linode_stackscripts/modules/stackscripts/main.tf
        1
        2
        3
        4
        5
        6
        7
        
        resource "linode_stackscript" "default" {
          label = "${var.stackscript_label}"
          description = "${var.description}"
          script = "${var.stackscript}"
          images = [ "${var.stackscript_image}" ]
          rev_note = "${var.rev_note}"
        }

        The main.tf file creates the linode_stackscript resource and provides the required configurations. All argument values use interpolation syntax to access input variable values. You will declare the input variables next and provide the variable values in the root module’s terraform.tfvars file. For more information on StackScripts see the Automate Deployments with StackScripts guide and the Linode APIv4 documentation.

      3. Create the variables.tf file to define your resource’s required variables:

        ~/linode_stackscripts/modules/stackscripts/variables.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        
        variable "stackscript_label" {
          description = "The StackScript's label is for display purposes only."
        }
        
        variable "description" {
          description = "A description for the StackScript."
        }
        
        variable "stackscript" {
          description = "The script to execute when provisioning a new Linode with this StackScript."
        }
        variable "stackscript_image" {
          description = " A list of Image IDs representing the Images that this StackScript is compatible for deploying with."
          type = "list"
        }
        variable "rev_note" {
          description = "This field allows you to add notes for the set of revisions made to this StackScript."
        }
      4. Create the outputs.tf file:

        ~/linode_stackscripts/modules/stackscripts/output.tf
        1
        2
        3
        
        output "stackscript_id" {
          value = "${linode_stackscript.default.id}"
        }

        The outputs.tf file exposes the value of the linode_stackscript resource’s ID. Every StackScript is assigned a unique ID upon creation. You will need this ID when creating your root module.

      You have now created the StackScripts module and are ready to use both modules within the root module. You will complete this work in the next section.

      Create the Root Module

      The root module will call the linode and stackscripts modules, satisfy their required variables and then apply those configurations to build your desired infrastructure. These configurations deploy a Linode based on a StackScript you will define in this section. When using nested modules, the modules will be hidden from your root configuration, so you’ll have to re-expose any variables and outputs you require.

      1. Ensure you are in the linode_stackscripts directory and create the main.tf file:

        linode_stackscripts/main.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        
        provider "linode" {
            token = "${var.token}"
        }
        
        module "stackscripts" {
            source = "./modules/stackscripts"
            stackscript_label = "${var.stackscript_label}"
            description = "${var.description}"
            stackscript = "${var.stackscript}"
            stackscript_image = [ "${var.stackscript_image}" ]
            rev_note = "${var.rev_note}"
        }
        
        module "linodes" {
            source = "./modules/linodes"
            key = "${var.key}"
            key_label = "${var.key_label}"
            image = "${var.image}"
            label = "${var.label}"
            region = "${var.region}"
            type = "${var.type}"
            root_pass = "${var.root_pass}"
            authorized_keys = [ "${module.linodes.sshkey_linode}" ]
            stackscript_id = "${module.stackscripts.stackscript_id}"
            stackscript_data = "${var.stackscript_data}"
        }

        The main.tf file uses the linodes and stackscripts modules that were created in the previous sections and provides the required arguments. All argument values use interpolation syntax to access variable values, which you will declare in a variables.tf file and then provide corresponding values for in a terraform.tfvars file.

        Let’s review each block:

        1
        2
        3
        
        provider "linode" {
            token = "${var.token}"
        }

        The first stanza declares Linode as the provider that will manage the lifecycle of any resources declared throughout the configuration file. The Linode provider requires your Linode APIv4 token for authentication.

        1
        2
        3
        4
        5
        6
        7
        8
        
        module "stackscripts" {
            source = "./modules/stackscripts"
            stackscript_label = "${var.stackscript_label}"
            description = "${var.description}"
            stackscript = "${var.stackscript}"
            stackscript_image = [ "${var.stackscript_image}" ]
            rev_note = "${var.rev_note}"
        }

        The next stanza instructs Terraform to create an instance of the stackscripts module and instantiate any of the resources defined within the module. The source attribute provides the location of the child module’s source code and is required whenever you create an instance of a module. All other attributes are determined by the module. Notice that all the attributes included in the module block correspond to the linode_stackscript resource’s arguments declared in the main.tf file of the stackscripts module.

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        
        module "linodes" {
            source = "./modules/linodes"
            key = "${var.key}"
            key_label = "${var.key_label}"
            image = "${var.image}"
            label = "${var.label}"
            group = "${var.group}"
            region = "${var.region}"
            type = "${var.type}"
            root_pass = "${var.root_pass}"
            authorized_keys = [ "${module.linodes.sshkey_linode}" ]
            stackscript_id = "${module.stackscripts.stackscript_id}"
            stackscript_data = "${var.stackscript_data}"
        }

        This stanza creates an instance of the linodes module and then instantiates the resources you defined in the module. Notice that authorized_keys = [ "${module.linodes.sshkey_id}" ] and stackscript_id = "${module.stackscripts.stackscript_id}" both access values exposed as output variables by the linodes and stackscripts modules. Any module’s exposed output variables can be referenced in your root module’s main.tf file.

      2. Create the variables.tf file to declare the input variables required by the module instances:

        ~/linode_stackscripts/variables.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        
        variable "token" {
          description = " Linode API token"
        }
        
        variable "stackscript_label" {
          description = "The StackScript's label is for display purposes only."
        }
        
        variable "description" {
          description = "A description for the StackScript."
        }
        
        variable "stackscript" {
          description = "The script to execute when provisioning a new Linode with this StackScript."
        }
        
        variable "stackscript_image" {
          description = "A list of Image IDs representing the Images that this StackScript is compatible for deploying with."
        }
        
        variable "rev_note" {
          description = "This field allows you to add notes for the set of revisions made to this StackScript."
        }
        
        variable "key" {
          description = "Public SSH Key's path."
        }
        
        variable "key_label" {
          description = "New SSH key label."
        }
        
        variable "image" {
          description = "Image to use for Linode instance."
          default = "linode/ubuntu18.04"
        }
        
        variable "label" {
          description = "The Linode's label is for display purposes only, but must be unique."
          default = "default-linode"
        }
        
        variable "region" {
          description = "The region where your Linode will be located."
          default = "us-east"
        }
        
        variable "type" {
          description = "Your Linode's plan type."
          default = "g6-standard-1"
        }
        
        variable "root_pass" {
          description = "Your Linode's root user's password."
        }
        
        variable "stackscript_data" {
          description = "Map of required StackScript UDF data."
          type = "map"
        }
      3. Create the outputs.tf file:

        ~/linode_stackscripts/outputs.tf
        1
        2
        3
        
        output "stackscript_id" {
          value = "${module.stackscripts.stackscript_id}"
        }

        In the outputs.tf file you will re-expose the output variables exposed by the stackscripts module.

      4. Create the terraform.tfvars file to provide values for all input variables defined in the variables.tf file. This file will exclude any values that provide sensitive data, like passwords and API tokens. A file containing sensitive values will be created in the next step:

        ~/linode_stackscripts/terraform.tfvars
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        
        key = "~/.ssh/id_rsa.pub"
        key_label = "my-ssh-key"
        label = "my-linode"
        stackscript_data {
          my_username = "username"
          my_hostname = "linode-hostname"
        }
        stackscript_id = "base-ubuntu-deployment"
        stackscript_label = "base-ubuntu-deployment"
        description = "A base deployment for Ubuntu 18.04 that creates a limited user account."
        stackscript = <<EOF
        #!/bin/bash
        # <UDF name="my_hostname" Label="Linode's Hostname" />
        # <UDF name="my_username" Label="Limited user account" />
        # <UDF name="my_password" Label="Limited user account's password" />
        # <UDF name="my_userpubkey" Label="Limited user account's public key" />
        
        source <ssinclude StackScriptID="1">
        
        set -x
        
        MY_IP=system_primary_ip
        system_set_hostname "$MY_HOSTNAME"
        system_add_host_entry "$MY_IP" "$MY_HOSTNAME"
        user_add_sudo "$MY_USERNAME" "$MY_PASSWORD"
        user_add_pubkey "$MY_USERNAME" "$MY_USERPUBKEY"
        ssh_disable_root
        goodstuff
        EOF
        stackscript_image = "linode/ubuntu18.04"
        rev_note = "First revision of my StackScript created with the Linode Terraform provider."

        The terraform.tfvars file supplies all values required by the linodes and stackscripts modules. Ensure you replace any values with your own values when using this example file.

        The stackscript variable provides the actual contents of the StackScript you create. This example StackScript requires four UDF values: my_hostname, my_username, my_password, and my_userpubkey. The my_hostname and my_username values are supplied by the stackscript_data map. The my_password and my_userpubkey values will be provided in the next step.

        The StackScript will then use these values to create a limited user account; set a hostname; add a host entry; add the created user to the sudo group; disable SSH access for the root user; and install vim, wget, and less. This StackScript uses bash functions defined in the Linode Community StackScript Bash Library.

      5. Create a file named secrets.tfvars to hold any sensitive values:

        ~/linode_stackscripts/secrets.tfvars
        1
        2
        3
        4
        5
        6
        
        token = "my-linode-api-token"
        root_pass = "my-secure-root-password"
        stackscript_data {
          my_password = "my-limited-users-password"
          my_userpubkey = "my-public-ssh-key"
        }

        This file contains all sensitive data needed for your Linode deployment. Ensure you replace all values with your own secure passwords and your Linode account’s APIv4 token. This file should never be tracked in version control software and should be listed in your .gitignore file if using GitHub.

        Note

      You are now ready to apply your linode_stackscripts module’s Terraform configuration. These steps will be completed in the next section.

      Initialize, Plan and Apply the Terraform Configuration

      Whenever a new provider is used in a Terraform configuration, it must first be initialized. The initialization process downloads and installs the provider’s plugin and performs any other steps needed for its use. Before applying your configuration, it is also useful to view your configuration’s execution plan before making any actual changes to your infrastructure. In this section, you will complete all these steps.

      1. Initialize the Linode provider. Ensure you are in the linode_stackscripts directory before running this command:

        terraform init
        

        You will see a message that confirms that the provider plugins have been successfully initialized.

      2. Run the Terraform plan command:

        terraform plan -var-file="secrets.tfvars" -var-file="terraform.tfvars"
        

        Terraform plan won’t take any action or make any changes on your Linode account. Instead, an analysis is done to determine which actions (i.e. Linode instance creations, deletions, or modifications) are required to achieve the state described in your configuration.

      3. You are now ready to create the infrastructure defined in your root module’s main.tf configuration file:

        terraform apply -var-file="secrets.tfvars" -var-file="terraform.tfvars"
        

        Since you are using multiple variable value files, you must call each file individually using the var-file argument. You will be prompted to confirm the apply action. Type yes and hit enter. Terraform will begin to create the resources you’ve defined throughout this guide. This process will take a couple of minutes to complete. Once the infrastructure has been successfully built you will see a similar output:

          
          Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
            
        
      4. To verify the deployment, retrieve your Linode instance’s IP address:

        terraform show | grep 'ip_address'
        

        You should see a similar output:

          
                ip_address = 192.0.2.0
              
        
      5. Open a new shell session and SSH into your Linode using the IP address you retrieved in the previous step and the username you defined in the terraform.tfvars file’s my_username variable:

        ssh [email protected]
        

        You should be able to access your Linode and then verify that what you defined in the StackScript was executed.

      Version Control Your Terraform Module

      To make the linode_stackscripts module available to other team members, you can version control it using GitHub. Before completing the steps in this section, ensure you have completed the steps in the Configure Git section of the Getting Started with Git guide.

      1. In the linode_stackscripts directory create a .gitignore file:

        ~/linode_stackscripts/.gitignore
        1
        2
        3
        4
        
        secrets.tfvars
        .terraform/
        terraform/
        terraform.tfstate

        Note

        If there are any files related to the Terraform installation steps completed before beginning this guide (i.e zip files and checksum files), you can remove these files from the linode_stackscripts directory, since you should not track them in version control and they are no longer necessary.

      2. Initialize the git repository:

        git init
        

        Stage all the files you’ve created so far for your first commit:

        git add -A
        
      3. Commit all the linode_stackscripts files:

        git commit -m "Initial commit"
        
      4. Navigate to your GitHub account and create a new repository. Ensure you name the repository the same name as that of your Terraform module. In this example, the GitHub repository will be named linode_stackscripts.

      5. At the top of your GitHub repository’s Quick Setup page, copy the remote repository URL.

      6. Return to your local computer’s linode_stackscripts directory and add the URL for the remote repository:

        git remote add origin https://github.com/my-github/linode_stackscripts.git
        
      7. Push your local linode_stackscripts repository to your remote GitHub repository:

        git push -u origin master
        

      Your Terraform module is now tracked via GitHub and can be used, shared and modified by anyone who has access to your GitHub account.

      Invoking Your GitHub-Hosted Module

      In the future, you can source this module from GitHub within your Terraform module declarations. You would write your module block like the following:

      1
      2
      3
      4
      5
      6
      
      module "linode_stackscripts" {
          source = "github.com/username/linode_stackscripts"
      
          VARIABLES HERE
          . . .
      }

      More Information

      You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

      Find answers, ask questions, and help others.

      This guide is published under a CC BY-ND 4.0 license.



      Source link

      Create a NodeBalancer with Terraform


      Updated by Linode Contributed by Linode

      Terraform allows you to represent Infrastructure as Code (IaC). You can use it to manage infrastructure, speed up deployments, and share your infrastructure’s configuration files within a team. In this guide you will use Terraform to create a NodeBalancer that distributes traffic between two Linodes.

      Caution

      The configurations and commands used in this guide will result in multiple billable resources being added to your account. Be sure to monitor your account closely in the Linode Manager to avoid unwanted charges. See the Billings and Payments guide for more details.

      If you would like to stop billing for the resources created in this guide, remove them when you have finished your work.

      Before You Begin

      1. You should have Terraform installed in your development environment, and have a working knowledge of Terraform resource configuration and the Linode provider. For more information on how to install and use Terraform, check out our Use Terraform to Provision Linode Environments guide.

      2. Terraform requires an API access token. Follow the Getting Started with the Linode API guide to obtain a token.

      3. Create a terraform_nodebalancer directory on your computer for the Terraform project you will create in this guide. All files you create in this guide should be placed in this directory, and you should run all commands from this directory. This new project should not be created inside another Terraform project directory, including the one you may have made when previously following Use Terraform to Provision Linode Environments.

      Create a Terraform Configuration File

      Create a Provider Block

      The first step to take when creating a Terraform configuration file is to create a provider block. This block lets Terraform know which provider to use. The only configuration value that the Linode provider needs is an API access token.

      Create a file named nodebalancer.tf in your Terraform project directory. You will be adding to this file throughout the guide. Add the provider block to the file:

      nodebalancer.tf
      1
      2
      3
      
      provider "linode" {
          token = "${var.token}"
      }

      This provider block uses variable interpolation to access the value of your API token. You will create input variables in a separate variables.tf file later in the Define Terraform Variables section of this guide. Any input variables you define within the variables.tf file are available from the var dictionary using dot notation. You will be using variable interpolation and referencing variables with dot notation throughout this guide.

      Create a NodeBalancer Resource

      Create a NodeBalancer resource in the nodebalancer.tf file:

      nodebalancer.tf
      1
      2
      3
      4
      5
      6
      7
      8
      
      ...
      
      resource "linode_nodebalancer" "example-nodebalancer" {
          label = "examplenodebalancer"
          region = "${var.region}"
      }
      
      ...

      The linode_nodebalancer resource supplies two labels. The first label, example-nodebalancer, is used internally by Terraform. The second label, examplenodebalancer, is used to reference your NodeBalancer in tools like the Manager and the Linode CLI. The region for this NodeBalancer is supplied with the variable region.

      Create NodeBalancer Config Resources

      In addition to the NodeBalancer resource, you must supply at least one NodeBalancer Configuration resource. This resource defines ports, protocol, health checks, and session stickiness, among other options, that the NodeBalancer might use. For this example, you will create a NodeBalancer configuration for HTTP access on port 80, but you could also create one for HTTPS access on port 443 if you have SSL/TLS certificates:

      nodebalancer.tf
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      
      ...
      
      resource "linode_nodebalancer_config" "example-nodebalancer-config" {
          nodebalancer_id = "${linode_nodebalancer.example-nodebalancer.id}"
          port = 80
          protocol = "http"
          check = "http_body"
          check_path = "/healthcheck/"
          check_body = "healthcheck"
          check_attempts = 30
          check_timeout = 25
          check_interval = 30
          stickiness = "http_cookie"
          algorithm = "roundrobin"
      }
      
      ...

      The NodeBalancer Config resource requires a NodeBalancer ID, which is populated in the first line with the variable linode_nodebalancer.example-nodebalancer.id. Because the nodebalancer_id argument references a NodeBalancer that has not been created yet, you can use this variable as a placeholder to reference the NodeBalancer ID. Terraform will automatically know to create the NodeBalancer resource before it creates any other resources that reference it. In this way you can craft intricate infrastructure that references its own parts, without having to worry about the order the resources appear in the Terraform configuration or whether or not the resources already exist.

      As far as settings go, the health check is set to http_body, meaning that the health check will look for the string set by check_body within the body of the page set at check_path. The NodeBalancer will take a node out of rotation after 30 failed check attempts. Each check will wait for a response for 25 seconds before it is considered a failure, with 30 seconds between checks. Additionally, the session stickiness setting has been set to http_cookie. This means that the user will continue to be sent to the same server by the use of a session cookie. The algorithm has been set to roundrobin, which will sort users evenly across your backend nodes based on which server was accessed last.

      Note

      Create NodeBalancer Node Resources

      The third part of setting up a NodeBalancer in Terraform is creating the NodeBalancer Node resource. This resource contains information about the individual Nodes and how they pertain to the NodeBalancer and NodeBalancer Configuration resources.

      nodebalancer.tf
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      
      ...
      
      resource "linode_nodebalancer_node" "example-nodebalancer-node" {
          count = "${var.node_count}"
          nodebalancer_id = "${linode_nodebalancer.example-nodebalancer.id}"
          config_id = "${linode_nodebalancer_config.example-nodebalancer-config.id}"
          label = "example-node-${count.index + 1}"
          address = "${element(linode_instance.example-instance.*.private_ip_address, count.index)}:80"
          mode = "accept"
      }
      
      ...

      This resource’s count argument will be populated with the node_count input variable you will define later on in this guide. The count argument tells Terraform that it should provision node_count number of Nodes.

      Because provisioning more than one node creates a loop in the Terraform process, where the step for creating a node is repeated, you can use the count.index variable to keep track of which iteration Terraform is on in the loop. The interpolation {count.index + 1} in the node’s label argument tells Terraform that you’d like each of the nodes to be labeled sequentially, and because count.index starts at zero, you’d like the count to begin at one.

      linode_instance.example-instance.*.private_ip_address references the private IP addresses of the yet-to-be-created Linode instances. In the next step, the Linode Instance resources will be labeled example-instance. Terraform has access to some attributes for each of the resources it creates, and private_ip_address is one of the available attributes from a Linode Instance resource. Because there will be two Linode instances created during the same step, Terraform groups these sets of attributes in a list. The element() function allows you to grab a single item from a list based on the item index. Here, instead of providing a hard-coded number for the index you can instead provide count.index. In this way the first NodeBalancer Node will reference the private IP address of the first Linode instance, and the second NodeBalancer Node will reference the private IP address of the second instance.

      Create a Linode Instance Resource

      Now that you have the NodeBalancer configured, you need to supply it with a Linode Instance resource. This resource will allow Terraform to know which instances it needs to create to meet the demand of our NodeBalancer example.

      nodebalancer.tf
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      
      ...
      
      resource "linode_instance" "example-instance" {
          count  = "${var.node_count}"
          label  = "example-instance-${count.index + 1}"
          group = "nodebalancer-example"
          tags = ["nodebalancer-example"]
          region = "${var.region}"
          type = "g6-nanode-1"
          image = "linode/ubuntu18.10"
          authorized_keys = ["${chomp(file(var.ssh_key))}"]
          root_pass = "${random_string.password.result}"
          private_ip = true
      
          provisioner "remote-exec" {
              inline = [
                  # install NGINX
                  "export PATH=$PATH:/usr/bin",
      
                  "apt-get -q update",
                  "mkdir -p /var/www/html/",
                  "mkdir -p /var/www/html/healthcheck",
                  "echo healthcheck > /var/www/html/healthcheck/index.html",
                  "echo node ${count.index + 1} > /var/www/html/index.html",
                  "apt-get -q -y install nginx",
              ]
      
              connection {
                  type = "ssh"
                  user = "root"
                  password = "${random_string.password.result}"
              }
          }
      }
      
      ...

      The above resource uses the same count argument as the NodeBalancer Node resource that was configured in the previous step. Also, the label argument is being sequentially incremented in a similar fashion to the NodeBalancer Node.

      The authorized_keys argument is supplied an SSH key input variable that will be defined later in this guide. It is passed to the file() function, which reads the contents of a file into a string. That string is then passed to the chomp() function, which strips any extra whitespace.

      root_pass is given the result of the random_string resource that will be defined later in this guide.

      The last thing of note in this Linode Instance resource is the remote-exec Provisioner block. This block contains two other components, the inline list and connection block. inline is a list of commands that Terraform will execute on the Linode instance once the Linode instance has booted. In this example, the inline commands will: update the Linode instance, create the necessary directory structure for NGINX, create the health check file and the more generalized index.html file, and install NGINX.

      The connection block explains to Terraform how it should gain access to the Linode instance in order to run the commands supplied by the inline list. In this case, Terraform will gain access over SSH, logging in as the root user.

      Create an Output

      The last step that you’ll take in creating nodebalancer.tf is adding an output. Terraform will add this information to the end of it’s output in the terminal. Outputs can be any information from your configuration you would like to expose. Below is an example that will display the public IP address of the NodeBalancer:

      nodebalancer.tf
      1
      2
      3
      4
      5
      
      ...
      
      output "NodeBalancer IP Address" {
          value = "${linode_nodebalancer.example-nodebalancer.0.ipv4}"
      }

      Define Terraform Variables

      You will now declare all variables required by your Terraform configuration in a variables.tf file.

      1. Create a file called variables.tf. This file will create the variables referenced in the configuration of your NodeBalancer and Nodes. You will supply values to the variables in another step.

        variables.tf
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        
        variable "token" {
            description = "Your APIv4 Access Token"
        }
        
        variable "region" {
            description = "The datacenter where your NodeBalancer and Nodes will reside. E.g., 'us-east'."
            default = "us-west"
        }
        
        variable "node_count" {
            description = "The amount of backend Nodes to create."
        }
        
        variable "ssh_key" {
            description = "The local file location of the SSH key that will be transferred to each Linode."
            default = "~/.ssh/id_rsa.pub"
        }
        
        resource "random_string" "password" {
            length = 32
            special = true
            upper = true
            lower = true
            number = true
        }

        Terraform allows each variable to have its own description and default value. These variables will have their values populated through the use of a terraform.tfvars file that you will create in the next step. Separating the variable definitions from their values helps to keep sensitive data from entering your Terraform code, should you choose to include your code in a version control system like Git.

        In addition to the variables you defined above, there is also a random_string resource with the label password. This resource is provided by the Random provider, and will generate a random string of 32 characters, including uppercase characters, lowercase characters, and numbers. This string will be the root password for your backend Nodes. If you would rather have exact control over your passwords, you can define a password here in variables.tf and set the value for that password in terraform.tfvars in the next step.

      2. Create the terraform.tfvars file and supply values for the token, region, and node_count variables. This example uses the us-east regional datacenter, and the node_count is two.

        terraform.tfvars
        1
        2
        3
        
        token = "your_api_token"
        region = "us-east"
        node_count = 2

        When Terraform runs, it looks for a file named terraform.tfvars, or files with the extension *.auto.tfvars, and populates the Terraform variables with those values. If your SSH key is at a file location that is different than the default value, i.e., it does not exist at ~/.ssh/id_rsa.pub, then you will need to add that value to terraform.tfvars.

        Note

        If you want to use an input variable’s default value defined in the variables.tf file, you can omit providing a value for that variable in the terraform.tfvars file.

        Feel free to change any of the values in the terraform.tfvars file to your liking. For a list of regional datacenter IDs, you can use the cURL command to query the API:

        curl https://api.linode.com/v4/regions
        

      Initializing, Planning, and Applying the Terraform State

      Because this guide employs two providers (Linode and Random) that you might not have installed on your local development environment, you’ll need to run the init command to install them.

      terraform init
      

      You should see a message that Terraform has been successfully initialized.

      To review the Terraform plan of action defined in the nodebalancer.tf file, run the plan command:

      terraform plan
      

      You should see a lengthy output with all the create actions that will take place. Review the output, taking note that the <computed> values you see will be defined on creation. Once you are satisfied with the proposed actions, it’s time to apply them.

      Run the apply command:

      terraform apply
      

      You will be prompted to approve the apply action. Type yes and hit Enter. Terraform will begin to create the resources you have configured in the previous steps. This will take a few minutes, after which you will start to see the output of the the remote-exec commands you defined in your Linode instance resource. Once all of the actions are completed you should see output like the following:

        
      Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
      
      Outputs:
      
      NodeBalancer IP Address = 104.237.148.131
      
      

      Navigate to your NodeBalancer IP address and view your NodeBalancer in action. You have successfully created a NodeBalancer and backend nodes in Terraform.

      (Optional) Remove the NodeBalancer Resources

      If you are done with the resources you just created, you can remove them with the destroy command

      terraform destroy
      

      This command will prompt you to confirm the action.

      More Information

      You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.

      Find answers, ask questions, and help others.

      This guide is published under a CC BY-ND 4.0 license.



      Source link