7 पॉइंट द्वारा GN⁺ 2023-07-17 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • व्यक्तिगत सेवाएँ DigitalOcean $5/माह VM और Debian 10 पर सीधे चलती हैं, और छोटे पैमाने की सेवाओं के लिए VM पर सर्वर सॉफ़्टवेयर चलाने का तरीका काफी सरल और व्यावहारिक है
  • सर्वर ऐप्स Rust static binary के रूप में बनाए जाते हैं, और HTML, CSS, config, secrets तक शामिल करके deployment artifact को एक ही फ़ाइल रखा जाता है
  • रनटाइम मैनेजमेंट systemd संभालता है, और HTTPS को nginx reverse proxy तथा Let’s Encrypt/certbot पर छोड़ा जाता है ताकि ऐप को TLS सीधे संभालना न पड़े
  • जिन सेवाओं को डेटा चाहिए, वे SQLite single file का उपयोग करती हैं, और Tarsnap daily backup के साथ Litestream की DigitalOcean Spaces streaming backup भी इस्तेमाल करती हैं
  • जब एक VM पर कई सेवाएँ रखी जाती हैं, तो प्रत्येक सेवा के लिए अलग Unix user से isolation किया जाता है, और ज़्यादा मज़बूत security चाहिए तो अलग VM, systemd-nspawn, या firejail चुना जाता है

सर्वर और deployment की बुनियादी संरचना

  • thoughts.page, hanabi.site, cgmserver, phonebridge जैसी कई सेवाएँ लगभग इसी संरचना में चलती हैं
  • ऐप्स DigitalOcean VM पर चलती हैं, प्लान $5/माह tier है और operating system Debian 10 है
    • कुछ सेवाएँ एक ही VM साझा करती हैं, और कुछ अलग VM पर अलग रखी गई हैं
  • सर्वर सॉफ़्टवेयर Rust में लिखा गया है
    • statically linked
    • HTML, CSS, config, secrets आदि binary में compile कर दिए जाते हैं
    • rust-musl-builder और rust-embed का उपयोग किया जाता है
  • इस तरीके में deployment, सर्वर पर एक single file कॉपी करने जितना सरल हो जाता है
    • लेखक के अनुसार Go, C++ आदि में भी ऐसा ही तरीका अपनाया जा सकता है
    • जिन भाषाओं में single binary deployment आसान नहीं है, वहाँ Docker container को build artifact बनाने का विकल्प है

रनटाइम, proxy, और डेटा संरक्षण

  • सेवा startup management systemd संभालता है
    • सर्वर boot होने पर binary भी साथ में चलने लगती है
    • ज़्यादातर systemd unit files 9 पंक्तियों वाली साधारण फ़ाइलें होती हैं
    • systemd अपने आप में जटिल है, लेकिन boot पर सर्वर start कराने के उपयोग में उसकी अधिकतर जटिलता सामने नहीं आती
  • deployment simple deploy script से किया जाता है
    • binary को सर्वर पर कॉपी किया जाता है और सर्वर restart किया जाता है
    • rollback संभव है, और deployment के दौरान connection टूट जाए तब भी हमेशा कोई valid version चलती रहती है
  • जिन प्रोग्रामों को database चाहिए, वे SQLite का उपयोग करते हैं
    • ऐप की पूरी state एक single file में रहती है
    • हर दिन SQLite .backup command से backup बनाया जाता है और Tarsnap में रखा जाता है
    • backup script cron से चलती है
    • Litestream के जरिए database की कॉपी सेकंड-स्तर पर DigitalOcean Spaces storage में stream की जाती है, और snapshot हर 6 घंटे में बनाया जाता है
  • सभी सर्वर nginx reverse proxy के पीछे चलते हैं
    • nginx TLS termination संभालता है, इसलिए ऐप को HTTPS की चिंता नहीं करनी पड़ती
    • HTTPS certificates Let’s Encrypt और certbot से लिए जाते हैं और अपने-आप renew होते हैं
    • hanabi.site की nginx config का उदाहरण अलग gist में है
    • static files nginx से serve की जा सकती हैं, और scp या rsync से सर्वर पर कॉपी की जा सकती हैं

