0Pricing
Linux Command Line & Bash Scripting Mastery · บทเรียน

โพรบสุขภาพ ด่านความพร้อม และลูปรอ

นำลูปรอทรัพยากรที่ต้องพึ่งพาและโพรบตรวจชีพจรมาใช้ เพื่อให้บริการในคอนเทนเนอร์เริ่มทำงานได้อย่างน่าเชื่อถือ

โพรบสุขภาพ ด่านความพร้อม และลูปรอ เป็นบทเรียน 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การเขียน Dockerfile และจุดเริ่มต้น Shell แบบกระชับ
  2. การสร้างแม่แบบการกำหนดค่าด้วย envsubst และ heredoc
  3. การเขียนสคริปต์จัดการทรัพยากรคลาวด์ด้วย CLI และ jq
  4. โพรบสุขภาพ ด่านความพร้อม และลูปรอ
← กลับไปที่ Linux Command Line & Bash Scripting Mastery