Terraform ile DigitalOcean ve Hetzner Karşılaştırması

Bulut altyapısı seçimi, bir projenin uzun vadeli maliyetini ve yönetilebilirliğini doğrudan etkileyen kritik bir karar. Özellikle Terraform ile altyapıyı kod olarak yönetmeye başladığınızda, provider seçimi daha da önem kazanıyor. Bu yazıda DigitalOcean ve Hetzner Cloud’u Terraform perspektifinden karşılaştıracağız; gerçek senaryolar, kod örnekleri ve pratik tavsiyelerle hangisinin sizin iş yükünüze daha uygun olduğunu anlamaya çalışacağız.

Neden Bu İkisi?

Piyasada AWS, GCP, Azure giital devler varken neden DigitalOcean ve Hetzner? Çünkü bu iki provider, özellikle startuplar, ajanslar ve orta ölçekli altyapılar için gerçekten makul bir denge sunuyor. AWS’nin karmaşıklığına boğulmadan production-ready altyapı kurmak isteyenler için her ikisi de güçlü seçenekler. Terraform ile de her ikisinin entegrasyonu oldukça olgun bir seviyede.

Terraform Provider Kurulumu

Her iki platform için de önce provider konfigürasyonunu halledelim. Genellikle projenizin kök dizininde providers.tf dosyası oluşturmak iyi bir pratik.

# providers.tf - DigitalOcean için
terraform {
  required_providers {
    digitalocean = {
      source  = "digitalocean/digitalocean"
      version = "~> 2.34"
    }
  }
}

provider "digitalocean" {
  token = var.do_token
}
# providers.tf - Hetzner için
terraform {
  required_providers {
    hcloud = {
      source  = "hetznercloud/hcloud"
      version = "~> 1.44"
    }
  }
}

provider "hcloud" {
  token = var.hcloud_token
}

Token yönetimi için .tfvars dosyası yerine environment variable kullanmanızı öneririm, özellikle CI/CD pipeline’larında:

# Bash ile environment variable set etmek
export TF_VAR_do_token="dop_v1_xxxxxxxxxxxx"
export TF_VAR_hcloud_token="xxxxxxxxxxxxxxxxxxxx"

# Sonra normal terraform komutları
terraform init
terraform plan
terraform apply

Temel Kaynak Tanımlamaları

DigitalOcean Droplet vs Hetzner Server

En temel kaynak olan sanal makine oluşturma açısından iki provider arasında sözdizimi farklılıkları var. DigitalOcean’da buna “Droplet”, Hetzner’de ise “Server” deniyor.

# DigitalOcean Droplet örneği
resource "digitalocean_droplet" "web" {
  name   = "web-server-01"
  size   = "s-2vcpu-4gb"
  image  = "ubuntu-22-04-x64"
  region = "fra1"

  ssh_keys = [data.digitalocean_ssh_key.default.id]

  tags = ["web", "production"]

  user_data = <<-EOF
    #!/bin/bash
    apt-get update -y
    apt-get install -y nginx
    systemctl enable nginx
    systemctl start nginx
  EOF
}
# Hetzner Server örneği
resource "hcloud_server" "web" {
  name        = "web-server-01"
  server_type = "cx22"
  image       = "ubuntu-22.04"
  location    = "fsn1"

  ssh_keys = [hcloud_ssh_key.default.id]

  labels = {
    role        = "web"
    environment = "production"
  }

  user_data = <<-EOF
    #!/bin/bash
    apt-get update -y
    apt-get install -y nginx
    systemctl enable nginx
    systemctl start nginx
  EOF
}

Burada dikkat çekici bir nokta: DigitalOcean tags için string listesi kullanırken, Hetzner labels için key-value map kullanıyor. Bu fark özellikle büyük altyapılarda kaynak filtreleme ve yönetim açısından önemli. Hetzner’in label sistemi daha esnek ve Kubernetes-benzeri bir yapıya sahip.

Fiyatlandırma Gerçekliği

Hetzner’in fiyat avantajı Terraform konfigürasyonlarınızı yazarken de hissedilir. Benzer kaynaklar için Hetzner genellikle DigitalOcean’ın yarı fiyatına hizmet sunuyor. Örneğin:

  • DigitalOcean s-2vcpu-4gb: Aylık yaklaşık 24 USD
  • Hetzner cx22 (2 vCPU, 4GB RAM): Aylık yaklaşık 4-5 EUR

Bu fark, özellikle çok sayıda sunucu ayağa kaldırdığınızda ciddi bir maliyet avantajına dönüşüyor.

Ağ Konfigürasyonu

DigitalOcean VPC ve Floating IP

