Eduarn – Online & Offline Training with Free LMS for Python, AI, Cloud & More

Thursday, April 2, 2026

Terraform Modules in Azure: Step-by-Step Guide with Count, for_each & YAML Examples

 

Terraform Modules in Azure: Step-by-Step Guide with Count, for_each & YAML Examples By EduArn.com

Introduction

In modern cloud environments, writing reusable and scalable infrastructure is critical. Using Terraform with Microsoft Azure, you can achieve this efficiently through Terraform modules.

This blog provides:
✅ Simple module example
count implementation
for_each implementation
✅ YAML-based configuration
✅ Fully working step-by-step code


📦 Step 1: Simple Terraform Module (Basic Example)

📁 Folder Structure

project/
├── main.tf
├── provider.tf
└── modules/
    └── rg/
        ├── main.tf
        ├── variables.tf
        └── outputs.tf

🔹 Module Code

modules/rg/main.tf

resource "azurerm_resource_group" "rg" {
  name     = var.rg_name
  location = var.rg_location
}

modules/rg/variables.tf

variable "rg_name" {
  type = string
}

variable "rg_location" {
  type = string
}

modules/rg/outputs.tf

output "rg_name" {
  value = azurerm_resource_group.rg.name
}

🔹 Root Module

provider.tf

provider "azurerm" {
  features {}
}

main.tf

module "rg" {
  source = "./modules/rg"

  rg_name     = "demo-rg"
  rg_location = "eastus"
}

▶️ Run

terraform init
terraform plan
terraform apply

🔁 Step 2: Using count in Module (Multiple Resources)

variable "rg_names" {
  default = ["rg-dev", "rg-test", "rg-prod"]
}

module "rg" {
  source = "./modules/rg"

  count       = length(var.rg_names)
  rg_name     = var.rg_names[count.index]
  rg_location = "eastus"
}

👉 Creates:

  • rg-dev
  • rg-test
  • rg-prod

🔄 Step 3: Using for_each (Recommended)

variable "rgs" {
  default = {
    dev  = "rg-dev"
    test = "rg-test"
    prod = "rg-prod"
  }
}

module "rg" {
  source = "./modules/rg"

  for_each = var.rgs

  rg_name     = each.value
  rg_location = "eastus"
}

📤 Output

output "rg_names" {
  value = {
    for key, mod in module.rg :
    key => mod.rg_name
  }
}

🧾 Step 4: Using YAML Configuration (Advanced)

📁 config.yaml

resource_groups:
  dev: rg-dev
  test: rg-test
  prod: rg-prod

🔹 Terraform Code

locals {
  config = yamldecode(file("${path.module}/config.yaml"))
}

module "rg" {
  source = "./modules/rg"

  for_each = local.config.resource_groups

  rg_name     = each.value
  rg_location = "eastus"
}

🧠 Key Concepts

FeatureUse
Module        Reusable code
count        Simple iteration
for_each        Map-based iteration
YAML        External config

⚖️ Count vs for_each

Feature    count            for_each
Input    List            Map
Stability   ❌ Index-based            ✅ Key-based
Recommended  ⚠️ Limited            ✅ Yes

🎯 Best Practices

  • Use modules for reusable design
  • Prefer for_each over count
  • Use YAML for external configuration
  • Keep modules small and focused
  • Avoid hardcoding values

🎓 Learn with Eduarn

At Eduarn, we provide hands-on training on:

  • Terraform
  • Microsoft Azure

✔ Real-time projects
✔ Corporate training
✔ Job-oriented learning

👉 Visit: https://eduarn.com


🚀 Conclusion

Terraform modules are essential for building scalable, reusable, and production-ready infrastructure.

By mastering:

  • Basic modules
  • count
  • for_each
  • YAML configs

👉 You become a real-world DevOps engineer


🔥 Hashtags

#Terraform #Azure #DevOps #InfrastructureAsCode #CloudAutomation #TerraformModules #EduArn

Wednesday, April 1, 2026

Terraform Module Versioning

 

Terraform Module Versioning

In Terraform, module versioning ensures you use a specific, stable version of a module instead of always pulling the latest code.

👉 This avoids breaking changes and keeps infrastructure predictable.


🔹 1. Why Module Versioning?

  • Prevent unexpected changes
  • Maintain stability across environments
  • Enable rollback to previous versions
  • Support team collaboration

🏷️ 2. Versioning with Git (Most Common)

Modules stored in GitHub can be versioned using:

✅ Git Tags (Recommended)

git tag v1.0.0
git push origin v1.0.0

