Docker Compose etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Docker Compose etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

4 Şubat 2026 Çarşamba

Docker Compose ile Yerel Bir RAG (Retrieval-Augmented Generation) Ortamı Kurulumu: PostgreSQL + pgvector + API Katmanı

RAG Nedir ve Neden Yerelde Kurulur?

RAG (Retrieval-Augmented Generation), bir dil modelinin cevabı “uydurmak” yerine önce güvenilir bir kaynaktan ilgili içerikleri bulup (retrieval), ardından bu içeriklerle zenginleştirilmiş bir yanıt üretmesi yaklaşımıdır. Son dönemde kurum içi dokümanlarla çalışan asistanlar, teknik arama kutuları ve destek botları RAG ile daha tutarlı sonuçlar verebiliyor. Yerel (local) kurulum ise hem gizlilik hem de maliyet açısından önemli: veriniz üçüncü taraf servislere gitmez, altyapı kontrolü sizde olur ve test/deneme döngüsü hızlanır.

Bu yazıda Docker Compose kullanarak güncel ve pratik bir RAG altyapısının çekirdeğini kuracağız: PostgreSQL üzerinde pgvector eklentisi ile vektör arama, ve bu veritabanına bağlanan örnek bir API katmanı. Amaç; doküman parçalarını (chunk) vektör olarak saklamak, benzerlik araması yapmak ve uygulamalar için tekrar kullanılabilir bir iskelet oluşturmaktır.

Mimari: Hangi Parçalar Var?

Kurulum üç ana parçadan oluşur: (1) PostgreSQL + pgvector: embedding’leri saklar ve benzerlik araması yapar. (2) API: doküman ekleme ve arama uçlarını sunar. (3) İsterseniz ileride LLM entegrasyonu: burada odak veritabanı ve retrieval tarafı olduğu için LLM kısmını opsiyonel bırakıyoruz. Bu iskelet, ister kendi LLM’inizle ister bir harici model API’si ile kolayca genişletilebilir.

Ön Koşullar

Bilgisayarınızda Docker ve Docker Compose kurulu olmalı. Windows’ta Docker Desktop, macOS’ta Docker Desktop, Linux’ta Docker Engine + Compose eklentisi yeterlidir. Ayrıca komut satırı kullanımı ve temel PostgreSQL kavramlarına aşinalık işinizi kolaylaştırır.

1) Docker Compose Dosyasını Hazırlama

Projeniz için bir klasör açın (ör. rag-local) ve içine docker-compose.yml dosyası oluşturun. Aşağıdaki yapı PostgreSQL’i pgvector etkin şekilde başlatır ve örnek bir API servisini ayağa kaldırır. API tarafını kendi projenize göre değiştirebilirsiniz; burada amaç, servislerin bir arada çalıştığı “omurga”yı kurmak.

docker-compose.yml içeriği:

Not: Aşağıdaki bloğu olduğu gibi ekleyebilirsiniz.

YAML:

version: "3.9"
services:
  db:
    image: pgvector/pgvector:pg16
    container_name: rag_db
    environment:
      POSTGRES_USER: rag
      POSTGRES_PASSWORD: ragpass
      POSTGRES_DB: ragdb
    ports:
      - "5432:5432"
    volumes:
      - rag_pgdata:/var/lib/postgresql/data
  api:
    image: node:20-alpine
    container_name: rag_api
    working_dir: /app
    volumes:
      - ./api:/app
    environment:
      DATABASE_URL: postgres://rag:ragpass@db:5432/ragdb
    command: sh -c "npm i && npm run dev"
    depends_on:
      - db
    ports:
      - "3000:3000"
volumes:
  rag_pgdata:

Burada kritik kısım, veritabanı imajının pgvector destekli olmasıdır. Böylece ayrı bir eklenti kurma süreciyle uğraşmadan vektör tiplerini ve indeksleri kullanabilirsiniz. API servisi için Node.js seçtik; ancak aynı yaklaşımı Python/FastAPI ya da Go ile de uygulayabilirsiniz.

2) Veritabanında Tablo ve İndeks Oluşturma

Şimdi PostgreSQL tarafında pgvector’ı etkinleştirelim ve RAG için temel bir tablo kuralım. Terminalden Compose’u başlatın:

Komut: docker compose up -d

Ardından veritabanı kabuğuna girip SQL çalıştırın:

Komut: docker exec -it rag_db psql -U rag -d ragdb

SQL adımları:

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE IF NOT EXISTS documents (
  id BIGSERIAL PRIMARY KEY,
  source TEXT NOT NULL,
  chunk TEXT NOT NULL,
  embedding vector(768),
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Benzerlik araması için ivfflat indeks (embedding dolduktan sonra daha verimli olur)
CREATE INDEX IF NOT EXISTS documents_embedding_idx
ON documents USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

Burada vector(768) boyutu örnek bir değerdir. Kullandığınız embedding modeline göre 384, 768, 1024 gibi farklı boyutlar seçebilirsiniz. Boyut ile model çıktısı tutarlı olmak zorunda; aksi halde insert sırasında hata alırsınız.

3) API Katmanını Hızlıca Ayağa Kaldırma

Proje kökünde api adlı klasör oluşturun. İçine basit bir Node.js API koyarak iki uç hazırlayacağız: /ingest (doküman ekleme) ve /search (benzerlik araması). Örnek olması açısından sade tutuldu; prod ortamda doğrulama, rate limit, kuyruk (queue) ve gözlemlenebilirlik eklemek gerekir.

api/package.json:

{
  "name": "rag-api",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "node index.js"
  },
  "dependencies": {
    "express": "^4.19.2",
    "pg": "^8.12.0"
  }
}

api/index.js:

import express from "express";
import pg from "pg";

const app = express();
app.use(express.json({ limit: "2mb" }));

const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });

// ingest: { source, chunk, embedding: [..] }
app.post("/ingest", async (req, res) => {
  const { source, chunk, embedding } = req.body;
  if (!source || !chunk || !Array.isArray(embedding)) {
    return res.status(400).json({ error: "source, chunk ve embedding (array) zorunlu" });
  }
  const emb = `[${embedding.join(",")}]`;
  await pool.query(
    "INSERT INTO documents(source, chunk, embedding) VALUES ($1, $2, $3::vector)",
    [source, chunk, emb]
  );
  res.json({ ok: true });
});

// search: { embedding: [..], topK: 5 }
app.post("/search", async (req, res) => {
  const { embedding, topK = 5 } = req.body;
  if (!Array.isArray(embedding)) {
    return res.status(400).json({ error: "embedding (array) zorunlu" });
  }
  const emb = `[${embedding.join(",")}]`;
  const { rows } = await pool.query(
    `SELECT id, source, chunk,
      1 - (embedding <=> $1::vector) AS score
      FROM documents
      ORDER BY embedding <=> $1::vector
      LIMIT $2`,
    [emb, topK]
  );
  res.json({ results: rows });
});

