โพรบสุขภาพ ด่านความพร้อม และลูปรอ
นำลูปรอทรัพยากรที่ต้องพึ่งพาและโพรบตรวจชีพจรมาใช้ เพื่อให้บริการในคอนเทนเนอร์เริ่มทำงานได้อย่างน่าเชื่อถือ
โพรบสุขภาพ ด่านความพร้อม และลูปรอ เป็นบทเรียน Linux Command Line & Bash Scripting Mastery ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Linux Command Line & Bash Scripting Mastery และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดบริการจึงทำงานล้มเหลวเมื่อเริ่มต้น
ในสภาพแวดล้อมแบบคอนเทนเนอร์ บริการต่าง ๆ แทบไม่เคยเริ่มทำงานโดยลำพัง แอปพลิเคชันเว็บต้องมีฐานข้อมูลที่พร้อมใช้งาน ไมโครเซอร์วิสต้องมีตัวรับส่งข้อความพร้อมใช้งาน และกระบวนการทำงานเบื้องหลังต้องมีแคชที่เติมข้อมูลแล้วก่อนจึงจะประมวลผลงานได้
หากไม่มีการประสานงาน คอนเทนเนอร์จะเริ่มทำงานพร้อมกัน และคำขอแรกจะมาถึงก่อนที่ระบบที่ต้องพึ่งพาจะพร้อมใช้งาน ผลลัพธ์คือ ข้อผิดพลาดการปฏิเสธการเชื่อมต่อ ข้อยกเว้นตัวชี้ค่าว่าง และ สถานะเริ่มต้นที่เสียหาย ซึ่งต้องแก้ไขด้วยการเริ่มต้นใหม่ด้วยตนเอง
- การตรวจสอบการทำงาน — กระบวนการยังทำงานอยู่และไม่ค้างใช่หรือไม่
- การตรวจสอบความพร้อม — บริการพร้อมรับการรับส่งข้อมูลหรือไม่
- ลูปการรอ — สคริปต์เริ่มต้นที่หยุดรอจนกว่าระบบที่ต้องพึ่งพาจะเข้าถึงได้
Kubernetes มีกลไกการตรวจสอบในตัว แต่สคริปต์เชลล์ที่ขับเคลื่อน initContainers ตัวห่อ entrypoint.sh และการตรวจสอบสุขภาพแบบแยกเดี่ยวเขียนด้วย Bash การเชี่ยวชาญสิ่งเหล่านี้เป็นทักษะหลักของ DevOps
รูปแบบการรอทรัพยากร
ลูปการรอระบบที่ต้องพึ่งพาแบบง่ายที่สุดจะตรวจสอบเป้าหมายตามช่วงเวลาคงที่จนกว่าจะเข้าถึงได้ รูปแบบมาตรฐานใช้ลูป while ร่วมกับ nc (netcat) หรือ curl เพื่อตรวจสอบพอร์ต TCP หรือปลายทาง HTTP
การตัดสินใจด้านการออกแบบที่สำคัญ:
- ระยะหมดเวลา — ยุติการรอหลังผ่านไป N วินาที เพื่อไม่ให้ระบบที่ต้องพึ่งพาซึ่งขัดข้องทำให้พ็อดค้างตลอดไป
- ช่วงเวลาหน่วงระหว่างการตรวจสอบ — หยุดพักระหว่างการตรวจสอบ เพื่อไม่ส่งคำขอจำนวนมากใส่บริการที่กำลังฟื้นตัว
- รหัสการออก — ออกจากการทำงานด้วยรหัส 1 เมื่อหมดเวลา เพื่อให้คอนเทนเนอร์เริ่มใหม่ หรือให้คอนเทนเนอร์เริ่มต้นรายงานความล้มเหลวอย่างชัดเจน
ส่วนโค้ดด้านล่างจะรอนานสูงสุด 60 วินาทีให้พอร์ต TCP ยอมรับการเชื่อมต่อก่อนเริ่มกระบวนการหลัก
#!/usr/bin/env bash
set -euo pipefail
HOST="${DB_HOST:-postgres}"
PORT="${DB_PORT:-5432}"
TIMEOUT=60
INTERVAL=2
ELAPSED=0
echo "[wait-for] Waiting for ${HOST}:${PORT}..."
until nc -z "$HOST" "$PORT" 2>/dev/null; do
if (( ELAPSED >= TIMEOUT )); then
echo "[wait-for] Timed out after ${TIMEOUT}s waiting for ${HOST}:${PORT}" >&2
exit 1
fi
echo "[wait-for] ${HOST}:${PORT} not ready — retrying in ${INTERVAL}s (${ELAPSED}s elapsed)"
sleep "$INTERVAL"
(( ELAPSED += INTERVAL ))
done
echo "[wait-for] ${HOST}:${PORT} is up — continuing"
exec "$@"การตรวจสอบความพร้อมของ HTTP ด้วย curl
การเชื่อมต่อ TCP เพียงบอกว่าพอร์ตเปิดอยู่เท่านั้น ไม่ได้บอกว่าแอปพลิเคชันที่อยู่เบื้องหลังพร้อมให้บริการคำขอแล้ว บริการจำนวนมากเปิดปลายทาง /health หรือ /readyz โดยเฉพาะ ซึ่งจะส่งคืน HTTP 200 ก็ต่อเมื่อระบบย่อยภายในทั้งหมดเริ่มต้นเสร็จแล้ว
ใช้ curl --fail --silent --output /dev/null เพื่อตรวจสอบปลายทางความพร้อมของ HTTP แฟล็ก --fail ทำให้ curl ออกจากการทำงานด้วยรหัส 22 เมื่อได้รับการตอบกลับ 4xx/5xx จึงควบคุมตรรกะการลองใหม่ได้อย่างเป็นระเบียบ
แฟล็กสำคัญที่ควรรู้:
--fail— ถือว่าข้อผิดพลาด HTTP เป็นข้อผิดพลาดของ curl (ออกด้วยรหัสที่ไม่ใช่ศูนย์)--silent— ไม่แสดงผลความคืบหน้า--max-time N— ระยะหมดเวลาต่อคำขอเป็นวินาที--retry N --retry-delay S— กลไกการลองใหม่ในตัวของ curl (มีประโยชน์สำหรับกรณีง่าย ๆ)
#!/usr/bin/env bash
set -euo pipefail
HEALTH_URL="${HEALTH_URL:-http://localhost:8080/healthz}"
TIMEOUT=90
INTERVAL=3
ELAPSED=0
echo "[probe] Polling readiness at ${HEALTH_URL}"
until curl --fail --silent --output /dev/null \
--max-time 2 "${HEALTH_URL}"; do
if (( ELAPSED >= TIMEOUT )); then
echo "[probe] Service not ready after ${TIMEOUT}s" >&2
exit 1
fi
printf '[probe] Not ready yet (%ds elapsed)\n' "$ELAPSED"
sleep "$INTERVAL"
(( ELAPSED += INTERVAL ))
done
echo "[probe] Service is ready"
exec "$@"การหน่วงเวลาแบบทวีคูณในลูปการรอ
ลูปการลองใหม่ตามช่วงเวลาคงที่จะส่งคำขอใส่บริการที่กำลังฟื้นตัวด้วยอัตราคงที่ การหน่วงเวลาแบบทวีคูณจะเพิ่มเวลารอเป็นสองเท่าในแต่ละครั้งที่ลองใหม่ ช่วยลดภาระระหว่างการฟื้นตัว ขณะเดียวกันก็กลับมาทำงานได้อย่างรวดเร็วเมื่อบริการเริ่มทำงานเร็ว
สูตรมาตรฐานคือ sleep_time = min(base * 2^attempt, max_sleep) องค์ประกอบการสุ่มเลื่อนเวลา ซึ่งเป็นการเลื่อนแบบเศษส่วนสุ่ม จะป้องกันปัญหาคำขอจำนวนมากแห่เข้าพร้อมกันเมื่อคอนเทนเนอร์หลายรายการเริ่มใหม่ในเวลาเดียวกัน
รูปแบบนี้ใช้ในเครื่องมือระดับใช้งานจริง เช่น wait-for-it การลองใหม่ของ AWS SDK และลูปการปรับสถานะของตัวควบคุม Kubernetes
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-redis}"
PORT="${PORT:-6379}"
MAX_ATTEMPTS=8
BASE_SLEEP=1
MAX_SLEEP=30
for attempt in $(seq 1 "$MAX_ATTEMPTS"); do
if nc -z "$HOST" "$PORT" 2>/dev/null; then
echo "[backoff] Connected to ${HOST}:${PORT} on attempt ${attempt}"
exec "$@"
fi
# Exponential backoff with jitter
raw=$(( BASE_SLEEP * (2 ** (attempt - 1)) ))
capped=$(( raw < MAX_SLEEP ? raw : MAX_SLEEP ))
jitter=$(( RANDOM % 3 ))
sleep_time=$(( capped + jitter ))
echo "[backoff] Attempt ${attempt}/${MAX_ATTEMPTS} failed — sleeping ${sleep_time}s"
sleep "$sleep_time"
done
echo "[backoff] ${HOST}:${PORT} unreachable after ${MAX_ATTEMPTS} attempts" >&2
exit 1การตรวจสอบระบบที่ต้องพึ่งพาหลายรายการ
แอปพลิเคชันจริงมีระบบที่ต้องพึ่งพาหลายรายการ ได้แก่ ฐานข้อมูล แคช ตัวรับส่งข้อความ และอาจมี API ภายนอกด้วย การตรวจสอบทีละรายการทำให้เสียเวลาเริ่มต้น แนวทางที่ดีกว่าคือตรวจสอบระบบที่ต้องพึ่งพาทั้งหมดพร้อมกัน แล้วรอให้ทุกรายการสำเร็จ
ตัวดำเนินการ Bash & ส่งการตรวจสอบแต่ละรายการไปทำงานเบื้องหลัง และ wait รวบรวมรหัสการออกของแต่ละรายการ หากการตรวจสอบรายการใดล้มเหลว สคริปต์เริ่มต้นจะออกด้วยรหัสที่ไม่ใช่ศูนย์ ซึ่งจะเรียกให้คอนเทนเนอร์เริ่มใหม่
เทคนิคสำคัญคือ จับรหัส PID เบื้องหลังด้วย $! แล้วส่งรหัสเหล่านั้นให้ wait อย่างชัดเจน เพื่อให้ตรวจสอบรหัสการออกของแต่ละรายการได้
#!/usr/bin/env bash
set -euo pipefail
wait_tcp() {
local host="$1" port="$2" timeout="${3:-30}"
local elapsed=0
until nc -z "$host" "$port" 2>/dev/null; do
(( elapsed >= timeout )) && { echo "TIMEOUT ${host}:${port}" >&2; return 1; }
sleep 2; (( elapsed += 2 ))
done
echo "[ok] ${host}:${port}"
}
# Launch all probes in parallel
wait_tcp postgres 5432 60 & PID_PG=$!
wait_tcp redis 6379 30 & PID_RD=$!
wait_tcp rabbitmq 5672 45 & PID_RQ=$!
# Collect results — fail fast if any probe failed
FAILED=0
for pid in $PID_PG $PID_RD $PID_RQ; do
wait "$pid" || (( FAILED++ ))
done
if (( FAILED > 0 )); then
echo "[entrypoint] ${FAILED} dependency probe(s) failed — aborting" >&2
exit 1
fi
echo "[entrypoint] All dependencies ready"
exec "$@"การตรวจสอบการทำงานกับการตรวจสอบความพร้อม: ใช้สคริปต์ต่างกันตามประเภทการตรวจสอบ
Kubernetes แยกการตรวจสอบการทำงานออกจากการตรวจสอบความพร้อม และทั้งสองประเภทควรทำงานต่างกัน:
- การตรวจสอบการทำงาน — ตอบคำถามว่า กระบวนการยังทำงานอยู่และไม่ค้างใช่หรือไม่ ควรทำงานรวดเร็วและตรวจสอบเฉพาะสถานะภายใน เช่น มีไฟล์ PID ของกระบวนการอยู่ หรือปลายทางตรวจสอบสุขภาพภายในส่งคืน 200 การตรวจสอบการทำงานที่ล้มเหลวจะยุติและเริ่มคอนเทนเนอร์ใหม่
- การตรวจสอบความพร้อม — ตอบคำถามว่า พ็อดนี้ควรได้รับการรับส่งข้อมูลหรือไม่ อาจตรวจสอบระบบที่ต้องพึ่งพาด้านปลายทาง การตรวจสอบความพร้อมที่ล้มเหลวจะนำพ็อดออกจากตัวกระจายโหลดของ Service แต่จะไม่เริ่มพ็อดใหม่
อย่านำการตรวจสอบระบบที่ต้องพึ่งพาซึ่งใช้เวลานานไปไว้ในการตรวจสอบการทำงาน การหยุดทำงานชั่วคราวของฐานข้อมูลเพียงเล็กน้อยอาจทำให้เริ่มพ็อดแอปพลิเคชันทั้งหมดใหม่อย่างไม่ถูกต้อง และทำให้ปัญหารุนแรงขึ้น
#!/usr/bin/env bash
# liveness.sh — fast local-only check
# Used in: livenessProbe.exec.command
set -euo pipefail
PID_FILE="/var/run/app/app.pid"
HEALTH_URL="http://127.0.0.1:8080/internal/live"
# Check 1: process is running
[[ -f "$PID_FILE" ]] || { echo "PID file missing" >&2; exit 1; }
kill -0 "$(cat "$PID_FILE")" 2>/dev/null || { echo "Process dead" >&2; exit 1; }
# Check 2: local endpoint responds (2s timeout — never block)
curl --fail --silent --max-time 2 --output /dev/null "$HEALTH_URL" || {
echo "Liveness endpoint unresponsive" >&2
exit 1
}
echo "live"
exit 0การตรวจสอบการเริ่มต้นและ initContainers
Kubernetes มีการตรวจสอบประเภทที่สามคือ startupProbe โดยจะทำงานแทนการตรวจสอบการทำงานและการตรวจสอบความพร้อมจนกว่าจะสำเร็จหนึ่งครั้ง ทำให้แอปพลิเคชันที่เริ่มต้นช้า เช่น การอุ่นเครื่อง JVM หรือการย้ายข้อมูลฐานข้อมูล มีเวลาเริ่มต้นโดยไม่ก่อให้เกิดความล้มเหลวของการตรวจสอบการทำงานที่ไม่เป็นจริง
สำหรับการรอระบบที่ต้องพึ่งพา การใช้ initContainers มักเป็นระเบียบกว่าสคริปต์เริ่มต้น โดยจะทำงานก่อนคอนเทนเนอร์ของแอป และ Kubernetes จะจัดการตรรกะการลองใหม่หรือเริ่มใหม่ให้อัตโนมัติ อิมเมจของคอนเทนเนอร์เริ่มต้นต้องมีเพียง sh, nc หรือ curl เท่านั้น คุณสามารถใช้อิมเมจขนาดเล็กอย่าง busybox หรือ alpine ได้
ตัวอย่างข้อกำหนด initContainer ในไฟล์แสดงรายการของพ็อด:
# kubernetes/pod-with-init.yaml (illustrative — not runnable as bash)
# initContainers run sequentially before app containers
initContainers:
- name: wait-for-postgres
image: busybox:1.36
command:
- sh
- -c
- |
set -e
echo 'Waiting for postgres...'
until nc -z postgres 5432; do
echo 'postgres not ready — sleeping 2s'
sleep 2
done
echo 'postgres is up'
- name: run-migrations
image: myapp:latest
command: ['python', 'manage.py', 'migrate', '--noinput']
envFrom:
- secretRef:
name: app-secretsสคริปต์ตรวจสอบสุขภาพที่มีผลลัพธ์ JSON
ระบบระดับใช้งานจริงมักรวบรวมสถานะสุขภาพจากระบบย่อยหลายรายการ แล้วเปิดเผยเป็นข้อมูล JSON ที่มีโครงสร้าง ตัวกระจายโหลด ระบบจัดการการทำงาน และแดชบอร์ดตรวจสอบจะนำข้อมูลนี้ไปใช้
สคริปต์ตรวจสอบสุขภาพของ Bash สามารถสร้างผลลัพธ์ JSON ได้โดยตรงด้วย printf หรือ jq รหัสการออกยังคงเป็นตัวควบคุมการทำงานอัตโนมัติ ส่วนเนื้อหา JSON มีไว้สำหรับผู้ปฏิบัติงานและระบบตรวจสอบ
แนวปฏิบัติคือ ส่งคืน HTTP 200 พร้อม {"status":"ok"} เมื่อสุขภาพปกติ และส่งคืน HTTP 503 พร้อม {"status":"degraded", "checks":{...}} เมื่อสุขภาพไม่ปกติ สคริปต์ด้านล่างมีไว้ให้ตัวห่อ HTTP ขนาดเล็ก เช่น socat เรียกใช้ หรือให้การตรวจสอบแบบ exec ของ Kubernetes เรียกใช้โดยตรง
#!/usr/bin/env bash
# health_check.sh — composite health with JSON output
set -uo pipefail
check_postgres() {
pg_isready -h "${DB_HOST:-postgres}" -p "${DB_PORT:-5432}" \
-U "${DB_USER:-app}" -t 2 &>/dev/null
}
check_redis() {
redis-cli -h "${REDIS_HOST:-redis}" -p "${REDIS_PORT:-6379}" \
PING 2>/dev/null | grep -q PONG
}
check_disk() {
local usage
usage=$(df / | awk 'NR==2{gsub(/%/,"",$5); print $5}')
(( usage < 90 ))
}
PG_OK=0; RD_OK=0; DSK_OK=0
check_postgres && PG_OK=1
check_redis && RD_OK=1
check_disk && DSK_OK=1
OVERALL=$(( PG_OK && RD_OK && DSK_OK ))
STATUS=$( (( OVERALL )) && echo 'ok' || echo 'degraded' )
printf '{"status":"%s","checks":{"postgres":%s,"redis":%s,"disk":%s}}\n' \
"$STATUS" "$PG_OK" "$RD_OK" "$DSK_OK"
(( OVERALL )) && exit 0 || exit 1เครื่องมือกำหนดระยะหมดเวลาตามรูปแบบเส้นตาย
คำสั่ง timeout ของ GNU จะครอบคำสั่งใด ๆ และยุติการทำงานหากคำสั่งนั้นไม่เสร็จภายในระยะเวลาที่กำหนด วิธีนี้เป็นวิธีที่สะอาดที่สุดในการบังคับใช้เส้นตายที่แน่นอนกับลูปการรอหรือการตรวจสอบสุขภาพ โดยไม่ต้องจัดการงานเบื้องหลังด้วยตนเอง
timeout DURATION COMMAND [ARGS...]
รหัสการออกจาก timeout:
- 0 — คำสั่งทำงานสำเร็จภายในเส้นตาย
- รหัสการออกของคำสั่ง — คำสั่งทำงานแล้วแต่ส่งคืนค่าที่ไม่ใช่ศูนย์
- 124 — คำสั่งหมดเวลา (ส่ง SIGTERM แล้ว)
- 137 — คำสั่งถูกยุติด้วย SIGKILL (หลังจาก
--kill-after)
การตรวจจับรหัสการออก 124 ทำให้คุณแสดงข้อความแจ้งระยะหมดเวลาที่ชัดเจนแทนข้อผิดพลาดทั่วไปได้
#!/usr/bin/env bash
set -euo pipefail
HOST="${DB_HOST:-postgres}"
PORT="${DB_PORT:-5432}"
DEADLINE=60 # seconds
# Inline poll loop, wrapped by timeout
timeout "$DEADLINE" bash -c "
until nc -z '$HOST' '$PORT' 2>/dev/null; do
echo '[wait] ${HOST}:${PORT} not ready...'
sleep 2
done
" && echo "[wait] ${HOST}:${PORT} is up" || {
code=$?
if (( code == 124 )); then
echo "[wait] Timed out after ${DEADLINE}s waiting for ${HOST}:${PORT}" >&2
else
echo "[wait] Probe failed with exit code ${code}" >&2
fi
exit "$code"
}
exec "$@"wait-for-it ที่ทำงานได้ในตัวด้วย Bash ล้วน
อิมเมจคอนเทนเนอร์ขนาดเล็กจำนวนมากไม่มี nc (netcat) แต่ Bash ล้วนสามารถเปิดการเชื่อมต่อ TCP ได้ด้วย การแทนที่กระบวนการไปยัง /dev/tcp ซึ่งเป็นความสามารถในตัวของ Bash ที่ไม่ใช่มาตรฐานแต่รองรับอย่างแพร่หลายและไม่ต้องใช้เครื่องมือภายนอกเลย
ไวยากรณ์: /dev/tcp/HOST/PORT — Bash จะเปิดการเชื่อมต่อ TCP เมื่อเปลี่ยนเส้นทางข้อมูลไปยังหรือออกจากพาธนี้ หากการเชื่อมต่อถูกปฏิเสธหรือหมดเวลา จะเกิดข้อผิดพลาด (การออกด้วยรหัสที่ไม่ใช่ศูนย์)
นี่คือเทคนิคที่ใช้ในสคริปต์ wait-for-it.sh ยอดนิยม ซึ่งมาพร้อมกับการตั้งค่า Docker Compose จำนวนมาก สคริปต์ด้านล่างเป็นการใช้งานแบบครบถ้วนและแยกเดี่ยวที่คุณสามารถ COPY ลงใน Dockerfile ใดก็ได้
#!/usr/bin/env bash
# wait-for-it.sh (pure bash, no nc/curl required)
set -uo pipefail
usage() { echo "Usage: $0 HOST:PORT [-t TIMEOUT] [-- COMMAND]"; exit 1; }
parse_hostport() {
HOST="${1%%:*}"
PORT="${1##*:}"
[[ -n "$HOST" && "$PORT" =~ ^[0-9]+$ ]] || usage
}
[[ $# -ge 1 ]] || usage
parse_hostport "$1"; shift
TIMEOUT=30
[[ "${1:-}" == "-t" ]] && { TIMEOUT="$2"; shift 2; }
[[ "${1:-}" == "--" ]] && shift
wait_for() {
local elapsed=0
while (( elapsed < TIMEOUT )); do
# Pure bash TCP probe — no nc, no curl
if (exec 3<>"/dev/tcp/${HOST}/${PORT}") 2>/dev/null; then
exec 3>&-
return 0
fi
sleep 1
(( elapsed++ ))
done
return 1
}
echo "Waiting for ${HOST}:${PORT} (timeout ${TIMEOUT}s)..."
if wait_for; then
echo "${HOST}:${PORT} is available"
[[ $# -gt 0 ]] && exec "$@"
else
echo "Timed out waiting for ${HOST}:${PORT}" >&2
exit 1
fiการผสานการตรวจสอบเข้ากับ entrypoint.sh
รูปแบบสคริปต์เริ่มต้นเป็นวิธีมาตรฐานในการรวมลูปการรอ การตรวจสอบตัวแปรสภาพแวดล้อม และการเริ่มกระบวนการไว้ในสคริปต์เดียวที่ดูแลรักษาได้ง่าย ENTRYPOINT ของ Docker จะเรียกสคริปต์นี้ และสคริปต์จะจบด้วย exec "$@" เพื่อส่งต่อการทำงานให้ CMD โดยใช้ PID เดิม ซึ่งทำให้ส่งต่อสัญญาณได้อย่างถูกต้อง
entrypoint.sh ระดับใช้งานจริงมักจะ:
- ตรวจสอบตัวแปรสภาพแวดล้อมที่จำเป็นตั้งแต่ต้น (ล้มเหลวอย่างรวดเร็ว)
- เรียกใช้ลูปการรอระบบที่ต้องพึ่งพา
- ดำเนินการย้ายข้อมูลฐานข้อมูล (หากเกี่ยวข้อง)
- เรียกใช้การตรวจสอบตัวเองขั้นสุดท้าย
- ส่งต่อการควบคุมด้วย
exec "$@"
การใช้ exec มีความสำคัญอย่างยิ่ง เพราะจะแทนที่กระบวนการเชลล์ ทำให้แอปกลายเป็น PID 1 และได้รับ SIGTERM จากการปิดระบบอย่างสุภาพของ Docker/Kubernetes โดยตรง
#!/usr/bin/env bash
# docker/entrypoint.sh
set -euo pipefail
# ── 1. Validate required env vars ────────────────────────────────────
for var in DATABASE_URL REDIS_URL SECRET_KEY; do
[[ -n "${!var:-}" ]] || { echo "FATAL: ${var} is not set" >&2; exit 1; }
done
# ── 2. Parse DB host/port from DATABASE_URL ──────────────────────────
DB_HOST=$(echo "$DATABASE_URL" | sed -E 's|.*@([^:/]+).*|\1|')
DB_PORT=$(echo "$DATABASE_URL" | sed -E 's|.*:([0-9]+)/.*|\1|')
# ── 3. Wait for dependencies ─────────────────────────────────────────
timeout 60 bash -c "
until nc -z '${DB_HOST}' '${DB_PORT}' 2>/dev/null; do sleep 2; done
" || { echo "Database unreachable" >&2; exit 1; }
# ── 4. Run migrations ────────────────────────────────────────────────
echo "[entrypoint] Running migrations..."
python manage.py migrate --noinput
# ── 5. Hand off to CMD (exec preserves PID 1 for signal handling) ────
echo "[entrypoint] Starting application: $*"
exec "$@"ตรวจสอบความรู้: การตรวจสอบการทำงานกับการตรวจสอบความพร้อม
ทดสอบความเข้าใจเกี่ยวกับแนวคิดสำคัญที่กล่าวถึงในบทเรียนนี้
ทบทวน: การตรวจสอบสุขภาพ ประตูความพร้อม และลูปการรอ
ในบทเรียนนี้ คุณได้สร้างชุดเครื่องมือ Bash สำหรับประสานงานการเริ่มต้นคอนเทนเนอร์อย่างน่าเชื่อถือ โดยครอบคลุมหัวข้อต่อไปนี้:
- รูปแบบการรอทรัพยากร — ลูป
until nc -z HOST PORTที่มีระยะหมดเวลาตายตัวและตัวป้องกันตามเวลาที่ผ่านไป ช่วยป้องกันการหยุดรอไม่สิ้นสุดเมื่อระบบที่ต้องพึ่งพาขัดข้อง - การตรวจสอบความพร้อมของ HTTP —
curl --fail --max-timeตรวจสอบว่าแอปพลิเคชันพร้อมใช้งานจริง ไม่ใช่เพียงแค่พอร์ตเปิดอยู่ - การหน่วงเวลาแบบทวีคูณ — การเพิ่มช่วงเวลาพักระหว่างการลองใหม่เป็นสองเท่าช่วยลดภาระจากคำขอจำนวนมากที่แห่เข้าพร้อมกัน และเปิดโอกาสให้บริการที่กำลังฟื้นตัวปรับสถานะได้อย่างมั่นคง
- การตรวจสอบระบบที่ต้องพึ่งพาพร้อมกัน — การส่งการตรวจสอบไปทำงานเบื้องหลังด้วย
&และรวบรวมผลลัพธ์ด้วยwait $PIDช่วยลดเวลาเริ่มต้นเมื่อมีระบบที่ต้องพึ่งพาหลายรายการ - การตรวจสอบการทำงานกับการตรวจสอบความพร้อม — การตรวจสอบการทำงานต้องรวดเร็วและตรวจสอบเฉพาะภายใน ส่วนการตรวจสอบความพร้อมอาจตรวจสอบระบบปลายทางได้ อย่าสับสนระหว่างสองประเภทนี้
- startupProbe — ป้องกันแอปที่เริ่มต้นช้าจากความล้มเหลวของการตรวจสอบการทำงานที่ไม่เป็นจริงระหว่างการเริ่มต้น
- การตรวจสอบด้วย /dev/tcp — การตรวจสอบ TCP ด้วย Bash ล้วนไม่ต้องใช้เครื่องมือภายนอก จึงเหมาะอย่างยิ่งกับอิมเมจคอนเทนเนอร์ขนาดเล็ก
- entrypoint.sh — การตรวจสอบตัวแปรสภาพแวดล้อม ลูปการรอ การย้ายข้อมูล และ
exec "$@"รวมกันเป็นรูปแบบมาตรฐานสำหรับการเริ่มต้นบริการแบบคอนเทนเนอร์
รูปแบบเหล่านี้เป็นรากฐานของการนำคอนเทนเนอร์ไปใช้งานระดับจริงที่ซ่อมแซมตัวเองได้บน Docker Compose, Kubernetes และ ECS
คำถามที่พบบ่อย
บทเรียน “โพรบสุขภาพ ด่านความพร้อม และลูปรอ” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “โพรบสุขภาพ ด่านความพร้อม และลูปรอ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Linux Command Line & Bash Scripting Mastery ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “โพรบสุขภาพ ด่านความพร้อม และลูปรอ”
นำลูปรอทรัพยากรที่ต้องพึ่งพาและโพรบตรวจชีพจรมาใช้ เพื่อให้บริการในคอนเทนเนอร์เริ่มทำงานได้อย่างน่าเชื่อถือ คุณปฏิบัติ Linux Command Line & Bash Scripting Mastery ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Linux Command Line & Bash Scripting Mastery หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Linux Command Line & Bash Scripting Mastery บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “โพรบสุขภาพ ด่านความพร้อม และลูปรอ” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Linux Command Line & Bash Scripting Mastery นี้ได้ไหม
ได้ บทเรียน Linux Command Line & Bash Scripting Mastery ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การเขียน Dockerfile และจุดเริ่มต้น Shell แบบกระชับ
- การสร้างแม่แบบการกำหนดค่าด้วย envsubst และ heredoc
- การเขียนสคริปต์จัดการทรัพยากรคลาวด์ด้วย CLI และ jq
- โพรบสุขภาพ ด่านความพร้อม และลูปรอ