SSD Nodes Learn 🎉 VPS $5.50/महिन्यापासून
मार्गदर्शक Matt Connorद्वारे Matt Connor

VPS वर Docker Compose: build आणि image मधील फरक

image key प्रकाशित tag pull करते, तर build key VPS वर Dockerfile वापरून image तयार करते. compose up बदल का घेत नाही आणि Dockerfile बदलल्यानंतर उपाय काय?

Docker Compose मधील build विरुद्ध image: थोडक्यात उत्तर

Docker Compose फाइलमध्ये, image: registry मधून pull करायच्या image चे नाव देते, तर build: या मशीनवर Dockerfile मधून image build करण्यास Compose ला सांगते. फक्त image: सेट केल्यास Compose तो tag pull करून चालवते. फक्त build: सेट केल्यास Compose या ठिकाणी image build करते आणि project name व service name यांवरून तिचे नाव तयार करते. दोन्ही सेट केल्यास Compose स्थानिक पातळीवर image build करते आणि नंतर image: मधील नावाने त्या परिणामाला tag करते. निवडलेल्या नावाखाली image build करून push करण्याची हीच पद्धत आहे.

हा संपूर्ण फरक एवढाच आहे. सर्व्हरवर प्रत्यक्ष अंमलबजावणीमध्ये याचा अर्थ काय होतो, ते खाली स्पष्ट केले आहे. येथे Docker Engine आणि Compose plugin आधीच स्थापित आहेत असे गृहीत धरले आहे; VPS वर Docker चालवणे या भागात त्याची माहिती दिली आहे.

पूर्ण तीन रूपे

प्रकाशित tag pull करून तो run करा. कोणत्याही टप्प्यावर Dockerfile वापरला जात नाही.

services:
  web:
    image: nginx:1.27
    restart: unless-stopped
    ports:
      - "80:80"

सध्याच्या directory मधील Dockerfile पासून build करा. FROM मध्ये नमूद केलेल्या base image शिवाय दुसरे काहीही pull केले जात नाही.

services:
  web:
    build: .
    restart: unless-stopped
    ports:
      - "80:80"

स्थानिक पातळीवर build करून परिणामाला tag द्या. त्यानंतर docker compose push तोच अचूक tag registry कडे पाठवू शकतो.

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    image: registry.example.com/acme/web:1.4.2
    restart: unless-stopped
    ports:
      - "80:80"

context ही builder कडे पाठवली जाणारी directory आहे. dockerfile चे resolution त्या context च्या सापेक्ष केले जाते. त्यामुळे context: . आणि dockerfile: docker/prod.Dockerfile एकत्र वापरणे सामान्य आणि योग्य आहे. प्रत्येक service container मागील image name आणि image ID पाहण्यासाठी docker compose images चालवा. तुम्ही प्रत्यक्षात या तीनपैकी कोणते रूप लिहिले आहे, याची खात्री करण्याचा हा सर्वात जलद मार्ग आहे.

Dockerfile बदलल्यानंतर docker compose up पुन्हा build का करत नाही?

कारण up ही image सध्याची आहे का हे तपासत नाही; ती image अस्तित्वात आहे का हे तपासते.

build: विभाग असलेली सेवा Compose सुरू करताना, ते स्थानिक image store मध्ये image शोधते. त्या नावाची image आधीपासून असल्यास Compose तीच वापरते. ते तुमचे Dockerfile वाचत नाही, source files ची तुलना करत नाही किंवा कोणताही timestamp तपासत नाही. Compose specification मध्ये हा नियम pull_policy attribute म्हणून नमूद केला आहे. Default behaviour नुसार image फक्त ती उपलब्ध नसताना build केली जाते. Image उपलब्ध असणे पुरेसे मानले जाते.

म्हणून तुम्ही app.py संपादित करता, docker compose up -d चालवता, Compose ने container running असल्याचे दाखवलेले पाहता आणि जुना code serve करता. काहीही fail झालेले नसल्याने कोणतीही warning मिळत नाही. Compose वापरताना “माझा बदल लागू झाला नाही” अशी तक्रार होण्याचे हे सर्वात सामान्य कारण आहे. Compose container name च्या शेजारी दाखवणारा status word याचा संकेत देतो: Compose ने बदललेला container recreated किंवा started असा status दाखवतो, तर Compose ने तसाच ठेवलेला container running असा status दाखवतो.