# DigitalOcean VPC tanımı
resource "digitalocean_vpc" "main" {
  name     = "production-vpc"
  region   = "fra1"
  ip_range = "10.10.0.0/16"
}

resource "digitalocean_droplet" "app" {
  name   = "app-server"
  size   = "s-2vcpu-4gb"
  image  = "ubuntu-22-04-x64"
  region = "fra1"
  vpc_uuid = digitalocean_vpc.main.id

  ssh_keys = [data.digitalocean_ssh_key.default.id]
}

# Floating IP atama
resource "digitalocean_floating_ip" "app_ip" {
  region = "fra1"
}

resource "digitalocean_floating_ip_assignment" "app_ip_assignment" {
  ip_address = digitalocean_floating_ip.app_ip.ip_address
  droplet_id = digitalocean_droplet.app.id
}

Hetzner Network ve Floating IP

# Hetzner private network tanımı
resource "hcloud_network" "main" {
  name     = "production-network"
  ip_range = "10.10.0.0/16"
}

resource "hcloud_network_subnet" "main" {
  network_id   = hcloud_network.main.id
  type         = "cloud"
  network_zone = "eu-central"
  ip_range     = "10.10.1.0/24"
}

resource "hcloud_server" "app" {
  name        = "app-server"
  server_type = "cx22"
  image       = "ubuntu-22.04"
  location    = "fsn1"
}

resource "hcloud_server_network" "app_network" {
  server_id  = hcloud_server.app.id
  network_id = hcloud_network.main.id
  ip         = "10.10.1.10"
}

# Hetzner Floating IP
resource "hcloud_floating_ip" "app_ip" {
  type     = "ipv4"
  location = "fsn1"
}

resource "hcloud_floating_ip_assignment" "app_ip_assignment" {
  floating_ip_id = hcloud_floating_ip.app_ip.id
  server_id      = hcloud_server.app.id
}

Hetzner’de IP adresi atamayı statik olarak belirtebilmeniz (ip = "10.10.1.10") altyapı planlaması açısından büyük kolaylık sağlıyor. DigitalOcean’da bu özellik daha kısıtlı.

Load Balancer Konfigürasyonu

Gerçek dünyada genellikle tek sunucu yetmiyor. Load balancer konfigürasyonuna bakalım.

# DigitalOcean Load Balancer
resource "digitalocean_loadbalancer" "main" {
  name   = "production-lb"
  region = "fra1"

  forwarding_rule {
    entry_port     = 80
    entry_protocol = "http"
    target_port     = 80
    target_protocol = "http"
  }

  forwarding_rule {
    entry_port      = 443
    entry_protocol  = "https"
    target_port     = 80
    target_protocol = "http"
    certificate_name = digitalocean_certificate.main.name
  }

  healthcheck {
    port     = 80
    protocol = "http"
    path     = "/health"
  }

  droplet_ids = [
    digitalocean_droplet.web_01.id,
    digitalocean_droplet.web_02.id
  ]
}
# Hetzner Load Balancer
resource "hcloud_load_balancer" "main" {
  name               = "production-lb"
  load_balancer_type = "lb11"
  location           = "fsn1"

  labels = {
    environment = "production"
  }
}

resource "hcloud_load_balancer_network" "main" {
  load_balancer_id = hcloud_load_balancer.main.id
  network_id       = hcloud_network.main.id
  ip               = "10.10.1.100"
}

resource "hcloud_load_balancer_service" "http" {
  load_balancer_id = hcloud_load_balancer.main.id
  protocol         = "http"
  listen_port      = 80
  destination_port = 80

  health_check {
    protocol = "http"
    port     = 80
    interval = 10
    timeout  = 5
    retries  = 3
    http {
      path         = "/health"
      status_codes = ["200"]
    }
  }
}

resource "hcloud_load_balancer_target" "web_01" {
  type             = "server"
  load_balancer_id = hcloud_load_balancer.main.id
  server_id        = hcloud_server.web_01.id
  use_private_ip   = true
}

Hetzner’in load balancer konfigürasyonu daha modüler; servis, target ve network tanımları ayrı resource blokları halinde yapılıyor. Bu başlangıçta daha karmaşık görünse de büyük altyapılarda daha iyi yönetilebilirlik sağlıyor.

Managed Kubernetes Karşılaştırması

Her iki platform da managed Kubernetes sunuyor. DOKS (DigitalOcean Kubernetes Service) ve Hetzner’in yönetilen k8s hizmeti Terraform üzerinden yönetilebiliyor.

