7 puan yazan GN⁺ 2023-07-17 | 1 yorum | WhatsApp'ta paylaş
  • Kişisel servisleri DigitalOcean $5/ay VM ve Debian 10 üzerinde doğrudan çalıştırıyorum; küçük ölçekli servisler için VM'e sunucu yazılımı kurma yöntemi yeterince basit ve mantıklı.
  • Sunucu uygulamalarını Rust statik ikili dosyası olarak oluşturuyor, HTML, CSS, yapılandırma ve gizli değerleri de içine dahil ederek dağıtım çıktısını tek bir dosya halinde tutuyorum.
  • Çalıştırma yönetimini systemd üstleniyor; HTTPS işlemleri için nginx reverse proxy ve Let’s Encrypt/certbot kullanıyorum, böylece uygulamanın TLS'yi doğrudan ele alması gerekmiyor.
  • Veri gerektiren servislerde SQLite tek dosya kullanıyor, Tarsnap günlük yedekleri ile Litestream'in DigitalOcean Spaces'e akış yedeklemesini birlikte kullanıyorum.
  • Tek bir VM üzerinde birden fazla servis bulunduğunda, bunları servis başına Unix kullanıcısı ile izole ediyorum; daha güçlü güvenlik gerekiyorsa ayrı VM, systemd-nspawn veya firejail tercih ediyorum.

Sunucu ve dağıtımın temel yapısı

  • thoughts.page, hanabi.site, cgmserver, phonebridge gibi çeşitli servisler bu yapıya yakın şekilde çalışıyor.
  • Uygulamalar DigitalOcean VM üzerinde çalışıyor; plan $5/ay katmanı ve işletim sistemi Debian 10.
    • Bazı servisler aynı VM'i paylaşıyor, bazıları ise farklı VM'lere ayrılmış durumda.
  • Sunucu yazılımı Rust ile yazılıyor.
    • Statik olarak bağlanıyor.
    • HTML, CSS, yapılandırma ve gizli değerler ikili dosyanın içine derleniyor.
    • rust-musl-builder ve rust-embed kullanılıyor.
  • Bu yaklaşımda dağıtım, sunucuya tek bir dosya kopyalama işine indirgeniyor.
    • Go, C++ gibi dillerde de benzer bir yaklaşımın kullanılabileceğini düşünüyorum.
    • Tek ikili dosya dağıtımının kolay olmadığı dillerde, Docker container'ı derleme çıktısı olarak kullanmak bir alternatif olabilir.

Çalıştırma, proxy ve veri saklama

  • Servislerin başlangıç yönetimini systemd üstleniyor.
    • Sunucu açıldığında ikili dosyanın da birlikte çalışmasını sağlıyor.
    • systemd unit dosyalarının çoğu 9 satırlık basit dosyalar.
    • systemd'nin kendisi karmaşık olsa da, önyükleme sırasında sunucuyu başlatma amacıyla kullanıldığında bu karmaşıklığın büyük kısmıyla karşılaşmıyorsunuz.
  • Dağıtım simple deploy script ile yapılıyor.
    • İkili dosya sunucuya kopyalanıyor ve sunucu yeniden başlatılıyor.
    • Geri alma mümkün; ayrıca dağıtım sırasında bağlantı kopsa bile her zaman geçerli bir sürümün çalışması sağlanıyor.
  • Veritabanı gereken programlarda SQLite kullanılıyor.
    • Uygulamanın tüm durumu tek bir dosyada bulunuyor.
    • Her gün SQLite .backup komutu ile yedek alınıp Tarsnap'e kaydediliyor.
    • Yedekleme script'i cron ile çalıştırılıyor.
    • Litestream ile veritabanı kopyası saniye düzeyinde DigitalOcean Spaces depolamasına akıtılıyor ve snapshot'lar 6 saatte bir oluşturuluyor.
  • Tüm sunucular nginx reverse proxy arkasında çalışıyor.
    • TLS sonlandırmasını nginx yaptığı için uygulamanın HTTPS ile ilgilenmesi gerekmiyor.
    • HTTPS sertifikaları Let’s Encrypt ve certbot ile alınıyor ve otomatik yenileniyor.
    • hanabi.site için nginx yapılandırma örneği ayrı bir gist içinde yer alıyor.
    • Statik dosyalar nginx ile sunulabilir; sunucuya scp veya rsync ile kopyalamak yeterlidir.

