Terraform + Terragrunt Basics
Note Repository
Basics
Commands
- 
terraform initcreates the Remote State: configures your local settings, downloads provider requirements, similar to activating a Python virtualenv
- 
terraform plancompares current state with desired state
- 
terraform applymakes the necessary API calls to create/delete/update the resources as needed, then polls them periodically until it is in its desired state
- 
terraform graphcreates a dependency graph with all resources
- 
terraform destroyremoves everything in the state file
Variables

- since there is no value declared, if you run terraform plan, it will prompt for input
- you can declare a value via CLI with terraform apply -var name=foo, or inside terraform.tfvars:name = "foo"
Dependencies
- reference a resource by their resource type and their name, eg: aws_instance.example1

- 
aws_eiprequires an instance’s ID to be specified
- ID is an attribute of aws_instancethat Terraform discovers, sets, and exports on creation
- terraform creates a dependency graph under the hood to figure out the order to create each resource based on dependencies, which can be viewed with terraform graph
State
- by default, state is stored locally in .tfstatefiles, but state can be stored remotely (for collaboration) using S3


- 
terraform initconfigures and connects to remote state storage
- most remote backends support locking and encryption
- locking: while using Terraform, you can request a lock and no one will be able to change the state
- lock is stored in DynamoDB
- encryption: terraform stores secrets in plaintext inside state file
Modules
- collection of Terraform code that you can reuse, configure, and version control — like blueprints
- module = folder with Terraform files
- convention for Gruntwork modules:
    - 
        vars.tf- specify module inputs 
- 
        main.tf- create resources 
- 
        outputs.tf- specify outputs (can be used as input for other modules) 
 
- 
        

- a source can be a directory or URL
- reference module outputs as attributes of that module
- the moduleblock needs to specify values for variables that don’t have default value — it cannot be passed via CLI and will not be prompted during plan/apply
Example

- 
./main.tf- only three block types: terraform (version), provider “aws”, and module blocks w/ the module’s variables specified inside the block
- 
./vars.tf- declaration (no values) of variables used insidemain.tf. Since there’s noterraform.tfvars, the values will need to be passed via CLI or prompt
- 
./outputs.tf- outputs values from a module’s output viamodule.module_label.output_label
- 
./rails-module/main.tf- has terraform (version) and resource blocks, no provider block needed
- 
./rails-module/vars.tf- variables used in[./rails-module/main.tf](http://main.tf)and declared here need to be addressed inside module block (see./main.tf)
- 
./rails-module/outputs.tf- outputs values from./rails-module/main.tfviaresource_type.resource_label_attribute
Module Community Standards
- 
variables.tfinstead of vars.tf
- description property to each variable and output + a README file
Best Practices
- 
planbeforeapply
- stage before prod
- 
    isolated environments  - there is a special data source called terraform_remote_statethat shares state between environments — you can read outputs from one environment into another
 
- there is a special data source called 
- use versioned modules
    - 
        if modules are defined in a separate repository, different environments can use different versioned URLs  
- 
        the sourceURL supports versioning using therefparameter to point to a tag or a commit ID 
 
- 
        
- use remote state
    - you have to create the bucket yourself — enabling versioning is recommended
        - the lock table is automatically created
 
 
- you have to create the bucket yourself — enabling versioning is recommended
        
 Tech Notebook by Lucas
  Tech Notebook by Lucas