Docker Compose build กับ image ต่างกันอย่างไรบน VPS
ไขข้อสงสัยความแตกต่างระหว่างคำสั่ง build และ image ใน Docker Compose เมื่อใช้งานบน VPS พร้อมวิธีแก้ไขปัญหา Docker ไม่ยอมอัปเดตไฟล์ใหม่หลังจากแก้ไข Dockerfile ด้วยคำสั่ง build
ความแตกต่างระหว่าง build กับ image ใน Docker Compose: คำตอบสั้นๆ
ในไฟล์ Docker Compose นั้น image: คือการระบุชื่อ image ที่จะดึงมาจาก registry ส่วน build: คือการสั่งให้ Compose สร้าง image ขึ้นมาบนเครื่องนี้จาก Dockerfile หากตั้งค่าเพียง image: ตัว Compose จะดึง tag นั้นมาใช้งานและรันทันที หากตั้งค่าเพียง build: ตัว Compose จะสร้าง image ขึ้นมาในเครื่องโดยตั้งชื่อตามชื่อโปรเจกต์และชื่อ service หากตั้งค่าทั้งสองอย่าง Compose จะทำการ build ในเครื่องแล้วติด tag ผลลัพธ์ด้วยชื่อที่ระบุใน image: ซึ่งเป็นวิธีที่คุณใช้สร้าง image และ push ขึ้น registry ด้วยชื่อที่คุณกำหนดเอง
นี่คือความแตกต่างทั้งหมด เนื้อหาหลังจากนี้คือสิ่งที่เกิดขึ้นจริงเมื่อใช้งานบนเซิร์ฟเวอร์ โดยสมมติว่ามีการติดตั้ง Docker Engine และ Compose plugin ไว้เรียบร้อยแล้ว ซึ่งเนื้อหา การรัน Docker บน VPS ได้ครอบคลุมส่วนนั้นไว้แล้ว
รูปแบบทั้งสามแบบโดยละเอียด
ดึง tag ที่เผยแพร่ไว้แล้วมาสั่งรัน โดยไม่มีการใช้ Dockerfile ในขั้นตอนใดเลย
services:
web:
image: nginx:1.27
restart: unless-stopped
ports:
- "80:80"สร้างอิมเมจจาก Dockerfile ในไดเรกทอรีปัจจุบัน โดยไม่มีการดึงข้อมูลใดๆ ยกเว้น base image ที่ระบุไว้ใน FROM
services:
web:
build: .
restart: unless-stopped
ports:
- "80:80"สร้างอิมเมจในเครื่องและกำหนด 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) โดย dockerfile จะถูกอ้างอิงจาก context นั้น ดังนั้นการใช้ context: . ร่วมกับ dockerfile: docker/prod.Dockerfile จึงเป็นเรื่องปกติและถูกต้อง ให้รันคำสั่ง docker compose images เพื่อดูชื่ออิมเมจและ image ID ของคอนเทนเนอร์แต่ละบริการ ซึ่งเป็นวิธีที่รวดเร็วที่สุดในการยืนยันว่าคุณได้เขียนรูปแบบใดในสามรูปแบบนี้ไปใช้งานจริง
ทำไม docker compose up ถึงไม่ build ใหม่หลังจากที่ฉันแก้ไข Dockerfile?
เพราะ up ตรวจสอบเพียงว่ามี image อยู่หรือไม่ ไม่ได้ตรวจสอบว่าเป็นเวอร์ชันล่าสุดหรือไม่
เมื่อ Compose เริ่มบริการที่มีส่วนของ build: มันจะค้นหา image ในที่เก็บ image ภายในเครื่อง หากมี image ที่ใช้ชื่อนั้นอยู่แล้ว Compose จะเลือกใช้ image ดังกล่าวทันที โดยไม่ได้อ่านไฟล์ Dockerfile, ไม่ได้เปรียบเทียบไฟล์ซอร์สโค้ด และไม่ได้ตรวจสอบ timestamp ใดๆ ข้อกำหนดของ Compose ระบุหลักการนี้ไว้ภายใต้ attribute pull_policy ซึ่งพฤติกรรมเริ่มต้นคือการ build image เฉพาะเมื่อ image นั้นยังไม่มีอยู่เท่านั้น หากพบว่ามีอยู่แล้วจะถือว่าใช้ได้
ดังนั้น เมื่อคุณแก้ไข app.py แล้วรัน docker compose up -d คุณจะเห็น Compose รายงานว่า container กำลังทำงานอยู่ แต่บริการยังคงแสดงผลโค้ดเวอร์ชันเก่า เนื่องจากไม่มีขั้นตอนใดที่ล้มเหลว ระบบจึงไม่มีการแจ้งเตือน นี่เป็นรายงานปัญหา "การเปลี่ยนแปลงของฉันไม่มีผล" ที่พบบ่อยที่สุดในการใช้งาน Compose จุดสังเกตที่ชัดเจนคือสถานะที่ Compose แสดงถัดจากชื่อ container: หาก container ถูกแทนที่ Compose จะรายงานว่า recreated หรือ started แต่หาก container ใดที่ Compose ตัดสินใจไม่ทำอะไรเลย มันจะรายงานว่า running
คุณสามารถตรวจสอบได้ด้วยสองวิธีนี้: docker compose images จะแสดง image ID ที่แต่ละ container ใช้งานอยู่ ให้คุณจดค่าไว้ก่อนการ deploy แล้วนำมาเปรียบเทียบหลังจากนั้น หรือใช้ docker image ls ซึ่งจะมีคอลัมน์ CREATED หาก image ถูกสร้างขึ้นก่อน commit ล่าสุดของคุณ แสดงว่าเป็น image ที่ล้าสมัย ไม่ว่าสคริปต์การ deploy จะแสดงผลอย่างไรก็ตาม
แฟล็กใดบ้างที่บังคับให้สร้างอิมเมจใหม่ (rebuild)
docker compose up -d --buildจะทำการ build ก่อน จากนั้นจึงสร้าง container ใหม่หากอิมเมจมีการเปลี่ยนแปลง นี่คือแฟล็กที่คนส่วนใหญ่ต้องการใช้งานdocker compose build webจะทำการ build เฉพาะ service เดียวและไม่เริ่มการทำงานใดๆ ให้ใช้ตามด้วยdocker compose up --no-deps -d webเพื่อแทนที่เฉพาะ container นั้นและปล่อยให้ stack ส่วนที่เหลือทำงานต่อไปdocker compose build --no-cache webจะทิ้ง layer ที่แคชไว้ทั้งหมดและเริ่ม build ใหม่ตั้งแต่คำสั่งแรกdocker compose build --pullจะพยายามดึงอิมเมจเวอร์ชันใหม่ของ base image ในFROMเพื่อให้ tag ที่มีการเปลี่ยนแปลงได้ เช่นnode:22ดึงเนื้อหาปัจจุบันมาแทนที่สำเนาที่คุณดาวน์โหลดไว้เมื่อเดือนมีนาคมdocker compose up -d --force-recreateจะสร้าง container ใหม่จากอิมเมจเดิมที่ใช้อยู่แล้ว โดยจะไม่ทำการ build ใดๆ การใช้แฟล็กนี้ในขณะที่คุณต้องการ--buildเป็นข้อผิดพลาดที่พบบ่อย
คุณยังสามารถกำหนดการตัดสินใจนี้ไว้ในไฟล์ได้ ตามข้อกำหนดของ Compose specification แล้ว pull_policy: build หมายความว่า Compose จะ build อิมเมจและสร้างใหม่หากมีอิมเมจนั้นอยู่แล้ว ทุกคำสั่ง up จะต้องเสียเวลาในการ build ซึ่งเป็นสิ่งที่คุณต้องการบนแล็ปท็อป แต่แทบจะไม่ใช่สิ่งที่คุณต้องการบนเซิร์ฟเวอร์
services:
web:
build: .
image: registry.example.com/acme/web:dev
pull_policy: buildมีการทำงานอีกรูปแบบหนึ่งที่ควรทราบ docker compose pull จะพยายามดึงอิมเมจสำหรับ service ที่มีส่วน build ด้วยเช่นกัน และหากการดึงข้อมูลล้มเหลว ระบบจะแจ้งว่าต้องใช้วิธี build อิมเมจแทน ให้ใส่แฟล็ก --ignore-buildable เพื่อข้าม service เหล่านั้นไปโดยไม่แสดงข้อความแจ้งเตือน
วิธีที่ build cache กำหนดระยะเวลาในการ deploy ของคุณ
คำสั่งแต่ละบรรทัดใน Dockerfile จะสร้าง layer ขึ้นมาหนึ่งชั้น และตัว builder จะนำ layer ที่อยู่ใน cache กลับมาใช้ใหม่เมื่อคำสั่งนั้นและข้อมูลนำเข้าไม่มีการเปลี่ยนแปลง สำหรับ COPY ข้อมูลนำเข้าคือเนื้อหาของไฟล์ที่ถูกคัดลอก เมื่อ layer ใด layer หนึ่งไม่พบใน cache layer ทั้งหมดที่ตามมาจะถูกสร้างใหม่ทั้งหมด เนื่องจากแต่ละ layer ถูกสร้างขึ้นบนระบบไฟล์ที่ layer ก่อนหน้าสร้างไว้
กฎข้อเดียวนี้นำไปสู่การตัดสินใจว่าการ deploy ของคุณจะใช้เวลาเพียงไม่กี่วินาทีหรือหลายนาที ให้เรียงลำดับ Dockerfile จากสิ่งที่เปลี่ยนแปลงน้อยที่สุดไปจนถึงสิ่งที่เปลี่ยนแปลงทุกครั้งที่มีการ commit
FROM node:22-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
CMD ["node", "server.js"]npm ci อยู่เหนือ COPY . . ดังนั้นการแก้ไขไฟล์ source code จะทำให้ layer ของการติดตั้งยังคงอยู่ใน cache และการ build จะกลับมาเริ่มใหม่ที่ขั้นตอนการคัดลอกไฟล์ หากสลับสองบรรทัดนี้ การเปลี่ยนแปลงเพียงตัวอักษรเดียวจะทำให้ต้องติดตั้ง dependency ใหม่ทั้งหมด เพราะ COPY . . จะทำให้ layer ที่ npm ci สร้างขึ้นนั้นใช้งานไม่ได้ รูปแบบเดียวกันนี้ยังใช้กับ pip install -r requirements.txt และ go mod download ได้เช่นกัน
--no-cache เป็นเครื่องมือที่เหมาะสมเมื่อคุณสงสัยว่า layer ที่ล้าสมัยกำลังบดบังการแก้ไขของคุณ แต่มันไม่ใช่ค่าเริ่มต้นที่ดี เพราะมันจะทิ้งประโยชน์จากการนำ cache กลับมาใช้ใหม่ซึ่งเป็นเหตุผลหลักในการจัดลำดับ Dockerfile
สิ่งหนึ่งที่ image กำหนดไว้และ Compose สามารถเขียนทับได้คือ CMD ของ Dockerfile ซึ่งเป็นสิ่งที่ image จะรันตามค่าเริ่มต้น และคีย์ command: ใน service จะเข้ามาแทนที่ค่าดังกล่าว วิธีที่ command และ entrypoint ทำงานร่วมกัน มีความสำคัญในจุดนี้ เพราะการเขียนทับผ่าน Compose อาจทำให้ image ที่เพิ่ง build ใหม่มีพฤติกรรมเหมือนกับ image ตัวเก่าทุกประการ
Build context และ .dockerignore
context: . หมายถึง Compose จะแพ็กไดเรกทอรีนั้นและส่งไปยังตัวสร้าง (builder) ก่อนที่คำสั่งแรกจะทำงาน ข้อมูลทุกอย่างภายใต้ไดเรกทอรีนั้นจะถูกส่งไปด้วย รวมถึง .git และไดเรกทอรีข้อมูลใดก็ตามที่คุณเก็บไว้ข้างซอร์สโค้ด หากการ build ค้างอยู่ที่ขั้นตอน transferring context ในโปรเจกต์ที่ไม่มีการเปลี่ยนแปลง แสดงว่า context ของคุณมีขนาดใหญ่เกินไป
ไฟล์ .dockerignore ที่วางไว้ที่ root ของ context จะทำหน้าที่ยกเว้น path ต่างๆ ไม่ให้ถูกโอนย้าย ไวยากรณ์ของไฟล์นี้คล้ายกับ .gitignore
.git
node_modules
*.log
data/
.envคุณจะได้รับประโยชน์สองประการ ประการแรกคือขนาดการโอนย้ายลดลง ทำให้การ build ทุกครั้งเริ่มต้นได้เร็วขึ้น ประการที่สองคือ COPY . . จะไม่สามารถคัดลอก .env ลงใน image ได้อีกต่อไป ซึ่งช่วยป้องกันไม่ให้ผู้ที่ดึง image นี้ไปใช้งานสามารถอ่านข้อมูลดังกล่าวออกมาได้
กรณีที่การ build ช้าลงเรื่อยๆ ตามกาลเวลามักเกิดจาก bind mount โดยปกติแล้ว named volume จะอยู่นอกไดเรกทอรีโปรเจกต์ของคุณ แต่ bind mount เช่น ./data:/var/lib/postgresql/data นั้นจะอยู่ภายใน build context ทำให้การ build ของคุณช้าลงทุกสัปดาห์เมื่อฐานข้อมูลมีขนาดใหญ่ขึ้น การเพิ่มบรรทัดเดียวใน .dockerignore จะช่วยแก้ไขปัญหานี้ได้ เนื้อหา Bind mounts เทียบกับ named volumes จะอธิบายถึงข้อดีข้อเสียในภาพรวม
Build arguments มีความเสี่ยงในลักษณะเดียวกันแต่ในระดับที่เล็กกว่า ค่าที่ส่งผ่าน args: จะปรากฏอยู่ในประวัติของ image ซึ่งทุกคนที่ถือครอง image นั้นสามารถมองเห็นได้ ดังนั้นควรใส่เฉพาะเลขเวอร์ชันเท่านั้น ห้ามใส่ token โดยเด็ดขาด เนื้อหา Env files และ secrets ใน Compose จะอธิบายว่าควรจัดเก็บข้อมูลรับรอง (credentials) ไว้ที่ใดแทน
ควร build บน VPS หรือ build ที่อื่นแล้วค่อยดึงมา?
การ build บนเครื่องที่ให้บริการ traffic เป็นวิธีเริ่มต้นเพราะเป็นเส้นทางที่สั้นที่สุด: git pull แล้วตามด้วย docker compose up -d --build วิธีนี้ใช้ได้ดีบนเซิร์ฟเวอร์ขนาดเล็กที่ยังไม่มีใครใช้งาน แต่จะเริ่มมีปัญหาด้วยเหตุผล 2 ประการที่คุณวัดค่าได้ และอีก 1 ประการที่จะปรากฏให้เห็นในวันที่ระบบมีปัญหา
หน่วยความจำ (Memory): กระบวนการ build จะรัน compiler และ bundler ควบคู่ไปกับแอปพลิเคชันที่กำลังทำงานอยู่ ซึ่งเครื่องมือเหล่านี้มักเป็นส่วนที่กินหน่วยความจำมากที่สุดในเกือบทุก stack บน VPS ขนาด 1 GB การรัน JavaScript bundler หรือการ compile ภาษา Rust มักจะกลายเป็นกระบวนการที่ใช้หน่วยความจำมากที่สุดในเครื่อง เมื่อ kernel พบว่าหน่วยความจำไม่เพียงพอ มันจะสั่ง kill กระบวนการที่ใช้หน่วยความจำมากที่สุด: ไม่ว่าจะเป็นการที่การ build หยุดลงพร้อมกับ Killed และ exit status 137 หรือฐานข้อมูลของคุณถูกสั่ง kill แทนจนทำให้เว็บไซต์ล่มกลางคันระหว่างการ deploy คุณสามารถใช้ dmesg -T | grep -i oom เพื่อดูบรรทัดที่ระบุว่ากระบวนการใดถูก kill ทำให้คุณทราบสาเหตุที่แน่ชัดแทนการคาดเดา
ดิสก์ (Disk): ทุกการ build จะทิ้ง layer ไว้เบื้องหลัง และตัว builder จะเก็บ cache ของตัวเองแยกต่างหากจาก image ของคุณ docker system df จะแสดงข้อมูลทั้งสองส่วน และแถวของ build cache จะมีแต่เพิ่มขึ้นเรื่อยๆ คุณสามารถกู้คืนพื้นที่คืนได้ด้วย docker image prune สำหรับ dangling images และ docker builder prune สำหรับ cached layers การที่ดิสก์เต็มไม่ได้ส่งผลแค่การ build เท่านั้น แต่ฐานข้อมูลจะหยุดเขียนข้อมูลด้วย ซึ่งความล้มเหลวนั้นสร้างความเสียหายมากกว่าการ deploy ที่ล่าช้า
ความสามารถในการทำซ้ำ (Reproducibility): image ที่สร้างบนเซิร์ฟเวอร์จะมีอยู่แค่บนเซิร์ฟเวอร์นั้นเท่านั้น การย้อนกลับ (rollback) หมายถึงการ checkout commit เก่าแล้วทำการ build ใหม่ ซึ่งการ build นั้นไม่ได้รับประกันว่าจะได้ผลลัพธ์เหมือนเดิม เพราะ base tag อาจมีการเปลี่ยนแปลงและ package mirror ก็อาจเปลี่ยนไปตามกาลเวลา การ build ที่อื่นแล้ว push tag ขึ้นไปจะทำให้การ rollback กลายเป็นเพียงการแก้ไขค่า: ให้ชี้ image: ไปที่ tag ก่อนหน้าแล้วรัน docker compose up -d
รูปแบบที่ยั่งยืนนั้นชัดเจน คือให้ระบบ continuous integration ของคุณทำการ build และ push ไปยัง registry.example.com/acme/web:<git-sha> ส่วนไฟล์ Compose บน VPS ให้ระบุ image: โดยไม่ต้องมีคีย์ build: เลย การ deploy จะเหลือเพียงสองคำสั่งที่แทบไม่ใช้หน่วยความจำ
docker compose pull
docker compose up -dรัน docker login registry.example.com บนเซิร์ฟเวอร์หนึ่งครั้ง แล้ว Compose จะสามารถดึง private tag มาใช้งานได้ตั้งแต่นั้นเป็นต้นไป
ให้คงส่วนการ build ไว้สำหรับการพัฒนาแทนที่จะลบทิ้ง โดยเก็บไว้ในไฟล์ที่คุณตั้งชื่อเอง
# compose.dev.yaml
services:
web:
build:
context: .
pull_policy: builddocker compose -f compose.yaml -f compose.dev.yaml up -d --buildตั้งชื่อไฟล์นั้นว่า compose.dev.yaml และห้ามใช้ชื่อ compose.override.yaml เพราะ Compose จะโหลดไฟล์ override โดยอัตโนมัติหากพบไฟล์ดังกล่าว ดังนั้นหากมีการคัดลอกไฟล์ override ที่ไม่ตั้งใจไว้บนเซิร์ฟเวอร์ ระบบจะเริ่มทำการ build บนเซิร์ฟเวอร์นั้นโดยเงียบๆ การซ้อนทับไฟล์ Compose หลายไฟล์ อธิบายวิธีการที่ระบบรวมคีย์แต่ละตัวเข้าด้วยกัน
กับดักทางสถาปัตยกรรมเมื่อคุณสร้างอิมเมจจากที่อื่น
อิมเมจจะระบุสถาปัตยกรรม CPU ที่ถูกสร้างขึ้นมา หากคุณสร้างบนแล็ปท็อป Apple Silicon แล้ว push ขึ้นไป จากนั้น pull tag นั้นลงมาบน VPS ที่เป็น x86_64 ตัว Docker จะแจ้งเตือนว่าแพลตฟอร์มของอิมเมจที่ร้องขอไม่ตรงกับแพลตฟอร์มของโฮสต์ที่ตรวจพบ กระบวนการจะหยุดทำงานพร้อมกับ exec format error ซึ่งดูเหมือนไฟล์ไบนารีเสียหายแต่จริงๆ แล้วไม่ใช่ ให้สร้างอิมเมจสำหรับเป้าหมายโดยระบุสถาปัตยกรรมให้ชัดเจน:
docker buildx build --platform linux/amd64 \
-t registry.example.com/acme/web:1.4.2 --push .ความไม่เข้ากันแบบเดียวกันจะเกิดขึ้นในทางกลับกันหากแล็ปท็อปของคุณเป็น x86 และคุณรัน บน VPS ที่เป็น ARM แทนที่จะเป็น x86 การปล่อยให้ระบบ CI สร้างอิมเมจบนสถาปัตยกรรมเดียวกับที่คุณใช้งานจริงจะช่วยขจัดปัญหานี้ไปได้
สิ่งที่ควรตรวจสอบหลังการ deploy
docker compose imagesแสดงภาพและแท็กที่อยู่เบื้องหลังคอนเทนเนอร์ที่กำลังทำงานอยู่ทุกตัว หาก ID ของภาพเปลี่ยนไป นั่นคือหลักฐานว่า build ใหม่ได้ถูกนำมาใช้งานแล้วdocker compose configแสดงไฟล์ที่รวมค่าตัวแปรเรียบร้อยแล้ว ทำให้คุณสามารถอ่านชื่อภาพสุดท้ายที่ Compose จะใช้ก่อนที่จะรันคำสั่งใดๆdocker compose logs -f webสำหรับช่วงครึ่งนาทีแรกหลังจากทำการสลับคอนเทนเนอร์ คอนเทนเนอร์ที่เริ่มทำงานแล้วหยุดทันทีจะวนลูปการเริ่มใหม่แทนที่จะทำงานต่อเนื่อง และการวนลูปนี้จะเงียบสนิทหากคุณไม่ได้ตรวจสอบdocker image lsแสดงคอลัมน์ CREATED หากภาพมีอายุเก่ากว่า commit ล่าสุดของคุณ แสดงว่าภาพนั้นไม่เคยถูก build ใหม่
หากคุณยังอยู่ในขั้นตอนการประกอบไฟล์ที่ใช้สำหรับการตรวจสอบเหล่านี้ พื้นฐานของไฟล์ Compose บน VPS จะครอบคลุมคีย์ที่เกี่ยวข้อง และ ตารางสรุปคำสั่ง Compose จะแสดงรายการคำสั่งย่อยที่เหลือทั้งหมด
FAQ
ฉันสามารถใช้ build และ image ใน service เดียวกันได้หรือไม่?
ได้ และนี่คือการตั้งค่าปกติสำหรับโปรเจกต์ที่คุณสร้างขึ้นเอง Compose จะทำการ build จากส่วน build: และแท็กผลลัพธ์ด้วยค่าของ image: แท็กดังกล่าวคือสิ่งที่ docker compose push จะส่งไปยัง registry และเป็นสิ่งที่เครื่องอื่นจะดึงไปใช้งาน หากไม่มีคีย์ image: ตัว Compose จะยังคง build ให้ แต่จะตั้งชื่อ image ตามชื่อโปรเจกต์และชื่อ service พร้อมกับแจ้งเตือนว่าการขาดแอตทริบิวต์นี้จะทำให้ไม่สามารถ push image ได้
ทำไม docker compose up ถึงไม่ตรวจพบการเปลี่ยนแปลงใน Dockerfile ของฉัน?
เพราะ up จะตรวจสอบเพียงว่ามี image ที่ใช้ชื่อนั้นอยู่แล้วหรือไม่ หากมีอยู่แล้ว Compose จะเริ่มทำงานโดยใช้ image นั้นทันทีโดยไม่เปรียบเทียบกับ Dockerfile หรือไฟล์ซอร์สโค้ดของคุณ ให้รันคำสั่ง docker compose up -d --build หรือรัน docker compose build web ตามด้วย docker compose up --no-deps -d web เพื่อแทนที่ service เฉพาะตัวนั้น การตั้งค่า pull_policy: build ไว้ที่ service จะทำให้ทุกคำสั่ง up ทำการ build ใหม่เสมอ ซึ่งเหมาะสำหรับเครื่องที่ใช้พัฒนา
--build กับ --force-recreate แตกต่างกันอย่างไร?
--build จะทำการ build image ใหม่ จากนั้นจึงสร้าง container ขึ้นมาใหม่หาก image มีการเปลี่ยนแปลง ส่วน --force-recreate จะสร้าง container ขึ้นมาใหม่จาก image เดิมที่มีอยู่แล้ว จึงไม่สามารถตรวจพบการเปลี่ยนแปลงของโค้ดได้ หากคุณมีการเปลี่ยนแปลงในซอร์สโค้ดหรือใน Dockerfile คุณต้องใช้แฟล็ก --build ส่วน --force-recreate มีไว้สำหรับการรีเซ็ตตัว container เอง เช่น เพื่อล้างเลเยอร์ที่เขียนได้ (writable layer) โดยที่ยังคงใช้ image เดิมอยู่
ฉันควร build Docker image บน VPS หรือที่อื่น?
ควร build ที่อื่นแล้วค่อยดึง (pull) แท็กมาใช้งานเมื่อเซิร์ฟเวอร์เริ่มให้บริการแล้ว การ build จะแย่งทรัพยากรหน่วยความจำกับแอปพลิเคชันของคุณ ซึ่งบน VPS ขนาดเล็กอาจทำให้ kernel สั่ง kill กระบวนการที่ใช้หน่วยความจำมากที่สุด ซึ่งอาจเป็นตัว build หรือฐานข้อมูลของคุณก็ได้ นอกจากนี้การ build ยังทิ้งไฟล์แคชไว้บนดิสก์ซึ่งไม่มีกระบวนการใดมาล้างให้โดยอัตโนมัติ การ build บนเซิร์ฟเวอร์ยังคงทำได้สำหรับโปรเจกต์ขนาดเล็กที่ยังไม่มีผู้ใช้งาน และการย้ายไปทำที่อื่นในภายหลังก็ทำได้ง่ายหากคุณแยกส่วน build: ไว้ในไฟล์ Compose สำหรับการพัฒนาโดยเฉพาะ
ฉันจะป้องกันไม่ให้ Docker build cache เต็มดิสก์ได้อย่างไร?
รันคำสั่ง docker system df เพื่อดูว่า image และ build cache ของคุณใช้พื้นที่ไปเท่าใด docker builder prune จะลบเลเยอร์ที่แคชไว้ และ docker image prune จะลบ image ที่ค้างอยู่ (dangling images) จากการ build ก่อนหน้า การเพิ่ม -a เข้าไปในคำสั่งใดคำสั่งหนึ่งจะทำงานอย่างรุนแรงขึ้นและบังคับให้การ build ครั้งถัดไปของคุณต้องเริ่มใหม่ทั้งหมด (cold build) อย่าตั้งเวลาทำงานอัตโนมัติสำหรับ docker system prune -af --volumes บนเซิร์ฟเวอร์ เพราะ --volumes จะลบ volume ใดก็ตามที่ไม่มี container ใช้งานอยู่ ซึ่งรวมถึงฐานข้อมูลใน stack ที่คุณหยุดไว้เพื่อการบำรุงรักษาด้วย