# जब होस्टेड CI सबसे धीमा कदम बन गया, तो बिल्ड घर लौट आए

Company: Webanion
Service: DevOps इंजीनियरिंग
Period: 2026-08 - 2026-09
Tech: GitHub Actions, CI/CD, Docker, zot, Verdaccio, Kubernetes, Go, SQLite, Linux, systemd
Canonical: https://webanion.com/hi/portfolio/replacing-hosted-ci-with-a-home-runner-pool-and-private-registries

बिल्ड और डिप्लॉय GitHub के होस्टेड रनर से, जहाँ हर रन नई मशीन पर शुरू होता था और रिलीज़ कतारों और गड़बड़ियों का इंतज़ार करती थीं, घर के एक रनर पूल पर आ गए: एक बिल्ड मशीन जो चालू रहते हुए हर जॉब लेती है, और हमेशा चालू सर्वर पर स्टैंडबाय रनर, एक ऐसे वॉचडॉग के पीछे जो शक होने पर शिपिंग जारी रखने की ओर झुकता है। इमेज एक प्राइवेट कंटेनर रजिस्ट्री में जाती हैं और स्टूडियो की लाइब्रेरी एक प्राइवेट npm रजिस्ट्री में, दोनों बिल्डिंग के अंदर, और हर रन GitHub की रिटेंशन से आगे तक संग्रह में रहता है। सबसे धीमा डिप्लॉय आठ मिनट चौबीस सेकंड से तीन मिनट पाँच सेकंड पर आ गया, और CI एक तिहाई तेज़ हो गया।

## पूरी कहानी

होस्टेड पाइपलाइन किसी व्यवसाय से इंतज़ार के रूप में क्या वसूलती है, और जब बिल्ड, इमेज और पैकेज एक ही छत के नीचे आ गए तो क्या बदला।

### पाइपलाइन किसी और की मशीन थी, और ख़राब दिन भी किसी और का

<p>सितंबर 2026 के मध्य तक हर बिल्ड और हर डिप्लॉय GitHub के होस्टेड रनर पर चलता था, और होस्टेड रनर हर बार एक नई वर्चुअल मशीन होता है: एक लाइन के बदलाव के लिए भी बेस इमेज, हर डिपेंडेंसी और बिल्ड की हर लेयर फिर से डाउनलोड होती, और फिर फेंक दी जाती। इसके बाद इमेज हमेशा चालू प्रोडक्शन सर्वर पर बनती थी, क्योंकि नतीजा वहीं चल सकता था, यानी जो मशीन डेटाबेस और पब्लिक साइटें चला रही थी, वही उस दौरान कंपाइल भी कर रही थी। सबसे धीमा डिप्लॉय मीडियन पर आठ मिनट चौबीस सेकंड लेता था, लगभग पूरा समय बिल्ड में, मर्ज एक के पीछे एक कतार में लगते थे, और कोई रिलीज़ सिर्फ़ इसलिए फ़ेल हो सकती थी कि किसी डिपेंडेंसी का डाउनलोड टाइम आउट हो गया, ऐसी विफलता जिसका कोड से कोई लेना-देना नहीं। रिकॉर्ड भी टिकता नहीं था: GitHub वर्कफ़्लो लॉग डिफ़ॉल्ट रूप से सिर्फ़ नब्बे दिन रखता है।</p><p>नीचे की सेवा का भी अपना मुश्किल साल रहा। 2 फ़रवरी को GitHub ने बताया कि उसके होस्टेड रनर उपलब्ध नहीं थे और जॉब कतार में इंतज़ार करते-करते टाइम आउट हो गए: "Actions jobs queued and timed out while waiting to acquire a hosted runner" (<a href="https://www.githubstatus.com/incidents/xwn6hjps36ty">घटना</a>)। 5 मार्च को पंचानवे प्रतिशत वर्कफ़्लो रन समय पर शुरू नहीं हुए: "failed to start within 5 minutes with an average delay of 30 minutes" (<a href="https://www.githubstatus.com/incidents/g5gnt5l5hf56">घटना</a>)। 9 जुलाई को करीब दस घंटे तक जॉब देर से शुरू हुए या शुरू ही नहीं हुए: Actions "experienced delayed and failed job starts on GitHub-hosted runners" (<a href="https://www.githubstatus.com/incidents/cstx3v63mklm">घटना</a>)। 26 अगस्त को जॉब शुरू नहीं हुए, "Actions jobs failed to start", और उसके बाद दो घंटे तक रन पाँच मिनट से ज़्यादा की देरी से शुरू हुए: "were delayed starting by more than 5 minutes as the system caught up with delayed load" (<a href="https://www.githubstatus.com/incidents/y1t7p9fzrlj2">घटना</a>)। 13 सितंबर को GitHub ने Actions समेत लगभग 28 सेवाओं में घटी हुई उपलब्धता बताई: "degraded availability across approximately 28 services, including Issues, Pull Requests, Actions" (<a href="https://www.githubstatus.com/incidents/0rn90wk115q9">घटना</a>)। <a href="https://www.githubstatus.com/history">उसके स्टेटस पेज</a> से गिनें तो जनवरी से सितंबर के बीच पचास से ज़्यादा घटनाओं ने Actions को छुआ। रिपॉज़िटरी, रिव्यू और वर्कफ़्लो की परिभाषाएँ GitHub पर ही रहती हैं; बदली सिर्फ़ वह मशीन जिस पर काम चलता है, और वह सब जो वह मशीन डाउनलोड करके फेंकती आ रही थी।</p>