दोन तपासण्यांनी हे स्पष्ट होते. docker compose images प्रत्येक container वापरत असलेला image ID दाखवते. त्यामुळे deploy पूर्वी तो नोंदवा आणि deploy नंतर त्याची तुलना करा. docker image ls मध्ये CREATED column असतो. तुमच्या शेवटच्या commit पूर्वी तयार झालेली image, deploy script ने काहीही दाखवले असले तरी, stale image असते.

कोणते flags rebuild सक्तीचे करतात

  • docker compose up -d --build प्रथम build करते आणि image बदललेल्या कोणत्याही container ची पुन्हा निर्मिती करते. बहुतेकांना हाच flag हवा असतो.
  • docker compose build web एका service चे build करते आणि काहीही सुरू करत नाही. त्यानंतर docker compose up --no-deps -d web वापरल्यास फक्त तो container बदलता येतो आणि उर्वरित stack सुरू राहतो.
  • docker compose build --no-cache web cached layer वगळते आणि पहिल्या instruction पासून पुन्हा build करते.
  • docker compose build --pull FROM मधील base image ची नवीन आवृत्ती pull करण्याचा प्रयत्न करते. त्यामुळे node:22 सारखा moving tag तुम्ही March मध्ये download केलेल्या copy ऐवजी त्यातील सध्याचा content वापरतो.
  • docker compose up -d --force-recreate container आधीपासून वापरत असलेल्या image पासून त्यांची पुन्हा निर्मिती करते. हे कधीही build करत नाही. --build अपेक्षित असताना हा flag वापरणे ही सामान्यतः निष्फळ ठरते.

तुम्ही हा निर्णय file मध्येही ठेवू शकता. Compose specification नुसार, pull_policy: build चा अर्थ Compose image build करते आणि ती आधीपासून उपलब्ध असल्यास पुन्हा build करते. त्यानंतर प्रत्येक up वेळी build करावे लागते. Laptop वर हे अपेक्षित असू शकते, परंतु server वर क्वचितच आवश्यक असते.

services:
  web:
    build: .
    image: registry.example.com/acme/web:dev
    pull_policy: build

आणखी एक परस्परसंवाद समजून घेणे उपयुक्त आहे. build section असलेल्या services साठीही docker compose pull images pull करण्याचा प्रयत्न करते. हा pull अयशस्वी झाल्यास image build करणे आवश्यक असल्याचे ते सांगते. त्या services शांतपणे वगळण्यासाठी --ignore-buildable द्या.

build cache तुमचा deploy वेळ कसा ठरवतो

Dockerfile मधील प्रत्येक instruction एक layer तयार करते. ते instruction आणि त्याचे inputs बदललेले नसतील, तर builder cached layer पुन्हा वापरतो. COPY साठी inputs म्हणजे copy केल्या जाणाऱ्या files मधील contents. एखाद्या layer साठी cache miss झाल्यानंतर त्यानंतरचे सर्व layers पुन्हा build केले जातात, कारण प्रत्येक layer हा त्याच्या आधीच्या layer ने तयार केलेल्या filesystem वर build केला जातो.

हा एक नियम तुमचा deploy काही seconds मध्ये होईल की minutes लागतील हे ठरवतो. Dockerfile मध्ये क्वचित बदलणाऱ्या गोष्टींपासून प्रत्येक commit वर बदलणाऱ्या गोष्टींपर्यंत instructions क्रमाने मांडा.

FROM node:22-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
CMD ["node", "server.js"]

npm ci हे COPY . . च्या वर आहे. त्यामुळे source file संपादित केल्यावर install layer cache मध्येच राहतो आणि build copy step पासून पुढे सुरू होतो. त्या दोन lines ची अदलाबदल केल्यास एका character मधील बदलामुळे सर्व dependencies पुन्हा install होतात, कारण COPY . . मुळे npm ci ज्या layer वर build केला जातो तो layer invalid होतो. हाच pattern pip install -r requirements.txt आणि go mod download साठीही लागू होतो.

