Hasura Docker Compose ile Kurulum ve İlk Yapılandırma
Eğer modern bir uygulama geliştiriyorsanız ve veritabanınızın üzerinde hızlıca bir GraphQL API’si ayağa kaldırmak istiyorsanız, Hasura tam olarak aradığınız araç. Üstelik Docker Compose ile kurulum yapmak, geliştirme ortamınızı dakikalar içinde hazır hale getiriyor. Bu yazıda sıfırdan başlayıp production’a taşıyabileceğiniz sağlam bir Hasura kurulumu yapacağız.
Hasura Nedir ve Neden Kullanmalıyız
Hasura, PostgreSQL veritabanınızı otomatik olarak tam özellikli bir GraphQL API’sine dönüştüren açık kaynaklı bir motor. Schema oluşturmak, resolver yazmak, N+1 problemleriyle boğuşmak yerine sadece veritabanı tablolarınızı tanımlıyorsunuz ve Hasura gerisini hallediyor.
Şu özellikleri sizi ikna edebilir:
- Gerçek zamanlı subscriptions desteği kutudan çıkıyor
- Role tabanlı yetkilendirme sistemi oldukça esnek
- Remote schema ve Action desteğiyle custom iş mantığı eklenebiliyor
- Migration yönetimi entegre geliyor
- Webhook desteğiyle event-driven mimari kurulabiliyor
Bir e-ticaret projesi düşünün. Ürünler, siparişler, kullanıcılar gibi onlarca tablo var. Geleneksel yaklaşımda her entity için ayrı endpoint yazmak, dokümantasyon tutmak, versiyon yönetimi yapmak saatler alır. Hasura ile bunu dakikalar içinde hallediyorsunuz.
Ön Gereksinimler
Başlamadan önce sistemde şunların kurulu olması gerekiyor:
- Docker Engine 20.10 ve üzeri
- Docker Compose v2 (eski
docker-composeyerinedocker composekomutu) - En az 2 GB RAM (geliştirme için yeterli)
- 10 GB boş disk alanı
Versiyonları kontrol edelim:
docker --version
docker compose version
Eğer Docker kurulu değilse Ubuntu/Debian için hızlıca kuralım:
curl -fsSL https://get.docker.com | bash
sudo usermod -aG docker $USER
newgrp docker
Proje Dizin Yapısı Oluşturma
Düzenli bir dizin yapısıyla başlamak, ilerleyen süreçte hayatınızı kolaylaştırır. Özellikle migration dosyaları ve metadata birikmeye başlayınca bu yapının önemi ortaya çıkıyor.
mkdir -p hasura-project/{migrations,metadata,seeds}
cd hasura-project
Dizin yapımız şöyle görünecek:
- migrations/: Veritabanı şema değişikliklerini tutar
- metadata/: Hasura konfigürasyon ve permission tanımlarını tutar
- seeds/: Test verilerini tutar
Docker Compose Dosyası Hazırlama
Ana yapılandırma dosyamızı oluşturalım. Bu dosya üç servisi bir arada yönetecek: PostgreSQL, Hasura Engine ve pgAdmin (opsiyonel ama pratik).
version: "3.8"
services:
postgres:
image: postgres:15-alpine
container_name: hasura-postgres
restart: unless-stopped
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_DB: ${POSTGRES_DB}
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- hasura-network
hasura:
image: hasura/graphql-engine:v2.35.0
container_name: hasura-engine
restart: unless-stopped
ports:
- "8080:8080"
depends_on:
postgres:
condition: service_healthy
environment:
HASURA_GRAPHQL_DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
HASURA_GRAPHQL_DEV_MODE: "true"
HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log
HASURA_GRAPHQL_ADMIN_SECRET: ${HASURA_ADMIN_SECRET}
HASURA_GRAPHQL_JWT_SECRET: ${HASURA_JWT_SECRET}
HASURA_GRAPHQL_UNAUTHORIZED_ROLE: public
HASURA_GRAPHQL_CORS_DOMAIN: "*"
HASURA_GRAPHQL_STRINGIFY_NUMERIC_TYPES: "false"
volumes:
- ./migrations:/hasura-migrations
- ./metadata:/hasura-metadata
networks:
- hasura-network
pgadmin:
image: dpage/pgadmin4:latest
container_name: hasura-pgadmin
restart: unless-stopped
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
ports:
- "5050:80"
depends_on:
- postgres
networks:
- hasura-network
volumes:
postgres_data:
driver: local
networks:
hasura-network:
driver: bridge
Bu compose dosyasında dikkat edilmesi gereken bazı noktalar var. depends_on ile condition: service_healthy kullanımı kritik. Hasura, PostgreSQL tamamen hazır olmadan bağlanmaya çalışırsa hata alırsınız. Healthcheck bu sorunu çözüyor.
Environment Değişkenleri
Hassas bilgileri compose dosyasına yazmak kötü pratik. .env dosyası oluşturalım:
cat > .env << 'EOF'
# PostgreSQL
POSTGRES_USER=hasura_user
POSTGRES_PASSWORD=guclu_bir_sifre_koy_buraya
POSTGRES_DB=hasura_db
# Hasura
HASURA_ADMIN_SECRET=admin_secret_en_az_32_karakter_olmali
HASURA_JWT_SECRET={"type":"HS256","key":"jwt_secret_key_en_az_32_karakter"}
# pgAdmin
[email protected]
PGADMIN_PASSWORD=pgadmin_sifresi
EOF
.gitignore dosyasına .env‘i eklemeyi unutmayın:
echo ".env" >> .gitignore
echo "*.env" >> .gitignore
Production ortamında bu değerleri Docker secrets veya HashiCorp Vault gibi araçlarla yönetmek daha güvenli. Geliştirme için .env yeterli.
Servisleri Ayağa Kaldırma
Her şey hazır, çalıştıralım:
docker compose up -d
# Logları takip etmek için
docker compose logs -f hasura
# Sadece son 50 satır görmek için
docker compose logs --tail=50 hasura
Servisler başarıyla ayağa kalktığında şu URL’leri kullanabilirsiniz:
- Hasura Console: http://localhost:8080
- GraphQL Endpoint: http://localhost:8080/v1/graphql
- pgAdmin: http://localhost:5050
Hasura Console’a girince admin secret soracak, .env dosyasında tanımladığınız değeri girin.
İlk Veritabanı Tabloları ve Migration
Hasura Console üzerinden tablo oluşturabilirsiniz ama migration dosyalarıyla yönetmek çok daha profesyonel. Hasura CLI kuralım:
# Linux/Mac için
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
# Versiyonu kontrol et
hasura version
Proje klasöründe Hasura CLI’yi initialize edelim:
hasura init . --endpoint http://localhost:8080 --admin-secret admin_secret_en_az_32_karakter_olmali --directory .
Örnek bir e-ticaret senaryosu için migration oluşturalım:
hasura migrate create "initial_schema" --database-name default
Bu komut migrations/default/ altında iki dosya oluşturur: up.sql ve down.sql. up.sql dosyasını düzenleyelim:
-- migrations/default/1234567890_initial_schema/up.sql
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
full_name VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
slug VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
parent_id INTEGER REFERENCES categories(id)
);
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
description TEXT,
price NUMERIC(10, 2) NOT NULL,
stock_quantity INTEGER NOT NULL DEFAULT 0,
category_id INTEGER REFERENCES categories(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
status VARCHAR(50) NOT NULL DEFAULT 'pending',
total_amount NUMERIC(10, 2) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE order_items (
id SERIAL PRIMARY KEY,
order_id UUID NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
product_id UUID NOT NULL REFERENCES products(id),
quantity INTEGER NOT NULL,
unit_price NUMERIC(10, 2) NOT NULL
);
-- updated_at otomatik güncellemek için trigger
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_products_updated_at BEFORE UPDATE ON products
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_orders_updated_at BEFORE UPDATE ON orders
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
Migration’ı uygulayalım:
hasura migrate apply --database-name default
Hasura Metadata Yapılandırması
Migration’lar veritabanı şemasını yönetir, metadata ise Hasura’nın davranışını. Permission’lar, relationships, computed fields gibi her şey metadata içinde tutuluyor.
Tabloları Hasura’ya tanıtalım ve metadata’ya ekleyelim:
hasura metadata apply
Eğer Console üzerinden tablo eklediyseniz mevcut metadata’yı çekelim:
hasura metadata export
Permission yapılandırması için örnek bir senaryo. users tablosu için bir kullanıcı sadece kendi verisini görebilmeli:
# metadata/databases/default/tables/public_users.yaml dosyasını düzenle
cat > metadata/databases/default/tables/public_users.yaml << 'EOF'
table:
name: users
schema: public
select_permissions:
- role: user
permission:
columns:
- id
- email
- full_name
- created_at
filter:
id:
_eq: X-Hasura-User-Id
limit: 1
- role: admin
permission:
columns: "*"
filter: {}
insert_permissions:
- role: user
permission:
columns:
- email
- full_name
check:
id:
_eq: X-Hasura-User-Id
EOF
Çalışan GraphQL Sorguları
Hasura Console’daki GraphiQL arayüzünden test edelim. Önce birkaç test verisi ekleyelim:
mutation InsertTestData {
insert_categories(objects: [
{name: "Elektronik", slug: "elektronik"},
{name: "Giyim", slug: "giyim"}
]) {
affected_rows
returning {
id
name
}
}
}
Ürünleri sorgulayalım:
query GetProductsWithCategory {
products(
where: {stock_quantity: {_gt: 0}},
order_by: {created_at: desc},
limit: 10
) {
id
name
price
stock_quantity
category {
name
slug
}
}
}
Subscription ile gerçek zamanlı sipariş takibi:
subscription WatchOrderStatus($orderId: uuid!) {
orders_by_pk(id: $orderId) {
id
status
total_amount
updated_at
order_items {
quantity
unit_price
product {
name
}
}
}
}
Servis Yönetimi ve Bakım Komutları
Günlük operasyonlarda işinize yarayacak komutlar:
# Servisleri durdur (verileri koru)
docker compose stop
# Servisleri tamamen kaldır (verileri koru)
docker compose down
# Verileri de sil (dikkatli ol!)
docker compose down -v
# Sadece Hasura'yı yeniden başlat
docker compose restart hasura
# Container kaynak kullanımını izle
docker stats hasura-engine hasura-postgres
# PostgreSQL'e doğrudan bağlan
docker exec -it hasura-postgres psql -U hasura_user -d hasura_db
# Hasura container'ına bash aç
docker exec -it hasura-engine /bin/sh
# Log boyutunu kontrol et
docker inspect hasura-engine | grep LogPath
Migration durumunu kontrol etmek için:
# Mevcut migration durumu
hasura migrate status --database-name default
# Belirli bir migration'a geri dön
hasura migrate apply --goto 1234567890 --database-name default
# Son migration'ı geri al
hasura migrate apply --down 1 --database-name default
Production için Ek Güvenlik Önlemleri
Geliştirme ortamında rahat çalışmak için açık bıraktığımız bazı ayarlar production’da kapatılmalı.
Console’u production’da kapatın, doğrudan erişimi engelleyin:
# .env.production dosyası
HASURA_GRAPHQL_ENABLE_CONSOLE=false
HASURA_GRAPHQL_DEV_MODE=false
HASURA_GRAPHQL_ENABLED_LOG_TYPES=startup,http-log,webhook-log
Rate limiting için Nginx reverse proxy ekleyin. nginx.conf örneği:
upstream hasura {
server hasura:8080;
}
limit_req_zone $binary_remote_addr zone=graphql:10m rate=30r/m;
server {
listen 80;
server_name api.yourdomain.com;
location /v1/graphql {
limit_req zone=graphql burst=10 nodelay;
proxy_pass http://hasura;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /healthz {
proxy_pass http://hasura/healthz;
}
}
Yaygın Sorunlar ve Çözümleri
Hasura PostgreSQL’e bağlanamıyor: Healthcheck’i kontrol edin. postgres servisinin healthy durumuna gelmesi birkaç saniye alabilir. docker compose ps ile durum kontrol edin.
Migration çakışmaları: Aynı anda iki geliştirici migration oluşturursa timestamp çakışabilir. hasura migrate squash komutu ile migration’ları birleştirebilirsiniz.
Console’da performans sorunu: HASURA_GRAPHQL_QUERY_PLAN_CACHE_SIZE değerini artırın, varsayılan 1000’dir.
JWT doğrulama hataları: JWT secret’ın en az 32 karakter olmasına dikkat edin. JSON formatının doğru olduğunu kontrol edin.
Container restart loop: docker compose logs hasura ile hata mesajını okuyun. Genellikle database URL veya admin secret formatı hatalıdır.
Sonuç
Hasura ile Docker Compose kurulumu, ilk bakışta karmaşık görünse de doğru yapılandırıldığında son derece güçlü bir geliştirme altyapısı ortaya çıkıyor. Migration tabanlı schema yönetimi, metadata ile permission kontrolü ve CLI araçlarıyla birlikte profesyonel bir GraphQL API geliştirme ortamınız hazır.
Bu kurulumu temel alarak şunları yapabilirsiniz:
- Remote schema ile mevcut REST API’lerinizi entegre edebilirsiniz
- Hasura Actions ile custom iş mantığı ekleyebilirsiniz
- Event triggers ile veritabanı değişikliklerini webhook’lara bağlayabilirsiniz
- Hasura Cloud’a geçerek yönetilen servis kullanabilirsiniz
Geliştirme ortamında docker compose up -d ile dakikalar içinde başlayıp, migration ve metadata yönetimiyle takım arkadaşlarınızla senkronize çalışmak artık çok daha kolay. Production’a taşırken güvenlik ayarlarını sıkılaştırmayı ve mutlaka bir reverse proxy önüne koymayı unutmayın.