### डिप्लॉय आठ की जगह तीन मिनट में, मापकर

<p>17 सितंबर को होस्टेड मीडियन के मुक़ाबले मापा गया: CMS का डिप्लॉय 8 मिनट 24 सेकंड से घटकर 3 मिनट 05 सेकंड, वेबसाइट का 6 मिनट 12 सेकंड से 2 मिनट 27 सेकंड और MCP सर्वर का 1 मिनट 45 सेकंड से 45 सेकंड पर आ गया। एक साथ मर्ज हुई दो रिलीज़ असल घड़ी के 3 मिनट 22 सेकंड में पहुँच गईं, और तीनों सेवाओं का CI एक साथ चलाने पर एक तिहाई तेज़ निकला।</p>

### हर रन उसी मशीन पर, जिसने पिछला बनाया था

<p>होस्टेड रनर हर बार एक नई मशीन होता है। घर का पूल हर जॉब के लिए वही मशीनें हैं, इसलिए उनकी इमेज लेयर और पैकेज कैश पहले से मौजूद रहते हैं, क्लस्टर तक जाते हुए इमेज कभी इंटरनेट पार नहीं करती, और बिल्ड उस मशीन पर चलता है जो बिल्ड के लिए बनी है, न कि उस पर जो साइटें चला रही है। एक ही बिल्ड ठंडे कैश से 528 सेकंड और गर्म कैश से 192 सेकंड में मापा गया। घर के पहले रन तीन गुना धीमे थे, जब तक एक कदम हटाया नहीं गया: हर बिल्ड अपना डिपेंडेंसी कैश घर के कनेक्शन से वापस GitHub पर अपलोड कर रहा था, वेबसाइट पर इसमें 411 सेकंड जाते थे, जो तब समझ में आता है जब रनर किसी और की मशीन हो, और तब बिल्कुल नहीं जब कैश पहले से वहीं रहता है जहाँ अगला बिल्ड चलेगा।</p><p>Runs व्यू निगरानी में रखी हर रिपॉज़िटरी का हर रन दिखाता है और हर रन पूरा होते ही उसे संग्रह में रख लेता है, इसलिए वह GitHub की रिटेंशन के बाद भी बचा रहता है। कैप्चर के दिन उसमें 49 सेकंड, 3 मिनट 15 सेकंड और 2 मिनट 51 सेकंड के डिप्लॉय और दो से तीन मिनट के CI रन दिख रहे थे, और विफलताएँ भी नज़र में थीं: एक डिप्लॉय की दो फ़ेल कोशिशें, फिर तीसरी जो पास हुई।</p>

### एक डिप्लॉय, कदम दर कदम, अपनी ही समय-रेखा पर

