ข้ามไปยังเนื้อหา

CMD vs ENTRYPOINT

Docker ให้ instruction สองตัวเพื่อกำหนดว่าจะเกิดอะไรขึ้นเมื่อ container เริ่มทำงาน:

  • CMD — คำสั่งเริ่มต้น (หรืออาร์กิวเมนต์เริ่มต้น) override ได้ง่ายตอน docker run
  • ENTRYPOINT — executable ที่ตายตัว override ได้ยากกว่า ทำให้ container ทำตัวเหมือนโปรแกรมเฉพาะตัวหนึ่ง

ทั้งสองมักถูกสับสนกัน การเข้าใจความต่างจะช่วยให้คุณสร้าง container ที่ใช้งานอย่างถูกต้องได้ง่าย

ทั้ง CMD และ ENTRYPOINT รับ syntax ได้สองรูปแบบ

CMD ["node", "server.js"]
ENTRYPOINT ["node"]

อาร์กิวเมนต์อยู่ในรูป JSON array Docker จะรันโปรแกรม โดยตรง — ไม่มี shell มาเกี่ยวข้อง PID 1 ภายใน container คือโปรเซสของคุณ นั่นหมายความว่าจะรับสัญญาณ OS (SIGTERM, SIGINT) ได้อย่างถูกต้อง ซึ่งสำคัญมากต่อการ shutdown แบบ graceful

CMD node server.js
ENTRYPOINT node

Docker จะห่อคำสั่งไว้ใน /bin/sh -c "..." shell จะกลายเป็น PID 1 แทนที่จะเป็นโปรเซสของคุณ แอปของคุณจะรันเป็น child ของ shell และสัญญาณ OS จะไม่ถูกส่งต่ออย่างเชื่อถือได้ หลีกเลี่ยงรูปแบบนี้สำหรับ production service

CMD กำหนดคำสั่งเริ่มต้นที่ container จะรัน ถ้าผู้ใช้ส่งคำสั่งมาตอน docker run จะ แทนที่ CMD ทั้งหมด

# syntax=docker/dockerfile:1
FROM alpine:3.20
CMD ["echo", "Hello from CMD!"]
Terminal window
# Uses CMD
docker run --rm myimage
# Output: Hello from CMD!
# Overrides CMD completely
docker run --rm myimage echo "Custom message"
# Output: Custom message

ENTRYPOINT กำหนด executable ที่จะรันเสมอ อาร์กิวเมนต์ที่ส่งมาตอน docker run จะถูก ต่อท้าย entry point — ไม่ใช่แทนที่

# syntax=docker/dockerfile:1
FROM alpine:3.20
ENTRYPOINT ["ping"]
CMD ["-c", "3", "8.8.8.8"]
Terminal window
# Uses ENTRYPOINT + CMD defaults
docker run --rm pinger
# Runs: ping -c 3 8.8.8.8
# Appends to ENTRYPOINT, replaces CMD
docker run --rm pinger -c 1 1.1.1.1
# Runs: ping -c 1 1.1.1.1

แพตเทิร์นที่ยืดหยุ่นที่สุดและเป็นสำนวนที่นิยมใช้:

  • ENTRYPOINT = executable (ตายตัว)
  • CMD = อาร์กิวเมนต์เริ่มต้น (ผู้ใช้แทนที่ได้)
# syntax=docker/dockerfile:1
FROM node:22-alpine
WORKDIR /app
COPY server.js .
ENTRYPOINT ["node"]
CMD ["server.js"]
Terminal window
# Default: node server.js
docker run --rm myapp
# Override: node --version
docker run --rm myapp --version

คุณยังสามารถ override ENTRYPOINT ได้เมื่อจำเป็นโดยใช้แฟล็ก --entrypoint:

Terminal window
docker run --rm --entrypoint sh myapp

คำสั่งนี้จะพาคุณเข้าสู่ shell ภายใน container — มีประโยชน์สำหรับการ debug

ไม่ overridedocker run img argsdocker run --entrypoint X img
มีแค่ CMDรัน CMDแทนที่ CMD ด้วย argsn/a — ใช้ entrypoint ใหม่
มีแค่ ENTRYPOINTรัน ENTRYPOINTต่อ args ท้าย ENTRYPOINTแทนที่ ENTRYPOINT
ENTRYPOINT + CMDรัน ENTRYPOINT + CMD เริ่มต้นแทนที่ CMD ด้วย argsแทนที่ ENTRYPOINT
# syntax=docker/dockerfile:1
FROM alpine:3.20
# ENTRYPOINT sets the fixed executable
# CMD sets the default arguments
ENTRYPOINT ["echo"]
CMD ["Hello from ENTRYPOINT + CMD!"]
# --- build ---
# docker build -t greet .
# Run with defaults (uses CMD):
# docker run --rm greet
# Override CMD with your own message:
# docker run --rm greet "My custom message"
# Override ENTRYPOINT entirely:
# docker run --rm --entrypoint sh greet
ตัวเลือกBenefitCost
CMDoverride ได้ง่ายตอน docker run เหมาะกับ dev/debugผู้ใช้เผลอเปลี่ยนพฤติกรรม default ทั้งหมดโดยไม่ตั้งใจได้
ENTRYPOINTตายตัว บังคับให้ container ทำหน้าที่เดียวเสมอ ปลอดภัยกว่าใน productionoverride ยากขึ้น ต้องใช้ --entrypoint ทำให้ debug ลำบากกว่า
  • ใช้ shell form แทน exec form ทำให้โปรเซสไม่ได้เป็น PID 1 รับสัญญาณ OS ไม่ได้ shutdown ไม่ graceful
  • ใส่ทั้ง executable และอาร์กิวเมนต์ไว้ใน ENTRYPOINT เดียวกันหมด ทำให้ CMD override อะไรไม่ได้เลย
  • เข้าใจผิดว่าอาร์กิวเมนต์ที่ส่งตอน docker run จะถูกต่อท้าย CMD เสมอ ทั้งที่จริงอาร์กิวเมนต์พวกนั้นแทนที่ CMD ทั้งหมด

💡 ตัวอย่างจากของจริง

Official image ของ postgres ใช้ ENTRYPOINT ["docker-entrypoint.sh"] เป็น executable ตายตัว และใช้ CMD ["postgres"] เป็นอาร์กิวเมนต์เริ่มต้น ผู้ใช้จึง override เฉพาะอาร์กิวเมนต์ของ postgres ได้โดยไม่ต้องแตะ entrypoint script

ทำไม exec form (`["node", "server.js"]`) จึงถูกแนะนำมากกว่า shell form (`node server.js`)?
ถ้า Dockerfile มีทั้ง ENTRYPOINT ["ping"] และ CMD ["-c", "3", "8.8.8.8"] อะไรจะรันเมื่อคุณสั่ง `docker run img -c 1 1.1.1.1`?
แฟล็ก docker run ใดที่ให้คุณแทนที่ ENTRYPOINT ตอน runtime?
การใช้ CMD ตามสำนวนที่นิยมเมื่อมีการตั้ง ENTRYPOINT ไว้ด้วยคืออะไร?