# DigitalOcean DOKS
resource "digitalocean_kubernetes_cluster" "main" {
  name    = "production-cluster"
  region  = "fra1"
  version = "1.29.1-do.0"

  node_pool {
    name       = "worker-pool"
    size       = "s-4vcpu-8gb"
    node_count = 3

    auto_scale = true
    min_nodes  = 2
    max_nodes  = 10

    labels = {
      role = "worker"
    }
  }
}

output "kubeconfig" {
  value     = digitalocean_kubernetes_cluster.main.kube_config[0].raw_config
  sensitive = true
}
# Hetzner Managed Kubernetes (hcloud-k8s provider)
resource "hcloud_server" "k8s_master" {
  count       = 1
  name        = "k8s-master-${count.index + 1}"
  server_type = "cx32"
  image       = "ubuntu-22.04"
  location    = "fsn1"

  network {
    network_id = hcloud_network.main.id
  }

  labels = {
    role = "master"
  }
}

resource "hcloud_server" "k8s_worker" {
  count       = 3
  name        = "k8s-worker-${count.index + 1}"
  server_type = "cx22"
  image       = "ubuntu-22.04"
  location    = "fsn1"

  network {
    network_id = hcloud_network.main.id
  }

  labels = {
    role = "worker"
  }
}

Önemli bir not: Hetzner’in tam anlamıyla managed Kubernetes servisi DigitalOcean kadar olgun değil. Hetzner’de genellikle kendi k8s kurulumunuzu yapmanız ya da Hetzner’in managed servisini hetzner terraform provider üzerinden yönetmeniz gerekiyor. Bu konuda topluluk tarafından geliştirilen kube-hetzner projesi oldukça popüler.

Modüler Yapı ile Gerçek Dünya Senaryosu

Bir e-ticaret platformu için Hetzner’de modüler Terraform yapısı kuralım. Gerçek projelerinizde bu tarz bir yapı kullanmanızı tavsiye ederim.

# modules/web-cluster/main.tf
variable "server_count" {
  type    = number
  default = 2
}

variable "server_type" {
  type    = string
  default = "cx22"
}

variable "environment" {
  type = string
}

resource "hcloud_server" "web" {
  count       = var.server_count
  name        = "${var.environment}-web-${count.index + 1}"
  server_type = var.server_type
  image       = "ubuntu-22.04"
  location    = "fsn1"

  labels = {
    environment = var.environment
    role        = "web"
    managed_by  = "terraform"
  }

  lifecycle {
    create_before_destroy = true
  }
}

output "server_ids" {
  value = hcloud_server.web[*].id
}

output "server_ips" {
  value = hcloud_server.web[*].ipv4_address
}

Bu modülü ana konfigürasyonunuzda şöyle kullanabilirsiniz:

# main.tf
module "production_web" {
  source = "./modules/web-cluster"

  server_count = 3
  server_type  = "cx32"
  environment  = "production"
}

module "staging_web" {
  source = "./modules/web-cluster"

  server_count = 1
  server_type  = "cx22"
  environment  = "staging"
}

State Yönetimi ve Backend Konfigürasyonu

Her iki provider ile çalışırken state dosyası yönetimi kritik. Terraform state’i remote’ta tutmak için DigitalOcean Spaces ya da Hetzner Object Storage kullanabilirsiniz.

# DigitalOcean Spaces backend
terraform {
  backend "s3" {
    endpoint                    = "https://fra1.digitaloceanspaces.com"
    region                      = "us-east-1"  # DO için placeholder
    bucket                      = "my-terraform-states"
    key                         = "production/terraform.tfstate"
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    skip_region_validation      = true
    force_path_style            = true

    access_key = var.spaces_access_key
    secret_key = var.spaces_secret_key
  }
}
# Hetzner Object Storage backend (S3 uyumlu)
terraform {
  backend "s3" {
    endpoint                    = "https://fsn1.your-objectstorage.com"
    region                      = "fsn1"
    bucket                      = "terraform-states"
    key                         = "production/terraform.tfstate"
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    skip_region_validation      = true
    force_path_style            = true
  }
}

Provider Ekosistemi ve Olgunluk Karşılaştırması

Terraform provider olgunluğu açısından değerlendirildiğinde, DigitalOcean provider daha uzun süredir aktif ve daha kapsamlı dokümantasyona sahip.

DigitalOcean provider güçlü yönleri:

  • Managed database (PostgreSQL, MySQL, Redis) desteği çok daha olgun
  • App Platform entegrasyonu mevcut
  • CDN ve Spaces entegrasyonu sorunsuz
  • Container Registry desteği stabil
  • Domain ve DNS yönetimi kapsamlı