app.listen(3000, () => console.log("RAG API 3000 portunda çalışıyor"));

Bu API, embedding üretmez; embedding’i dışarıdan bekler. Böylece hangi embedding modelini kullanacağınızı (yerel bir model, bir CLI aracı veya bir bulut servisi) siz belirlersiniz. RAG projelerinde bu ayrım pratik bir avantaj sağlar: depolama/arama altyapısı sabit kalırken model katmanı kolay değişir.

4) Test: Veri Ekleme ve Arama

Servisler ayaktayken basit bir test yapabilirsiniz. Örnek olarak 768 boyut yerine kısa bir vektörle test etmek istiyorsanız tablo boyutunu da ona göre ayarlamanız gerekir. Gerçek kullanımda modelin ürettiği boyutla aynı vektörü göndermelisiniz. Uygulamada tipik akış şudur: (1) dokümanı parçalara böl, (2) her parça için embedding üret, (3) /ingest ile kaydet, (4) kullanıcı sorusu için embedding üret, (5) /search ile en alakalı parçaları çek, (6) bu parçaları LLM’e bağlam olarak ver.

Benzerlik metriklerinde en sık kullanılan seçenekler cosine ve L2’dir. Burada vector_cosine_ops ve <=> operatörü ile cosine mesafesine dayalı sıralama yapıyoruz. Sonuçtaki score alanı basit bir dönüştürme ile “yakınlık” hissi verir; uygulamanızda eşik (threshold) tanımlayarak düşük skorlu sonuçları elemek iyi bir pratik olabilir.

Performans ve Üretim Notları

Yerel RAG ortamı hızlı sonuç verir ama birkaç noktaya dikkat etmek gerekir. ivfflat indeks, veri büyüdükçe anlamlı hale gelir; küçük veri setlerinde tam tarama bazen daha tutarlı sonuç verebilir. Ayrıca ivfflat için ANALYZE çalıştırmak ve “lists” parametresini veri boyutuna göre ayarlamak önemlidir. Daha ileri seviyede hnsw gibi indeks türlerini ve PostgreSQL ayarlarını (work_mem, maintenance_work_mem) incelemek performansı ciddi şekilde artırabilir.

Güvenlik tarafında ise API’ye kimlik doğrulama eklemek, veritabanı şifresini .env dosyasına almak, ağ izolasyonu yapmak ve logları izlemek temel gereksinimlerdir. Bu iskeleti kendi projelerinize uyarlarken en büyük kazanım, retrieval katmanını standardize etmeniz olur; çünkü RAG projelerinde asıl fark genellikle doğru chunking, iyi embedding seçimi ve doğru indeks/parametre kombinasyonunda ortaya çıkar.

20 Ocak 2026 Salı

Windows 11’de WSL2 ile Docker Desktop Kullanmadan Docker Kurulumu ve Performans Ayarları

WSL2 ile “hafif” Docker fikri neden mantıklı?

Windows 11 üzerinde Docker çalıştırmanın en popüler yolu Docker Desktop. Ancak bazı senaryolarda (kurumsal lisans politikaları, kaynak tüketimi, arka planda çalışan servisler, ekstra arayüz katmanı) Docker Desktop yerine doğrudan WSL2 içinde Docker Engine kurmak daha temiz bir çözüm olabiliyor. Bu yazıda, Docker Desktop kullanmadan WSL2 üzerinde Docker’ı kuracağız; ardından performans ve disk kullanımını iyileştiren birkaç kritik ayarı yapacağız.

Ön koşullar

Gerekenler: Windows 11, yönetici yetkisi, WSL2 desteği ve bir Linux dağıtımı (Ubuntu önerilir). Windows tarafında WSL2 etkin değilse önce etkinleştirmeniz gerekir. Ayrıca BIOS/UEFI’de sanallaştırmanın açık olması, WSL2’nin stabil çalışması için önemlidir.

Adım 1: WSL2 ve Ubuntu kurulumu

PowerShell’i yönetici olarak açıp aşağıdaki komutu çalıştırın. Bu komut WSL’yi kurar ve varsayılan olarak Ubuntu’yu indirip kurabilir:

Komut: wsl --install

Kurulumdan sonra bilgisayarınızı yeniden başlatın. Ardından Ubuntu ilk açılışta kullanıcı adı/şifre oluşturmanızı ister. Mevcut WSL dağıtımlarınızı görmek için:

wsl -l -v

Burada dağıtımınızın Version 2 olduğundan emin olun. Değilse:

wsl --set-version Ubuntu 2

Adım 2: WSL2 içinde Docker Engine kurulumu

Ubuntu terminalini açın ve sistemi güncelleyin:

sudo apt update && sudo apt upgrade -y

Docker’ın resmi deposunu eklemek güncel sürüm için daha sağlıklıdır. Sırasıyla şu komutları çalıştırın:

sudo apt install -y ca-certificates curl gnupg

sudo install -m 0755 -d /etc/apt/keyrings

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update

Şimdi Docker Engine ve gerekli bileşenleri kurun:

sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Adım 3: Docker’ı root’suz kullanmak (sudo derdini bitirin)

Geliştirici deneyimi açısından en önemli adım: kullanıcıyı docker grubuna eklemek. Böylece her komutta sudo yazmanız gerekmez.

sudo usermod -aG docker $USER

Değişikliğin uygulanması için Ubuntu oturumunu kapatıp açın ya da şu komutla kabuğu yenileyin:

newgrp docker

Docker’ın çalıştığını doğrulamak için:

docker run --rm hello-world

Adım 4: WSL2’de Docker servisini otomatik başlatma

WSL, klasik Linux gibi her zaman systemd ile açılmayabilir. Windows 11 ve güncel WSL sürümlerinde systemd desteği var. Etkinleştirerek Docker’ın açılışta başlamasını sağlayabilirsiniz.

WSL içinde /etc/wsl.conf dosyasını düzenleyin:

sudo nano /etc/wsl.conf

İçerik şu şekilde olsun:

[boot] systemd=true

Ardından Windows tarafında WSL’yi yeniden başlatın:

wsl --shutdown

Ubuntu’yu tekrar açınca Docker servisini başlatıp kalıcı hale getirebilirsiniz:

sudo systemctl enable --now docker

Adım 5: Performans için kritik ayar: proje dosyalarını nereye koymalısınız?

WSL2’de en sık yapılan hata, proje klasörünü /mnt/c gibi Windows dosya sistemi altında tutup Docker build ve bind mount işlemlerini burada yapmak. Bu kullanım çalışır ama dosya erişimi katmanı nedeniyle özellikle Node.js, PHP, Python gibi çok sayıda küçük dosya okuyan projelerde performans düşebilir.

