Sandcorp샌드코프 · 웹·AI 제품 개발

새 프로젝트 받는 중 · 갱신 2026.11sandcorp.co.krGitHub

← 팁

배포·인프라

로그용 임시 명령 파일이 원본 스크립트와 같은 경로면 스크립트가 자기 자신을 부른다

단계 출력을 tee로 남기려고 명령을 임시 파일에 적을 때, 그 이름이 감싸는 스크립트와 겹치면 원본이 「자기 실행」 한 줄로 덮여 무한 재귀가 된다. 이름 규칙과 쓰기 전 검사로 막는다.

문제

배포 단계가 끝나지 않고 bash: warning: shell level (1000) too high, resetting to 1 경고만 몇 초 간격으로 되풀이됩니다. 그동안 빌드 에이전트의 메모리가 몇 분 만에 수 GB로 불어나고, 같은 서버에서 도는 다른 서비스까지 응답하지 않게 됩니다.

원인

단계 출력을 로그 파일로도 남기려고 래퍼를 바꾼 것이 시작이었습니다. 새 래퍼는 단계 명령을 임시 파일에 적은 뒤 sh -xe 파일 | tee 로그로 실행합니다. 명령 파일 이름은 $TMP/app-{단계}.sh로 지었는데, 배포 단계가 실제로 돌리는 스크립트도 하필 $TMP/app-deploy.sh였습니다. 래퍼가 그 경로에 bash $TMP/app-deploy.sh 한 줄을 쓰는 순간 원본이 사라지고, 파일은 자기 자신을 부르는 한 줄만 남습니다. 셸이 셸을 끝없이 띄우고, 셸 깊이 경고는 1000에서 1로 되돌아갈 뿐 실행을 멈추지 않습니다.

해법

  • 래퍼가 만드는 파일에는 감싸는 대상과 겹칠 수 없는 표시를 넣습니다(예: app-step-deploy.sh).
  • 쓰기 전에 검사합니다. 명령 문자열에 자기 파일 경로가 들어 있으면 실패하게 해서, 이름 규칙이 나중에 다시 겹쳐도 재귀 대신 멈추게 합니다.
  • 「단계 파일 경로는 실제 스크립트 목록 어느 것과도 겹치지 않는다」는 단위 시험을 둡니다. 옛 경로로 사고를 재현하는 경우도 넣습니다.
  • 여러 저장소가 함께 쓰는 공유 파이프라인이라면, 「로그만 더 남기는」 작은 변경도 다음 배포부터 모든 저장소에 들어간다는 점을 기억합니다.
run_logged() {  # run_logged 단계 명령
  local key=$1 cmd=$2
  local file="$TMP/app-step-$key.sh" log="$TMP/app-$key.log"
  case "$cmd" in
    *"$file"*) echo "단계 명령이 자기 파일($file)을 실행한다 — 멈춤" >&2; return 1 ;;
  esac
  printf '%s\n' "$cmd" > "$file"
  sh -xe "$file" 2>&1 | tee "$log"
  return "${PIPESTATUS[0]}"
}

run_logged deploy "bash '$TMP/app-deploy.sh'"   # 원본과 다른 파일이라 안전

문의 →