🔗 3. Use Version in Terraform

module "rg" {
source = "git::https://github.com/org/repo.git//modules/rg?ref=v1.0.0"

rg_name = "my-rg"
rg_location = "eastus"
}

👉 ?ref= supports:

  • Tag → v1.0.0 ✅ best
  • Branch → main
  • Commit → a1b2c3d

📦 4. Terraform Registry Versioning

If using Terraform Registry:

module "rg" {
source = "app.terraform.io/org/rg-module/azurerm"
version = "1.0.0"
}

👉 Uses semantic versioning (SemVer)


🔢 5. Semantic Versioning (Best Practice)

Format:

MAJOR.MINOR.PATCH

Example:

  • 1.0.0 → initial release
  • 1.1.0 → new feature (no breaking)
  • 2.0.0 → breaking changes

🧠 6. Version Constraints

version = "~> 1.0"

👉 Means:

  • Allow: 1.0.x, 1.1.x
  • Block: 2.0.0

⚠️ 7. Without Versioning (Risk)

source = "git::https://github.com/org/repo.git"

❌ Always pulls latest → risky
❌ Can break production


🎯 8. Best Practices

  • ✅ Always use version/tag
  • ✅ Follow semantic versioning
  • ✅ Avoid using main in production
  • ✅ Maintain changelog
  • ✅ Test before upgrading versions

🧩 Real-World Flow

  1. Develop module
  2. Tag version (v1.0.0)
  3. Use in projects
  4. Update module → release v1.1.0
  5. Upgrade safely

✅ Summary

  • Module versioning = stable infrastructure
  • Use ?ref= for Git modules
  • Use version for registry modules
  • Follow SemVer best practices

Tuesday, March 31, 2026

Terraform Module with for_each INSIDE Module (Azure RG)

 Terraform Module with for_each INSIDE Module (Azure RG)

#!/bin/bash

# Create directory structure
mkdir -p tfmodule-foreach-inside/modules/rg
cd tfmodule-foreach-inside || exit

echo "📁 Creating Terraform files..."

# -------------------------
# provider.tf
# -------------------------
cat <<EOF > provider.tf
provider "azurerm" {
features {}
}
EOF

# -------------------------
# main.tf (NO loop here)
# -------------------------
cat <<EOF > main.tf

module "rg" {
source = "./modules/rg"

resource_groups = {
dev = "rg-dev"
test = "rg-test"
prod = "rg-prod"
}

rg_location = "eastus"
}

output "rg_names_output" {
value = module.rg.rg_names_output
}
EOF

# -------------------------
# modules/rg/rg.tf (for_each HERE)
# -------------------------
cat <<EOF > modules/rg/rg.tf
resource "azurerm_resource_group" "rg" {
for_each = var.resource_groups

name = each.value
location = var.rg_location

tags = {
environment = each.key
}
}
EOF

# -------------------------
# modules/rg/variable.tf
# -------------------------
cat <<EOF > modules/rg/variable.tf
variable "resource_groups" {
type = map(string)
}

variable "rg_location" {
type = string
}
EOF

# -------------------------
# modules/rg/output.tf
# -------------------------
cat <<EOF > modules/rg/output.tf
output "rg_names_output" {
value = {
for key, rg in azurerm_resource_group.rg :
key => rg.name
}
}
EOF

echo "✅ Terraform module with for_each INSIDE module created!"
echo ""
echo "👉 Next steps:"
echo "cd tfmodule-foreach-inside"
echo "terraform init"
echo "terraform plan"
echo "terraform apply"

▶️ How to Run

chmod +x setup.sh
./setup.sh

🎯 What This Does

  • Module called once
  • for_each inside module creates:
    • rg-dev
    • rg-test
    • rg-prod

📤 Output Example

{
"dev": "rg-dev",
"test": "rg-test",
"prod": "rg-prod"
}

🧠 Key Concept (Very Important)

🔹 for_each inside module

  • Loops over map
  • Uses:
    • each.key → dev/test/prod
    • each.value → resource name

⚖️ Count vs for_each (Inside Module)

Featurecountfor_each
Input typelistmap
Stability❌ index-based✅ key-based
Production use⚠️ limited✅ recommended

✅ Summary

  • for_each inside module = best practice
  • Cleaner, stable, production-ready
  • Ideal for multi-environment setups

Terraform Module with count INSIDE Module (Azure RG) By EduArn

Save below code int setup.sh file:

 vi setup.sh 

#!/bin/bash

# Create directory structure
mkdir -p tfmodule-count-inside/modules/rg
cd tfmodule-count-inside || exit