Hetzner provider güçlü yönleri:

  • Fiyat-performans oranı üstün
  • Bare metal server yönetimi mümkün
  • Placement groups ile sunucu dağıtımı kontrol edilebilir
  • Server type çeşitliliği ARM dahil daha fazla seçenek sunuyor
  • Avrupa merkezli GDPR uyumluluğu konusunda daha net

Hangi Durumda Hangisini Seçmeli?

DigitalOcean daha uygun senaryolar:

  • Managed database kesinlikle gerekiyorsa ve bunu platform seviyesinde yönetmek istiyorsanız
  • Güçlü bir destek ekibine erişim önceliğinizse
  • App Platform gibi PaaS özelliklerini kullanacaksanız
  • Ekibiniz DevOps olgunluğu henüz gelişmekte olan bir startup ise

Hetzner daha uygun senaryolar:

  • Maliyet optimizasyonu birincil önceliğiniz ise
  • Hesaplama yoğun iş yükleriniz varsa ve çok sayıda sunucu ayağa kaldırmanız gerekiyorsa
  • Avrupa’da veri residency önemliyse
  • Kendi Kubernetes’inizi kurup yönetme kapasiteniz varsa
  • Dedicated sunuculara Terraform ile erişim istiyorsanız

CI/CD Pipeline Entegrasyonu

Her iki provider ile GitHub Actions üzerinden Terraform pipeline’ı nasıl kurulur, kısa bir örnek verelim:

# .github/workflows/terraform.yml
name: Terraform Deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  terraform:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "1.7.0"

      - name: Terraform Init
        run: terraform init
        env:
          TF_VAR_hcloud_token: ${{ secrets.HCLOUD_TOKEN }}
          AWS_ACCESS_KEY_ID: ${{ secrets.SPACES_KEY }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET }}

      - name: Terraform Plan
        run: terraform plan -out=tfplan
        env:
          TF_VAR_hcloud_token: ${{ secrets.HCLOUD_TOKEN }}

      - name: Terraform Apply
        if: github.ref == 'refs/heads/main'
        run: terraform apply -auto-approve tfplan
        env:
          TF_VAR_hcloud_token: ${{ secrets.HCLOUD_TOKEN }}

Pratik Tavsiyeler

Yıllar içinde her iki platform ile çalışırken öğrendiğim bazı şeyleri paylaşayım.

DigitalOcean ile çalışırken dikkat edilecekler:

  • Droplet creation sırası bazen tahmin edilemez, depends_on kullanmaktan çekinmeyin
  • Floating IP atamalarında race condition olabiliyor, apply sürelerini takip edin
  • Firewall kuralları ve VPC konfigürasyonları aynı apply içinde karışınca sorun çıkabiliyor, ayrı apply çalıştırmak bazen daha güvenli

Hetzner ile çalışırken dikkat edilecekler:

  • Server silme işlemleri çok hızlı gerçekleşiyor, prevent_destroy lifecycle bloğunu production’da kullanın
  • Network attachment sonrası sunucunun private IP’sini alması bazen biraz zaman alıyor, provisioner’larda bekleme ekleyin
  • Placement group limitleri dikkat gerektirir, büyük cluster’larda limit request yapın
  • API rate limiting var, büyük deploymentlarda parallelism değerini Terraform’da düşürün: terraform apply -parallelism=5

Sonuç

DigitalOcean ve Hetzner, Terraform ekosistemi içinde her ikisi de ciddi ve kullanılabilir seçenekler. Ancak doğru seçim tamamen ihtiyacınıza bağlı.

Eğer fiyat hassasiyetiniz yüksekse ve ekibinizin teknik kapasitesi altyapıyı kendiniz yönetmeye yeterliyse, Hetzner açık ara daha ekonomik bir seçim. Özellikle Avrupa merkezli bir kullanıcı kitlesine hitap eden, hesaplama yoğun uygulamalarda Hetzner’in fiyat avantajı zamanla ciddi bir bütçe tasarrufuna dönüşüyor.

DigitalOcean ise managed servislerin olgunluğu, kullanımı kolay arayüzü ve geniş ekosistemiyle daha az operasyonel yük isteyen ekipler için daha uygun. Özellikle managed database, app platform ve CDN gibi hizmetleri tek çatı altında kullanmak isteyenler için değer önerisi daha güçlü.

Kendi deneyimimde karma bir yaklaşım da işe yarıyor: Hetzner’i hesaplama katmanı için, DigitalOcean’ı ise managed veritabanları gibi daha karmaşık yönetilen servisler için kullanmak. Terraform’un multi-provider desteği bu tarz hibrit senaryoları gayet güzel yönetmenizi sağlıyor. Hangisini seçerseniz seçin, altyapınızı kod olarak yönetmek her zaman kazandırır.

Bir yanıt yazın

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