Öneri: Kodunuzu WSL2 Linux dosya sistemi içinde (ör. /home/kullanici/proje) tutun. Windows’tan erişmek için de Dosya Gezgini’ne \\wsl$ yazarak Ubuntu dizinlerine ulaşabilirsiniz. Bu sayede Docker build süreleri ve canlı geliştirme (hot reload) daha stabil hale gelir.

Adım 6: Disk şişmesini kontrol etme ve temizlik

Docker kullanırken imajlar ve kullanılmayan katmanlar zamanla disk alanını şişirir. Düzenli aralıklarla temizlik yapmak iyi bir alışkanlık:

docker system df

docker system prune -a

Eğer sadece kullanılmayan container’ları ve dangling imajları temizlemek isterseniz daha güvenli bir yaklaşım seçebilirsiniz. Ancak prune -a tüm kullanılmayan imajları da siler; tekrar gerektiğinde yeniden indirmek zorunda kalırsınız.

Sık karşılaşılan sorunlar

“Cannot connect to the Docker daemon”: Docker servisi çalışmıyor olabilir. Systemd etkinse sudo systemctl status docker ile kontrol edin. Değilse geçici olarak sudo dockerd ile daemon başlatılabilir, fakat kalıcı çözüm systemd’yi aktif etmektir.

Port çakışmaları: Windows’ta aynı portu kullanan bir servis varsa container ayağa kalksa bile erişim sorunları yaşayabilirsiniz. netstat ile Windows tarafında portu kim kullanıyor bakın ve compose dosyanızdaki portları değiştirin.

Ağ erişimi: WSL2 ağ katmanı NAT üzerinden çalışır. Yerel ağdan WSL2 içindeki bir servise erişmek bazen ekstra yönlendirme gerektirebilir; çoğu geliştirme senaryosunda ise localhost yeterlidir.

Sonuç

Docker Desktop olmadan WSL2 üzerinde Docker Engine kurmak, daha az arka plan bileşeniyle daha “Linux’a yakın” bir deneyim sunar. Özellikle performans hassas projelerde dosyaları Linux tarafında tutmak ve systemd ile Docker’ı otomatik başlatmak günlük kullanım konforunu ciddi şekilde artırır. Bu kurulumla hem docker compose kullanabilir hem de modern buildx özelliklerinden faydalanabilirsiniz.

11 Ocak 2026 Pazar

Docker Compose ile Yerel LLM (Ollama) Kurulumu ve Open WebUI Üzerinden ChatGPT Benzeri Arayüz

Yerelde LLM Çalıştırmak Neden Gündemde?

Bulut tabanlı yapay zekâ servisleri pratik olsa da, veri gizliliği, maliyet ve gecikme (latency) gibi konular birçok kişiyi yerel (local) çözümlere yönlendiriyor. Son dönemde öne çıkan yaklaşımlardan biri, LLM modellerini bilgisayarında veya ev sunucunda çalıştırıp, web arayüzü üzerinden sohbet edebilmek. Bu yazıda, Ollama ile yerel model çalıştırmayı ve Open WebUI ile tarayıcıdan kullanmayı Docker Compose üzerinden adım adım kuracağız. Hedefimiz: birkaç komutla, sürdürülebilir ve güncellenebilir bir kurulum yapmak.

Ön Koşullar ve Sistem Notları

Kurulum Linux tabanlı bir sistemde (Ubuntu/Debian gibi) en sorunsuz şekilde ilerler. macOS ve Windows üzerinde de Docker ile yapılabilir; ancak GPU kullanımı (özellikle NVIDIA) için Linux tarafı daha stabil. Minimumda 8 GB RAM ile küçük modeller çalıştırılabilir; 16 GB ve üzeri daha rahat olur. GPU’nuz varsa performans belirgin şekilde artar. Gerekenler: Docker, Docker Compose ve internete erişim (modeli ilk kez indirirken).

Mimari: Ollama + Open WebUI Nasıl Çalışır?

Ollama, LLM modellerini indirip yerelde servis eden bir katman gibi düşünülebilir. Siz “modeli indir, çalıştır” dersiniz; o da arka tarafta bir API üzerinden yanıt üretir. Open WebUI ise bu API’ye bağlanan modern bir web arayüzüdür. Böylece tarayıcıdan sohbet edebilir, model seçebilir, geçmiş konuşmaları saklayabilir ve temel ayarları yönetebilirsiniz. İkisini Docker Compose ile yönetmek, güncelleme ve taşınabilirlik açısından büyük kolaylık sağlar.

Adım 1: Docker Compose Dosyasını Oluşturma

Önce bir klasör açın ve içine docker-compose.yml dosyası oluşturun. Örnek içerik aşağıdaki gibi olabilir. Bu yapı iki servisi çalıştırır: Ollama ve Open WebUI. Open WebUI, Ollama’nın API’sine bağlanır ve 3000 portundan yayın yapar.

docker-compose.yml:

version: "3.8"
services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    ports:
      - "11434:11434"
    volumes:
      - ollama:/root/.ollama

  openwebui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: openwebui
    restart: unless-stopped
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    depends_on:
      - ollama
    volumes:
      - openwebui:/app/backend/data

volumes:
  ollama:
  openwebui:

Not: Bu örnek temel kurulumdur. NVIDIA GPU ile hızlandırma isterseniz Docker’ın GPU runtime ayarlarını ayrıca yapılandırmanız gerekebilir. CPU ile de çalışır; sadece daha yavaş yanıt alırsınız.

Adım 2: Servisleri Ayağa Kaldırma

Compose dosyasının bulunduğu klasörde şu komutu çalıştırın:

docker compose up -d

Ardından konteynerlerin durumunu kontrol edin:

docker ps

Her şey yolundaysa tarayıcıdan http://localhost:3000 adresine gidin. İlk açılışta Open WebUI sizden bir kullanıcı oluşturmanızı isteyebilir; bu normaldir.

Adım 3: Model İndirme ve İlk Çalıştırma

Ollama tarafında bir model indirmek için iki yol var: Open WebUI içinden model çekmek veya terminalden indirmek. Terminal üzerinden daha kontrol edilebilir olduğu için şu komutla başlayabilirsiniz:

docker exec -it ollama ollama pull llama3.1

Model adı zamanla değişebilir; Ollama’nın desteklediği güncel isimleri kontrol etmek gerekebilir. İndirme bittiğinde Open WebUI’ye dönün. Model seçimi bölümünde indirdiğiniz modeli görüp sohbet başlatabilirsiniz. İlk yanıtlar biraz yavaş gelebilir; modelin “ısınması” ve CPU/GPU durumuna göre performans değişir.

İpuçları: Performans, Depolama ve Güvenlik

Depolama: Modeller büyük yer kaplar. Compose dosyasında tanımlı volume’lar sayesinde konteyner silinse bile modelleriniz kalır. Disk alanınızı izlemek için düzenli kontrol edin.

