कल्पना करें: आपका Docker Compose सेटअप आपकी लोकल मशीन पर पूरी तरह काम करता है। आप CI में पुश करते हैं, और अचानक हर इंटीग्रेशन टेस्ट Connection refused के साथ फेल हो जाता है।
डेटाबेस कंटेनर "चल रहा" है। API कंटेनर "स्वस्थ" है। टेस्ट प्रक्रिया शुरू होती है। फिर वह आवश्यक सेवा से कनेक्ट नहीं हो पाती।
यह विफलता यादृच्छिक लगती है जब तक आपको एक बात याद न आए: लोकल Docker नेटवर्किंग और CI Docker नेटवर्किंग एक ही वातावरण नहीं हैं।
लोकल सेटअप आपको धोखा देता है
आपकी मशीन पर, आप Postgres से localhost:5432 पर कनेक्ट कर सकते हैं।
Compose नेटवर्क के अंदर, एक अन्य कंटेनर को आमतौर पर postgres:5432 से कनेक्ट करना चाहिए, जहाँ postgres सेवा का नाम है।
CI में, टेस्ट रनर हो सकता है:
- Compose नेटवर्क के अंदर
- होस्ट पर Compose नेटवर्क के बाहर
- CI सर्विस कंटेनर के अंदर
- नेस्टेड Docker एक्जीक्यूटर के अंदर
ये चार मामले अलग-अलग होस्टनेम का उपयोग करते हैं।
यही कारण है कि एक कनेक्शन स्ट्रिंग लोकल पर "सही" और पाइपलाइन में गलत हो सकती है।
पहले, पहचानें कि टेस्ट प्रक्रिया कहाँ चलती है
पोर्ट बदलने से पहले, एक प्रश्न पूछें:
क्या टेस्ट कमांड Compose सेवा के अंदर चल रहा है या CI होस्ट पर?
यदि टेस्ट Compose के अंदर चलते हैं:
DATABASE_URL=postgres://user:pass@postgres:5432/appयदि टेस्ट CI होस्ट पर चलते हैं और Compose ने पोर्ट प्रकाशित किया है:
DATABASE_URL=postgres://user:pass@127.0.0.1:5432/appयदि टेस्ट एक अलग CI कंटेनर में चलते हैं, तो CI प्लेटफ़ॉर्म की सर्विस नेटवर्किंग कॉन्फ़िगर होने तक कोई भी काम नहीं कर सकता है।
सही होस्टनेम इस बात पर निर्भर करता है कि टेस्ट रनर कहाँ रहता है। सेवा के नाम Compose नेटवर्क के अंदर काम करते हैं। प्रकाशित localhost पोर्ट होस्ट से काम करते हैं।
depends_on को तत्परता के रूप में न भरोसा करें
depends_on शुरुआती क्रम को नियंत्रित कर सकता है। यह गारंटी नहीं देता कि Postgres, Redis, या आपका ऐप कनेक्शन स्वीकार करने के लिए तैयार है।
सामान्य खराब संस्करण:
services:
api:
depends_on:
- postgresइसका केवल यह मतलब है कि postgres कंटेनर api से पहले शुरू होता है। इसका मतलब यह नहीं है कि माइग्रेशन चले। इसका मतलब यह नहीं है कि TCP तैयार है। इसका मतलब यह नहीं है कि डेटाबेस ने प्रमाणीकरण स्वीकार किया।
हेल्थ चेक या एक स्पष्ट प्रतीक्षा स्क्रिप्ट का उपयोग करें।
services:
postgres:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
timeout: 5s
retries: 12
api:
depends_on:
postgres:
condition: service_healthyयह अभी भी हर CI प्लेटफ़ॉर्म को हल नहीं करता है, लेकिन यह सबसे आम रेस को हटा देता है।
चार विफलता वर्गों की जाँच करें
जब मैं Connection refused देखता हूँ, तो मैं इस क्रम में काम करता हूँ।
TCP जाँच उबाऊ लेकिन उपयोगी है:
node -e "require('net').connect(5432, process.env.DB_HOST).on('connect', () => { console.log('ok'); process.exit(0) }).on('error', e => { console.error(e.message); process.exit(1) })"यदि वह विफल होता है, तो आपका एप्लिकेशन टेस्ट सूट अभी डीबग करने वाली चीज़ नहीं है।
विभिन्न सीमाओं के लिए अलग-अलग कनेक्शन स्ट्रिंग का उपयोग करें
एक साफ पैटर्न सीमा को स्पष्ट बनाना है:
DATABASE_URL_INTERNAL=postgres://app:app@postgres:5432/app
DATABASE_URL_HOST=postgres://app:app@127.0.0.1:5432/appफिर आपका CI जॉब इस आधार पर सही चुनता है कि कमांड कहाँ चलता है।
यह एक URL को हर जगह काम करने की कोशिश करने से कम जादुई है।
माइग्रेशन को तत्परता से अलग रखें
एक डेटाबेस स्कीमा तैयार होने से पहले स्वस्थ हो सकता है।
यदि आपके ऐप को माइग्रेशन की आवश्यकता है, तो इसे एक स्पष्ट पाइपलाइन चरण बनाएँ:
docker compose up -d postgres
docker compose run --rm migrate
docker compose run --rm testया टेस्ट को एक सेवा के अंदर चलाएँ जो दोनों की प्रतीक्षा करती है:
- डेटाबेस स्वास्थ्य
- माइग्रेशन पूर्ण
- सीड डेटा लोड
अन्यथा आपको एक बदतर प्रकार की विफलता मिलती है: रुक-रुक कर होने वाली टेस्ट त्रुटियाँ जो ऐप बग की तरह दिखती हैं लेकिन वास्तव में सेटअप रेस हैं।
डीबग आउटपुट जो मैं हर CI विफलता में चाहता हूँ
सीक्रेट डंप न करें। एनवायरनमेंट का आकार प्रिंट करें।
उपयोगी आउटपुट:
- Docker Compose सेवाएँ और स्थिति
- निर्भरता के लिए कंटेनर लॉग
- पासवर्ड रिडैक्टेड के साथ रिज़ॉल्व किया गया होस्ट और पोर्ट
- नेटवर्क नाम
- हेल्थ-चेक स्थिति
- माइग्रेशन स्थिति
उदाहरण:
docker compose ps
docker compose logs --tail=80 postgres
docker network lsलक्ष्य अगली विफलता को एक पास में निदान योग्य बनाना है।
प्रोडक्शन सबक
CI नेटवर्किंग दर्द प्रोडक्शन इंटीग्रेशन दर्द का एक पूर्वावलोकन है।
यदि आपके टेस्ट उम्मीद पर निर्भर हैं, तो आपकी डिप्लॉयमेंट शायद भी ऐसा ही करती हैं। सेवा सीमाओं को स्पष्ट बनाएँ। हेल्थ चेक जोड़ें। तत्परता को माइग्रेशन से अलग करें। सही तथ्यों को लॉग करें।
इस तरह आप "मेरी मशीन पर काम करता है" को किसी ऐसी चीज़ में बदल देते हैं जिसे पाइपलाइन साबित कर सकती है।
