COMPLETE LAB 2 SUMMARY: Infrastructure as Code
Project: devops_base/td2 Date: November 26, 2025 Region: us-east-2 AWS Profile: labs-devops_diallo
======================================== SECTIONS COMPLETED
✅ Section 1: Bash Scripting
- Created deploy-ec2-instance.sh
- Manual EC2 provisioning with security groups
✅ Section 2: Ansible Configuration Management
- Created playbooks and roles
- Deployed Node.js application
- Demonstrated idempotence
- Exercises 3 & 4: Analyzed limitations
✅ Section 3: Packer Image Building
- Built custom AMI with Node.js 16.20.0
- AMI ID: ami-07eb809c44dd0fcab
- Exercise 5: Demonstrated non-idempotence (2 different AMIs)
- Exercise 6: Multi-provider support (VirtualBox template)
✅ Section 4: OpenTofu Single Instance
- Deployed 1 instance: 18.220.53.35:8080
- Tested application successfully
✅ Section 5: OpenTofu Multi-Instance
- Deployed 2 instances with for_each pattern
- Exercise 7: Destroy/Apply behavior
- Exercise 8: Multiple instances demonstration
✅ Section 6: OpenTofu Modules
- Created reusable module: modules/ec2-instance
- Exercise 9: Parameterized module (instance_type, port)
- Exercise 10: Scalable deployment with for_each
- Deployed: 2 static + 3 scalable instances
======================================== DIRECTORY STRUCTURE
/home/sable/devops_base/scripts/ ├── bash/ │ └── deploy-ec2-instance.sh ├── ansible/ │ ├── configure_sample_app_playbook.yml │ ├── create_ec2_instance_playbook.yml │ ├── inventory.aws_ec2.yml │ └── roles/ │ └── sample-app/ ├── packer/ │ ├── sample-app.pkr.hcl (HCL template) │ ├── sample-app.json (JSON backup) │ ├── sample-app-virtualbox.pkr.hcl │ ├── app.js │ ├── user-data.sh │ ├── EXERCISE_5_EXPLANATION.md │ └── EXERCISE_6_EXPLANATION.md ├── modules/ │ └── ec2-instance/ │ ├── main.tf │ ├── variables.tf │ ├── outputs.tf │ └── user-data.sh ├── tofu/ │ ├── ec2-instance/ │ │ ├── main.tf │ │ ├── variables.tf │ │ ├── outputs.tf │ │ └── user-data.sh │ ├── ec2-multi/ │ │ ├── main.tf │ │ ├── variables.tf │ │ ├── outputs.tf │ │ └── user-data.sh │ └── EXERCISE_7_AND_8.md ├── live/ │ ├── sample-app/ │ │ ├── main.tf │ │ ├── variables.tf │ │ └── outputs.tf │ └── sample-app-scalable/ │ └── main.tf └── EXERCISE_9_AND_10.md
======================================== ACTIVE AWS RESOURCES
Total EC2 Instances: 8
From Section 4:
- Instance: 18.220.53.35:8080 (Single module test)
From Section 5:
- Instance: 18.218.153.160:8080 (prod-1 multi)
- Instance: 18.218.187.192:8080 (prod-2 multi)
From Section 6 - Static (live/sample-app):
- Instance: 13.58.147.3:8080 (sample-app-tofu-1)
- Instance: 18.191.207.76:8080 (sample-app-tofu-2)
From Section 6 - Scalable (live/sample-app-scalable):
- Instance: 18.222.76.46:8080 (prod-app-1)
- Instance: 3.137.158.194:8080 (prod-app-2)
- Instance: 18.116.203.64:8080 (prod-app-3)
Total Security Groups: 8+ (one per instance)
All instances: ✅ Running ✅ Responding to HTTP on port 8080 ✅ Returning hostname in response
======================================== KEY LEARNINGS
-
Bash Scripting
- Manual but flexible
- No state management
- Error-prone at scale
-
Ansible (Configuration Management)
- Good for existing resources
- Idempotent operations
- Limited provisioning capability
- Exercises 3-4: Showed limitations with dynamic processes
-
Packer (Image Building)
- One-time image creation
- Consistent base for instances
- Not idempotent (each build = new image)
- Multi-provider support possible
- Node.js 16.20.0 binary installation strategy worked
-
OpenTofu (Infrastructure as Code)
- State management critical
- Idempotent deployments
- Destroy/Apply predictable
- Module approach scalable
- for_each pattern superior to count for flexibility
-
Modular Architecture
- Separation: modules vs live configurations
- Reusability across projects
- Parameterization for flexibility
- Professional IaC patterns
======================================== TECHNOLOGY STACK
IaC Tools:
- Bash (0.1: Manual)
- Ansible 2.x (Configuration mgmt)
- Packer 1.9.4 (Image building)
- OpenTofu 1.9.x (Infrastructure provisioning)
Cloud Platform:
- AWS EC2
- AWS Security Groups
- AWS VPC (default)
Application:
- Node.js 16.20.0
- Custom HTTP server (port 8080)
- Response: Hostname of instance
======================================== EXERCISES COMPLETED
Exercise 3: Ansible Idempotence ✅ Tested: Running configure playbook 2+ times ✅ Finding: Most tasks idempotent, except “Start sample app”
Exercise 4: Multi-instance with Ansible ✅ Created template for 3+ instances ✅ Demonstrated scaling capability
Exercise 5: Packer Build Behavior ✅ Ran packer build twice ✅ Result: Different AMI IDs (non-idempotent) ✅ Reason: Timestamp in ami_name ensures uniqueness
Exercise 6: Multi-provider Packer ✅ Created VirtualBox template ✅ Showed same logic, different provider ✅ Concept: “Single source of truth” across platforms
Exercise 7: OpenTofu Post-Destruction ✅ Demonstrated: destroy → new apply = recreation ✅ Insight: New resource IDs assigned ✅ Benefit: Clean state, reproducible
Exercise 8: Multiple Instances ✅ Used for_each to deploy 2+ instances ✅ Cleaner than hardcoded modules
Exercise 9: Module Parameterization ✅ Added instance_type variable ✅ Added port variable ✅ Root module passes parameters ✅ Result: Reusable, flexible module
Exercise 10: Scalable Modules ✅ Used for_each with var.instances map ✅ Deployed 3 instances from single module ✅ Demonstrated production-ready pattern
======================================== BEST PRACTICES DEMONSTRATED
Infrastructure as Code: ✅ Version control ready (all .tf files) ✅ State management with OpenTofu ✅ Modular design ✅ DRY principle (Don’t Repeat Yourself) ✅ Parameterized configurations ✅ Clear separation of concerns
Security: ✅ Security groups for port access control ✅ AWS profile usage (not hardcoded credentials) ✅ Variable inputs not in code
Automation: ✅ User-data scripts for initialization ✅ Consistent deployment across instances ✅ Repeatable apply/destroy cycles
Documentation: ✅ Exercise explanations in markdown ✅ Module variables documented ✅ Output descriptions clear ✅ Comments in configuration
======================================== SCALING SCENARIOS
Scenario 1: Dev Environment (1 instance) tofu apply -var=“ami_id=ami-…” -var=“instance_count=1”
Scenario 2: Staging (3 instances) cd live/sample-app-scalable tofu apply -var=“ami_id=ami-…” -var=‘instances={…3 configs…}’
Scenario 3: Production (10+ instances) module “prod_apps” { for_each = var.prod_instances source = ”../../modules/ec2-instance” … }
All achieved with minimal code changes, maximum reuse.
======================================== COST OPTIMIZATION
Current Setup:
- t3.micro instances (AWS Free Tier eligible for 12 months)
- No persistent storage
- Minimal data transfer
- No additional services
Estimated Monthly Cost (post Free Tier):
- 8 instances × 730 hours × 60/month
- Can reduce to 2-3 instances for dev/staging
Optimization Strategies: ✅ Use Free Tier eligible instance types ✅ Destroy when not needed (tofu destroy) ✅ Right-size instances (don’t over-provision) ✅ Use spot instances for non-production ✅ Implement auto-shutdown schedules
======================================== CLEANUP & NEXT STEPS
Current State: 8 instances running
Cleanup Command (all at once): cd /home/sable/devops_base/scripts/live/sample-app && tofu destroy -auto-approve cd /home/sable/devops_base/scripts/live/sample-app-scalable && tofu destroy -auto-approve
Next Steps:
- Implement CI/CD pipeline (GitHub Actions / GitLab CI)
- Add monitoring (CloudWatch / Prometheus)
- Implement auto-scaling groups
- Add database layer
- Implement infrastructure testing (terratest)
- Add secrets management (AWS Secrets Manager)
- Implement blue-green deployments
======================================== CONCLUSION
Lab 2 demonstrates complete IaC workflow:
Progression: Bash (manual) → Ansible (config mgmt) → Packer (image building) → OpenTofu (provisioning)
Key Achievement: ✅ Scalable, maintainable, repeatable infrastructure ✅ From 1 to 1000+ instances with minimal code changes ✅ Professional-grade patterns ready for production ✅ All concepts integrated: modules, parameters, scaling
This lab provides foundation for enterprise infrastructure automation.
Documentation Files:
- /home/sable/devops_base/SUMMARY_LAB2.md (Sections 1-5)
- /home/sable/devops_base/SECTION_6_SUMMARY.md (Section 6)
- /home/sable/devops_base/scripts/EXERCISE_9_AND_10.md (Exercises 9-10)
- /home/sable/devops_base/scripts/packer/EXERCISE_5_EXPLANATION.md
- /home/sable/devops_base/scripts/packer/EXERCISE_6_EXPLANATION.md
- /home/sable/devops_base/scripts/tofu/EXERCISE_7_AND_8.md
END OF LAB 2