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_onkullanmaktan ç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_destroylifecycle 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
parallelismdeğ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.