जुना layer तुमचा fix लपवत असल्याची शंका असल्यास --no-cache हे योग्य tool आहे. मात्र तो default म्हणून वापरणे योग्य नाही, कारण Dockerfile च्या ordering मुळे मिळणारा reuse तो काढून टाकतो.

Image sets आणि Compose यापैकी एक गोष्ट override करू शकतात: image default म्हणून काय चालवते हे Dockerfile मधील CMD ठरवतो. Service मधील command: key त्याची जागा घेतो. command आणि entrypoint परस्पर कसे कार्य करतात हे येथे महत्त्वाचे आहे, कारण Compose override मुळे नव्याने build केलेली image जुन्या image प्रमाणेच वागू शकते.

Build context आणि .dockerignore

context: . म्हणजे Compose त्या directory ला package करून पहिली instruction चालण्यापूर्वी builder कडे पाठवते. त्यातील सर्व काही पाठवले जाते. यात .git आणि source च्या बाजूला ठेवलेली कोणतीही data directory यांचाही समावेश होतो. Project मध्ये कोणताही बदल नसताना build transferring-context टप्प्यावर थांबत असेल, तर build context खूप मोठा आहे.

Context च्या root मध्ये असलेली .dockerignore file त्या transfer मधून paths वगळते. तिची syntax .gitignore शी साधर्म्य असलेली आहे.

.git
node_modules
*.log
data/
.env

याचे दोन फायदे आहेत. Transfer लहान होतो, त्यामुळे प्रत्येक build जलद सुरू होतो. तसेच COPY . . आता .env image मध्ये copy करू शकत नाही. त्यामुळे ती image pull करणाऱ्या कोणालाही तेथील सामग्री वाचता येत नाही.

काळानुसार मोठा होत जाणाऱ्या slow-build च्या प्रकरणात bind mount कारणीभूत असतो. Named volume तुमच्या project directory च्या बाहेर असतो. मात्र ./data:/var/lib/postgresql/data सारखा bind mount build context च्या आत असतो. त्यामुळे database वाढत गेल्यावर दर आठवड्याला builds अधिक धीमे होतात. .dockerignore मधील एक line ही समस्या सोडवते. Named volumes च्या तुलनेत bind mounts मध्ये या trade-off चे अधिक विस्तृत स्पष्टीकरण आहे.

Build arguments मध्ये याच जोखमीची लहान आवृत्ती असते. args: द्वारे पास केलेली values image history मध्ये दिसतात. Image असलेल्या कोणालाही त्या पाहता येतात. त्यामुळे तेथे version number द्या आणि token कधीही देऊ नका. Credentials कुठे ठेवायची यासाठी Compose मधील env files आणि secrets पहा.

VPS वर build करायचे की दुसरीकडे build करून pull करायचे?

तुमचा traffic पुरवणाऱ्या box वर build करणे हे default आहे, कारण तो सर्वात थेट मार्ग आहे: git pull, त्यानंतर docker compose up -d --build. अद्याप ज्यावर कोणाचीही अवलंबित्व नाही अशा छोट्या server वर हे योग्य आहे. मात्र, मोजता येणाऱ्या दोन कारणांमुळे आणि एखादा वाईट दिवस आल्यावरच दिसणाऱ्या आणखी एका कारणामुळे हे योग्य राहात नाही.

Memory. Build दरम्यान compilers आणि bundlers तुमच्या live application च्या शेजारी चालतात. बहुतेक stacks मध्ये हेच memory सर्वाधिक वापरणारे घटक असतात. 1 GB VPS वर JavaScript bundler किंवा Rust compile हा server वरील सर्वात मोठा process असणे नेहमीचे आहे. Kernel कडे memory संपल्यावर तो सर्वात मोठा process बंद करतो: एकतर build Killed आणि exit status 137 सह थांबतो, किंवा त्याऐवजी तुमचा database बंद होतो आणि deploy च्या मध्यात site down होते. dmesg -T | grep -i oom kill line process name सह दाखवते. त्यामुळे अंदाज न लावता यापैकी नेमके काय झाले ते समजू शकते.