echo "📁 Creating Terraform files..."

# -------------------------
# provider.tf
# -------------------------
cat <<EOF > provider.tf
provider "azurerm" {
features {}
}
EOF

# -------------------------
# main.tf (NO count here)
# -------------------------
cat <<EOF > main.tf

module "rg" {
source = "./modules/rg"

rg_names = ["rg-dev", "rg-test", "rg-prod"]
rg_location = "eastus"
}

output "rg_names_output" {
value = module.rg.rg_names_output
}
EOF

# -------------------------
# modules/rg/rg.tf (COUNT HERE)
# -------------------------
cat <<EOF > modules/rg/rg.tf
resource "azurerm_resource_group" "rg" {
count = length(var.rg_names)

name = var.rg_names[count.index]
location = var.rg_location

tags = {
environment = "Dev"
}
}
EOF

# -------------------------
# modules/rg/variable.tf
# -------------------------
cat <<EOF > modules/rg/variable.tf
variable "rg_names" {
type = list(string)
}

variable "rg_location" {
type = string
}
EOF

# -------------------------
# modules/rg/output.tf
# -------------------------
cat <<EOF > modules/rg/output.tf
output "rg_names_output" {
value = azurerm_resource_group.rg[*].name
}
EOF

echo "✅ Terraform module with count INSIDE module created!"
echo ""
echo "👉 Next steps:"
echo "cd tfmodule-count-inside"
echo "terraform init"
echo "terraform plan"
echo "terraform apply"

▶️ How to Run

chmod +x setup.sh
./setup.sh

🎯 What This Does

  • count is used inside module
  • Root module calls only once
  • Module creates multiple resources internally

📁 Output

rg-dev
rg-test
rg-prod

🧠 Key Concept (Important for Interviews)

🔹 Count in Root Module

  • Creates multiple module instances

🔹 Count in Module (this example)

  • Creates multiple resources inside module

👉 This is a very important distinction


✅ Summary

  • Module called once
  • count handled internally
  • Clean and reusable design
  • Best for encapsulated logic

Terraform Module + Count Setup Script By EduArn



In this post we will see how to create root and other code with help of bash script:

vi script.sh

Pest the code in that file:  

#!/bin/bash

# Create directory structure
mkdir -p tfmodule-count/modules/rg
cd tfmodule-count || exit

echo "📁 Creating Terraform files..."

# -------------------------
# main.tf (uses count)
# -------------------------
cat <<EOF > main.tf
provider "azurerm" {
  features {}
}

variable "rg_names" {
  type    = list(string)
  default = ["rg-dev", "rg-test", "rg-prod"]
}

variable "location" {
  default = "eastus"
}

module "rg" {
  source = "./modules/rg"

  count       = length(var.rg_names)
  rg_name     = var.rg_names[count.index]
  rg_location = var.location
}

output "rg_names_output" {
  value = [for m in module.rg : m.rg_output.name]
}
EOF

# -------------------------
# modules/rg/rg.tf
# -------------------------
cat <<EOF > modules/rg/rg.tf
resource "azurerm_resource_group" "rg" {
  name     = var.rg_name
  location = var.rg_location

  tags = {
    environment = "Dev"
  }
}
EOF

# -------------------------
# modules/rg/variable.tf
# -------------------------
cat <<EOF > modules/rg/variable.tf
variable "rg_name" {
  type = string
}

variable "rg_location" {
  type = string
}
EOF

# -------------------------
# modules/rg/output.tf
# -------------------------
cat <<EOF > modules/rg/output.tf
output "rg_output" {
  value = azurerm_resource_group.rg
}
EOF

echo "✅ Terraform module with count created successfully!"
echo ""
echo "👉 Next steps:"
echo "cd tfmodule-count"
echo "terraform init"
echo "terraform plan"
echo "terraform apply" 

 

▶️ How to Run

chmod +x setup.sh
./setup.sh
 

📁 What You Get

  • Root module with count
  • Reusable module (modules/rg)
  • 3 Azure Resource Groups created:
    • rg-dev
    • rg-test
    • rg-prod

🎯 After Setup

Run:

terraform init
terraform plan
terraform apply
 

 Contact EduArn.com for Retail and corporate training: www.eduarn.com

Terraform Modules Explained with Azure Example (Reusable Infrastructure Made Easy)

 

Terraform, Azure, DevOps, Infrastructure as Code, Terraform Modules, Azure DevOps, Cloud Automation, Eduarn

📘 What is a Terraform Module?

In Terraform, a module is a container for multiple resources that are used together.