मेंटेनेंस और सेवा isolation

  • यह संरचना सरल और मज़बूत operational path को लक्ष्य बनाती है
    • ऐप को छोड़कर serving path में आने वाला software दशकों से इस्तेमाल हुए, परखे हुए components हैं
    • जब तक DigitalOcean का भुगतान चलता रहे, साइट चलाने में मूल रूप से बहुत कम maintenance चाहिए
    • monitoring ने जिन समस्याओं का पता लगाया, वे सिर्फ अस्थायी DigitalOcean network issues थीं
  • operating system और security updates कभी-कभी ज़रूरी होते हैं
    • Debian release 5 साल का support देती है, इसलिए लगभग ढाई साल बाद Debian 11 में upgrade करना होगा
    • अगर Heartbleed जैसी घटना फिर हो, तो patch लगाना पड़ेगा
    • ऐसी घटनाएँ दुर्लभ हैं
  • हर सेवा के लिए $5/माह VM रखना महँगा लग सकता है, लेकिन कई सेवाएँ एक ही VM पर चलाई जा सकती हैं
    • isolation के लिए हर सेवा के लिए अलग Unix user account बनाया जाता है
    • यह isolation तरीका Unix के शुरुआती दौर से मौजूद है, इसलिए काफ़ी मज़बूत लगता है
    • और ज़्यादा मज़बूत isolation चाहिए तो systemd-nspawn या firejail का उपयोग किया जा सकता है
    • अगर चीज़ वाकई security-critical हो, तो अतिरिक्त $5/माह देकर उसे अलग VM पर चलाया जाता है
  • नए प्रोजेक्ट की setup प्रक्रिया छोटी है
    • नया user बनाना
    • nginx virtual host जोड़ना और certbot से HTTPS certificate जारी करना
    • systemd unit जोड़ना
    • repository में deploy script commit करना और चलाना
  • शुरुआत में सीखने के लिए बहुत कुछ है, लेकिन यह infrastructure cloud infrastructure की तुलना में कहीं अधिक धीरे बदलता है
    • nginx config format पिछले 10 वर्षों में मूल रूप से लगभग वैसा ही रहा है
    • Debian system administration में आख़िरी बड़ा बदलाव लगभग 10 साल पहले systemd migration था
    • cloud providers द्वारा services बंद कर देने या चुपचाप behavior बदल देने की स्थिति का असर कम पड़ता है
    • निर्भरता सिर्फ VPS provider पर है, और सर्वर एक सामान्य commodity है, इसलिए उसे दूसरे provider पर ले जाया जा सकता है