<p>कोई रन खोलने पर हर जॉब और हर कदम उस रन की अपनी समय-रेखा पर दिखता है, जो GitHub के टाइमस्टैंप से मापी जाती है, और साथ में वह इमेज जो रन ने पुश की, उसके digest, साइज़ और प्लेटफ़ॉर्म के साथ, और यह भी कि वह इमेज अभी कहाँ चल रही है। दोबारा की गई कोशिशें मिटाई नहीं जातीं, रखी जाती हैं: कैप्चर वाला डिप्लॉय अपनी पहली दो कोशिशों में फ़ेल हुआ और तीसरी में पास, हर कोशिश अलग से खुलती है, और दूसरी में डिप्लॉय का कदम छियालीस सेकंड बाद फ़ेल होता दिखता है, इसलिए फ़िक्स के बाद भी विफलता की वजह वहीं मौजूद रहती है।</p><p>पास हुई कोशिश दिखाती है कि घर के पूल पर समय कहाँ जाता है: checkout और वर्ज़न बढ़ाने में कुछ सेकंड, और बिल्ड और क्लस्टर पर डिप्लॉय में ढाई मिनट से थोड़ा कम। यह वह भी दिखाती है जो एक कंसोल बता सकता है और CI का लॉग नहीं: कि वह इमेज अब रजिस्ट्री में नहीं है, क्योंकि रिटेंशन सिर्फ़ हाल के बिल्ड रखती है, और क्लस्टर में अब कुछ भी उस digest को नहीं चला रहा।</p>

### जब बिल्ड मशीन चली जाए, तब भी काम होता रहता है

<p>रनर पूल में एक प्राइमरी है और एक स्टैंडबाय। बिल्ड मशीन चालू रहते हुए उसके रनर हर जॉब लेते हैं, और हमेशा चालू सर्वर पर स्टैंडबाय रनर रहते हैं जो तभी शुरू होते हैं जब एक वॉचडॉग तय करता है कि बिल्ड मशीन नहीं रही। मशीन को डाउन मानने से पहले वॉचडॉग को एक से ज़्यादा फ़ेल जाँच चाहिए, और उसे वापस मानने से पहले एक से ज़्यादा पास जाँच, इसलिए नेटवर्क की एक छोटी-सी रुकावट से कुछ भी इधर-उधर नहीं होता, और हैंडओवर दोनों दिशाओं में दो-एक मिनट के भीतर हो जाता है। यह किसी जॉब को बीच में नहीं काटता: बंद होने से पहले चल रहे जॉब का इंतज़ार होता है, और स्टैंडबाय तभी हटता है जब वह ख़ाली हो।</p><p>अगर वॉचडॉग GitHub तक पहुँच ही न पाए, तो भी वह स्टैंडबाय शुरू कर देता है, क्योंकि निगरानी की ऐसी विफलता जो डिप्लॉय रोक दे, उस आउटेज से भी बुरी है जिस पर वह नज़र रख रही थी। कंसोल के ओवरव्यू पर रनर पूल पैनल बताता है कि जॉब कौन सा पक्ष ले रहा है और कौन से स्टैंडबाय रनर तैयार हैं।</p>

### इमेज और पैकेज, एक ही छत के नीचे से

<p>हमेशा चालू सर्वर पर एक कंटेनर रजिस्ट्री और एक npm रजिस्ट्री साथ-साथ चलती हैं, क्योंकि कंटेनर इमेज और npm पैकेज ऐसे प्रोटोकॉल बोलते हैं जिनमें कुछ भी साझा नहीं। कंटेनर रजिस्ट्री पूल की बनाई हर इमेज लोकल नेटवर्क पर लेती है: पुश करने के लिए सिर्फ़ एक अकाउंट, पुल करने वाली हर चीज़ के लिए रीड-ओनली अकाउंट और कोई अनाम पहुँच नहीं, और एक ही टैग दोनों प्रोसेसर आर्किटेक्चर रख सकता है ताकि हर नोड अपने से मेल खाता बिल्ड खींचे। रिटेंशन हर सर्विस के दो सबसे हाल के बिल्ड और आख़िरी बार खींचा गया बिल्ड रखती है, और यही रोलबैक की खिड़की है, जिसे मान नहीं लिया जाता, साफ़ लिखा जाता है।</p><p>npm रजिस्ट्री स्टूडियो की अपनी लाइब्रेरी फ़ैमिली परोसती है। हर लाइब्रेरी की रिलीज़ उसके GitHub Release से बाइट-दर-बाइट उसमें प्रकाशित होती है, क्लस्टर के अंदर चलने वाले एक सिंक के ज़रिए हर पाँच मिनट में, हर रीड के लिए लॉगिन चाहिए, पब्लिक नाम पर लिखना मना है, और रात का एक जॉब हर प्रकाशित वर्ज़न को उसकी रिलीज़ से मिलाता है। किसी भी रजिस्ट्री का अपना इंटरफ़ेस नहीं है, इसलिए कंसोल ही उनकी स्क्रीन है: Estate व्यू कंटेनर रजिस्ट्री की रिपॉज़िटरी उनके साइज़ और प्लेटफ़ॉर्म के साथ दिखाता है, और इन लाइब्रेरी को इस्तेमाल करने वाले किसी भी प्रोजेक्ट में इंस्टॉल बिल्डिंग के अंदर से ही पूरा हो जाता है।</p>

