Terraform Kurulumu ve İlk Provider Yapılandırması

Altyapıyı kod olarak yönetmek, modern DevOps dünyasının olmazsa olmaz pratiği haline geldi. Sunucu kurup elle yapılandırma dönemi geride kalıyor; artık her şey versiyon kontrollü, tekrarlanabilir ve otomatize edilmiş olmalı. Terraform, HashiCorp tarafından geliştirilen ve “Infrastructure as Code” (IaC) felsefesinin en popüler temsilcilerinden biri. AWS, Azure, GCP, hatta kendi veri merkeziniz olsun, Terraform ile hepsini tek bir araçla yönetebiliyorsunuz. Bu yazıda sıfırdan başlayarak Terraform kurulumunu yapacak, provider kavramını derinlemesine inceleyecek ve gerçek dünya senaryolarıyla ilk yapılandırmalarınızı oluşturacaksınız.

Terraform Nedir ve Neden Kullanmalısınız

Terraform, HCL (HashiCorp Configuration Language) adı verilen kendine özgü bir dil kullanarak altyapı kaynaklarını tanımlamanıza olanak sağlar. Klasik shell scriptlerden farkı şu: Terraform mevcut durumu takip eder. “Şu anda ne var, ne olması gerekiyor?” sorusunu sürekli kendine sorarak değişiklikleri hesaplar ve sadece gerekli olanı uygular.

Bir sistemi elle kurduğunuzda ne olur? Üç ay sonra kim neyi değiştirdi, neden değiştirdi, hangi port neden açık bilmiyorsunuz. Terraform kullandığınızda her şey Git reponuzda, her değişiklik commit geçmişinde. Yeni bir ekip üyesi geldiğinde “şu klasörü aç, terraform apply çalıştır” diyebiliyorsunuz.

Terraform’un öne çıkan avantajları:

  • Çoklu provider desteği: 1000’den fazla provider mevcut, AWS’den Cloudflare’e, Kubernetes’ten GitHub’a kadar
  • State yönetimi: Neyin var olduğunu takip eder, tutarsızlıkları saptar
  • Plan-Apply döngüsü: Değişiklik yapmadan önce ne yapılacağını gösterir
  • Modüler yapı: Tekrar kullanılabilir modüller yazabilirsiniz
  • Büyük topluluk: Hazır modüller ve çözümler bolca mevcut

Kurulum

Linux’ta Kurulum

Debian/Ubuntu tabanlı sistemlerde HashiCorp’un resmi reposunu ekleyerek kurulum yapmanız en sağlıklı yol. Böylece güncellemeleri apt upgrade ile otomatik alırsınız.

# Gerekli araçları yükle
sudo apt-get update && sudo apt-get install -y gnupg software-properties-common

# HashiCorp GPG anahtarını ekle
wget -O- https://apt.releases.hashicorp.com/gpg | 
  gpg --dearmor | 
  sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null

# Repoyu ekle
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] 
  https://apt.releases.hashicorp.com $(lsb_release -cs) main" | 
  sudo tee /etc/apt/sources.list.d/hashicorp.list

# Terraform'u kur
sudo apt-get update && sudo apt-get install terraform

RHEL/CentOS/Rocky Linux için:

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum install terraform

Kurulumun başarılı olup olmadığını doğrulayın:

terraform version
# Çıktı: Terraform v1.7.x
# on linux_amd64

macOS’ta Kurulum

macOS kullanıcıları için Homebrew en temiz yöntem:

brew tap hashicorp/tap
brew install hashicorp/tap/terraform

# Güncellemek için
brew upgrade hashicorp/tap/terraform

Windows’ta Kurulum

Windows ortamında Chocolatey veya doğrudan binary indirme yöntemini kullanabilirsiniz. Chocolatey ile:

choco install terraform

Ya da HashiCorp’un sitesinden zip dosyasını indirip PATH’e ekleyebilirsiniz. WSL2 kullananlar için Linux kurulum adımlarını direkt uygulayabilirsiniz, ki bu daha pratik bir seçenek.

Shell Tamamlama Ayarları

Günlük kullanımda hayat kurtarır:

# Bash için
terraform -install-autocomplete

# Zsh kullananlar için ~/.zshrc'ye ekleyin
autoload -U +X bashcompinit && bashcompinit
complete -o nospace -C /usr/bin/terraform terraform

Temel Kavramlar: Provider Nedir

Terraform tek başına hiçbir şey yapamaz. AWS’de bir EC2 instance açmak istiyorsanız, Terraform’un AWS API’siyle nasıl konuşacağını bilmesi gerekir. İşte bu noktada provider devreye girer. Provider, belirli bir platformun kaynaklarını yönetmek için Terraform’a gerekli API entegrasyonunu sağlayan plugin’dir.