1 टिप्पणियां

 
GN⁺ 2023-07-17
Hacker News की राय
  • अगर isolation के लिए हर service को अलग Unix user के रूप में चला रहे हैं, तो systemd का DynamicUser feature समय बचा सकता है
    यह UID assign करता है और log/state directories को सही permissions के साथ बनाता है
    https://0pointer.net/blog/dynamic-users-with-systemd.html

    • अगर UID persistent होना चाहिए, तो systemd-sysusers से नया system user बनाना भी बहुत आसान है
      /etc/sysusers.d/ में username, home directory जैसी जानकारी वाली एक छोटी text file डालें और sysusers command या service चला दें
    • हर service/app के लिए अलग service account इस्तेमाल करना काफी standard तरीका है, और server भी अलग रखना बेहतर है
  • HTTP-triggered cloud functions मुझे आजकल सबसे ज्यादा पसंद हैं
    vendor-specific pitfalls से सावधानी से बचें, तो ये complexity को काफी कम कर देती हैं, और cloud native abstractions में अकेली ऐसी चीज लगती हैं जो “final form” जैसी महसूस होती है
    सिर्फ एक app में 2000 से ज्यादा बार deploy किया है, लेकिन कभी ऐसा नहीं हुआ कि runtime environment टूट गया हो और support team से संपर्क करना पड़ा हो या कोई उलझी हुई console command चलानी पड़ी हो
    Azure के isolated App Service plan के हिसाब से performance भी शानदार है, और per-request billing को लेकर ideological objection भी अब खत्म हो गया है
    अपने server वाली real estate तक खुद के पास हो तो इसे सस्ता किया जा सकता है, लेकिन एक simple HTTP function से मिलने वाली compliance और audit जैसी properties खुद implement करनी हों, तो असल में एक बहुत बड़ी company बनाकर ढेरों लोगों को hire करना पड़ेगा
    vendor lock-in वाली दलील भी अब ज्यादा समझ नहीं आती। HTTP request लेकर HTTP response लौटाने वाला interface स्वाभाविक है, और vendor-specific differences trigger method signature या OIDC/SAML claims जैसे extra context तक ही सीमित हैं, इसलिए ऐसी structure बनानी हो जिसे एक हफ्ते में दूसरे vendor पर refactor न किया जा सके, तो उल्टा मेहनत करनी पड़ेगी
    personal blog हो तो Hetzner VM खरीदकर craftsperson की तरह उसे polish करना ज्यादा मजेदार है, यह समझता हूं। अगर industry पर बिल्कुल regulation न हो, तो server को पूरी तरह outsource करने की बजाय margin और complexity को बारीकी से तौलने वाली बात भी ज्यादा मजबूती से कही जा सकती है

    • “खुद implement करना हो तो 1 अरब डॉलर की company बनानी पड़ेगी और 1000 और लोगों को hire करना पड़ेगा” वाले हिस्से पर मैंने आंखें घुमा लीं
      cloud migration से पहले सब क्या करते थे, यह इन्हें क्या लगता है, पता नहीं
      अभी मैं एक बड़ी industrial company में कई teams संभालते हुए Azure पर innovation apps को scale और deploy कर रहा हूं, और users की संख्या के मुकाबले cloud cost बेतुकी रूप से ज्यादा है
      पहले users की संख्या 10 गुना वाले apps को 1/100 लागत पर, और कम complexity के साथ चलाया था
      यह cost उन दूसरे departments को charge होती है जिन्होंने ऐसे संदिग्ध choices किए हैं, इसलिए मुझे निजी तौर पर फर्क नहीं पड़ता, लेकिन cloud पर अंधविश्वास वाला रवैया समझना मुश्किल है
    • मैं बेहद heavily regulated industry में काम करता हूं, लेकिन आखिरी sentence समझ नहीं आता
      हमारे लिए अपना hardware operate करना ही सबसे अच्छा है, और office में photo तक नहीं खींच सकते, इसलिए cloud provider को कुछ भी सौंपने की संभावना 0% है
    • functions simple API host करने के लिए ठीक जगह हैं
      लेकिन app को useful बनने के लिए database जैसी दूसरी चीजें भी चाहिए होती हैं, और वहां cost जुड़ती नहीं है क्या?
    • यहां जिस HTTP-triggered cloud function की बात हो रही है, वह ठीक-ठीक क्या है, समझ नहीं आ रहा
      यह HTTP server का request handler है, functional service cloud computing है, या बस पुराना RPC है—confusing है
    • function असल में क्या करती है, यह मायने रखता है
      अगर कोई script kiddie हर minute 10 requests भेजना शुरू कर दे, तो function की cost VPS से महंगी होने में कितना समय लगेगा?
  • personal site और project sites के लिए मैं मिलता-जुलता setup इस्तेमाल करता हूं
    Linode VM महीने के 5 dollar वाला इस्तेमाल करता हूं, Debian GNU/Linux चलाता हूं, और software Common Lisp में लिखता हूं
    personal website या blog के लिए Common Lisp program से static site generate करता हूं, और online services या web apps को Hunchentoot से HTTP requests handle कर response देने वाले Common Lisp programs के रूप में बनाता हूं
    VM start/restart होने पर sites/services अपने-आप शुरू हों, इसके लिए systemd unit files इस्तेमाल करता हूं, और ज्यादातर करीब 10–15 lines की होती हैं
    VM की initial setup को shell script में codify कर रखा है: https://github.com/susam/dotfiles/blob/main/linode.sh
    project-wise और service-wise settings अलग-अलग Makefile से manage करता हूं: https://github.com/susam/susam.net/blob/main/Makefile, https://github.com/susam/mathb/blob/main/Makefile
    containers इस्तेमाल नहीं करता। ये sites containers के popular होने से पहले से कई सालों से चल रही हैं, और अब तक initialization scripts और Makefile काफी रहे हैं
    Nginx भी इस्तेमाल करता हूं। यह static files serve करता है, backend service होने पर reverse proxy की भूमिका निभाता है, और TLS termination के अलावा request rate limiting या backend protection के लिए HTTP header allowlist configuration जैसे फायदे भी देता है
    मेरे छोटे personal playbook में curl LINK -o linode.sh && sh linode.sh, git clone LINK && cd PROJECT && sudo make setup https जैसी कुछ commands हैं
    make targets Nginx, certbot, sbcl जैसे tools install करना, Nginx configuration, certificate setup आदि site चलाने के लिए जरूरी काम संभालते हैं, और command खत्म होते ही website तुरंत public हो जाती है

    • जानना चाहूंगा कि कौन-सा Common Lisp implementation इस्तेमाल करते हैं
      Makefile देखकर लगता है कि SBCL इस्तेमाल कर रहे हैं, लेकिन जानना चाहूंगा कि memory usage कभी issue बना है या नहीं
      मैं 512MB RAM VPS इस्तेमाल करता हूं, और एक SBCL instance लगभग 100MB खा जाता है, इसलिए एक साथ सिर्फ कुछ ही services चला पाता हूं
      सबसे कम traffic वाली service को CLISP पर move करने का भी सोचा था, लेकिन इस्तेमाल हो रहे features में से एक package-local nickname उसमें नहीं है
  • कई सालों तक configuration को लगातार refine करने के बाद, अब मैं सब कुछ Docker containers में चलाने पर settled हूं
    orchestrator के लिए systemd की जगह docker-compose, और proxy के लिए nginx की जगह Caddy इस्तेमाल करता हूं
    मूल लेख की तरह, हर उस project के लिए deploy script लिखता हूं जिसे चलाना होता है, इसलिए कुल मिलाकर setup काफी मिलता-जुलता है
    Docker के कई फायदों में से एक यह है कि उसी configuration से third-party software भी चलाया जा सकता है
    कई सालों से यह setup इस्तेमाल कर रहा हूं और यह बहुत अच्छा है; मूल लेख की तरह मजबूत है और जरूरत पड़ने पर मनचाहे बदलाव करने की flexibility भी देता है
    अभी की एकमात्र परेशानी rolling deployment है। software बड़ा होने के साथ हर deployment में कुछ seconds का downtime समस्या बन रहा है, और अभी कोई सरल समाधान नहीं है, लेकिन docker swarm शायद सही रास्ता हो सकता है

    • मैं भी Caddy के साथ कुछ ऐसा ही operate कर रहा हूं
      downtime घटाने के लिए health_uri /health, lb_try_duration 30s आजमा सकते हैं
      उदाहरण के लिए, अगर reverse_proxy api:8089 { health_uri /health lb_try_duration 30s } की तरह configure करें, तो नई version deploy होने के दौरान Caddy requests को buffer करेगा और नई service के up होने तक 30 seconds देगा
      ideal रूप से, नई version healthy होने के बाद ही Caddy उसे इस्तेमाल करना शुरू करे और पुराने container को बंद करना चाहिए
      https://github.com/Wowu/docker-rollout और https://github.com/lucaslorentz/caddy-docker-proxy देखे हैं, लेकिन अभी priority तय नहीं कर पाया हूं
    • अगर Caddy जैसा load balancer pod के आगे है, तो उसे नए pod के up होने तक requests hold करने के लिए configure किया जा सकता है: https://twitter.com/bradleyjkemp/status/1486756361845329927
      यह perfect नहीं है, लेकिन browser को connection error मिलने के बजाय कुछ seconds तक सिर्फ loading दिखती रहती है
      https://mrsk.dev/ भी यही technique इस्तेमाल करता है
    • जिस startup में काम करता हूं, वहां software stack शुरू से बनाते समय application को सीधे Docker से package किया था
      production compose से शुरू हुआ, और बाद में stack को automatically upgrade करने वाली continuous deployment pipeline में improve किया
      जैसे-जैसे company और user base बढ़े, restart या deployment के समय downtime की समस्या दिखने लगी, और जब भी additional apps चलाने होते, नया deployment environment तैयार करना पड़ता था
      डर था कि शायद Kubernetes इस्तेमाल करने का दिन आएगा, क्योंकि उसकी complexity खुद देख चुका था और दिन का ज्यादातर हिस्सा cluster को मनाने में नहीं बिताना चाहता था
      इसलिए Swarm mode अपनाया, लेकिन यह सफर कभी Jekyll तो कभी Hyde जैसा रहा
      ऐसे bugs जिन्हें कोई ठीक नहीं करना चाहता, Docker spec के कुछ हिस्से जो implement नहीं हुए लेकिन बताया भी नहीं जाता, implementation choices जो सिर पकड़ने पर मजबूर कर दें, और ऐसा लगता है जैसे Docker Inc के employees आपस में बात नहीं करते या अंत तक focus नहीं रख पाते
      फिर भी इसके खूबसूरत पहलू भी हैं। compose stack वैसे ही काम करता है और जरूरत पड़ने पर बढ़ सकता है; सही तरह setup करने पर zero-downtime deployment, upgrades, load balancing और rollback अच्छे से चलते हैं
      Raft, दूसरी जगहों की तरह, cluster को बनाए रखने में भरोसेमंद है, और थोड़ी मेहनत से K8s maintenance budget के एक हिस्से में भी flexible, safe और automatically distributed self-service platform बनाया जा सकता है
      हालांकि deployment scripts सही से बनाने की तैयारी चाहिए। valid Docker spec compose file को Swarm spec में बदलने, secrets को renew और clean करने, और environment variables expand करने वाला Python tool बनाने में काफी समय लगाया
      VPS provider के हिसाब से network MTU भी जरूर सही set करना पड़ता है। इसकी वजह से लगता है मेरी उम्र कुछ कम हो गई होगी
    • अगर आपके पास पहले से compose file है तो Swarm ही रास्ता है, लेकिन personally मुझे लगा कि यह उतनी मेहनत के लायक नहीं है
      जब तक customers या users की संख्या इतनी न बढ़ जाए कि scaling problem सच में सामने आ जाए
    • मैंने मिलता-जुलता setup बनाया है, लेकिन docker save और docker import से images को SSH के जरिए push करने का तरीका पसंद नहीं है
      जानना चाहूंगा कि क्या आप अपनी registry खुद चला रहे हैं
  • physical server पर Podman Pod में PostgreSQL database और app रखते हैं, सब कुछ localhost के 5000 से ऊपर वाले ports पर चलता है, और Caddy 443 पर reverse proxy की तरह काम करता है
    systemd Timer से हर दिन शाम 4:55 बजे सभी databases को एक directory में dump किया जाता है
    उसके बाद DejaDup [1] हर दिन शाम 5 बजे $HOME को external HDD पर automatically backup करता है; cache files exclude रहती हैं लेकिन database dumps शामिल होते हैं
    OS Debian पर GNOME Core [2] के साथ है, और firewalld rules सिर्फ 80, 443 और custom SSH port allow करते हैं
    SSH key-based है और password authentication बंद है
    यह सबसे boring तरीका है, लेकिन बस अच्छे से काम करता है
    1 - https://flathub.org/apps/org.gnome.DejaDup
    2 - https://packages.debian.org/bookworm/gnome-core

    • जानना चाहूंगा कि server पर GNOME क्यों चला रहे हैं
    • cron jobs की जगह systemd timers इस्तेमाल करने की कोई वजह है क्या
  • इन दिनों एक server पर Dokku लगाकर इस्तेमाल कर रहा हूं
    manage करना आसान है, developers Heroku style में सिर्फ git push करके deploy कर सकते हैं, और plugins बहुत हैं इसलिए database जोड़ना या HTTPS setup करना भी ज्यादा से ज्यादा 10 seconds का काम है

    • मैं भी यही तरीका इस्तेमाल करता हूं, और git push से deploy कर पाना सच में सुविधाजनक है
      app जोड़ना, database जोड़ना, environment variables manage करना और domain manage करना—सब बहुत intuitive है
  • सरल कॉन्फ़िगरेशन पसंद होने की वजह से, यह तरीका काम करने में मज़ेदार लगता है
    99% सेवाओं के लिए इसके पर्याप्त होने की संभावना बड़ी है
    सर्वर सेटअप और deploy scripts के लिए शायद Ansible इस्तेमाल करूंगा
    इससे सर्वर documented हो सकता है और deploy scripts भी और सरल हो सकती हैं
    हालांकि debugging या verification के लिए सर्वर में सीधे लॉग इन करने से नहीं बचूंगा

    • Ansible इस्तेमाल तो कर रहा हूं, लेकिन फिर सोच रहा हूं कि क्या यह वाकई value देता है
      मेरी scripts पिछले 7 सालों में लगभग बदली नहीं हैं, जबकि Ansible धीमा है और कई files को लगातार maintain करने की प्रवृत्ति रखता है
      debugging के मामले में, nginx के जरिए app logs को password-protected endpoint पर expose भी किया जा सकता है
  • लगता है हम कभी-कभी भूल जाते हैं कि cloud से पहले भी CI/CD और प्रभावी server management आम practice थी

  • Rust में server software लिखकर उसे statically link करने और HTML, CSS, settings, secrets आदि सब कुछ binary में compile करके डालने के तरीके के बारे में: हाल में Go में मैं यही कर रहा हूं, और static files पर निर्भर software लिखना और deploy करना सच में बहुत आसान हो गया है, इसलिए यह मुझे बहुत पसंद है

    • compiled binary में secrets शामिल करना अब भी सवालिया लगता है
      secrets के लिए environment variables या config इस्तेमाल करना लगभग standard तरीका है; इससे execution से पहले एक step बढ़ता है, लेकिन binary share करते समय यह भूल जाने की स्थिति से बचा जा सकता है कि उसमें secrets मौजूद थे
      binary को unpack करके strings ढूंढना काफी आसान है
      static frontend assets और default settings को साथ में डालना बड़ा फायदा है
    • Go मुझे खास पसंद नहीं है, लेकिन इसी वजह से बार-बार इस्तेमाल कर लेता हूं
      Rust में, खासकर Mac से Linux के लिए cross-compile करना तुलनात्मक रूप से दर्दनाक है, जबकि Go में यह मामूली काम है और go tool में built-in है
      side project खत्म करके deploy करते समय friction हटाना सच में बहुत आसान हो जाता है
    • https://play.clickhouse.com/play?user=play भी इसी तरीके से कर रहा है
      हालांकि एक सवाल है। लेख में कहा गया है, “Let’s Encrypt certificate certbot से लिया जाता है और auto-renewal भी handle हो जाता है”, लेकिन मैं दो servers और geo-DNS वाला cross-region setup इस्तेमाल करता हूं, इसलिए certbot सिर्फ US server पर चलता है और certificate को Europe server पर manual copy करना पड़ता है
      क्या इसे हल करने का कोई तरीका है?
      ClickHouse Playground का विवरण यहां है: https://ghe.clickhouse.tech/
    • मेरा भी यही तरीका है
      वही statically compiled service, जो backend API देती है, web application भी serve करती है
      CI में npm build चलाकर output embed कर देता हूं, जिससे local testing या demo instance चलाना बहुत आसान हो जाता है