Performans: Daha küçük bir model seçmek (ör. daha düşük parametreli sürümler) yanıt süresini ciddi biçimde iyileştirir. Ayrıca aynı anda çok uzun bağlam (context) kullanmak RAM tüketimini artırır.

Güvenlik: Kurulumu ev ağı dışına açacaksanız (port yönlendirme gibi), mutlaka ters proxy + HTTPS ve kimlik doğrulama kullanın. Varsayılan şekilde yerelde kullanmak daha güvenlidir.

Sık Karşılaşılan Sorunlar

Open WebUI model görmüyor: OLLAMA_BASE_URL değişkeninin doğru olduğundan emin olun. Compose içinde servis adı “ollama” ise URL de “http://ollama:11434” olmalı. Ayrıca konteynerlerin aynı network’te olması gerekir; Compose bunu varsayılan olarak sağlar.

Yanıtlar çok yavaş: CPU ile çalışıyorsanız bu normal olabilir. Daha küçük model deneyin, arka planda çalışan uygulamaları azaltın. GPU kurulumuna geçmek ciddi fark yaratır.

Port çakışması: 3000 veya 11434 portu başka bir uygulama tarafından kullanılıyorsa, compose dosyasında sol taraftaki portu değiştirin (ör. “3001:8080”).

Sonuç

Docker Compose ile Ollama ve Open WebUI kurmak, yerel LLM dünyasına hızlı bir giriş sunuyor. Kurulum hem taşınabilir hem de güncellemesi kolay: yeni sürümler için genellikle docker compose pull ve docker compose up -d yeterli. En önemlisi, sohbet veriniz ve model kullanımı sizin kontrolünüzde kalıyor. Eğer hedefiniz gizlilik odaklı bir “yerel yapay zekâ asistanı” ise bu ikili, güncel ve pratik bir başlangıç noktası.

23 Aralık 2025 Salı

Docker Compose ile PostgreSQL + pgAdmin Kurulumu: Geliştirme Ortamını 10 Dakikada Ayağa Kaldırma

Hedef: Tek Komutla Veritabanı Ortamı

Yerel geliştirme ortamında PostgreSQL kurmak çoğu zaman “kuruldu mu, servis başladı mı, port çakıştı mı, kullanıcı yetkileri doğru mu?” gibi küçük ama zaman yiyen sorularla uzar. Üstelik ekip çalışmasında herkesin makinesinde aynı sürüm ve aynı ayarlarla çalışmak daha da zorlaşır. Bu yazıda, Docker Compose ile PostgreSQL’i ve yönetim aracı olarak pgAdmin’i birlikte çalıştıran, tekrar üretilebilir (reproducible) bir kurulum hazırlayacağız. Amaç: projeyi klonlayan herkesin tek komutla aynı veritabanına erişebilmesi.

Konu “ileri seviye” tarafına şu noktada yaklaşıyor: sadece konteyneri çalıştırmakla kalmayacağız; kalıcı veri (volume), başlangıç SQL dosyaları, servis bağımlılıkları ve güvenli sayılabilecek temel ayarlarla pratik bir şablon oluşturacağız. Bu yapı; Node.js, Python, Java, .NET gibi farklı backend’lerle rahatça kullanılabilir.

Ön Koşullar

Bilgisayarınızda Docker ve Docker Compose yüklü olmalı. Güncel Docker Desktop sürümlerinde Compose genellikle hazır gelir. Terminalde docker --version ve docker compose version komutlarıyla kontrol edebilirsiniz.

Proje Yapısını Hazırlama

Proje klasörünüzde aşağıdaki gibi bir yapı işinizi kolaylaştırır. Özellikle init dosyalarını ayrı klasörde tutmak, veritabanını ilk kurulumda otomatik hazırlamak için idealdir.

Önerilen dizinler:
- docker-compose.yml
- db/init/01-schema.sql
- db/init/02-seed.sql

docker-compose.yml Dosyası

Aşağıdaki Compose tanımı PostgreSQL (db) ve pgAdmin (pgadmin) servislerini ayağa kaldırır. PostgreSQL verisi named volume ile kalıcı hale gelir; pgAdmin ayarları da ayrı volume’da tutulur. Ayrıca PostgreSQL’e ilk kurulumda SQL çalıştırmak için ./db/init klasörünü otomatik mount ediyoruz.

docker-compose.yml içeriği:

version satırı artık zorunlu olmasa da okunabilirlik için ekleyebilirsiniz. Örnek YAML:

Not: Aşağıdaki blokları dosyanıza aynen yazın (girintiler YAML için kritiktir).

docker-compose.yml
services:
  db:
    image: postgres:16
    container_name: local_postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: apppass
      POSTGRES_DB: appdb
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./db/init:/docker-entrypoint-initdb.d:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
      interval: 5s
      timeout: 3s
      retries: 20

  pgadmin:
    image: dpage/pgadmin4:latest
    container_name: local_pgadmin
    restart: unless-stopped
    environment:
      PGADMIN_DEFAULT_EMAIL: [email protected]
      PGADMIN_DEFAULT_PASSWORD: adminpass
    ports:
      - "5050:80"
    volumes:
      - pgadmin_data:/var/lib/pgadmin
    depends_on:
      db:
        condition: service_healthy

volumes:
  postgres_data:
  pgadmin_data:

Başlangıç SQL Dosyaları (Opsiyonel ama Çok Faydalı)

PostgreSQL’in resmi imajı, ilk kez boş bir data dizini oluştururken /docker-entrypoint-initdb.d altındaki .sql dosyalarını otomatik çalıştırır. Bu sayede tablo şemasını ve örnek veriyi sürüm kontrolüne alabilirsiniz. Örnek iki dosya hazırlayalım:

db/init/01-schema.sql