Disk. प्रत्येक build मागे layers ठेवतो आणि builder तुमच्या images पासून स्वतंत्रपणे स्वतःचा cache ठेवतो. docker system df हे दोन्ही दाखवते आणि build cache row सतत वाढत राहते. dangling images साठी docker image prune आणि cached layers साठी docker builder prune वापरून जागा मोकळी करा. Disk पूर्ण भरल्यावर फक्त build थांबत नाही. Database देखील लिहिणे थांबवतो आणि या अपयशाची किंमत slow deploy पेक्षा खूप जास्त असते.

Reproducibility. Server वर build केलेली image फक्त त्याच server वर उपलब्ध असते. Rollback करण्यासाठी जुना commit checkout करून पुन्हा build करावा लागतो. मात्र, त्या build मधून आधीचीच image तयार होईल याची खात्री नसते, कारण base tag बदललेला असू शकतो आणि package mirrors देखील त्यासोबत बदललेले असतात. दुसरीकडे build करून tag push केल्यास rollback साठी फक्त एक edit करावा लागतो: image: मागील tag कडे निर्देशित करा आणि docker compose up -d चालवा.

टिकाऊ रचना साधी आहे. तुमचे continuous integration build चालवते आणि registry.example.com/acme/web:<git-sha> push करते. VPS वरील Compose file मध्ये image: असते आणि त्यात build: key अजिबात नसते. त्यामुळे deployment साठी जवळजवळ कोणतीही memory न लागणारे दोन commands पुरेसे ठरतात.

docker compose pull
docker compose up -d

Server वर एकदा docker login registry.example.com चालवा. त्यानंतर Compose private tags pull करू शकते.

Development साठी build section ठेवा; तो delete करू नका. तो तुम्ही स्वतः नाव दिलेल्या file मध्ये ठेवा.

# compose.dev.yaml
services:
  web:
    build:
      context: .
    pull_policy: build
docker compose -f compose.yaml -f compose.dev.yaml up -d --build

त्या file ला compose.dev.yaml असे नाव द्या, compose.override.yaml नाही. Override file उपलब्ध असल्यास Compose ती आपोआप load करते. त्यामुळे server वर चुकून copy केलेली override file तेथे पुन्हा build सुरू करू शकते आणि हे शांतपणे घडते. अनेक Compose files चे layering केल्यावर प्रत्येक key चे merge कसे resolve होते हे स्पष्ट करते.

तुम्ही दुसरीकडे build करता तेव्हा उद्भवणारा architecture trap

एखाद्या image मध्ये तो ज्या CPU architecture साठी build केला आहे ती architecture नोंदलेली असते. Apple Silicon laptop वर build करून image push केल्यानंतर तो tag x86_64 VPS वर pull केल्यास, मागितलेल्या image platform चा detected host platform शी मेळ नसल्याची warning Docker दाखवतो. त्यानंतर process exec format error सह बंद होतो. हा संदेश corrupt binary असल्यासारखा दिसतो, पण तसे नसते. Target साठी स्पष्टपणे build करा:

docker buildx build --platform linux/amd64 \
  -t registry.example.com/acme/web:1.4.2 --push .

तुमचा laptop x86 असेल आणि तुम्ही x86 VPS ऐवजी ARM VPS वापरत असाल, तर हाच mismatch उलट दिशेनेही होतो. तुम्ही deploy करत असलेल्या architecture वर CI ला build करू दिल्यास हा प्रश्नच निर्माण होत नाही.