### एक मर्ज से चलते पॉड तक, और वापसी की एक लाइन

<p>एक मर्ज पूल पर बिल्ड को कतार में लगाता है, इमेज लोकल नेटवर्क पर रजिस्ट्री में जाती है, और डिप्लॉय एक ऐसी पहचान से चलता है जो एक namespace तक सीमित है, जिसे मिटाने का अधिकार नहीं और जिसके पास सिर्फ़ एक नामित secret है। हर नोड अपने से मेल खाता बिल्ड खींचता है, और हर रिपॉज़िटरी का एक वेरिएबल किसी सर्विस को उसके अगले push पर होस्टेड रनर पर वापस भेज देता है।</p>

### कामकाजी हफ़्ते पर इसका असर, और यह किसके लिए है

<p>मर्ज अब एक-दूसरे का इंतज़ार नहीं करते: बिल्ड मशीन चालू हो तो रिलीज़ साथ-साथ बनती और डिप्लॉय होती हैं, और स्टैंडबाय पर एक लॉक भारी कदमों को एक-एक करके चलाता है ताकि कुछ टकराए नहीं। एक फ़िक्स आठ की जगह करीब तीन मिनट में निकल जाता है, हमेशा चालू सर्वर सिर्फ़ तब कंपाइल करता है जब बिल्ड मशीन मौजूद न हो, और हर रन का रिकॉर्ड GitHub के हटा देने के बाद भी बिल्डिंग में ही रहता है। रिपॉज़िटरी, रिव्यू और वर्कफ़्लो की परिभाषाएँ सब GitHub पर ही रहीं; बदली सिर्फ़ मशीनें, कैश, इमेज और पैकेज।</p><p>सीमा पहले ही बता दी जाती है: बिल्ड के बीच बिजली कट जाए तो वह बिल्ड फ़ेल हो जाता है, और उसे फिर से चलाया जाता है। यह सही कदम है उस टीम के लिए जिसकी रिलीज़ कतार में लगने लगी हैं, उसके लिए जिसका कोड और इमेज बिल्डिंग से बाहर नहीं जाने चाहिए, और उस फ़ाउंडर के लिए जिसने किसी फ़िक्स को किसी और की कतार में अटका देखा है। यह उस टीम के लिए ग़लत कदम है जिसके पास मशीनों की ज़िम्मेदारी लेने वाला कोई नहीं, और यह साफ़ कहना ज़रूरी है। नीचे का क्लस्टर <a href="/portfolio/scaling-a-homelab-from-one-node-to-a-multi-node-cluster">एक नोड के क्लस्टर बनने</a> की कहानी है, उसके चारों ओर का प्लेटफ़ॉर्म <a href="/portfolio/self-hosted-homelab-that-runs-the-studio-infrastructure">स्टूडियो चलाने वाला होमलैब</a> है, और यही तरीका किसी क्लाइंट के प्लेटफ़ॉर्म पर लागू हुआ तो वह <a href="/portfolio/fully-booked-zero-downtime-migration-to-self-hosted-kubernetes">सेल्फ़-होस्टेड Kubernetes पर बिना डाउनटाइम का माइग्रेशन</a> बना।</p>
