एक वाक्य में
Docker Compose एक टूल है जो आपको ढेर सारे लंबे, अजीब docker run कमांड्स के बजाय एक सिंगल, इंसानों के पढ़ने लायक YAML फ़ाइल का उपयोग करके multi-container एप्लिकेशन को डिफाइन और रन करने देता है।
यह कौनसी समस्या हल करता है
शुरू शुरू में, docker run था। और वो... ठीक-ठाक ही था। एक कंटेनर चलाने के लिए, यह ठीक है। आप अपना कमांड टाइप करते हैं, शायद एक पोर्ट मैपिंग और एक वॉल्यूम के साथ, और बूम, आपके पास एक रनिंग सर्विस होती है।
लेकिन क्या होता है जब आपका ऐप सिर्फ एक सर्विस नहीं है? क्या हो अगर आपके पास एक वेब फ्रंटएंड, एक बैकएंड API, एक PostgreSQL डेटाबेस, और एक Redis कैश हो? अचानक, आप सिर्फ एक कमांड नहीं चला रहे हैं। आप चार-चार कमांड्स को संभाल रहे हैं।
आपको मैन्युअल रूप से एक नेटवर्क बनाना पड़ता है ताकि वे एक-दूसरे से बात कर सकें। आपको यह सुनिश्चित करना होता है कि आप गलती से उन सभी को एक ही होस्ट पोर्ट पर मैप न कर दें। आपको हर सर्विस के लिए सटीक, बहुत लंबा docker run कमांड याद रखना पड़ता है, उसके सभी एनवायरनमेंट वेरिएबल्स और वॉल्यूम माउंट्स के साथ। अगर आप इस सेटअप को किसी नए टीममेट के साथ शेयर करना चाहते हैं, तो आप एक विशाल README.md फ़ाइल लिखते हैं जो मूल रूप से एक प्रार्थना होती है कि वे सब कुछ सही-सही कॉपी-पेस्ट करेंगे। यह अराजकता, टाइपो और उस क्लासिक "अरे, मेरी मशीन पर तो चलता है!" वाली दुविधा का नुस्खा है।
यह वह अराजकता है जिसे Docker Compose, जो Fig नामक एक प्रोजेक्ट से पैदा हुआ था जिसे Docker ने 2014 में अधिग्रहित किया था, काबू में करने के लिए डिज़ाइन किया गया था। इसका मतलब है अलग-अलग कंटेनर "पालतू जानवरों" को मैनेज करने से आगे बढ़कर पूरे एप्लिकेशन "झुंड" को ऑर्केस्ट्रेट करना। आदेशात्मक कमांड (इसे चलाओ, फिर उसे चलाओ, उन्हें ऐसे लिंक करो...) जारी करने के बजाय, आप एक सिंगल घोषणात्मक फ़ाइल (यहाँ बताया गया है कि मेरा पूरा एप्लिकेशन स्टैक कैसा दिखता है) लिखते हैं और Compose को इसे हकीकत बनाने के कीचड़ भरे विवरणों को संभालने देते हैं।
अंदर से यह कैसे काम करता है
अपने मूल में, Docker Compose एक अनुवादक है। यह एक वर्णनात्मक YAML फ़ाइल को Docker Engine को किए जाने वाले API कॉल्स की एक श्रृंखला में अनुवाद करता है। यह कंटेनर मैनेजमेंट का "दिखाओ, बताओ मत" वाला सिद्धांत है।
docker run फ्लैग्स से YAML कीज़ तक
मान लीजिए आप एक PostgreSQL डेटाबेस चलाना चाहते हैं। docker run कमांड किसी हैकर मूवी से उठाए गए अल्फाबेट सूप जैसी लाइन लग सकती है:
docker run --name my-postgres-db \
-e POSTGRES_PASSWORD=supersecret \
-p 5432:5432 \
-v pgdata:/var/lib/postgresql/data \
--restart unless-stopped \
-d postgres:14
इस कमांड में एक नाम, पासवर्ड के लिए एक एनवायरनमेंट वेरिएबल, एक पोर्ट मैपिंग, डेटा को बनाए रखने के लिए एक नेम्ड वॉल्यूम, एक रीस्टार्ट पॉलिसी है, और यह बैकग्राउंड में चलता है (-d)।
अब, docker-compose.yml फ़ाइल में Docker Compose का समकक्ष देखें:
version: '3.8' # Compose फ़ाइल का वर्शन बताता है
services:
db: # यह हमारी सर्विस के लिए एक दोस्ताना नाम है
image: postgres:14
container_name: my-postgres-db
restart: unless-stopped
environment:
POSTGRES_PASSWORD: supersecret
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata: # हम यहां नेम्ड वॉल्यूम को डिक्लेअर करते हैं
समानता देखी? कमांड-लाइन फ्लैग्स साफ-सुथरे, व्यवस्थित YAML कीज़ बन गए हैं। यह सिर्फ सुंदर नहीं है; यह आपकी सर्विस की एक वर्शन-कंट्रोल करने योग्य, शेयर करने योग्य, और बहुत कम त्रुटि-प्रवण परिभाषा है।
docker run फ्लैग |
docker-compose.yml की |
यह क्या करता है |
|---|---|---|
postgres:14 (the image) |
image: postgres:14 |
उपयोग करने के लिए कंटेनर इमेज निर्दिष्ट करता है। |
--name my-postgres-db |
container_name: my-postgres-db |
कंटेनर को एक विशिष्ट नाम देता है। |
-p 5432:5432 |
ports: ["5432:5432"] |
होस्ट से कंटेनर में एक पोर्ट मैप करता है। |
-v pgdata:/var/lib/... |
volumes: [pgdata:/var/lib/...] |
परसिस्टेंट डेटा के लिए एक वॉल्यूम माउंट करता है। |
-e VAR=value |
environment: { VAR: value } |
कंटेनर के अंदर एनवायरनमेंट वेरिएबल्स सेट करता है। |
--restart unless-stopped |
restart: unless-stopped |
कंटेनर की रीस्टार्ट पॉलिसी को परिभाषित करता है। |
नेटवर्किंग का जादू
यहीं पर Compose वास्तव में चमकता है। यदि आप उसी YAML फ़ाइल में एक वेब ऐप सर्विस जोड़ते हैं, जैसे:
services:
db:
# ... (ऊपर से हमारी postgres कॉन्फ़िगरेशन)
api:
image: my-cool-api:latest
ports:
- "8000:8000"
environment:
DATABASE_URL: postgresql://user:supersecret@db:5432/mydatabase
depends_on:
- db
जब आप docker-compose up चलाते हैं, तो Compose कुछ शानदार करता है: यह आपके एप्लिकेशन के लिए एक समर्पित वर्चुअल नेटवर्क बनाता है। db और api दोनों कंटेनर इस नेटवर्क से जुड़े होते हैं।
अब, api सर्विस होस्टनाम db का उपयोग करके डेटाबेस से कनेक्ट हो सकती है—वही नाम जो हमने YAML फ़ाइल में सर्विस को दिया था! अब IP एड्रेस देखने या नाजुक --link फ्लैग्स की कोई जरूरत नहीं। Compose अपने निजी नेटवर्क के भीतर सभी DNS रिज़ॉल्यूशन को संभालता है। इस तरह आपका वेब ऐप कंटेनर आपके डेटाबेस कंटेनर को सुरक्षित और मज़बूती से प्यारी-प्यारी बातें फुसफुसा सकता है (या, आप जानते हैं, SQL क्वेरीज़)।
Compose लाइफसाइकिल
docker-compose कमांड आपके पूरे एप्लिकेशन स्टैक के लिए आपका कंट्रोल पैनल है।
docker-compose up: यह मुख्य कमांड है। यह आपकीdocker-compose.ymlको पढ़ता है, आपके सिस्टम की स्थिति की जाँच करता है, और इसे फ़ाइल से मेल खाने के लिए जो कुछ भी आवश्यक है, वह करता है। यह नेटवर्क बनाएगा, इमेज बिल्ड करेगा (यदि आपनेbuildनिर्देश निर्दिष्ट किया है), वॉल्यूम बनाएगा, और आपकी सभी सर्विस कंटेनरों को शुरू करेगा। यदि आप इसे फिर से चलाते हैं, तो यह समझदारी से परिवर्तनों की जाँच करेगा और केवल उन कंटेनरों को फिर से बनाएगा जिन्हें अपडेट करने की आवश्यकता है।docker-compose down:upका दोस्ताना उल्टा। यह सभी कंटेनरों को रोकता और हटाता है, और डिफ़ॉल्ट रूप से, इसके द्वारा बनाए गए नेटवर्क को भी हटा देता है। यह 'मेरा फैलाया रायता समेटो' वाला बटन है। वास्तव में पूरी तरह से साफ करने के लिए,docker-compose down -vनेम्ड वॉल्यूम को भी हटा देता है।docker-compose ps: आपको आपकी Compose फ़ाइल द्वारा प्रबंधित सभी कंटेनरों की स्थिति दिखाता है।docker-compose logs -f: आपकी सभी सेवाओं से लॉग को एक सुविधाजनक स्ट्रीम में दिखाता है, जो सर्विस के अनुसार कलर-कोडेड होता है। डीबगिंग के लिए अमूल्य है।
असल दुनिया की कहानियाँ
'मेरी मशीन पर तो चलता है' वाली कहानी
डेवॉन ने अपनी कंपनी के एनालिटिक्स डैशबोर्ड के लिए एक नया फ़ीचर पूरा किया, जो Node.js बैकएंड और MongoDB डेटाबेस का उपयोग करता है। यह उनके लैपटॉप पर पूरी तरह से काम करता है। वे कोड पुश करते हैं और एक नए कर्मचारी, सैम, को इसे पुल करके चलाने के लिए कहते हैं। डेवॉन की README में दो विशाल docker run कमांड हैं। सैम, इंसान होने के नाते, डेटाबेस वॉल्यूम पाथ में एक टाइपो कर देता है। ऐप शुरू होता है, लेकिन यह कुछ भी सहेज नहीं पाता है। सैम तीन घंटे ऐप के कोड को डीबग करने में बिताता है, यह सोचते हुए कि बग वहीं है, जबकि डेवॉन जोर देकर कहता है कि सब ठीक है। अंत में, वे स्क्रीन-शेयर करते हैं और टाइपो को पकड़ते हैं। सब बहुत फ्रस्ट्रेट हो जाते हैं।
सबक: अगर उन्होंने docker-compose.yml का इस्तेमाल किया होता, तो ऑनबोर्डिंग एक सिंगल docker-compose up कमांड होती। पूरा एनवायरनमेंट—पोर्ट्स, वॉल्यूम, एनवायरनमेंट वेरिएबल्स—एक जैसा होता, जिससे सेटअप त्रुटियों का एक पूरा वर्ग समाप्त हो जाता और आधे दिन की डीबगिंग 30-सेकंड के स्टार्टअप में बदल जाती।
CI/CD पाइपलाइन का बुरा सपना
एक DevOps टीम अपने माइक्रोसर्विसेज ऐप का परीक्षण करने के लिए एक कंटीन्यूअस इंटीग्रेशन पाइपलाइन बना रही थी। ऐप में एक वेब सर्वर, एक API गेटवे, एक यूजर सर्विस और एक Redis कैश था। उनकी Jenkinsfile शेल कमांड्स की एक डरावनी स्क्रिप्ट थी, जिसमें चार अलग-अलग docker run कॉल और sleep 30 कमांड्स का एक गुच्छा था, इस उम्मीद में कि API के कनेक्ट होने की कोशिश करने से पहले डेटाबेस तैयार हो जाएगा। टेस्ट अविश्वसनीय थे; कभी वे पास हो जाते, कभी वे फेल हो जाते क्योंकि sleep पर्याप्त लंबा नहीं होता था।
सबक: उन्होंने Docker Compose का उपयोग करने के लिए पाइपलाइन को फिर से लिखा। Jenkinsfile को docker-compose -f docker-compose.ci.yml up -d तक सरल बना दिया गया। उन्होंने depends_on के साथ condition: service_healthy का उपयोग यह सुनिश्चित करने के लिए किया कि API केवल तभी शुरू हो जब डेटाबेस अपनी आंतरिक स्वास्थ्य जाँच पास कर ले। वो अविश्वसनीय टेस्ट रातों-रात गायब हो गए। Compose ने हर बार आवश्यक सटीक परीक्षण वातावरण को परिभाषित करने और लॉन्च करने का एक विश्वसनीय, घोषणात्मक तरीका प्रदान किया।
भूला हुआ साइडकार
एक डेवलपर, मारिया, ने अपना मुख्य Python एप्लिकेशन एक Docker कंटेनर में डिप्लॉय किया। कुछ हफ़्ते बाद, उसके मैनेजर ने उसे विस्तृत प्रदर्शन निगरानी जोड़ने के लिए कहा। सबसे अच्छा तरीका एक Prometheus एक्सपोर्टर को "साइडकार" के रूप में चलाना था—एक दूसरा कंटेनर जो मुख्य ऐप के साथ रहता है, मेट्रिक्स स्क्रैप करने के लिए अपना नेटवर्क साझा करता है। मारिया ने इसे एक और docker run कमांड के साथ सेट किया। लेकिन अब उसे हर बार बदलाव करने पर दो कंटेनरों को शुरू करने, रोकने और पुनरारंभ करने के लिए याद रखना पड़ता था। एक दिन, उसने ऐप को पुनरारंभ किया लेकिन साइडकार को भूल गई, और उन्होंने पूरे दिन के मेट्रिक्स खो दिए।
सबक: मारिया ने अपने सेटअप को docker-compose.yml में रीफैक्टर किया। उसने अपने Python ऐप को एक सर्विस और Prometheus एक्सपोर्टर को दूसरी सर्विस के रूप में परिभाषित किया। अब, docker-compose up उन दोनों को एक साथ जीवन में लाता, और docker-compose down उन्हें एक साथ रिटायर कर देता। उन्हें एक सिंगल लॉजिकल यूनिट के रूप में प्रबंधित किया गया, जैसा कि उन्हें होना चाहिए। Compose साइडकार जैसे पैटर्न को प्रबंधित करना बहुत आसान बना देता है।
आम गलतियाँ और जाल
- यह मान लेना कि
depends_onरेडी होने का इंतजार करता है। डिफ़ॉल्ट रूप से,depends_onकेवल डिपेंडेंसी कंटेनर के शुरू होने का इंतजार करता है, न कि उसके अंदर के एप्लिकेशन के पूरी तरह से इनिशियलाइज़ होने और कनेक्शन स्वीकार करने के लिए तैयार होने का। आपका API आपके डेटाबेस के क्वेरी किए जाने के लिए तैयार होने से पहले शुरू हो सकता है, जिससे क्रैश हो सकता है। असली समाधान यह है कि आप अपने डेटाबेस सर्विस की परिभाषा मेंhealthcheckनिर्देश का उपयोग करें और फिरdepends_onसिंटैक्स के लंबे रूप का उपयोगcondition: service_healthyके साथ करें। - Git में सीक्रेट्स कमिट करना।
docker-compose.ymlमेंPOSTGRES_PASSWORD: my-secret-passwordको हार्डकोड करना बहुत लुभावना लगता है। ऐसा न करें। अब जिस किसी के पास भी आपके रिपॉजिटरी तक पहुंच है, उसके पास आपका डेटाबेस पासवर्ड है। सही तरीका है एक.envफ़ाइल का उपयोग करना (जिसे आप.gitignoreमें जोड़ते हैं) और अपनी Compose फ़ाइल में${POSTGRES_PASSWORD}जैसे वेरिएबल्स का संदर्भ देना। - बाइंड माउंट्स और नेम्ड वॉल्यूम को कन्फ्यूज़ करना।
.या/से शुरू होने वाला पाथ (जैसे,./my-app:/app) एक बाइंड माउंट है, जो आपके होस्ट मशीन से एक डायरेक्टरी को मैप करता है। यह डेवलपमेंट के लिए बहुत अच्छा है ताकि कोड परिवर्तन तुरंत दिखाई दें। सिर्फ एक नाम से शुरू होने वाला पाथ (जैसे,db-data:/var/lib/mysql) एक Docker-प्रबंधित नेम्ड वॉल्यूम है। यह डेटाबेस जैसे डेटा को बनाए रखने के लिए बेहतर है, क्योंकि यह प्लेटफ़ॉर्म-स्वतंत्र है और Docker इंजन द्वारा प्रबंधित किया जाता है। गलत का उपयोग करने से अनुमति संबंधी समस्याएं या ऐसा डेटा हो सकता है जो उतना पोर्टेबल नहीं है जितना आप सोचते हैं। - बड़े पैमाने पर प्रोडक्शन के लिए इसका उपयोग करना। Docker Compose डेवलपमेंट, टेस्टिंग और यहां तक कि छोटे, सिंगल-होस्ट प्रोडक्शन डिप्लॉयमेंट के लिए शानदार है। लेकिन यह Kubernetes या Docker Swarm जैसे पूर्ण विकसित कंटेनर ऑर्केस्ट्रेटर का विकल्प नहीं है। इसमें मल्टी-नोड क्लस्टर, सेल्फ-हीलिंग, नोड्स में लोड बैलेंसिंग, या परिष्कृत रोलिंग अपडेट की कोई अंतर्निहित अवधारणा नहीं है। इसकी सीमाओं को जानें।
यह आपके रडार पर क्यों होना चाहिए
जैसे ही आपके एप्लिकेशन में एक से अधिक चलने वाले हिस्से शामिल हों, आपको Docker Compose के बारे में सोचना चाहिए।
- क्या आप एक अलग डेटाबेस के साथ एक वेब ऐप बना रहे हैं? Compose का प्रयोग करें।
- क्या आपको अपना ऐप, एक कैश, और एक बैकग्राउंड वर्कर चलाने की ज़रूरत है? Compose का प्रयोग करें।
- क्या आप अपनी टीम के साथियों को पूरे डेव स्टैक को चलाने के लिए एक-कमांड वाला तरीका देना चाहते हैं? Compose का प्रयोग करें।
- क्या आप एक CI पाइपलाइन स्थापित कर रहे हैं जिसे परीक्षण के लिए एक अस्थायी वातावरण बनाने की आवश्यकता है? Compose का प्रयोग करें।
यह स्थानीय कंटेनर-आधारित विकास के लिए डिफ़ॉल्ट, उद्योग-मानक उपकरण है। इसे सीखना docker run के बाद स्वाभाविक अगला कदम है, और यह एप्लिकेशन ऑर्केस्ट्रेशन की अधिक जटिल दुनिया को समझने का प्रवेश द्वार है। यह एक सिंगल कंटेनर चलाने और एक पूर्ण, वितरित सिस्टम चलाने के बीच की खाई को पाटता है।
और गहराई में जाएं
- Docker Docs: Compose file version 3 reference - सभी उपलब्ध कीज़ और सिंटैक्स के लिए आधिकारिक विनिर्देश और सत्य का स्रोत।
- Docker Docs: Overview of Docker Compose - इसके बनाने वालों की ओर से एक उच्च-स्तरीय परिचय।
- YAML Spec - चूंकि सभी
docker-compose.ymlफ़ाइलें YAML हैं, सिंटैक्स (मैप्स, लिस्ट्स, एंकर) को समझना बहुत मददगार हो सकता है। - Awesome Docker - Docker संसाधनों की एक क्यूरेटेड सूची, जिनमें से कई में विभिन्न स्टैक के लिए ट्यूटोरियल और उदाहरण
docker-compose.ymlफ़ाइलें शामिल हैं।