👉 Simple definition:
A module = reusable Terraform code block

  • Root module → main configuration
  • Child module → reusable components

🎯 Why Use Modules?

  • Reusability (write once, use many times)
  • Standardization across environments
  • Cleaner and organized code
  • Easy scaling for large infrastructure

☁️ Azure Use Case

Using AzureRM Provider, you can create reusable modules for:

  • Resource Groups
  • Virtual Networks
  • Storage Accounts
  • AKS Clusters

📁 Project Structure

/home/user/tfmodule
│
├── provider.tf
├── m_imp_rg.tf
└── modules/
    └── rg/
        ├── rg.tf
        ├── variable.tf
        └── output.tf

⚙️ Module Code (Resource Group)

📌 modules/rg/rg.tf

resource "azurerm_resource_group" "rg" {
  name     = var.rg_name
  location = var.rg_location

  tags = {
    environment = "Dev"
  }
}

📌 modules/rg/variable.tf

variable "rg_name" {
  default = "demo_rg"
}

variable "rg_location" {
  default = "eastus"
}

📌 modules/rg/output.tf

output "rg_output" {
  value = azurerm_resource_group.rg
}

👉 This output exposes the resource group details to the root module.


🧩 Root Module Usage

📌 provider.tf

provider "azurerm" {
  features {}
}

📌 m_imp_rg.tf

module "prj_001_rg" {
  source      = "./modules/rg"
  rg_name     = "mydemorg"
  rg_location = "eastus"
}

module "prj_002_rg" {
  source      = "./modules/rg"
  rg_name     = "mydemorg2"
  rg_location = "eastus"
}

👉 Same module reused twice → creates two resource groups


📤 Access Module Output

output "myoutput" {
  value = module.prj_001_rg.rg_output
}

👉 Syntax:

module.<module_name>.<output_name>

🔎 What Happens Here?

  • Module rg is defined once
  • Called multiple times with different inputs
  • Each call creates a separate Azure Resource Group
  • Outputs allow sharing values

💡 Real-World Benefits

  • Create 10+ resource groups using one module
  • Maintain consistency across environments
  • Reduce duplication and errors
  • Faster deployments

🧠 Best Practices

  • Keep modules small and focused
  • Use variables for flexibility
  • Expose only required outputs
  • Follow naming conventions
  • Store modules in version-controlled repos

🎓 Learn with EduArn

At Eduarn, we teach real-world DevOps using:

  • Terraform
  • Azure cloud projects
  • Hands-on labs and corporate scenarios

✔ Retail training (individual learners)
✔ Corporate training (team upskilling)


🚀 Final Thoughts

Terraform modules are the foundation of scalable infrastructure design.

If you're not using modules yet, you're:
❌ Writing duplicate code
❌ Increasing risk
❌ Slowing down deployments

👉 Start modularizing today and build like a pro DevOps engineer.


#Terraform #Azure #DevOps #InfrastructureAsCode #TerraformModules #CloudComputing #EduArn

 

 Copy Pest code:

#!/bin/bash

# Create directory structure
mkdir -p tfmodule/modules/rg
cd tfmodule || exit

# Create provider.tf
cat <<EOF > provider.tf
provider "azurerm" {
  features {}
}
EOF

# Create main module usage file
cat <<EOF > m_imp_rg.tf
module "prj_001_rg" {
  source      = "./modules/rg"
  rg_name     = "mydemorg"
  rg_location = "eastus"
}

module "prj_002_rg" {
  source      = "./modules/rg"
  rg_name     = "mydemorg2"
  rg_location = "eastus"
}

output "myoutput" {
  value = module.prj_001_rg.rg_output
}
EOF

# Create module: rg.tf
cat <<EOF > modules/rg/rg.tf
resource "azurerm_resource_group" "rg" {
  name     = var.rg_name
  location = var.rg_location

  tags = {
    environment = "Dev"
  }
}
EOF

# Create module: variable.tf
cat <<EOF > modules/rg/variable.tf
variable "rg_name" {
  default = "demo_rg"
}

variable "rg_location" {
  default = "eastus"
}
EOF

# Create module: output.tf
cat <<EOF > modules/rg/output.tf
output "rg_output" {
  value = azurerm_resource_group.rg
}
EOF

echo "✅ Terraform module structure created successfully!"
echo "👉 Next steps:"
echo "1. terraform init"
echo "2. terraform plan"
echo "3. terraform apply" 

Monday, March 30, 2026

Terraform Logging Deep Dive: TF_LOG, Log Files & Azure Debugging (Step-by-Step)

 