Bakım ve servis izolasyonu

  • Bu yapı, basit ve sağlam bir işletim yolu hedefliyor.
    • Uygulamanın kendisi dışında, sunum yolundaki yazılımlar onlarca yıldır kullanılan, kendini kanıtlamış bileşenler.
    • DigitalOcean ücretini ödemeye devam ettiğiniz sürece, siteyi çalışır durumda tutmak için özünde neredeyse hiç bakım gerekmiyor.
    • İzlemenin tespit ettiği sorunlar yalnızca geçici DigitalOcean ağ problemleriydi.
  • İşletim sistemi ve güvenlik güncellemeleri ara sıra gerekiyor.
    • Debian sürümleri 5 yıllık destek sağladığından, yaklaşık 2,5 yıl sonra Debian 11'e yükseltmek gerekecek.
    • Heartbleed benzeri bir olay tekrar yaşanırsa yama uygulamak gerekir.
    • Bu tür olaylar nadir görülür.
  • Her servis için $5/ay VM kullanmanın maliyeti yük olabilir, ancak birden fazla servis aynı VM üzerinde çalıştırılabilir.
    • İzolasyon, her servis için ayrı Unix kullanıcı hesabı oluşturularak sağlanıyor.
    • Bu izolasyon yöntemi Unix'in ilk günlerinden beri var olduğundan sağlam görünüyor.
    • Daha güçlü izolasyon gerekirse systemd-nspawn veya firejail kullanılabilir.
    • Gerçekten güvenlik açısından kritikse, ek $5/ay ödeyip ayrı bir VM üzerinde çalıştırıyorum.
  • Yeni proje kurulum süreci kısa.
    • Yeni kullanıcı oluştur.
    • nginx sanal host ekle ve certbot ile HTTPS sertifikası ver.
    • systemd unit ekle.
    • Depoya deploy script'i commit et ve çalıştır.
  • Başta öğrenilecek çok şey var, ancak bu altyapı bulut altyapısına göre çok daha yavaş değişiyor.
    • nginx yapılandırma biçimi son 10 yılda özünde neredeyse hiç değişmedi.
    • Debian sistem yönetimindeki son büyük değişiklik, yaklaşık 10 yıl önceki systemd geçişiydi.
    • Bulut sağlayıcısının bir servisi sonlandırması ya da davranışını sessizce değiştirmesi gibi durumlara daha az maruz kalıyorsunuz.
    • Bağımlılık yalnızca VPS sağlayıcısı; sunucu genel amaçlı bir ürün olduğu için başka bir sağlayıcıya taşınabiliyor.

