Yazılımcılar Vercel, Netlify veya Heroku’ya self-hosted bir alternatif aradıklarında neredeyse her zaman tanıdık bir tuzağa düşerler: Tek bir uygulama kılığına girmiş hantal bir mikroservis dağıtık sistemi.
Aylık 10 dolarlık mütevazı bir Hetzner ya da DigitalOcean sunucusunda “basit” bir PaaS çalıştırmak istediğinizde, aniden karşınıza şunlar dikilir:
- Sırf rota ve proje meta verilerini saklamak için harici bir PostgreSQL veya MySQL veritabanı.
- Sırf derleme durumu mesajlarını iletmek için bir Redis ya da RabbitMQ kuyruğu.
- Boşta 1.5GB RAM tüketen arka plan işçileri, Celery daemon’ları ve Node.js süreçleri.
- Zombi süreçler sızdıran ve imaj etiketinde özel karakter olunca patlayan kırılgan kabuk komutları (
exec.Command("sh", "-c", "docker run ...")). - Her rota değişiminde diske
Caddyfileya danginx.confyazıp süreci yeniden yükleyen (kill -HUP) hantal ingress katmanları.
Gece saat 02:00’de, basit bir rota güncellemesi yüzünden konfigürasyon yeniden yüklenirken aktif WebSocket bağlantılarının koptuğunu izledikten sonra temel bir soru sorduk:
Ya bir PaaS kontrol düzleminin tamamı ~14MB’lık tek bir statik Go ikilisine derlenseydi, sıfır harici daemon gerektirseydi ve 15 milisaniyenin altında, hiçbir TCP bağlantısını koparmadan dinamik rota güncelleyebilseydi?
İşte pikpik böyle doğdu.
Dört Tavizsiz Mühendislik Değişmezi (Invariants)
Mimarinin acımasızca minimalist, deterministik ve dayanıklı kalması için ilk günden itibaren dört temel değişmez belirledik:
[ Değişmez 1: Sıfır Shell ] --> /var/run/docker.sock üzerinden doğrudan Docker Engine API
[ Değişmez 2: Tek Birleşik Çalışma ] --> Tek Go ikilisi + gömülü SQLite WAL + bellek içi halka tamponlar
[ Değişmez 3: Dinamik Ingress ] --> Caddy dinamik Admin REST API (<15ms rota mutasyonları)
[ Değişmez 4: Saf Veri Akışı ] --> io.Pipe -> gzip -> S3 multipart (en fazla <32MB bellek)
Gelin bu değişmezlerin pratikte ne anlama geldiğine yakından bakalım.
1. Değişmez 1: Sıfır Shell (API-First Motor)
Amatör DevOps araçlarında konteyner yönetimi genellikle bash dizgilerini birleştirmekten ibarettir:
// ❌ KIRILGAN YÖNTEM: Shell injection, zombi süreçler ve kaçış karakteri hatalarına açık
cmd := exec.Command("sh", "-c", fmt.Sprintf("docker run -d -p %s:%s %s", hostPort, port, image))
pikpik içerisinde bash ya da sh çalıştırmak tüm kod tabanında kesin olarak yasaklanmıştır.
Her konteyner yaşam döngüsü, overlay ağ bağlantısı, volume bağlaması, exec PTY terminal oturumu ve metrik toplama işlemi doğrudan /var/run/docker.sock üzerinden tipli Docker Engine SDK ile konuşur.
- Konteyner çalışma durumları atomik Go struct’larıdır.
- Canlı log akışları
stdcopy.StdCopyile doğrudan WebSocket çerçevelerine çoğullanır. - Etkileşimli terminal oturumları çift yönlü
io.ReadWriterköprüleriyle Docker’ın ham TTY akışına doğrudan bağlanır.
Sıfır kabuk müdahalesi. Sıfır alt süreç çatallanması. Sıfır kaçış karakteri hatası.
2. Değişmez 2: Tek Birleşik Çalışma Zamanı (SQLite WAL)
Bir Next.js uygulamasını veya bir Postgres konteynerini yayına almak için bir sistem yöneticisinin neden harici Postgres, Redis ve üç ayrı arka plan işçisi yönetmesi gereksin?
pikpik tüm kontrol düzlemini tek bir bağımsız ikiliye derler (cmd/pikpik, ~14MB).
- Write-Ahead Logging (
WAL) Modunda SQLite: Bağlantı başına pragmalarla (PRAGMA busy_timeout=5000; PRAGMA foreign_keys=ON; PRAGMA journal_mode=WAL;), SQLite tüm proje alanlarını, servis ayarlarını, API anahtarlarını ve yedekleme planlarını milisaniye altı gecikmeyle yönetir. - Bellek İçi Halka Tamponlar (Ring Buffers): Yüksek frekanslı konteyner telemetrisi (CPU %, bellek kullanımı, ağ I/O), konteyner başına 8.640 veri noktası tutan dairesel bellek içi yapılarda saklanır.
- Tersine Çevrilmiş Ajan Tünelleri: Uzak işçi makineler
pikpik-agent(~6.2MB) çalıştırır ve kontrol düzlemine doğru dışarıya giden bir mTLS/WSS tüneli (/agent/connect) açar. Böylece güvenlik duvarında port açmaya gerek kalmadan NAT arkasındaki makineler Swarm filosuna dahil edilir.
3. Değişmez 3: Dinamik Bellek İçi REST Ingress
Geleneksel self-hosted PaaS araçlarının yumuşak karnı rota güncellemeleridir. Kullanıcı yeni bir özel alan adı eklediğinde diske /etc/caddy/Caddyfile yazılır ve caddy reload komutu tetiklenir. Bu durum disk I/O gecikmesine, sözdizimi hatalarına ve anlık TCP kopmalarına yol açar.
pikpik, doğrudan Caddy’nin dinamik Admin REST API’si (http://127.0.0.1:2019/load) ile konuşur:
// <15ms içinde bellek içi rota mutasyonu
func (m *IngressManager) Reconcile(ctx context.Context, routes []Route) error {
caddyConfig := m.buildJSONConfig(routes)
return m.caddyClient.LoadJSON(ctx, caddyConfig)
}
- Rotalar, SNI eşleyicileri ve ters vekil sunucuları doğrudan Caddy’nin yerel bellek içi JSON ağacına dönüştürülür.
- Rota değişiklikleri 15 milisaniyenin altında atomik olarak uygulanır.
- Otomatik ACME TLS sertifika yönetimi (Let’s Encrypt / ZeroSSL) diske tek bir konfigürasyon dosyası yazılmadan bellekten idare edilir.
4. Değişmez 4: Saf Veri Akışı Boru Hatları
20GB’lık bir veritabanını yedeklerken veya devasa bir Docker build logunu işlerken naif mimariler tüm veriyi /tmp/backup.sql.gz dosyasına boşaltır, sunucunun diskini doldurur ve çalışan diğer servisleri çökertir.
pikpik içinde tüm ağır I/O operasyonları sınırlandırılmış saf veri akışlarıdır:
- Veritabanı yedekleri doğrudan akar:
Docker Exec stdout$\rightarrow$io.Pipe$\rightarrow$gzip.Writer$\rightarrow$S3 Çok Parçalı Yükleme - Veritabanının boyutu ne olursa olsun tepe bellek tüketimi kesin olarak <32MB ile sınırlandırılmıştır.
- Diske (
/tmp) asla tek bir geçici dosya yazılmaz.
Kontrol Düzlemi Arayüzünün Yenilenmesi: 5 Sütunlu Bilgi Mimarisi
Bir altyapı platformu, yalnızca onu kullanan mühendisin bilişsel yükünü hafiflettiği ölçüde başarılıdır. Son gece maratonumuzda, arayüzü 5 ana operasyonel alana ayırdık:
| Operasyonel Alan | Bilişsel Rol | Temel Yetenekler |
|---|---|---|
| 1. Genel Bakış & Katalog | Durumsal farkındalık | Gerçek zamanlı küme sağlığı, kıvılcım grafikleri, 1-Tık hazır şablonlar |
| 2. İş Yükleri & Hesaplama | Temel çalıştırma katmanı | Bağımsız uygulamalar, çoklu Compose yığınları, yönetilen veritabanları |
| 3. Trafik & Ingress | Kenar ve yönlendirme katmanı | Caddy ters vekil, Otomatik-TLS, sanal mesh ağları, canlı tanı paneli |
| 4. Filo & Depolama | Fiziksel ve kalıcı kaynaklar | Swarm düğümleri, WSS ajan tünelleri, dahili OCI registry, S3 yedekleri |
| 5. Platform & Yönetişim | Sistem sağlığı ve güvenlik | Sunucu telemetrisi, Docker disk önbellek temizliği, RBAC, AES gizli kasa |
Bu hiyerarşiyi tamamlamak için platform mühendislerinin herhangi bir konteynere, veritabanına veya düğüme anında atlamasını sağlayan genel bir Komut Paleti (Cmd+K) ekledik.
Geliştirici Hızı Sırrı: Go Derlemesi Olmadan Anlık HMR
Gömülü web SPA içeren (//go:embed all:dist) tek ikili Go uygulamaları geliştirirken en büyük dert geri bildirim döngüsüdür. Her React veya CSS değişikliğinde Go ikilisini baştan derlemek yaratıcı akışı öldürür.
Bunu çift modlu bir geliştirme protokolüyle çözdük:
- Prodüksiyon: Go ikilisi
web/distklasörünüembed.FSile içine gömer ve değişmez önbellek başlıklarıyla sunar. - Geliştirme: Vite sunucusu
:3000portunda React Fast Refresh / HMR ile çalışır ve/api,/ws,/healthzisteklerini arka plandaki Go sunucusuna (:8080) şeffafça vekil eder. - Genel Test:
server.allowedHosts: trueayarıyla Cloudflare Quick Tunnels (trycloudflare.com) üzerinden anında dış dünyaya açılarak uzak cihazlarda canlı test edilir.
React 19 / Tailwind (HMR :3000) <--[Ters Vekil]--> pikpik Go Kontrol Düzlemi (:8080)
│ │
▼ ▼
Cloudflare Quick Tunnel SQLite WAL + Docker Socket
Modern Sistem Mühendisliğinden Çıkarılacak Ders
pikpik’i inşa etmek bize sistem tasarımının zamansız bir gerçeğini bir kez daha kanıtladı: Karmaşıklık, genellikle sorgulanmamış varsayılanların bir sonucudur.
50 düğümlü bir filo için Kubernetes’e ihtiyacınız yok. Konteyner meta verisini yönetmek için Postgres ve Redis’e ihtiyacınız yok. Docker ile konuşmak için kabuk betiklerine ihtiyacınız yok.
Sınır değişmezlerini katı bir şekilde uyguladığınızda, standart kütüphaneye güvendiğinizde ve tek ikili mimariyi benimsediğinizde; 12 milisaniyede açılan, 18MB RAM ile çalışan ve sizi asla gece saat 3’te uykunuzdan uyandırmayan yazılımlar üretirsiniz.