Terraform Logging Explained: TF_LOG, TRACE, DEBUG with Azure Example By EduArn.com & LMS

If you’re working with Terraform in real-world environments—especially on Azure—understanding logging is not optional. It’s the difference between guessing and diagnosing.

In this guide, we’ll cover:

  • Terraform log levels hierarchy
  • How to generate log files with timestamps
  • Debugging Azure resources using logs
  • Professional logging patterns used in enterprise teams

🔍 Why Terraform Logging Matters

Terraform hides a lot of internal operations:

  • Provider API calls
  • Dependency graph execution
  • Authentication flows

When something fails, logs are your single source of truth.


📊 Terraform Log Levels (Hierarchy)

OFF → ERROR → WARN → INFO → DEBUG → TRACE

Best practice:

  • INFO → Basic troubleshooting
  • DEBUG → Provider/API debugging
  • TRACE → Deep internal analysis

⚙️ Enable Terraform Logging

Linux / macOS

export TF_LOG=DEBUG
terraform plan

Save Logs to File

export TF_LOG=TRACE
export TF_LOG_PATH="terraform.log"

terraform apply

📁 Dynamic Log File Naming (Professional Setup)

Terraform doesn’t support timestamps natively, so use shell:

ENV=dev

export TF_VAR_environment=$ENV
export TF_LOG=DEBUG
export TF_LOG_PATH="terraform-${ENV}-$(date +%Y%m%d_%H%M%S).log"

terraform apply

Example Output:

terraform-dev-20260330_142510.log

☁️ Azure Terraform Example (Real Debug Scenario)

Let’s debug an Azure Resource Group deployment using the AzureRM Provider.

main.tf

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "demo-rg"
  location = "eastus"
}

Run with Debug Logs

export TF_LOG=DEBUG
export TF_LOG_PATH="azure-debug-$(date +%Y%m%d_%H%M%S).log"

terraform init
terraform apply

🔎 Sample Log Output (Simplified)

[DEBUG] provider.azurerm: Sending request to Azure API
[INFO]  ResourceGroup Create: demo-rg
[TRACE] EvalApplyResource: azurerm_resource_group.rg

🧪 Professional Debugging Workflow

Step 1: Start Small

export TF_LOG=INFO

Step 2: Increase Detail

export TF_LOG=DEBUG

Step 3: Deep Analysis

export TF_LOG=TRACE

🔒 Security Warning

Terraform logs may include:

  • Access tokens
  • Secrets
  • API payloads

👉 Always sanitize logs before sharing.


🧹 Cleanup After Debugging

unset TF_LOG
unset TF_LOG_PATH

🚀 Enterprise Best Practices

  • Use structured naming:

    terraform-<env>-<region>-<timestamp>.log
  • Store logs in:
    • CI/CD artifacts
    • Central logging systems
  • Rotate logs:
find . -name "terraform-*.log" -mtime +7 -delete

🧠 Pro Tips

  • Use DEBUG for Azure API failures
  • Use TRACE when raising provider issues
  • Combine with CI/CD pipeline logs

🎯 SEO Keywords (for learning & training visibility)

Terraform logging tutorial, TF_LOG explained, Terraform debug logs Azure, Terraform log file example, Terraform TRACE DEBUG INFO difference, Azure Terraform troubleshooting, Infrastructure as Code debugging, DevOps training Terraform, Terraform best practices enterprise


🎓 Learn Terraform with Eduarn

If you’re looking to master Terraform, Azure DevOps, and real-world cloud automation:

👉 Eduarn.com offers:

  • Hands-on online training for retail learners
  • Customized corporate training programs
  • Real-time projects with Azure & Terraform
  • Expert-led DevOps and Cloud courses

Whether you're an individual learner or an enterprise team, Eduarn helps you build production-ready skills.


✅ Final Thoughts

Terraform logging is not just for debugging—it’s a core skill for DevOps engineers working at scale.

Master it, and you’ll:

  • Solve issues faster
  • Understand infrastructure deeply
  • Work like a senior engineer 


 

 

💬 Want a follow-up post?
I can cover:

  • Terraform TRACE log analysis (line-by-line)
  • Debugging Azure authentication failures
  • Logging in CI/CD pipelines (Azure DevOps & GitHub Actions)

#Terraform #Azure #DevOps #InfrastructureAsCode #CloudComputing #Eduarn

Terraform Modules in Azure: Step-by-Step Guide with Count, for_each & YAML Examples

  Introduction In modern cloud environments, writing reusable and scalable infrastructure is critical. Using Terraform with Microsoft Azur...