CREATE TABLE IF NOT EXISTS users (
  id SERIAL PRIMARY KEY,
  email TEXT UNIQUE NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

db/init/02-seed.sql

INSERT INTO users (email) VALUES ('[email protected]')
ON CONFLICT DO NOTHING;

Buradaki önemli detay: init dosyaları sadece veritabanı ilk kez oluşturulurken devreye girer. Eğer volume zaten doluysa ve siz SQL’i değiştirdiyseniz, değişikliğin uygulanması için ya manuel migration çalıştırmanız ya da geliştirme ortamında ilgili volume’u temizleyip yeniden başlatmanız gerekir.

Servisleri Başlatma

Aynı klasörde terminal açın ve şu komutu çalıştırın:

docker compose up -d

Ardından konteynerlerin durumunu görmek için:

docker compose ps

pgAdmin ile Bağlantı Kurma

Tarayıcıdan http://localhost:5050 adresine gidin. Giriş için Compose dosyasındaki PGADMIN_DEFAULT_EMAIL ve PGADMIN_DEFAULT_PASSWORD değerlerini kullanın. Yeni bir server kaydı eklerken:

Host name/address: db
Port: 5432
Maintenance database: appdb
Username: appuser
Password: apppass

Burada “host” olarak db yazmamızın sebebi, Compose ağında servis isimlerinin DNS gibi çalışmasıdır. Yani pgAdmin konteyneri, PostgreSQL’e db:5432 üzerinden erişir.

Sık Karşılaşılan Sorunlar ve İpuçları

Port çakışması: Makinenizde 5432 zaten kullanılıyorsa, “5432:5432” satırını örneğin “5433:5432” yapın. Uygulamanızdan bağlanırken host portunu (5433) kullanırsınız.

Şifreleri dosyaya yazmak: Bu örnek geliştirme içindir. Ekip içinde daha güvenli kullanım için ortam değişkenlerini .env dosyasına taşıyıp Compose’dan çağırabilirsiniz.

Veriyi sıfırlama: Tamamen temiz kurulum için servisleri durdurup volume’ları silin: docker compose down -v. Sonra tekrar docker compose up -d dediğinizde init SQL dosyaları yeniden çalışır.

Sonuç

Docker Compose ile PostgreSQL + pgAdmin kurulumu, hem tek kişilik projelerde hem de ekip çalışmalarında standart bir geliştirme zemini sağlar. En büyük kazanım; “benim makinemde çalışıyor” problemini azaltmanız, versiyon uyumunu korumanız ve veritabanını birkaç komutla yönetebilmenizdir. Bu şablonu temel alıp Redis, MinIO, Kafka gibi servisleri de aynı Compose dosyasına ekleyerek daha kapsamlı bir yerel ortam kurabilirsiniz.

18 Aralık 2025 Perşembe

Docker Compose ile Yerel Geliştirme Ortamı Kurma: PostgreSQL + Redis + Uygulama Servisi (İleri Seviye How-To)

Docker Compose neden hâlâ en pratik seçenek?

Yerel geliştirme ortamı kurarken en çok vakit yediren şey, bağımlılıkların (veritabanı, cache, mesaj kuyruğu, reverse proxy vb.) makineden makineye farklı davranmasıdır. Docker Compose, birden fazla servisi tek bir dosyada tanımlayıp ayağa kaldırarak “bende çalıştı” problemini ciddi ölçüde azaltır. Bu yazıda PostgreSQL ve Redis’i, bir uygulama servisiyle birlikte aynı ağda koşturacak; kalıcı veri, healthcheck, profil ve ortam değişkeni yönetimi gibi ileri seviye pratiklere değineceğiz.

1) Proje yapısı: düzenli başlamak önemli

Örnek bir dizin yapısı oluşturalım. Terminalde bir klasör açıp içerisine aşağıdaki gibi dosyalar koymanız yeterli: docker-compose.yml, .env ve isterseniz uygulamanız için bir Dockerfile. Uygulama diliniz önemli değil; Compose tarafında servislerin birbirini görmesi ve konfigürasyonun taşınabilir olması hedef.

2) .env ile gizli bilgileri yönetmek

Compose dosyasına gömmek yerine şifreleri ve sık değişen değerleri .env içine almak daha temizdir. Proje köküne bir .env dosyası oluşturun ve örnek olarak şunları ekleyin: POSTGRES_DB=appdb, POSTGRES_USER=appuser, POSTGRES_PASSWORD=gucluSifre123, REDIS_PASSWORD=redisSifre123. Bu dosyayı versiyon kontrolüne koymamayı unutmayın; gerekirse örnek bir .env.example

3) docker-compose.yml: PostgreSQL + Redis + app

Aşağıdaki Compose tanımı, üç servisi aynı network üzerinde çalıştırır. PostgreSQL için kalıcı volume, Redis için parola ve iki servis için healthcheck ekledik. Uygulama servisini ise örnek bir “app” konteyneri olarak tanımlıyoruz; burada kendi Dockerfile’ınızı kullanabilir ya da hazır bir imajla test edebilirsiniz.

docker-compose.yml içeriği:

version: "3.9"
services:
  db:
    image: postgres:16-alpine
    container_name: local-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 5s
      timeout: 3s
      retries: 20

  redis:
    image: redis:7-alpine
    container_name: local-redis
    restart: unless-stopped
    command: ["sh", "-c", "redis-server --requirepass ${REDIS_PASSWORD}"]
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD-SHELL", "redis-cli -a ${REDIS_PASSWORD} ping | grep PONG"]
      interval: 5s
      timeout: 3s
      retries: 20

  app:
    build: .
    container_name: local-app
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
      REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0
    ports:
      - "8080:8080"

volumes:
  pgdata:

4) Uygulama servisi için minimal Dockerfile fikri

“app” servisi için örnek bir Dockerfile ihtiyacınız olacak. Kendi stack’inize göre değişir; ancak temel prensip aynıdır: bağımlılıkları kur, kaynak kodu kopyala, uygulamayı çalıştır. Örneğin Node.js kullanıyorsanız node:20-alpine ile başlayabilir; Python’da python:3.12-slim tercih edebilirsiniz. Önemli nokta, Compose içindeki bağlantı adreslerinin db ve redis servis adları üzerinden verilmesidir; çünkü konteynerlar aynı Compose ağı içinde DNS ile birbirini bu isimlerle bulur.

5) Çalıştırma, log takibi ve durdurma

Kurulumdan sonra proje kökünde şu komut yeterlidir: docker compose up -d. İlk çalıştırmada imajlar indirileceği için birkaç dakika sürebilir. Servislerin durumunu görmek için docker compose ps, logları takip etmek için docker compose logs -f kullanın. Her şeyi kapatmak için docker compose down işinizi görür; veriyi de silmek istiyorsanız (PostgreSQL volume) docker compose down -v uygulayabilirsiniz.

6) Sık yapılan hatalar ve pratik ipuçları

En yaygın hata, uygulama içinde veritabanına localhost ile bağlanmaya çalışmaktır. Konteyner içinden “localhost”, o konteynerın kendisini ifade eder; bu yüzden bağlantı adresi db:5432 olmalı. İkinci hata, servisler hazır olmadan uygulamanın ayağa kalkmasıdır; burada kullandığımız healthcheck ve depends_on condition: service_healthy yaklaşımı bu sorunu büyük ölçüde azaltır. Son olarak, geliştirme sürecinde dosya değişikliklerini anında görmek istiyorsanız volumes ile proje klasörünü konteynere mount edebilir, fakat bu ayarı işletim sisteminize ve kullandığınız dile göre dikkatle yapmalısınız.

Sonuç: taşınabilir, tekrarlanabilir bir yerel ortam

