#!/usr/bin/env bash # ============================================================================= # 헬스체크 스크립트 (HTTP / TCP) # Jenkins Stage 7: Health Check에서 호출 # 사용: health_check.sh --url [--timeout 60] [--retries 3] [--interval 10] # ============================================================================= set -euo pipefail CHECK_URL="" CHECK_TYPE="http" # http | tcp TCP_HOST="" TCP_PORT="" TIMEOUT="${HEALTH_TIMEOUT:-60}" RETRIES="${HEALTH_RETRIES:-3}" INTERVAL="${HEALTH_INTERVAL:-10}" EXPECT_STATUS="${EXPECT_STATUS:-200}" LOG_DIR="${WORKSPACE:-/tmp}/build-logs" HC_LOG="${LOG_DIR}/healthcheck-$(date +%Y%m%d-%H%M%S).log" GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; NC='\033[0m' log() { echo -e "${GREEN}[HEALTH]${NC} $*" | tee -a "${HC_LOG}"; } err() { echo -e "${RED}[ERROR]${NC} $*" | tee -a "${HC_LOG}"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*" | tee -a "${HC_LOG}"; } mkdir -p "${LOG_DIR}" while [[ $# -gt 0 ]]; do case $1 in --url) CHECK_URL="$2"; CHECK_TYPE="http"; shift 2 ;; --host) TCP_HOST="$2"; CHECK_TYPE="tcp"; shift 2 ;; --port) TCP_PORT="$2"; CHECK_TYPE="tcp"; shift 2 ;; --timeout) TIMEOUT="$2"; shift 2 ;; --retries) RETRIES="$2"; shift 2 ;; --interval) INTERVAL="$2"; shift 2 ;; --expect) EXPECT_STATUS="$2";shift 2 ;; *) shift ;; esac done # ── HTTP 헬스체크 ──────────────────────────────────────────────────────────── check_http() { log "HTTP 헬스체크: ${CHECK_URL}" log " 예상 상태코드: ${EXPECT_STATUS}" log " 타임아웃: ${TIMEOUT}초 / 재시도: ${RETRIES}회" local attempt=0 while [[ ${attempt} -lt ${RETRIES} ]]; do attempt=$((attempt + 1)) log " 시도 ${attempt}/${RETRIES}..." local http_code local response_time_ms local start_ns start_ns=$(date +%s%N 2>/dev/null || echo 0) http_code=$(curl \ --silent \ --output /dev/null \ --write-out "%{http_code}" \ --max-time "${TIMEOUT}" \ --connect-timeout 10 \ --location \ "${CHECK_URL}" 2>/dev/null || echo "000") local end_ns end_ns=$(date +%s%N 2>/dev/null || echo 0) if [[ "${start_ns}" != "0" ]]; then response_time_ms=$(( (end_ns - start_ns) / 1000000 )) else response_time_ms="N/A" fi log " 응답: HTTP ${http_code} (${response_time_ms}ms)" if [[ "${http_code}" == "${EXPECT_STATUS}" ]]; then log "✅ 헬스체크 통과: HTTP ${http_code}" return 0 elif [[ "${http_code}" == "000" ]]; then warn " 연결 실패 (타임아웃 또는 접속 거부)" else warn " 예상과 다른 응답: ${http_code} (예상: ${EXPECT_STATUS})" fi if [[ ${attempt} -lt ${RETRIES} ]]; then log " ${INTERVAL}초 후 재시도..." sleep "${INTERVAL}" fi done err "헬스체크 실패: ${RETRIES}회 모두 실패" return 1 } # ── TCP 헬스체크 ──────────────────────────────────────────────────────────── check_tcp() { [[ -z "${TCP_HOST}" ]] && { err "--host 파라미터가 필요합니다"; exit 1; } [[ -z "${TCP_PORT}" ]] && { err "--port 파라미터가 필요합니다"; exit 1; } log "TCP 헬스체크: ${TCP_HOST}:${TCP_PORT}" local attempt=0 while [[ ${attempt} -lt ${RETRIES} ]]; do attempt=$((attempt + 1)) log " 시도 ${attempt}/${RETRIES}..." if timeout "${TIMEOUT}" bash -c \ "echo >/dev/tcp/${TCP_HOST}/${TCP_PORT}" 2>/dev/null; then log "✅ TCP 연결 성공: ${TCP_HOST}:${TCP_PORT}" return 0 fi warn " TCP 연결 실패: ${TCP_HOST}:${TCP_PORT}" if [[ ${attempt} -lt ${RETRIES} ]]; then log " ${INTERVAL}초 후 재시도..." sleep "${INTERVAL}" fi done err "TCP 헬스체크 실패: ${RETRIES}회 모두 실패" return 1 } # ── 복합 헬스체크 ───────────────────────────────────────────────────────────── check_composite() { # HTTP + 추가 TCP 포트 확인 check_http || return 1 if [[ -n "${TCP_HOST}" ]] && [[ -n "${TCP_PORT}" ]]; then check_tcp || return 1 fi return 0 } # ── 메인 ───────────────────────────────────────────────────────────────────── main() { log "=== 헬스체크 시작: $(date) ===" case "${CHECK_TYPE}" in http) [[ -z "${CHECK_URL}" ]] && { err "--url 파라미터가 필요합니다"; exit 1; } check_http ;; tcp) check_tcp ;; composite) check_composite ;; *) err "알 수 없는 헬스체크 유형: ${CHECK_TYPE}" exit 1 ;; esac log "=== 헬스체크 통과 ===" } main "$@"