Provider’lar üç kategoride toplanır:

  • Official: HashiCorp tarafından yönetilen AWS, Azure, GCP, Kubernetes gibi büyük platformlar
  • Partner: HashiCorp ile ortak çalışan şirketlerin oluşturduğu, Datadog, MongoDB Atlas, Cloudflare gibi
  • Community: Topluluk tarafından geliştirilen ve Terraform Registry’de yayınlanan

terraform init komutunu çalıştırdığınızda Terraform, .terraform.lock.hcl dosyasını oluşturur ve tanımladığınız provider’ları indirir. Bu dosyayı Git’e commit edin, böylece ekip üyeleri aynı provider versiyonlarını kullanır.

İlk Yapılandırma Dosyalarını Oluşturmak

Terraform projeleri birkaç temel dosya üzerine kurulur. Dosya isimlerinin .tf uzantısı olması yeterli, Terraform aynı dizindeki tüm .tf dosyalarını birleştirerek işler. Ancak genel kabul gören yapı şöyle:

  • main.tf: Ana kaynak tanımları
  • providers.tf: Provider yapılandırmaları
  • variables.tf: Değişken tanımları
  • outputs.tf: Çıktı tanımları
  • terraform.tfvars: Değişken değerleri (Git’e push etmeyin, hassas veriler içerebilir)

Bir proje dizini oluşturarak başlayalım:

mkdir terraform-ilk-proje
cd terraform-ilk-proje
touch main.tf providers.tf variables.tf outputs.tf

AWS Provider Yapılandırması

En yaygın kullanım senaryolarından biri AWS. providers.tf dosyasını oluşturalım:

terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = {
      Environment = var.environment
      ManagedBy   = "Terraform"
      Project     = var.project_name
    }
  }
}

Bu yapılandırmada dikkat edilmesi gereken birkaç nokta var. required_version ile Terraform’un minimum versiyonunu zorunlu kılıyoruz. ~> 5.0 ifadesi “5.x versiyonları kabul et ama 6.0’a geçme” anlamına geliyor. default_tags bloğu ise bu provider üzerinden oluşturulan tüm kaynaklara otomatik tag ekler, her kaynağa ayrı ayrı tag yazmak zorunda kalmıyorsunuz.

variables.tf dosyasını düzenleyelim:

variable "aws_region" {
  description = "AWS region where resources will be created"
  type        = string
  default     = "eu-west-1"
}

variable "environment" {
  description = "Deployment environment (dev, staging, prod)"
  type        = string
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be one of: dev, staging, prod."
  }
}

variable "project_name" {
  description = "Project identifier for tagging"
  type        = string
}

validation bloğu önemli bir detay. Birisi yanlış environment değeri girdiğinde Terraform plan aşamasında hata verir, apply’a geç kalmadan sorunu yakalar.

Kimlik Doğrulama Yöntemleri

Provider yapılandırmasında credential nasıl yönetilir? Bu konu çok kritik. Asla access key ve secret key’i .tf dosyasına yazmayın. Üç temiz yöntem var:

Environment Variables ile Kimlik Doğrulama

En basit ve taşınabilir yöntem:

export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
export AWS_DEFAULT_REGION="eu-west-1"

# Terraform otomatik olarak bu değişkenleri okur
terraform plan

AWS Profile Kullanımı

Birden fazla AWS hesabıyla çalışıyorsanız named profile kullanın:

# ~/.aws/credentials dosyasında
[proje-dev]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

[proje-prod]
aws_access_key_id = AKIAI44QH8DHBEXAMPLE
aws_secret_access_key = je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY

Provider’da profili belirtin:

provider "aws" {
  region  = var.aws_region
  profile = "proje-dev"
}

IAM Role ile Kimlik Doğrulama (Üretim Ortamı İçin)

EC2 üzerinde çalışıyorsanız veya CI/CD pipeline’ınız varsa IAM role kullanımı en güvenli yol:

provider "aws" {
  region = var.aws_region

  assume_role {
    role_arn     = "arn:aws:iam::123456789012:role/TerraformDeployRole"
    session_name = "terraform-session"
  }
}

Birden Fazla Provider Kullanmak

Gerçek dünya projelerinde genellikle birden fazla provider gerekir. Örneğin AWS altyapısı kurarken Cloudflare DNS kaydı da oluşturmak isteyebilirsiniz.

terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = "~> 4.0"
    }
    random = {
      source  = "hashicorp/random"
      version = "~> 3.5"
    }
  }
}