1 yorum

 
GN⁺ 2023-07-17
Hacker News yorumları
  • Yalıtım için her hizmeti ayrı bir Unix kullanıcısı olarak çalıştırıyorsanız, systemd’nin DynamicUser özelliği zaman kazandırabilir
    UID atar ve günlük/durum dizinlerini doğru izinlerle oluşturur
    https://0pointer.net/blog/dynamic-users-with-systemd.html

    • UID’nin kalıcı olması gerekiyorsa systemd-sysusers ile yeni bir sistem kullanıcısı oluşturmak da çok kolay
      /etc/sysusers.d/ içine kullanıcı adı, home dizini gibi bilgileri içeren küçük bir metin dosyası koyup sysusers komutunu ya da servisini çalıştırmanız yeterli
    • Her hizmet/uygulama için ayrı bir servis hesabı kullanmak oldukça standart bir yöntem; sunucuları da ayırmak daha iyi olur
  • HTTP tetiklemeli bulut fonksiyonları son zamanlarda en çok hoşuma giden şey
    Sağlayıcıya özgü tuzaklardan dikkatle kaçınırsanız karmaşıklığı ciddi ölçüde azaltıyor ve bulut yerel soyutlamalar içinde “nihai biçim” gibi hissettiren tek şey bu
    Tek bir uygulamada 2000’den fazla dağıtım yaptım; çalışma ortamı bozulduğu için destek ekibiyle iletişime geçmem ya da anlaşılması güç konsol komutları yazmam gereken tek bir durum bile olmadı
    Azure’un yalıtılmış App Service planı bazında performans da harika; istek başına ücretlendirmeye yönelik ideolojik itirazım da artık kalmadı
    Sunucuların bulunduğu gayrimenkule kadar kendiniz sahip olursanız daha ucuza getirebilirsiniz, ama basit bir HTTP fonksiyonunun sunduğu uyumluluk ve denetim gibi özellikleri kendiniz uygulamak için fiilen dev bir şirket kurup bir sürü insan işe almanız gerekir
    Sağlayıcıya bağımlılık argümanı da artık pek ikna edici gelmiyor. HTTP isteği alıp HTTP yanıtı döndüren arayüz doğal; sağlayıcılar arasındaki farklar da tetikleyici metod imzası ya da OIDC/SAML claim’leri gibi ek bağlamlardan ibaret. Bir hafta içinde başka bir sağlayıcıya refactor edilemeyecek bir yapı kurmak için özellikle uğraşmak gerekir
    Kişisel blog söz konusuysa bir Hetzner VM alıp zanaatkâr gibi ince ince ayarlamanın daha eğlenceli olduğunu anlıyorum. Hiç regülasyon olmayan bir sektördeyseniz de sunucuyu tamamen dışarıya vermektense marjı ve karmaşıklığı ince ince tartmayı daha güçlü savunabilirsiniz

    • “Kendiniz uygulamak için 1 milyar dolarlık bir şirket kurup 1000 kişi daha işe almanız gerekir” kısmında gözlerimi devirdim
      Buluttan önce herkesin ne yaptığını sanıyorlar, bilmiyorum
      Şu anda büyük bir sanayi şirketinde birden fazla ekibi yönetiyorum ve Azure üzerinde inovasyon uygulamalarını ölçekleyip dağıtıyoruz; kullanıcı sayısına kıyasla bulut maliyeti akıl almaz derecede yüksek
      Eskiden kullanıcı sayısı 10 kat fazla olan uygulamaları maliyetin yüzde biriyle ve daha düşük karmaşıklıkla işletiyorduk
      Bu maliyet, bu şüpheli tercihi yapan başka bir departmana faturalandığı için kişisel olarak umurumda değil; ama buluta körü körüne inanma tavrını anlamakta zorlanıyorum
    • Aşırı derecede regüle edilen bir sektörde çalışıyorum ama son cümleyi anlamıyorum
      Bizim için kendi donanımımızı işletmek en iyi seçenek; ofiste fotoğraf çekmenin bile yasak olduğu bir düzeydeyiz, bu yüzden bir bulut sağlayıcıya herhangi bir şey emanet etme ihtimalimiz %0
    • Fonksiyonlar basit API’leri barındırmak için fena bir konum değil
      Ama uygulamanın faydalı olması için veritabanı gibi başka unsurlar da gerekiyor; maliyet de oradan eklenmiyor mu?
    • Burada sözü edilen HTTP tetiklemeli bulut fonksiyonlarının tam olarak ne olduğunu bilmiyorum
      HTTP sunucusunun istek handler’ı mı, fonksiyonel servis bulut bilişimi mi, yoksa sadece eski usul RPC mi, kafam karışıyor
    • Fonksiyonun gerçekte ne yaptığı önemli
      Bir script kiddie dakikada 10 kez istek göndermeye başlarsa, fonksiyon maliyetinin VPS’ten pahalı hale gelmesi ne kadar sürer?
  • Kişisel sitem ve proje sitelerim için benzer bir yapı kullanıyorum
    Aylık 5 dolarlık bir Linode VM kullanıyorum; Debian GNU/Linux üzerinde çalışıyor ve yazılımları Common Lisp ile yazıyorum
    Kişisel web sitesi veya blog için bir Common Lisp programıyla statik site üretiyorum; çevrimiçi servisler veya web uygulamaları içinse HTTP isteklerini işleyip yanıtlayan, Hunchentoot kullanan Common Lisp programları yazıyorum
    VM başlatıldığında ya da yeniden başlatıldığında site/servislerin otomatik ayağa kalkması için systemd unit dosyaları kullanıyorum; çoğu yaklaşık 10–15 satır
    VM’in ilk kurulumunu bir shell script ile kodladım: https://github.com/susam/dotfiles/blob/main/linode.sh
    Proje ve servis bazındaki ayarları ayrı ayrı Makefile’larla yönetiyorum: https://github.com/susam/susam.net/blob/main/Makefile, https://github.com/susam/mathb/blob/main/Makefile
    Konteyner kullanmıyorum. Bu siteler konteynerler moda olmadan yıllar önce çalışmaya başladı ve şimdiye kadar init script’i ile Makefile yeterli oldu
    Nginx de kullanıyorum. Statik dosyaları sunuyor; backend servisi olduğunda ters proxy görevi görüyor; TLS sonlandırmanın yanı sıra istek hızı sınırlama veya backend’i korumak için HTTP header izin listesi ayarlama gibi avantajları da var
    Kendi küçük playbook’umda curl LINK -o linode.sh && sh linode.sh, git clone LINK && cd PROJECT && sudo make setup https gibi birkaç komut var
    make hedefleri Nginx, certbot, sbcl gibi araçların kurulumu, Nginx yapılandırması, sertifika ayarı gibi siteyi çalıştırmak için gereken işleri hallediyor; komut bittiğinde web sitesi hemen yayına giriyor

    • Hangi Common Lisp implementasyonunu kullandığını merak ediyorum
      Makefile’a bakınca SBCL kullanıyor gibi görünüyor; bellek kullanımının hiç sorun olup olmadığını merak ediyorum
      512 MB RAM’li bir VPS kullanıyorum ve tek bir SBCL instance’ı yaklaşık 100 MB yiyor; bu yüzden aynı anda sadece birkaç servis çalıştırabiliyorum
      Trafiği en düşük servisi CLISP’e taşımayı da düşündüm, ama kullandığım özelliklerden biri olan paket yerel alias’ları onda yok
  • Birkaç yıl boyunca yapılandırmayı sürekli iyileştirdikten sonra artık her şeyi Docker container olarak çalıştırma yaklaşımında karar kıldım
    Orkestratör olarak systemd yerine docker-compose, proxy olarak nginx yerine Caddy kullanıyorum
    Orijinal yazıda olduğu gibi çalıştırmam gereken her proje için dağıtım script'i yazdığımdan genel olarak oldukça benzer
    Docker'ın birçok avantajından biri, aynı yapılandırmayla üçüncü taraf yazılımları da çalıştırabilmek
    Bu yapılandırmayı birkaç yıldır kullanıyorum; çok iyi, orijinal yazıdaki gibi sağlam ama gerektiğinde istediğim gibi değiştirecek esnekliğe de sahip
    Şu anki tek sıkıntı rolling deployment. Yazılım büyüdükçe her dağıtımda birkaç saniyelik kesinti yaşanması sorun olmaya başladı; henüz basit bir çözüm yok ama docker swarm doğru yol olabilir

    • Caddy kullanarak benzer şekilde işletiyorum
      Kesinti süresini azaltmak için health_uri /health, lb_try_duration 30s kullanmayı deneyebilirsiniz
      Örneğin reverse_proxy api:8089 { health_uri /health lb_try_duration 30s } şeklinde ayarlarsanız, yeni sürümü dağıtırken Caddy istekleri buffer'lar ve yeni servisin ayağa kalkması için 30 saniye tanır
      İdeal olarak yeni sürüm sağlıklı duruma geldikten sonra Caddy onu kullanmaya başlamalı ve eski container'ı öldürmeli
      https://github.com/Wowu/docker-rollout ve https://github.com/lucaslorentz/caddy-docker-proxy projelerine baktım ama henüz önceliklendiremedim
    • Caddy gibi bir load balancer pod'ların önündeyse, yeni pod ayağa kalkarken istekleri tutacak şekilde yapılandırabilirsiniz: https://twitter.com/bradleyjkemp/status/1486756361845329927
      Kusursuz değil ama tarayıcı bağlantı hatası almak yerine birkaç saniye boyunca yalnızca yükleniyor olarak kalıyor
      https://mrsk.dev/ de aynı tekniği kullanıyor
    • Çalıştığım startup'ın yazılım stack'ini sıfırdan oluştururken uygulamaları en baştan Docker ile paketledim
      Production compose ile başladı, daha sonra stack'i otomatik yükselten sürekli dağıtım pipeline'ına dönüştürdüm
      Şirket ve kullanıcı tabanı büyüdükçe yeniden başlatma veya dağıtım sırasında kesinti yaşanması sorunu ortaya çıktı ve ek uygulamalar çalıştırmak istediğimiz her seferinde yeni bir dağıtım ortamı hazırlamak gerekiyordu
      Bir gün Kubernetes kullanmak zorunda kalmaktan korkuyordum; karmaşıklığını bizzat görmüştüm ve günün çoğunu cluster'ı yatıştırmakla geçirmek istemiyordum
      Bu yüzden Swarm moduna geçtik; bazen Jekyll, bazen Hyde gibi bir yolculuk
      Kimsenin düzeltmeye çalışmadığı bug'lar, uygulanmamış ama bunun da söylenmediği Docker spesifikasyonunun bazı bölümleri, saç baş yolduran implementasyon tercihleri ve Docker Inc çalışanlarının birbiriyle konuşmadığı ya da sonuna kadar odaklanamadığı hissi var
      Yine de güzel tarafları da çok. Compose stack'i olduğu gibi çalışırken gereken noktalarda büyüyebiliyor; doğru ayarlandığında kesintisiz dağıtım, yükseltme, load balancing ve rollback iyi çalışıyor
      Raft, başka yerlerde olduğu gibi cluster'ı ayakta tutmada güvenilir; biraz emekle K8s bakım bütçesinin bir kısmıyla bile esnek, güvenli ve otomatik dağıtılan bir self-servis platformu kurabilirsiniz
      Ancak dağıtım script'lerini düzgün hazırlamak gerekiyor. Geçerli Docker spesifikasyonuna uygun compose dosyasını Swarm spesifikasyonuna dönüştüren, secret'ları yenileyip temizleyen ve ortam değişkenlerini genişleten bir Python aracı yapmak için epey zaman harcadım
      VPS sağlayıcısına bağlı olarak network MTU'sunu da mutlaka doğru ayarlamak gerekiyor. Bu yüzden ömrümden epey gitmiş olabilir
    • Zaten compose dosyanız varsa gidilecek yol Swarm, ama ben şahsen buna değmeyeceğine karar verdim
      Müşteri veya kullanıcı sayısı artıp ölçekleme sorunu gerçekten ortaya çıkana kadar böyle
    • Benzer bir yapılandırma kurdum ama image'ları SSH üzerinden docker save ve docker import ile itme yöntemini sevmiyorum
      Kendi registry'nizi işletip işletmediğinizi merak ediyorum
  • Fiziksel sunucuda PostgreSQL veritabanını ve uygulamayı Podman Pod içine koyuyorum; hepsi localhost'ta 5000'in üzerindeki portlarda çalışıyor, Caddy ise 443 üzerinde reverse proxy olarak görev yapıyor
    systemd Timer ile her gün 16:55'te tüm veritabanlarını tek bir dizine dump ediyorum
    Ardından DejaDup [1] her gün 17:00'de $HOME dizinini harici HDD'ye otomatik yedekliyor; cache dosyaları hariç tutuluyor ama veritabanı dump'ları dahil ediliyor
    OS olarak Debian üzerine GNOME Core [2] kurulu, firewalld kuralları yalnızca 80, 443 ve özel SSH portuna izin veriyor
    SSH anahtar tabanlı, parola ile kimlik doğrulama kapalı
    En sıkıcı yöntem ama sorunsuz çalışıyor
    1 - https://flathub.org/apps/org.gnome.DejaDup
    2 - https://packages.debian.org/bookworm/gnome-core

    • Sunucuda neden GNOME çalıştırdığınızı merak ediyorum
    • cron job'ları yerine systemd timers kullanmanızın bir nedeni var mı merak ediyorum
  • Son zamanlarda tek bir sunucuya Dokku kurup kullanıyorum
    Yönetimi kolay; geliştiriciler Heroku tarzında sadece git push ile dağıtım yapabiliyor, plugin'i çok olduğu için veritabanı eklemek veya HTTPS ayarlamak da en fazla 10 saniye sürüyor

    • Aynı yöntemi kullanıyorum; git push ile dağıtım yapabilmek gerçekten çok rahat
      Uygulama eklemek, veritabanı eklemek, ortam değişkenlerini yönetmek ve domain yönetimi hepsi çok sezgisel
  • Basit yapılandırmaları sevdiğim için bu yöntemle çalışmak keyifli görünüyor
    Hizmetlerin %99'u için yeterli olma ihtimali yüksek
    Sunucu ayarları ve dağıtım betikleri için Ansible kullanırdım sanırım
    Böylece sunucu belgelenmiş olur, dağıtım betikleri de daha basit hale gelebilir
    Ancak hata ayıklama ya da kontrol için sunucuya doğrudan bağlanmaktan kaçınmazdım

    • Ansible kullanıyorum ama buna değip değmediğini yeniden düşünüyorum
      Betiklerim son 7 yılda neredeyse hiç değişmedi; Ansible ise yavaş ve sürekli birden fazla dosyayı bakımda tutma eğiliminde
      Hata ayıklama açısından, uygulama günlüklerini nginx ile parola korumalı bir endpoint üzerinden açmak da mümkün olabilir
  • Bazen, buluttan önce de CI/CD ve etkili sunucu yönetiminin yaygın uygulamalar olduğunu unutuyor gibiyiz

  • Sunucu yazılımını Rust ile yazıp statik linkledikten sonra HTML, CSS, yapılandırma, secret'lar vb. her şeyi ikili dosyaya derleyip koyma yaklaşımı hakkında: son zamanlarda Go'da bunu yapıyorum; statik dosyalara bağımlı yazılım yazmayı ve dağıtmayı gerçekten kolaylaştırdığı için çok hoşuma gidiyor

    • Derlenmiş ikili dosyaya secret eklemek hâlâ bana kuşkulu geliyor
      Secret'lar için ortam değişkenleri ya da yapılandırma kullanmak standarda daha yakın; çalıştırmadan önce bir adım daha eklese de ikili dosyayı paylaşırken içinde secret olduğunu unutma durumunu önler
      İkili dosyayı açıp string aramak oldukça kolaydır
      Statik frontend varlıklarını ve varsayılan ayarları birlikte koymak ise büyük avantaj
    • Go'yu pek sevmiyorum ama bu yüzden sürekli kullanır oldum
      Rust ile, özellikle Mac'ten Linux'a çapraz derleme yapmak görece zahmetliyken Go'da bu önemsiz ve go aracına yerleşik
      Yan projeyi bitirip dağıtırken sürtünmeyi ortadan kaldırmak gerçekten kolaylaşıyor
    • https://play.clickhouse.com/play?user=play de aynı şekilde yapıyor
      Ancak bir sorum var. Yazıda “Let’s Encrypt sertifikalarını certbot ile alıyorum ve otomatik yenileme de hallediliyor” deniyor; ben ise iki sunucu ve geo-DNS kullanan bölgeler arası bir kurulumdayım, bu yüzden certbot yalnızca ABD sunucusunda çalışıyor ve sertifikayı Avrupa sunucusuna elle kopyalamam gerekiyor
      Bunu çözmenin bir yolu var mı?
      ClickHouse Playground açıklaması burada: https://ghe.clickhouse.tech/
    • Ben de aynı yöntemi kullanıyorum
      Backend API'yi sunan aynı statik derlenmiş servis web uygulamasını da sunuyor
      CI'da npm build çalıştırıp çıktıları gömünce yerel test ya da demo instance'ı ayağa kaldırmak çok kolay oluyor