Bu yapı sayesinde PostgreSQL ve Redis’i tek komutla ayağa kaldırıp uygulamanızla aynı ağda konuşturabilirsiniz. Üstelik ekipteki herkes aynı Compose dosyasını kullandığı için ortam farklılıkları azalır, hata ayıklama hızlanır. İsterseniz bir sonraki adım olarak profil ekleyip (ör. test/prod), ya da ters proxy (Nginx/Traefik) ile TLS ve routing katmanı ekleyerek daha da gerçekçi bir geliştirme ortamı kurabilirsiniz.

18 Kasım 2025 Salı

Docker Compose ile Traefik v3, Cloudflare ve Let's Encrypt ile Otomatik Reverse Proxy Kurulumu

Giriş

Kendi sunucunuzda birden fazla web uygulamasını alan adlarıyla yönetmek, güvenli SSL sertifikalarını otomatik yenilemek ve trafik yönlendirmelerini zahmetsizce yapmak istiyorsanız, Traefik v3 sizin için biçilmiş kaftan. Bu yazıda, Docker Compose kullanarak Traefik v3 ile Cloudflare DNS ve Let’s Encrypt entegrasyonunu adım adım kuracağız. Hedefimiz: tek bir reverse proxy arkasında otomatik HTTPS, kolay yönlendirme ve minimum bakım maliyeti.

Neden Traefik v3?

Traefik, container tabanlı ortamlarda dinamik servis keşfi, otomatik TLS ve güçlü yönlendirme kurallarıyla öne çıkıyor. v3 sürümü, performans ve güvenlik iyileştirmeleri ile birlikte yapılandırma tutarlılığı sunuyor. Docker üzerinde çalışan mikro servisleriniz için exposedByDefault=false gibi güvenli varsayılanlarla ince ayar yapmak da oldukça kolay.

Önkoşullar

- Docker ve Docker Compose kurulu bir Linux sunucu (ör. Ubuntu 22.04).

- 80 ve 443 portlarının dış dünyaya açık olması.

- Alan adınız Cloudflare üzerinde yönetiliyor olmalı.

- Cloudflare üzerinde DNS düzenleme yetkisine sahip bir API Token (Zone.DNS.Edit, Zone.Read).

- Let’s Encrypt için bir e-posta adresi.

Adım 1: Cloudflare API Token oluşturun

Cloudflare hesabınızda User Profile > API Tokens > Create Token yolunu izleyin. “Edit zone DNS” şablonunu seçip alan adınızı kısıtlayın. Token’ı güvenle saklayın; birazdan docker-compose içinde kullanacağız.

Adım 2: Proje dizinini hazırlayın

Sunucuda boş bir klasör oluşturup içine docker-compose.yml ve isteğe bağlı .env dosyası yerleştireceğiz. Aşağıdaki örnek, Traefik v3’ü, Cloudflare DNS-01 challenge ile Let’s Encrypt sertifika yenilemesi yapacak şekilde hazırlar.

version: "3.8"

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    command:
      - --api.dashboard=true
      - --providers.docker=true
      - --providers.docker.exposedByDefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - [email protected]
      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.letsencrypt.acme.dnschallenge=true
      - --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare
    ports:
      - "80:80"
      - "443:443"
    environment:
      - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`)"
      - "traefik.http.routers.http-catchall.entrypoints=web"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
      - "traefik.http.routers.traefik.rule=Host(`proxy.example.com`)"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.middlewares.dashboard-auth.basicauth.users=${TRAEFIK_DASHBOARD_USER}:${TRAEFIK_DASHBOARD_HASH}"
      - "traefik.http.routers.traefik.middlewares=dashboard-auth"

  whoami:
    image: traefik/whoami:latest
    container_name: whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`demo.example.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"

Yukarıdaki örnekte dashboard’ı proxy.example.com üzerinden Basic Auth ile koruyoruz. whoami servisi ise demo.example.com üzerinden otomatik TLS ile yayınlanacak. Cloudflare tarafında bu iki alt alan adını A/AAAA kaydıyla sunucunuza yönlendirin. Cloudflare “turuncu bulut” (proxy) açık olabilir; DNS-01 challenge, proxied modda da sorunsuz çalışır.

Adım 3: Ortam değişkenleri ve parola karması

.env dosyanıza aşağıdaki gibi değerleri ekleyin. Basic Auth için bir bcrypt karma gerekir. Linux’ta hızla üretmek için şu komutu kullanabilirsiniz: htpasswd -nbB admin 'Sifre123' çıktısındaki admin:$2y$... kısmını kopyalayın.

CF_DNS_API_TOKEN=cf_api_tokeniniz_buraya
TRAEFIK_DASHBOARD_USER=admin
TRAEFIK_DASHBOARD_HASH=$2y$05$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Adım 4: Servisleri başlatın

Klasörde docker compose up -d komutunu çalıştırın. İlk kurulumda Let’s Encrypt DNS-01 challenge ile TXT kaydı oluşturup doğrulama yapar ve acme.json içine sertifikaları yazar. Ardından https://demo.example.com adresini açtığınızda whoami çıktısını, https://proxy.example.com adresini açtığınızda ise kimlik doğrulama sonrası Traefik dashboard’ını görmelisiniz.

İpuçları ve iyi uygulamalar

- letsencrypt klasörünün izinlerini 600 veya 700 seviyesinde tutun; acme.json hassas bilgiler içerir.

- production ortamında traefik konteynerinin yalnızca ihtiyaç duyduğu ağlara eriştiğinden emin olun; Docker network’leri ile segmentasyon yapın.

- Rate limitlere takılmamak için Let’s Encrypt’in staging ortamını testlerde kullanabilirsiniz: --certificatesresolvers.letsencrypt.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory parametresini ekleyip denemeler tamamlanınca kaldırın.

- Cloudflare’de DNSSEC aktifse, zone yapılandırmanızın doğru olduğundan emin olun; yanlış DS kayıtları çözümleme sorunlarına neden olabilir.

Sık karşılaşılan hatalar ve çözümler

- Giriş başarısız: CF_DNS_API_TOKEN yetkileri eksik olabilir. Token’a Zone.DNS.Edit ve Zone.Read sağlandığından ve doğru zone’da sınırlandığından emin olun.

- Sertifika alınamıyor: Alan adınız doğru IP’ye işaret ediyor mu? DNS yayılımı tamamlandı mı? Ayrıca Cloudflare’de CNAME flattening ayarları bazen beklenmedik davranışlar gösterebilir; A kaydıyla test etmek daha sağlıklıdır.

- 404 veya yönlendirme döngüsü: http-catchall ve redirect-to-https etiketlerinin çakışmadığından emin olun. Aynı ana bilgisayar için hem http hem https router tanımlarını kontrol edin.

Sonuç