तैनातीनंतर काय तपासावे

  • docker compose images प्रत्येक चालू container मागील image आणि tag दाखवते. Image ID बदललेला दिसणे म्हणजे नवीन build सेवेत वापरात असल्याचा पुरावा आहे.
  • docker compose config variable substitution नंतरची एकत्रित file दाखवते. त्यामुळे काहीही चालवण्यापूर्वी Compose वापरणार असलेले अंतिम image name वाचता येते.
  • docker compose logs -f web swap केल्यानंतर पहिल्या अर्ध्या मिनिटात monitor करा. सुरू होऊन लगेच बंद होणारा container सतत restart loop मध्ये जातो. तुम्ही तपासले नाही तर हा loop शांतपणे सुरू राहतो.
  • docker image ls CREATED column दाखवते. तुमच्या शेवटच्या commit पेक्षा जुनी image पुन्हा build केलेली नसते.

या checks ज्या file वर चालणार आहेत ती तुम्ही अजून तयार करत असाल, तर VPS वरील Compose file ची मूलभूत माहिती संबंधित keys स्पष्ट करते आणि Compose command cheat sheet उर्वरित subcommands ची यादी देते.

FAQ

build आणि image एकाच service मध्ये वापरता येतात का?

होय. स्वतः build करत असलेल्या project साठी ही नेहमीची रचना आहे. Compose build: section मधून build करते आणि परिणामाला image: मधील value ने tag करते. हा tag docker compose push registry कडे पाठवते आणि दुसरे machine pull करते. image: key नसतानाही Compose build करते. मात्र image ला project आणि service यांच्या नावावरून नाव देते आणि missing attribute मुळे image push करता येत नाही, असा इशारा देते.

docker compose up माझ्या Dockerfile मधील बदल का घेत नाही?

कारण up फक्त त्या नावाचे image अस्तित्वात आहे का हे तपासते. Image उपलब्ध असल्यास Compose तेच सुरू करते आणि त्याची Dockerfile किंवा source files शी तुलना करत नाही. docker compose up -d --build चालवा. किंवा एकाच service साठी docker compose build web नंतर docker compose up --no-deps -d web चालवा. Service वर pull_policy: build सेट केल्यास प्रत्येक up वेळी rebuild होते. Development machine साठी ही पद्धत योग्य आहे.

--build आणि --force-recreate यांच्यात काय फरक आहे?

--build image पुन्हा build करते आणि image बदललेल्या containers ची पुनर्निर्मिती करते. --force-recreate आधीपासून असलेल्या image मधून containers पुन्हा तयार करते. त्यामुळे code मधील बदल ती कधीही लागू करू शकत नाही. बदल source किंवा Dockerfile मध्ये असल्यास --build हा flag वापरा. Container स्वतः reset करण्यासाठी --force-recreate वापरा. उदाहरणार्थ, समान image ठेवून त्याचा writable layer साफ करण्यासाठी तो उपयोगी आहे.

माझे Docker images VPS वर build करावेत का, की दुसरीकडे?

Build दुसरीकडे करा आणि machine network traffic देत असल्यास tag एकदाच pull करा. Build तुमच्या application सोबत memory साठी स्पर्धा करते. लहान VPS मध्ये kernel सर्वात मोठी process बंद करून ही स्पर्धा हाताळू शकतो. ती process build असू शकते किंवा database. Build मुळे disk वर cache देखील राहतो आणि तो आपोआप साफ होत नाही. Users नसलेल्या लहान project साठी server वर build करणे योग्य आहे. build: section development-only Compose file मध्ये ठेवल्यास नंतर दुसरीकडे build करण्यासाठी बदल करणे सोपे राहते.

Docker build cache मुळे disk भरू नये यासाठी काय करावे?

तुमच्या images आणि build cache पैकी प्रत्येकाने किती space व्यापले आहे हे पाहण्यासाठी docker system df चालवा. docker builder prune cached layers काढते आणि docker image prune आधीच्या builds मुळे उरलेली dangling images काढते. यांपैकी कोणत्याही command मध्ये -a जोडल्यास cleanup अधिक आक्रमक होते आणि पुढील build शून्यापासून सुरू होते. Server वर docker system prune -af --volumes schedule करू नका. कारण --volumes सध्या कोणताही container वापरत नसलेले volume delete करते. Maintenance साठी थांबवलेल्या stack मध्ये database अशाच volume मध्ये असू शकतो.