Kımıldamadan Göç Etmek: Canlı Swarm İşçisinde Sıfır Kesintili PaaS Değişimi
Öz-barındırılan (self-hosted) PaaS kontrol düzleminizi değiştirmeye karar verdiğinizde, geleneksel DevOps kılavuzu göz korkutucudur:
- Yepyeni bir VPS sunucu kiralayın.
- Düzinelerce ortam değişkenini, veritabanını ve Compose yığınını elle yeniden oluşturun.
- Gece 02:00’ye stresli bir bakım penceresi planlayın.
- DNS kayıtlarını kesin, küresel yayılımı bekleyin ve Traefik’in ACME sertifikalarını kullanıcılar fark etmeden önce yenilemesi için dua edin.
Bu gece daha zor ve çok daha heyecan verici bir soru sorduk:
Yeni nesil, yüksek güvenilirlikli bir PaaS kontrol düzlemini doğrudan mevcut üretim makinenizin içine—halihazırda eski iş yüklerini çalıştıran aktif bir Docker Swarm işçi düğümüne—kurup trafiği canlı olarak sıfır port çakışması, sıfır disk tıkanması ve sıfır kesintiyle taşıyabilir miyiz?
İşte Dokploy’dan pikpik’e geçişi nasıl tasarladığımızın, Swarm işçi kısıtlamasını nasıl aştığımızın ve Cloudflare Tüneli’nin uçuş sırasında kontrol düzlemi değişimini nasıl zahmetsiz kıldığının mimari otopsisi.
1. Eski Sorunun Anatomisi
Dokploy ve Coolify gibi popüler açık kaynaklı PaaS motorları geliştirici ergonomisi için büyük adımlardır; ancak kaputun altında ciddi bir mimari borç taşırlar:
- Ağır Dağıtık Ayak İzi: Yalnızca yönetim panosunu ayakta tutabilmek için bir Node.js/tRPC çalışma zamanı, Prisma ORM, özel bir PostgreSQL veritabanı ve arka plan işçileri çalıştırmak boşta
~1.5GBRAM tüketir. - Kırılgan Kabuk Komutları (Shelling): Konteyner inşa ve dağıtım süreçleri çoğunlukla ana makinede çalışan metin birleştirmeli
exec.Command("sh", "-c", ...)komutlarına dayanır. Kaçırılmış tek bir tırnak işareti veya özel karakter içeren bir imaj etiketi zombi süreçler sızdırabilir. - Diski Boğan Yedekleme Mantığı: Veritabanı dökümleri (
pg_dump,mongodump), S3’e yüklenmeden önce yerel/tmpdizinindeki diske yazılır. Büyük veritabanlarına sahip $10’lık VPS düğümlerinde beklenmedik bir yedekleme görevi kolayca disk alanını tüketip sunucuyu çökertebilir. - Dosya Bazlı Giriş Yeniden Yüklemeleri: Yönlendirme değişiklikleri, statik yapılandırma dosyalarının yazılmasını veya diskteki Traefik dinamik YAML dosyalarının güncellenmesini gerektirir; bu da süreç düzeyinde yeniden yükleme sinyallerini (
kill -HUP) tetikler.
Buna karşılık pikpik, ilk günden itibaren Dört Pazarlıksız Değişmez (Invariant) etrafında tasarlandı:
┌──────────────────────────────────────────────────────────────────────────┐
│ Değişmez 1 (Sıfır Kabuk): /docker.sock üzerinden %100 tipli Docker SDK │
│ Değişmez 2 (Bütünleşik Çalışma): Tek ~14MB Go ikilisi + SQLite WAL │
│ Değişmez 3 (Dinamik Giriş): Caddy Admin REST API (15ms altı mutasyon) │
│ Değişmez 4 (Saf Akış): io.Pipe -> gzip -> S3 (RAM <32MB, 0 /tmp diski) │
└──────────────────────────────────────────────────────────────────────────┘
Peki asıl soru şuydu: pikpik’i halihazırda Dokploy tarafından kullanılan bir makineye nasıl sokarsınız?
2. Sunucu Gerçeği: Aktif Bir Swarm İşçisi
Hedef makineyi incelediğimizde iki somut kısıtla karşılaştık:
$ docker info --format 'Swarm: {{.Swarm.LocalNodeState}}, ControlPlane: {{.Swarm.ControlAvailable}}'
Swarm: active, ControlPlane: false
$ ss -tulpn | grep -E ':(80|443)\b'
tcp LISTEN 0 4096 0.0.0.0:80 0.0.0.0:*
tcp LISTEN 0 4096 0.0.0.0:443 0.0.0.0:*
- Makine Bir Swarm İşçisidir (Worker): Docker Swarm Manager konsensüs yetkisine sahip değildir.
/var/run/docker.socküzerinden yerel olarak gönderilen Swarm küme mutasyonları (docker service create, replika ölçekleme) Docker Engine tarafından reddedilir. - 80 ve 443 Portları Tamamen Doludur: Dokploy’un Traefik ters vekili ve Swarm giriş ağı
0.0.0.0:80ve0.0.0.0:443üzerinde aktif olarak dinleme yapmaktadır.
Eğer ana makine üzerinde doğrudan ikinci bir ters vekil başlatmaya çalışırsanız, anında bind: address already in use hatasıyla çöker.
3. Birlikte Yaşama Mimarisi: Ayrıştırıcı Olarak Cloudflare Tüneli
Ana makinenin 80 ve 443 portları için savaşmak yerine, giriş trafiğini Cloudflare Tunnel (cloudflared) kullanarak tamamen soyutluyoruz:
┌─────────────────────────┐
│ Genel Kullanıcı │
└────────────┬────────────┘
│ HTTPS (443)
▼
┌─────────────────────────┐
│ Cloudflare Uç Ağı (Edge)│
└────────────┬────────────┘
│
Şifreli Dışa-Doğru Tünel (İçe Port Açılmaz)
│
▼
┌────────────────────────────── Ana Makine ─────────────────────────────────┐
│ │
│ ┌─────────────────────────┐ │
│ │ cloudflared Daemon │ │
│ └───────────┬─────────────┴────────────┐ │
│ │ │ │
│ HTTP (127.0.0.1:8080) HTTP (127.0.0.1:8088) │
│ ▼ ▼ │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ pikpik Kontrol Düzlemi │ │ Caddy Dinamik Vekil │ │
│ │ (Tek Go İkilisi) │ │ (Dinamik REST Motoru) │ │
│ └───────────┬─────────────┘ └─────────┬───────────────┘ │
│ │ │ │
│ │ Tipli Docker SDK │ Ters Vekil Yönlendirme │
│ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Yerel Docker Motoru │ │
│ │ - Bağımsız Uygulamalar ve Compose Yığınları │ │
│ │ - Yönetilen Veritabanları (Postgres, Redis, Mongo) │ │
│ │ - Eşzamanlı Çalışan Eski Dokploy Konteynerleri │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ [ Eski Dokploy / Traefik: 0.0.0.0:80 / 443 üzerinde dokunulmadan sürer ] │
└───────────────────────────────────────────────────────────────────────────┘
Bu Birlikte Yaşamın Kusursuz Çalışma Nedenleri:
- Sıfır Port Çakışması:
cloudflareddışarıya doğru giden QUIC/WebSocket bağlantılarıyla çalışır. Ana makinede genel port dinlemez.pikpik127.0.0.1:8080üzerinde, Caddy ise127.0.0.1:8088gibi bir iç portta dinler. - Bağımsız Docker Yürütmesi: Docker Swarm küme çapındaki servis komutları yönetici gerektirse de; bağımsız konteyner yaşam döngüleri, Compose yığınları ve yönetilen veritabanları
/var/run/docker.socküzerinden hiçbir konsensüse ihtiyaç duymadan tam hızda çalışır.pikpik’inDockerStackManagermotoru tam verimle işler. - Mikroskobik Ayak İzi:
pikpikboşta yalnızca~14–25MBRAM harcar. Dokploy’un yanında çalışması sunucuya neredeyse sıfır ek yük getirir.
4. Veri Düzlemi Göçü: Değişmez 4 İş Başında
İlişkisel veritabanlarını (PostgreSQL, MySQL, MongoDB) Dokploy’dan pikpik’e taşırken Değişmez 4 (Saf Akış Hatları) fark yaratır.
Diske 10GB’lık bir .sql dökümü yazıp /tmp dizininin dolmaması için dua etmek yerine, baytları işletim sistemi borusu üzerinden doğrudan eski Dokploy konteynerinden yeni pikpik veritabanı konteynerine akıtıyoruz:
# Sıfır disk kullanımıyla doğrudan PostgreSQL akış göçü
docker exec -i dokploy_postgres pg_dump -U dokploy user_service_db \
| docker exec -i pikpik_db_postgres psql -U pikpik_user user_service_db
Kalıcı Docker birimleri (yüklenen dosyalar, medya, depolama alanları) için:
# Docker isimli birimleri arasında veriyi atomik kopyalama
docker run --rm \
-v dokploy_storage_volume:/from:ro \
-v pikpik_storage_volume:/to \
alpine sh -c "cp -a /from/. /to/"
Sıfır ara disk dosyası. Sıfır çöp kayıt. Sınırlandırılmış bellek kullanımı.
5. Giriş Dönüşümü: Traefik Etiketlerinden 15ms Altı Caddy REST’e
Dokploy’da yönlendirme kuralları statik konteyner etiketleri olarak tanımlanır:
labels:
- "traefik.http.routers.api.rule=Host(`api.example.com`) && PathPrefix(`/v1`)"
- "traefik.http.middlewares.strip.stripprefix.prefixes=/v1"
pikpik’te ise giriş motoru bu kuralları yapılandırılmış AST’lere çevirir ve doğrudan Caddy’nin bellek içi dinamik Admin API’sine (http://127.0.0.1:2019) yollar:
# pikpik CLI domain bağlama
pikpik-cli domain bind --app "app_api" --domain "api.example.com" --tls
Arka planda:
pkg/ingress/builder.go, rota eşleştiricilerini, güvenlik başlıklarını (HSTS,X-Frame-Options) ve hedef adresleri bir JSON gövdesinde derler.pkg/ingress/client.go, Caddy’nin belleğinePUT /id/route_app_api_api_example_comisteği atar.- Rota, tek bir HTTP isteğini veya WebSocket hattını düşürmeden
<15msiçinde tüm iş parçacıklarında canlıya girer.
6. Canlıya Geçiş: Anlık ve Geri Döndürülebilir
Uygulamalar ve veritabanları pikpik üzerinde çalıştırılıp önizleme adresleri üzerinden doğrulandıktan sonra:
cloudflaredgiriş kuralını güncelleyin:ingress: - hostname: api.example.com service: http://127.0.0.1:8088 # Caddy hedeficloudflaredservisini yeniden yükleyin (systemctl reload cloudflared).- Trafik anında
pikpik’e yönlenir. - Bir sorun çıkarsa, tünel ayarını eski Dokploy hedefine geri döndürmek iki saniyeden az sürer.
- Sistem oturduğunda, eski Dokploy konteynerlerini durdurabilirsiniz:
docker rm -f dokploy_app_container.
7. Çıkarılan Dersler
Temel bir altyapı bileşenini değiştirmek; kaba kuvvetle her şeyi yıkmayı veya yüksek riskli hafta sonu göçlerini gerektirmez.
Sert mimari sınırlar koyduğunuzda:
- Tek bir bütünleşik ikili, hantal arka plan daemon bağımlılıklarını yok eder.
- Saf akış hatları, küçük sunucuları disk tükenmesinden korur.
- Dinamik API girişi, hantal yapılandırma dosyası yeniden yüklemelerini ortadan kaldırır.
- Dışa-doğru tüneller, giriş yönlendirmesini fiziksel ana makine port bağlamalarından soyutlar.
Bulutunuzu yükseltmek için sunucu taşımak zorunda değilsiniz. Yalnızca daha iyi yapı taşları inşa etmeniz yeterli.