Providers i Recursos: Parlant amb el Cloud
5. Providers i Recursos: Parlant amb el Cloud
Els providers i recursos són els blocs de construcció fonamentals de qualsevol configuració de Terraform. Aprofundim en com funcionan.
Providers en Detall
Cada provider té la seva pròpia configuració i opcions. Vegem els providers més comuns en detall:
AWS Provider:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # Versió 5.x, compatible amb patches
}
}
}
provider "aws" {
region = "eu-west-1"
# Autenticació (millor via variables d'entorn o IAM roles)
# access_key = "YOUR_ACCESS_KEY" # No fer això!
# secret_key = "YOUR_SECRET_KEY" # No fer això!
# Opcions avançades
default_tags {
tags = {
Environment = "Production"
ManagedBy = "Terraform"
Project = "MyApp"
}
}
# Assumir un rol (útil per multi-account)
assume_role {
role_arn = "arn:aws:iam::123456789:role/TerraformRole"
}
}
# Proveïdor secundari per una altra regió
provider "aws" {
alias = "us"
region = "us-east-1"
}
# Utilitzar el provider secundari
resource "aws_instance" "us_server" {
provider = aws.us
ami = "ami-0123456789"
instance_type = "t3.micro"
}
Referència oficial: Documentació completa del provider d'AWS: https://registry.terraform.io/providers/hashicorp/aws/latest/docs
Azure Provider:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {
# Comportament al destruir recursos
resource_group {
prevent_deletion_if_contains_resources = false
}
key_vault {
purge_soft_delete_on_destroy = true
}
}
subscription_id = var.azure_subscription_id
tenant_id = var.azure_tenant_id
}
Referència oficial: Documentació del provider d'Azure: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Google Cloud Provider:
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
provider "google" {
project = "my-project-id"
region = "europe-west1"
zone = "europe-west1-b"
# Autenticació via service account key (millor via ADC)
# credentials = file("path/to/service-account-key.json")
}
Referència oficial: Documentació del provider de Google Cloud: https://registry.terraform.io/providers/hashicorp/google/latest/docs
Explorant Recursos: AWS com a Exemple
Cada provider té desenes o centenars de recursos. Vegem alguns exemples d'AWS per entendre la varietat:
Compute (Servidors):
# Instància EC2 bàsica
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
# User data per inicialització
user_data = <<-EOF
#!/bin/bash
apt-get update
apt-get install -y nginx
systemctl start nginx
EOF
# Volums addicionals
ebs_block_device {
device_name = "/dev/sdf"
volume_size = 100
volume_type = "gp3"
encrypted = true
}
# Metadata options
metadata_options {
http_tokens = "required" # Requerir IMDSv2 per seguretat
}
tags = {
Name = "Web Server"
}
}
# Auto Scaling Group
resource "aws_autoscaling_group" "web" {
name = "web-asg"
min_size = 2
max_size = 10
desired_capacity = 3
health_check_type = "ELB"
vpc_zone_identifier = [aws_subnet.private_a.id, aws_subnet.private_b.id]
launch_template {
id = aws_launch_template.web.id
version = "$Latest"
}
tag {
key = "Name"
value = "web-server"
propagate_at_launch = true
}
}
Networking (Xarxes):
# VPC (Virtual Private Cloud)
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "Main VPC"
}
}
# Subnets
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "Public Subnet ${count.index + 1}"
Type = "Public"
}
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "Main IGW"
}
}
# Route Table
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "Public Route Table"
}
}
# Security Group
resource "aws_security_group" "web" {
name = "web-sg"
description = "Security group for web servers"
vpc_id = aws_vpc.main.id
ingress {
description = "HTTP from anywhere"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTPS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
description = "All traffic out"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "Web Security Group"
}
}
Databases:
# RDS (PostgreSQL)
resource "aws_db_instance" "main" {
identifier = "myapp-db"
engine = "postgres"
engine_version = "15.3"
instance_class = "db.t3.medium"
allocated_storage = 100
storage_type = "gp3"
storage_encrypted = true
db_name = "myapp"
username = "dbadmin"
password = var.db_password # Mai hardcodejar passwords!
# Multi-AZ per alta disponibilitat
multi_az = true
# Backups
backup_retention_period = 7
backup_window = "03:00-04:00"
maintenance_window = "mon:04:00-mon:05:00"
# Networking
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.database.id]
publicly_accessible = false
# Protecció contra eliminació
deletion_protection = true
skip_final_snapshot = false
final_snapshot_identifier = "myapp-db-final-snapshot"
tags = {
Name = "Main Database"
}
}
# DynamoDB (NoSQL)
resource "aws_dynamodb_table" "sessions" {
name = "user-sessions"
billing_mode = "PAY_PER_REQUEST"
hash_key = "session_id"
range_key = "timestamp"
attribute {
name = "session_id"
type = "S"
}
attribute {
name = "timestamp"
type = "N"
}
# TTL per expiració automàtica
ttl {
attribute_name = "expiration_time"
enabled = true
}
# Encriptació
server_side_encryption {
enabled = true
}
# Point-in-time recovery
point_in_time_recovery {
enabled = true
}
tags = {
Name = "User Sessions Table"
}
}
Load Balancing:
# Application Load Balancer
resource "aws_lb" "main" {
name = "web-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = aws_subnet.public[*].id
enable_deletion_protection = true
enable_http2 = true
enable_cross_zone_load_balancing = true
tags = {
Name = "Web ALB"
}
}
# Target Group
resource "aws_lb_target_group" "web" {
name = "web-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.main.id
health_check {
enabled = true
healthy_threshold = 2
interval = 30
matcher = "200"
path = "/health"
port = "traffic-port"
protocol = "HTTP"
timeout = 5
unhealthy_threshold = 3
}
stickiness {
type = "lb_cookie"
cookie_duration = 86400
enabled = true
}
}
# Listener
resource "aws_lb_listener" "https" {
load_balancer_arn = aws_lb.main.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS-1-2-2017-01"
certificate_arn = aws_acm_certificate.main.arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.web.arn
}
}
Data Sources: Consultant el Món Existent
Els data sources són increïblement útils per fer la teva configuració dinàmica i adaptable:
# Obtenir informació del compte AWS actual
data "aws_caller_identity" "current" {}
output "account_id" {
value = data.aws_caller_identity.current.account_id
}
# Obtenir totes les zones de disponibilitat
data "aws_availability_zones" "available" {
state = "available"
}
# Obtenir una AMI específica
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# Obtenir informació d'una VPC existent
data "aws_vpc" "selected" {
tags = {
Name = "Production VPC"
}
}
# Obtenir subnets dins d'una VPC
data "aws_subnets" "private" {
filter {
name = "vpc-id"
values = [data.aws_vpc.selected.id]
}
tags = {
Tier = "Private"
}
}
# Obtenir un secret des de Secrets Manager
data "aws_secretsmanager_secret_version" "db_password" {
secret_id = "production/database/password"
}
# Utilitzar els data sources
resource "aws_instance" "app" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.micro"
availability_zone = data.aws_availability_zones.available.names[0]
subnet_id = data.aws_subnets.private.ids[0]
}
Multi-Provider: Combinant Diferents Clouds i Serveis
Una de les grans fortaleses de Terraform és la capacitat de gestionar múltiples providers simultàniament:
# Configurar AWS
provider "aws" {
region = "eu-west-1"
}
# Configurar Cloudflare per DNS
provider "cloudflare" {
api_token = var.cloudflare_api_token
}
# Configurar Datadog per monitorització
provider "datadog" {
api_key = var.datadog_api_key
app_key = var.datadog_app_key
}
# Crear infraestructura a AWS
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
tags = {
Name = "Web Server"
}
}
# Configurar DNS a Cloudflare
resource "cloudflare_record" "web" {
zone_id = var.cloudflare_zone_id
name = "www"
value = aws_instance.web.public_ip
type = "A"
ttl = 3600
}
# Configurar monitorització a Datadog
resource "datadog_monitor" "web_down" {
name = "Web Server Down"
type = "service check"
message = "Web server is down! @team-devops"
query = "\"http.can_connect\".over(\"instance:${aws_instance.web.id}\").by(\"*\").last(2).count_by_status()"
thresholds = {
critical = 2
warning = 1
}
}
Aquest exemple mostra com Terraform pot orquestrar recursos en múltiples plataformes, creant una infraestructura completament integrada amb un sol flux de treball.