Bu kurulumla Docker tabanlı servisleriniz için modern, güvenli ve otomatik bir reverse proxy katmanı elde ettiniz. Traefik v3, Cloudflare DNS-01 ve Let’s Encrypt birleşimi; mikro servislerinizi hızlıca yayına almanızı, sertifikaları otomatik yenilemeyi ve tek noktadan görünürlük sağlamayı mümkün kılıyor. Bundan sonra yeni bir servis eklemek yalnızca birkaç label yazmak kadar basit. Üstelik, aynı mimariyi staging ve production çevrelerinde tekrar kullanarak sürdürülebilir bir dağıtım modeli kurabilirsiniz.

20 Ekim 2025 Pazartesi

Traefik v3 ile Docker Compose Üzerinde Çoklu Alan Adı ve Otomatik SSL: Adım Adım Rehber

Bir sunucuda birden fazla web uygulamasını farklı alan adlarıyla güvenli (HTTPS) şekilde yayınlamak istiyorsanız, modern bir ters proxy çözümü olan Traefik v3 harika bir seçenek. Bu rehberde, Docker Compose kullanarak Traefik v3 ile otomatik Let’s Encrypt sertifika yönetimini, HTTP’den HTTPS’e yönlendirmeyi ve birden fazla alan adını tek yapılandırmada yönetmeyi adım adım göstereceğim.

Traefik v3 nedir ve neden tercih edilmeli?

Traefik v3, konteyner tabanlı mimariler için optimize edilmiş, otomatik keşif ve sade etiketleme (label) mantığıyla çalışan bir ters proxy ve yük dengeleyicidir. Docker, Kubernetes ve diğer sağlayıcılarla derin entegrasyon sunar. v3 sürümü, performans ve yapılandırma deneyiminde iyileştirmeler getirirken, Let’s Encrypt ile otomatik TLS/SSL sertifikalandırmayı pratik hale getirir.

Ön koşullar ve DNS

- Bir Linux sunucu (Ubuntu/Debian/CentOS vb.)

- Docker ve Docker Compose kurulu

- Alan adınızda, sunucunuzun IP adresine işaret eden A/AAAA kayıtları (örnek: app.example.com ve traefik.example.com)

İpucu: Cloudflare kullanıyorsanız ve HTTP-01 doğrulaması yapacaksanız, ilgili DNS kaydını “DNS only” (turuncu bulut kapalı) olarak ayarlayın; aksi halde Let’s Encrypt doğrulaması başarısız olabilir.

Adım 1: Docker ağı ve klasörler

Aşağıdaki ağ, farklı Compose dosyaları arasında servisleri paylaşmanızı sağlar. Oluşturun:

docker network create web
mkdir -p traefik/letsencrypt
touch traefik/letsencrypt/acme.json
chmod 600 traefik/letsencrypt/acme.json

Adım 2: Traefik v3 için docker-compose.yml

Aşağıdaki dosya, Traefik’i 80/443 portlarına bağlar, Let’s Encrypt’i HTTP-01 ile etkinleştirir, HTTP’yi otomatik olarak HTTPS’e yönlendirir ve güvenli bir kontrol paneli kurar. E-postayı ve alan adlarını kendinize göre düzenlemeyi unutmayın.

