143 lines
4.7 KiB
Markdown
143 lines
4.7 KiB
Markdown
# 4) Variables, tfvars & Outputs (20 min)
|
||
|
||
In this section, you’ll **parameterize** your Terraform configuration so it’s flexible across environments (like *dev* and *prod*) and learn how to **print useful values** after deployment.
|
||
|
||
|
||
## Why variables and tfvars?
|
||
- **Variables** let you avoid hard‑coding values (e.g., instance type, names).
|
||
- **.tfvars files** store a specific set of variable values for each environment. You can switch environments quickly without editing code.
|
||
- **Outputs** print important information (IDs, IPs, AZs) for later use in scripts, CD pipelines, or as inputs to other modules.
|
||
|
||
|
||
## Step 1: Create a working directory
|
||
|
||
```bash
|
||
mkdir -p ~/terraform-vars-lab && cd ~/terraform-vars-lab
|
||
```
|
||
Creates a clean folder for this exercise and moves into it.
|
||
|
||
## Step 2: Define variables
|
||
|
||
Create a file **variables.tf**:
|
||
|
||
```hcl
|
||
variable "instance_type" {}
|
||
variable "instance_name" {}
|
||
```
|
||
- Declares two variables, `instance_type` and `instance_name`.
|
||
- No defaults are provided, so Terraform will expect values (either via `-var` flags, `.tfvars` files, or prompts).
|
||
|
||
> Tip: You can add descriptions and types to make your code self-documenting:
|
||
> ```hcl
|
||
> variable "instance_type" { type = string, description = "EC2 size, e.g. t2.micro" }
|
||
> variable "instance_name" { type = string, description = "Tag: Name for the instance" }
|
||
> ```
|
||
|
||
## Step 3: Write the main configuration
|
||
|
||
Create **main.tf**:
|
||
|
||
```hcl
|
||
provider "aws" { region = "ap-south-1" }
|
||
|
||
resource "aws_instance" "ec2_instance" {
|
||
ami = "ami-0e6329e222e662a52"
|
||
instance_type = var.instance_type
|
||
|
||
tags = { Name = var.instance_name }
|
||
}
|
||
```
|
||
- **provider "aws"**: points Terraform to AWS in the Mumbai region.
|
||
- **resource "aws_instance" "ec2_instance"**: creates an EC2 instance.
|
||
- `ami`: the base OS image (Amazon Linux 2 for ap-south-1).
|
||
- `instance_type`: references your variable using `var.instance_type`.
|
||
- `tags`: uses `var.instance_name` so the tag can change per environment.
|
||
|
||
## Step 4: Expose useful outputs
|
||
|
||
Create **outputs.tf**:
|
||
|
||
```hcl
|
||
output "instance_id" { value = aws_instance.ec2_instance.id }
|
||
output "public_ip" { value = aws_instance.ec2_instance.public_ip }
|
||
output "availability_zone" { value = aws_instance.ec2_instance.availability_zone }
|
||
```
|
||
- After apply, Terraform will print these values.
|
||
- Great for quickly finding the instance or for handing values to other tools.
|
||
|
||
> Tip: Add `sensitive = true` to hide secrets in logs:
|
||
> ```hcl
|
||
> output "db_password" { value = var.db_password, sensitive = true }
|
||
> ```
|
||
|
||
## Step 5: Create environment files (tfvars)
|
||
|
||
Create **dev.tfvars**:
|
||
|
||
```hcl
|
||
instance_type = "t2.micro"
|
||
instance_name = "Dev-Instance"
|
||
```
|
||
|
||
Create **prod.tfvars**:
|
||
|
||
```hcl
|
||
instance_type = "t3.micro"
|
||
instance_name = "Prod-Instance"
|
||
```
|
||
- These files define different values for the *same* variables.
|
||
- You can add more environments (e.g., `test.tfvars`, `staging.tfvars`) as needed.
|
||
|
||
> Tip: Keep environment files in version control, but never commit secrets. For secrets, use a secure tool (e.g., AWS SSM Parameter Store, Vault) or CI/CD‑controlled variables.
|
||
|
||
## Step 6: Initialize, apply, output, and switch environments
|
||
|
||
```bash
|
||
terraform init
|
||
```
|
||
- Downloads provider plugins and prepares the working directory.
|
||
|
||
```bash
|
||
terraform apply -var-file="dev.tfvars" -auto-approve
|
||
```
|
||
- Applies with **dev** values.
|
||
- Creates a `t2.micro` instance named **Dev-Instance**.
|
||
|
||
```bash
|
||
terraform output
|
||
```
|
||
- Prints the values from **outputs.tf** to the terminal (instance id, public IP, AZ).
|
||
|
||
```bash
|
||
terraform destroy -auto-approve
|
||
```
|
||
- Destroys the **dev** instance to avoid charges before testing **prod**.
|
||
|
||
```bash
|
||
terraform apply -var-file="prod.tfvars" -auto-approve
|
||
```
|
||
- Applies with **prod** values.
|
||
- Creates a `t3.micro` instance named **Prod-Instance**.
|
||
|
||
```bash
|
||
terraform output -json > output.json
|
||
cat output.json
|
||
```
|
||
- Exports outputs in **JSON** format, perfect for automation pipelines.
|
||
- `output.json` can be parsed by scripts or downstream systems.
|
||
|
||
## Common gotchas & best practices
|
||
- **Keep AMIs per region**: AMI IDs are region‑specific. If you change regions, update the AMI.
|
||
- **Validate before apply**: Run `terraform validate` and `terraform plan` to catch mistakes early.
|
||
- **Naming**: Tags are your friend. Use `Name` tags consistently so you can find resources fast.
|
||
- **Separate state**: For real projects, use separate state/workspaces or remote backends (S3 + DynamoDB) per environment.
|
||
|
||
## Wrap-Up
|
||
You now know how to:
|
||
- Declare variables and pass values with `.tfvars`
|
||
- Reuse the same code for **multiple environments**
|
||
- Surface key information using **outputs**
|
||
- Export outputs to **JSON** for automation
|
||
|
||
This pattern is the backbone of scalable Terraform projects.
|