provider "aws" {
  region = "eu-west-1"
}

provider "cloudflare" {
  api_token = var.cloudflare_api_token
}

random provider’ı harici bir servise bağlanmaz, sadece rastgele değerler üretir. Kaynak isimlerine unique suffix eklemek için çok kullanışlı.

Provider Alias ile Çoklu Region

Aynı provider’ı farklı konfigürasyonlarla kullanmanız gerekebilir. Multi-region deployment en yaygın senaryo:

# Primary region
provider "aws" {
  region = "eu-west-1"
}

# DR region için alias
provider "aws" {
  alias  = "us-east"
  region = "us-east-1"
}

# Kaynakta kullanımı
resource "aws_s3_bucket" "backup" {
  provider = aws.us-east
  bucket   = "proje-yedek-bucket-us"
}

Bu pattern disaster recovery yapılarında, CloudFront dağıtımlarında (us-east-1 zorunlu) ve multi-region aktif-aktif mimarilerde sıkça kullanılır.

İlk terraform init ve Dosya Yapısı

Yapılandırmayı hazırladıktan sonra init çalıştırın:

terraform init

# Çıktı benzeri:
# Initializing the backend...
# Initializing provider plugins...
# - Finding hashicorp/aws versions matching "~> 5.0"...
# - Installing hashicorp/aws v5.31.0...
# - Installed hashicorp/aws v5.31.0 (signed by HashiCorp)
#
# Terraform has been successfully initialized!

Init sonrasında .terraform/ dizini oluşur, içinde provider binary’leri bulunur. Bu dizini .gitignore‘a ekleyin:

cat >> .gitignore << 'EOF'
.terraform/
*.tfstate
*.tfstate.backup
*.tfvars
.terraform.lock.hcl
EOF

Dikkat: .terraform.lock.hcl dosyasını bazı kaynaklar gitignore’a ekliyor ama bu yanlış. Lock dosyasını commit edin, provider versiyonlarının tutarlı kalması için gerekli.

Gerçek Dünya Senaryosu: VPC Altyapısı Kurulumu

Teoriden pratiğe geçelim. Bir web uygulaması için basit ama gerçekçi bir AWS altyapısı kuralım. main.tf dosyasına ekleyelim:

# Mevcut AZ'leri dinamik olarak çek
data "aws_availability_zones" "available" {
  state = "available"
}

# VPC
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "${var.project_name}-vpc"
  }
}

# Public subnet - her AZ için bir tane
resource "aws_subnet" "public" {
  count             = 2
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.${count.index}.0/24"
  availability_zone = data.aws_availability_zones.available.names[count.index]

  map_public_ip_on_launch = true

  tags = {
    Name = "${var.project_name}-public-${count.index + 1}"
    Tier = "public"
  }
}

# Internet Gateway
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.project_name}-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 = "${var.project_name}-public-rt"
  }
}

# Route table association
resource "aws_route_table_association" "public" {
  count          = 2
  subnet_id      = aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}

outputs.tf ile önemli değerleri dışa aktaralım:

output "vpc_id" {
  description = "VPC ID"
  value       = aws_vpc.main.id
}

output "public_subnet_ids" {
  description = "Public subnet ID listesi"
  value       = aws_subnet.public[*].id
}

output "vpc_cidr" {
  description = "VPC CIDR blogu"
  value       = aws_vpc.main.cidr_block
}

Şimdi plan aşamasını çalıştırın:

# Değişkenleri tfvars dosyasına yazın
cat > dev.tfvars << 'EOF'
environment  = "dev"
project_name = "webapp"
aws_region   = "eu-west-1"
EOF

terraform plan -var-file="dev.tfvars"

Plan çıktısı size tam olarak ne oluşturulacağını, ne değiştirileceğini ve ne silineceğini gösterir. Yeşil + ekleme, sarı ~ değişiklik, kırmızı - silme anlamına gelir. Apply’dan önce bu çıktıyı dikkatle okuma alışkanlığı edinin.

terraform apply -var-file="dev.tfvars"
# "yes" yazarak onaylayın

State Dosyası Nedir, Nereye Koymalısınız

Terraform uyguladığı değişiklikleri terraform.tfstate dosyasında saklar. Bu dosya mevcut altyapınızın haritası. Yerel diskte tutmak tek kişilik projeler için kabul edilebilir ama ekip çalışmasında felaket reçetesi. İki kişi aynı anda apply çalıştırırsa state dosyası bozulur.

Çözüm: Remote backend. AWS S3 + DynamoDB kombinasyonu en yaygın kullanılan:

terraform {
  backend "s3" {
    bucket         = "sirket-terraform-state"
    key            = "webapp/dev/terraform.tfstate"
    region         = "eu-west-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}

DynamoDB tablosu state locking için kullanılır, aynı anda iki kişinin değişiklik yapmasını engeller. Backend’i değiştirdiğinizde terraform init -migrate-state komutunu kullanarak mevcut state’i taşıyabilirsiniz.

Sık Yapılan Hatalar ve Çözümleri

Terraform öğrenirken neredeyse herkesin takıldığı noktalara değinelim:

  • Provider versiyonu sabitlememek: version = "~> 5.0" yerine version = ">= 5.0" yazmak ilerleyen zamanlarda breaking change’e yol açabilir. Her zaman tilde-major notation kullanın.
  • Terraform.tfvars’ı Git’e push etmek: Credentials veya hassas veriler bu dosyada bulunabilir. .gitignore‘a eklemek zorunlu.
  • State dosyasını elle düzenlemek: State bozulursa terraform state komutlarını kullanın, dosyayı elle düzenlemeyin.
  • terraform destroy‘u yanlış ortamda çalıştırmak: Workspace veya -var-file kontrolünü atlamamak için TF_WORKSPACE environment variable’ı ve shell alias’ları kullanın.
  • Büyük monolitik main.tf: Her şeyi tek dosyaya yazmak yerine modüler yapıya geçin. Network için network.tf, compute için compute.tf gibi.

Terraform Fmt ve Validate

Kod kalitesi için iki komut günlük kullanımın parçası olmalı:

# Tüm .tf dosyalarını otomatik formatla
terraform fmt -recursive

# Sözdizimi ve mantık hatalarını kontrol et
terraform validate

# Çıktı:
# Success! The configuration is valid.

terraform fmt kodunuzu HCL standartlarına göre düzenler, boşlukları ve hizalamaları düzeltir. CI/CD pipeline’ınıza terraform fmt -check ekleyin, format hatası varsa pipeline başarısız olsun.

CI/CD Entegrasyonu için Temel Yapı

GitLab CI örneğiyle nasıl entegre edeceğinize kısa bir bakış:

# .gitlab-ci.yml
stages:
  - validate
  - plan
  - apply

variables:
  TF_ROOT: ${CI_PROJECT_DIR}
  TF_VERSION: "1.7.0"

terraform:validate:
  stage: validate
  image: hashicorp/terraform:${TF_VERSION}
  script:
    - terraform init -backend=false
    - terraform fmt -check -recursive
    - terraform validate
  only:
    - merge_requests

terraform:plan:
  stage: plan
  image: hashicorp/terraform:${TF_VERSION}
  script:
    - terraform init
    - terraform plan -var-file="prod.tfvars" -out=tfplan
  artifacts:
    paths:
      - tfplan
  only:
    - main

terraform:apply:
  stage: apply
  image: hashicorp/terraform:${TF_VERSION}
  script:
    - terraform init
    - terraform apply tfplan
  when: manual
  only:
    - main

when: manual ile apply aşaması elle onay gerektiriyor. Production’a otomatik apply yapmak, ne kadar testiniz olursa olsun, riskli. İnsan gözü bir kez daha geçmeli.

Sonuç

Terraform’u kurmak ve ilk provider’ı yapılandırmak başlangıç noktası ama asıl öğrenme “plan-apply” döngüsünde ve gerçek projeler üzerinde çalışırken geliyor. Bu yazıda ele aldıklarımızı özetlemek gerekirse:

Terraform kurulumunu HashiCorp’un resmi reposundan yapın, bu sayede güncellemeler sorunsuz gelir. Provider yapılandırmasında versiyon sabitleme ve credential yönetimi en kritik iki konu. Hiçbir zaman kimlik bilgilerini .tf dosyasına yazmayın, environment variable veya IAM role kullanın. State dosyasını uzaktan yönetin, S3+DynamoDB kombinasyonu production için standart kabul edilebilir.

Altyapıyı küçük, anlaşılır parçalara bölün. Her şeyi tek main.tf‘e doldurmak kısa vadede kolay görünse de ekip büyüdükçe ve proje karmaşıklaştıkça idare edilemez hale gelir. terraform fmt ve terraform validate komutlarını alışkanlık edinin, CI/CD pipeline’ınızın parçası yapın.

Bir sonraki adım olarak Terraform modülleri, workspace kavramı ve remote state referanslarını incelemenizi öneririm. Bu üç konu, kurumsal ölçekte Terraform kullanımının temel taşları.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir