Ansible sunucuların içini yapılandırır — paketler, kullanıcılar, container’lar. Peki o sunucunun kendisi (bir bulut sağlayıcıda bir sanal makine, ağ, güvenlik grubu) nereden geliyor? Genellikle bulut sağlayıcının web konsolundan elle tıklanarak oluşturuluyor — ki bu da tıpkı elle sunucu yapılandırmak gibi, tutarsız ve tekrarlanamaz bir süreçtir. Terraform, altyapının kendisini de (Infrastructure as Code — IaC) kod olarak tanımlamanızı sağlar.

Infrastructure as Code nedir, neden önemli?

IaC, sunucuları, ağları, veritabanlarını ve diğer altyapı kaynaklarını bir web konsolunda elle tıklamak yerine, versiyon kontrolüne (Git’e) konabilen dosyalarla tanımlama pratiğidir. Faydaları somuttur:

  • Tekrarlanabilirlik: Aynı kod, “staging” ve “production” ortamlarında birebir aynı altyapıyı kurar — “konsolda hangi ayarı unuttum?” sorunu ortadan kalkar.
  • İzlenebilirlik: Altyapıdaki her değişiklik bir Git commit’idir — kim, ne zaman, neden değiştirdi, tam olarak bilinir.
  • Felaket kurtarma: Bir bölge tamamen kaybolsa bile, kodu başka bir bölgede çalıştırarak altyapıyı dakikalar içinde yeniden kurabilirsiniz.

Terraform’un çalışma mantığı

Terraform, HashiCorp tarafından geliştirilen, bulut-bağımsız (Docker, AWS, Azure, Google Cloud, Cloudflare, hatta Kubernetes için de) bir IaC aracıdır. HCL (HashiCorp Configuration Language) adlı, YAML’a benzer okunabilir bir dille kaynakları deklaratif olarak tanımlarsınız: “şu özelliklerde bir sunucu olsun” dersiniz, nasıl oluşturulacağıyla Terraform ilgilenir. Dört temel komuttan oluşan bir döngüyle çalışır:

terraform init      # gerekli provider eklentilerini indirir
terraform plan      # mevcut durumla istenen durum arasındaki farkı gösterir (dry-run)
terraform apply     # planı onaylayıp gerçek değişiklikleri uygular
terraform destroy   # tanımlanan tüm kaynakları güvenle kaldırır

En yakın örnek: Terraform’un Docker provider’ı

Terraform’u anlamanın en hızlı yolu, zaten bildiğiniz Docker üzerinden gitmektir — resmi kreuzwerker/docker provider’ı, docker run ile yaptığınız şeyi HCL ile tanımlamanızı sağlar:

# main.tf
terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "~> 3.0"
    }
  }
}

provider "docker" {}

resource "docker_image" "nginx" {
  name = "nginx:1.27-alpine"
}

resource "docker_network" "app_net" {
  name = "app-network"
}

resource "docker_container" "web" {
  name  = "terraform-web"
  image = docker_image.nginx.image_id
  ports {
    internal = 80
    external = 8080
  }
  networks_advanced {
    name = docker_network.app_net.name
  }
}
terraform init
terraform apply   # onay istediğinde "yes" yazın

Bu birkaç satır, bir imajı çeker, bir ağ oluşturur ve bu ağa bağlı bir container’ı 8080 portundan yayınlayarak başlatır — docker network create + docker run‘un deklaratif karşılığı. Fark şurada: bu tanımı Git’e commit edersiniz, tekrar terraform apply çalıştırdığınızda Terraform sadece farkı uygular; container zaten doğru haldeyse hiçbir şey değişmez.

State (durum) dosyası: Terraform’un hafızası

terraform apply her çalıştığında, Terraform oluşturduğu kaynakların güncel halini terraform.tfstate adlı bir dosyaya kaydeder. Bir sonraki plan/apply çalıştığında, kodunuzdaki tanımı bu state dosyasıyla karşılaştırıp sadece gereken farkı uygular. Ekiple çalışırken bu dosyayı Git’e commit etmek yerine, birden fazla kişinin aynı anda güvenle çalışabilmesi için genellikle uzak bir remote backend‘de (AWS S3 + DynamoDB lock, Terraform Cloud gibi) saklanır:

terraform {
  backend "s3" {
    bucket = "sirketim-terraform-state"
    key    = "prod/terraform.tfstate"
    region = "eu-central-1"
  }
}
i

terraform.tfstate dosyası kaynaklarınızın (bazen parola gibi hassas değerler içeren) tam bir haritasını tutar. Bu dosyayı asla genel bir Git reposuna commit etmeyin — .gitignore‘a ekleyin ve remote backend kullanın.

Gerçekçi örnek: Docker çalıştıracak bir bulut sunucusu oluşturmak

Asıl güç, bulut sağlayıcılarla birleştiğinde ortaya çıkar. Örneğin AWS’de Docker’ın kurulu geleceği bir EC2 sunucusunu tanımlamak:

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

resource "aws_instance" "docker_host" {
  ami           = "ami-0c55b159cbfafe1f0"   # Ubuntu 24.04 LTS
  instance_type = "t3.small"

  user_data = <<-EOF
    #!/bin/bash
    curl -fsSL https://get.docker.com | sh
  EOF

  tags = {
    Name = "docker-host-prod"
  }
}

output "sunucu_ip" {
  value = aws_instance.docker_host.public_ip
}

user_data, sunucu ilk açıldığında bir kerelik çalışan bir başlangıç betiğidir — burada Docker'ı otomatik kurar. Daha kapsamlı bir kurulum (paket güncellemeleri, kullanıcı yönetimi, birden fazla sunucu) için genellikle bu noktadan sonra devreye Ansible girer: Terraform sunucuyu oluşturur, Ansible onu yapılandırır.

Değişkenler ve modüller: kodu yeniden kullanılabilir kılmak

# variables.tf
variable "environment" {
  description = "Ortam adı (staging / production)"
  type        = string
}

variable "instance_type" {
  default = "t3.small"
}

# main.tf içinde kullanım
resource "aws_instance" "docker_host" {
  instance_type = var.instance_type
  tags = { Environment = var.environment }
}
# staging ve production için aynı kodu farklı değerlerle çalıştırın
terraform apply -var="environment=staging" -var="instance_type=t3.micro"
terraform apply -var="environment=production" -var="instance_type=t3.large"

Tekrarlanan altyapı parçaları (örneğin "standart bir web sunucusu + güvenlik grubu") bir modül haline getirilip, tıpkı bir fonksiyon gibi farklı projelerde tekrar tekrar çağrılabilir.

Terraform ve Ansible: rakip değil, tamamlayıcı

Terraform Ansible
Görevi Altyapıyı oluşturur (provisioning) Var olan sunucuyu yapılandırır (configuration)
Odak "Şu kaynaklar var olsun" (sunucu, ağ, veritabanı) "Sunucunun içi şöyle olsun" (paketler, kullanıcılar, dosyalar)
Durum takibi State dosyasıyla açık şekilde takip eder Durum tutmaz, her çalıştırmada mevcut durumu kontrol eder
Tipik birliktelik Terraform sunucuyu ayağa kaldırır → Ansible (veya bir user_data betiği) onu yapılandırır → Docker/Kubernetes uygulamayı çalıştırır

Artık altyapının tamamı — sunucudan container'a kadar — kod olarak tanımlı ve tekrarlanabilir durumda. Bu kadar çok hareketli parçayı (Terraform, Ansible, Docker, CI/CD) production'da güvenle işletmenin son ayağı, her şeyin sağlıklı çalıştığını sürekli görebilmek — bunu bir sonraki yazıda, Elastic Stack ile log analizi başlığı altında derinleştiriyoruz.