version: "3.8"

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - [email protected]
      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.letsencrypt.acme.httpchallenge=true
      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
      - --api.dashboard=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik/letsencrypt:/letsencrypt
    networks:
      - web
    labels:
      - "traefik.enable=true"
      # Dashboard için güvenli router
      - "traefik.http.routers.api.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.api.service=api@internal"
      - "traefik.http.routers.api.entrypoints=websecure"
      - "traefik.http.routers.api.tls.certresolver=letsencrypt"
      # Basit BasicAuth middleware (parolayı hashleyip $$ ile kaçırın)
      - "traefik.http.middlewares.basicauth.basicauth.users=admin:$$2y$$12$$REPLACE_WITH_YOUR_BCRYPT_HASH"
      - "traefik.http.routers.api.middlewares=basicauth@docker"

  # Örnek uygulama
  whoami:
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`app.example.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
    networks:
      - web

networks:
  web:
    external: true

Bu dosyada iki önemli nokta var: “exposedbydefault=false” etiketsiz konteynerların dış dünyaya açılmasını engeller; “http redirections” ise tüm HTTP trafiğini otomatik olarak HTTPS’e taşır. Dashboard’ı traefik.example.com üzerinden basit bir BasicAuth ile koruyoruz. Parola hash’ini üretmek için şu komutlardan birini kullanabilirsiniz:

# OpenSSL ile bcrypt:
htpasswd -nbB admin SIFRENIZ

# Ya da Python:
python3 -c "import bcrypt; print(b'admin:' + bcrypt.hashpw(b'SIFRENIZ', bcrypt.gensalt()))"

Elde ettiğiniz hash’i compose dosyasına yapıştırırken $ karakterlerini $$ ile kaçırın; aksi halde Compose bunu çevresel değişken sanacaktır.

Adım 3: Servis ekleme ve çoklu alan adı

Yeni bir servis eklemek için ilgili konteynere “traefik.enable=true” etiketi ve “rule=Host(`sub.example.com`)" kuralı tanımlayın. Her servis için ayrı router, entrypoint ve TLS resolver atayabilirsiniz. Örneğin bir Node.js uygulaması için:

myapp:
  image: node:20-alpine
  working_dir: /app
  command: ["node", "server.js"]
  volumes:
    - ./myapp:/app
  labels:
    - "traefik.enable=true"
    - "traefik.http.routers.myapp.rule=Host(`api.example.com`)"
    - "traefik.http.routers.myapp.entrypoints=websecure"
    - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
  networks:
    - web

Statik dosya sunucuları, PHP-FPM arkasındaki Nginx veya Go/Rust uygulamaları da benzer şekilde etiketlenir. Tüm servisler aynı “web” ağına bağlı oldukça Traefik onları otomatik keşfeder.

Güvenlik ve en iyi uygulamalar

- Dashboard’ı mutlaka alt alan adı ve BasicAuth (veya IP kısıtlaması) ile koruyun.

- “acme.json” dosyasını 600 izinleriyle saklayın; sertifika anahtarları bu dosyada tutulur.

- Gereksiz portları açmayın; yalnızca 80 ve 443 çoğu kurulum için yeterlidir.

- Üretimde otomatik yeniden başlatma politikası (“restart: unless-stopped”) kullanabilirsiniz.

Sık karşılaşılan hatalar ve çözümler

- Sertifika alınamadı: DNS kayıtlarınız doğru mu? Cloudflare “proxied” açık mı? HTTP-01 için kapalı olmalı. Alternatif olarak DNS-01 challenge kullanarak wildcard (*.example.com) alabilirsiniz.

- 80/443 dinlenemiyor: Sunucuda bu portları kullanan farklı bir servis (ör. Nginx) çalışıyor olabilir. Kapatın veya taşıyın.

- Rate limit: Let’s Encrypt test sırasında üretim yerine staging sunucularını deneyin. Traefik için “acme.caserver” parametresiyle staging’e geçebilirsiniz.

- “acme.json permission denied”: Dosya izinlerini 600 yapın ve doğru mount yolunu kontrol edin.

Sonuç

Traefik v3 ve Docker Compose ile çok sayıda servisi tek bir sunucu üzerinde, otomatik SSL ve modern yönlendirme yetenekleriyle dakikalar içinde yayına alabilirsiniz. Etiket tabanlı mimari, CI/CD süreçlerine rahatça entegre olurken, yeniden başlatma ihtiyacı olmadan konfigürasyon değişikliklerini devreye almanızı sağlar. Üstelik ölçeklenebilir ve gözlemlenebilir bir altyapının temelini atmış olursunuz.

17 Eylül 2025 Çarşamba

Docker Compose ile Yerel LLM Kurulumu: Ollama ve Open WebUI (Llama 3.1 8B Rehberi)

Özet ve Amaç

Yerel büyük dil modeli (LLM) çalıştırmak artık sadece veri bilimi ekiplerinin değil, geliştiricilerin ve meraklı kullanıcıların da gündeminde. Bu rehberde, Docker Compose kullanarak Ollama ve Open WebUI ile bilgisayarınızda Llama 3.1 8B modelini nasıl çalıştıracağınızı adım adım anlatıyorum. Kurulum tamamen yerel olduğu için gizlilik avantajı sağlar, gecikme süresini düşürür ve internet erişimi olmadan üretken yapay zeka deneyimi yaşatır.

Gereksinimler

- İşletim sistemi: Linux, macOS veya Windows (Windows için WSL2 önerilir).
- Donanım: En az 16 GB RAM önerilir. GPU şart değil; olsa da performans artar. NVIDIA GPU hızlandırması için Linux + NVIDIA Container Toolkit gerekir.
- Yazılım: Docker ve Docker Compose (Docker Desktop içerir).
- İnternet: İlk model indirme için gerekli.

Adım 1: Docker’ı Hazırlayın

Docker yüklü değilse Docker Desktop’ı kurun. Kurulum sonrası aşağıdaki komutlarla sürümü doğrulayın:
docker --version
docker compose version
Her iki komut da sürüm döndürüyorsa hazırsınız.

Adım 2: Proje Klasörü ve Compose Dosyası

Boş bir klasör oluşturun ve kök dizine docker-compose.yml dosyasını ekleyin. Aşağıdaki içerik, Ollama ve Open WebUI’yi tek komutla ayağa kaldırır. WebUI, Ollama’yı dahili ağ üzerinden görecek şekilde ayarlanmıştır.

version: "3.9"
services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama:/root/.ollama
    restart: unless-stopped

  open-webui:
    image: ghcr.io/open-webui/open-webui:latest
    container_name: open-webui
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    depends_on:
      - ollama
    volumes:
      - openwebui:/app/backend/data
    restart: unless-stopped

volumes:
  ollama:
  openwebui:

Not: GPU hızlandırması istiyorsanız Linux’ta NVIDIA Container Toolkit kurup Ollama servisini GPU ile çalıştırabilirsiniz. Compose tarafında farklı varyasyonlar olsa da en sorunsuz yol genellikle tek servis için docker run --gpus all ... kullanmaktır. Bu rehber CPU’da sorunsuz çalışan kurulum üzerine odaklanır.

Adım 3: Servisleri Başlatın

Proje klasörünüzde şu komutu çalıştırın:
docker compose up -d
İlk kurulumda imajlar indirileceği için biraz zaman alabilir. Durumu görmek için:
docker compose ps ve docker compose logs -f ollama komutlarını kullanabilirsiniz.

Adım 4: Modeli İndirin (Llama 3.1 8B)

Ollama konteynerine girip modeli çekin:
docker exec -it ollama bash
ollama pull llama3.1:8b
İlk indirme birkaç GB olabilir. Sisteminizin RAM ve disk durumuna göre indirip hazırlayacaktır. Daha az bellek kullanan kuantize sürümler için Ollama içindeki etiketleri inceleyebilir veya ollama run llama3.1:8b ile doğrudan test edebilirsiniz.

Adım 5: Open WebUI ile Görsel Arayüz

Tarayıcınızda http://localhost:3000 adresine gidin. İlk açılışta basit bir kayıt formu çıkabilir. Ardından sol alttaki model listesinden llama3.1:8b seçin. Eğer listede görünmüyorsa OLLAMA_BASE_URL ayarının http://ollama:11434 olduğundan ve Ollama servisinin çalışma durumundan emin olun. Alternatif olarak “Add Model” bölümünden ismi elle girebilirsiniz.

Performans İpuçları

- Kuantize modeller: 8B modellerde q4 veya q5 gibi kuantizasyonlar RAM kullanımını ciddi azaltır. Doğruluk bir miktar düşse de masaüstü sistemlerde büyük fark yaratır.
- Bağlam penceresi: Gerekli değilse yüksek context length kullanmayın. Daha az bellek tüketir ve yanıtlar hızlanır.
- Paralellik: Aynı anda çok istek göndermeyin. OLLAMA_NUM_PARALLEL=1 bırakmak çoğu sistemde daha kararlı sonuç verir.

Sorun Giderme

- Port çakışması: 11434 veya 3000 kullanımda ise compose dosyasındaki portları değiştirin (ör. 3001:8080).
- Yavaş ilk yanıt: Model ilk yüklemede belleğe alınır; ikinci istekler daha hızlı olacaktır.
- Bellek yetersiz: Kuantize sürüme geçin veya daha küçük bir model seçin (ör. 7B/8B yerine 3B-4B familyası).
- Güncelleme: docker compose pull ardından docker compose up -d ile imajları güncel tutun.

Güvenlik ve Ağ

Bu kurulum yerel geliştirme içindir. Portları internetten erişilebilir yapmayın. Uzak erişim gerekiyorsa ters proxy ve kimlik doğrulama koyun. Verileriniz container volume’larında tutulur; hassas içerik paylaşıyorsanız yedekleme ve şifreleme politikalarınızı belirleyin.

Sonuç

Dakikalar içinde Docker Compose ile Ollama ve Open WebUI’yi kurup Llama 3.1 8B gibi güncel bir LLM’i yerelde çalıştırabilirsiniz. Bu yaklaşım, gizlilik, kontrol ve düşük gecikme avantajları sunar. İhtiyaçlarınıza göre kuantize modellerle bellek kullanımını düşürüp verimi artırabilir, ileride GPU desteği ekleyerek daha hızlı sonuçlar alabilirsiniz. Yerel LLM ile prototipleme, dahili araç geliştirme ve offline kullanım senaryoları çok daha erişilebilir hale geliyor.