[QnA] SAP BTP CF 앱 배포 후 Crashed — 원인 5가지와 즉시 해결법

Moderator · 조회 2
SAP BTP CF Crashed 원인 5가지

1. 개요 및 학습 목표

SAP BTP Cloud Foundry 환경에서 cf push 명령으로 애플리케이션을 배포한 뒤, BTP Cockpit이나 CLI에서 "Crashed" 상태를 마주하는 것은 개발자라면 누구나 한 번쯤 겪는 상황입니다. 이 글에서는 Crashed가 발생하는 가장 빈번한 5가지 원인을 Q&A 형식으로 분석하고, 각각에 대해 즉시 적용 가능한 해결법을 제시합니다.

이 글을 마치면 다음을 할 수 있습니다:

2. 선수 지식

이 튜토리얼을 따라가려면 아래 항목에 대한 기본적인 이해가 필요합니다.

3. 환경 / 버전 / 준비물

항목권장 버전 / 설정
SAP BTPCloud Foundry Environment (Trial 또는 Enterprise)
CF CLIv8 이상 (2024년 기준 v8.8+)
RuntimeNode.js 18/20 LTS, Java 17, Python 3.11 등
BuildpackSAP 제공 또는 Cloud Foundry community buildpack
BTP Cockpit 접근Subaccount > Cloud Foundry > Spaces 접근 권한

CF CLI가 설치되어 있지 않다면 brew install cloudfoundry/tap/cf-cli@8(macOS) 또는 SAP Development Tools에서 다운로드할 수 있습니다. cf version으로 설치 여부를 확인하세요.

4. 핵심 개념 — Cloud Foundry 앱 생명주기와 Crashed 상태

Cloud Foundry에서 애플리케이션은 다음과 같은 생명주기를 거칩니다.

Staging (소스 코드 + buildpack = droplet 생성) → Starting (컨테이너 할당, 프로세스 시작) → Running (헬스체크 통과, 트래픽 수신)

"Crashed"는 Starting 또는 Running 단계에서 프로세스가 비정상 종료(exit code != 0)되거나, 헬스체크에 지정 시간 내 응답하지 못했을 때 부여되는 상태입니다. Cloud Foundry 컨트롤러는 자동으로 재시작을 시도하지만, 근본 원인이 해결되지 않으면 CrashLoopBackOff와 유사한 반복 실패에 빠집니다.

비유하자면, cf push는 택배를 보내는 행위이고, Staging은 포장 과정, Starting은 배송 출발입니다. Crashed는 배송지 주소가 잘못되었거나, 포장이 터져서 반송된 상태에 해당합니다. 반송 사유(로그)를 확인하지 않고 같은 택배를 다시 보내봤자 동일한 결과를 얻게 됩니다.

Crashed 원인을 파악하는 가장 기본적인 도구는 두 가지입니다:

이 두 명령을 먼저 실행하는 것이 모든 트러블슈팅의 출발점입니다.

5. 실전 Q&A — Crashed 원인 5가지와 해결법

Q1. 메모리 초과(Out of Memory)로 Crashed가 발생합니다

증상: cf eventsindex: 0, reason: CRASHED, cell_id: ..., instance: ..., exit_description: out of memory 메시지가 표시됩니다. 앱이 시작 직후 또는 부하가 걸릴 때 반복적으로 죽습니다.

원인: manifest.yml에 설정된 메모리 한도가 앱 실제 사용량보다 낮을 때 Cloud Foundry의 컨테이너 cgroup이 프로세스를 강제 종료(OOMKill)합니다. Java 앱의 경우 JVM 힙 + 메타스페이스 + 스레드 스택이 합산되므로 특히 주의가 필요합니다.

해결법:

# manifest.yml — 메모리 설정 예시
applications:
- name: my-srv-app
  memory: 512M        # Trial 기본 256M은 Java에서 거의 항상 부족
  disk_quota: 1G
  instances: 1
  buildpacks:
    - java_buildpack
  env:
    JBP_CONFIG_OPEN_JDK_JRE: '{ jre: { version: 17.+ }, memory_calculator: { stack_threads: 100 } }'
    JAVA_OPTS: '-Xmx384m -Xms256m'

Q2. 서비스 바인딩 오류로 앱이 시작되지 않습니다

증상: 로그에 VCAP_SERVICES 파싱 실패 또는 데이터베이스 연결 거부(Connection refused) 메시지가 나타납니다. 앱이 기동 중 예외를 던지며 종료됩니다.

원인: manifest.ymlservices 섹션에 선언한 서비스 인스턴스 이름이 실제 CF Space에 존재하지 않거나, 바인딩이 완료되지 않은 상태에서 앱이 해당 서비스 크리덴셜을 참조하려 할 때 발생합니다.

해결법:

REM CF CLI로 서비스 바인딩 상태 점검하기

cf services
REM 현재 Space의 서비스 인스턴스 목록 확인

cf env my-srv-app
REM VCAP_SERVICES 환경변수에 바인딩된 서비스 크리덴셜 확인

cf bind-service my-srv-app my-hana-hdi
REM 수동으로 서비스 바인딩 (manifest.yml에 누락된 경우)

cf restage my-srv-app
REM 바인딩 후 반드시 restage 필요

Q3. 포트 설정 문제로 헬스체크가 실패합니다

증상: 로그에 특별한 에러가 없는데도 앱이 약 60초 후 Crashed 상태로 전환됩니다. cf eventsfailed to accept connections within health check timeout 메시지가 표시됩니다.

원인: Cloud Foundry는 앱이 PORT 환경변수(일반적으로 8080)에 바인딩된 포트에서 TCP 연결을 수락하기를 기대합니다. 앱이 하드코딩된 다른 포트(예: 3000, 4004)로 리스닝하면 헬스체크가 실패합니다.

해결법:

# manifest.yml — 헬스체크 설정
applications:
- name: my-srv-app
  memory: 512M
  health-check-type: http          # port(기본값) 대신 http 사용 가능
  health-check-http-endpoint: /    # HTTP 헬스체크 시 엔드포인트 지정
  timeout: 180                     # 기동이 느린 앱은 타임아웃을 늘림 (기본 60초)
  env:
    PORT: 8080
  services:
    - my-xsuaa
    - my-hana-hdi

특히 Java 앱은 Spring Context 초기화에 시간이 걸리므로 timeout을 120~180초로 설정하는 것이 일반적입니다.

Q4. 환경변수 누락으로 런타임 에러가 발생합니다

증상: 로그에 undefined, null reference, 또는 특정 설정값을 찾지 못한다는 에러가 나타나며 앱이 시작 직후 종료됩니다.

원인: 애플리케이션이 process.env.API_KEY, System.getenv("DESTINATION_NAME") 등으로 환경변수를 참조하지만, 해당 값이 manifest.ymlenv: 섹션이나 cf set-env로 설정되어 있지 않은 경우입니다. 로컬 개발 환경의 .env 파일이나 default-env.json에만 값이 있고, CF 환경에는 누락된 것이 전형적인 패턴입니다.

해결법:

Q5. Buildpack 감지 실패 또는 호환성 문제가 있습니다

증상: Staging 단계에서 None of the buildpacks detected a compatible application 에러가 발생하거나, Staging은 성공했지만 런타임에서 의존성 관련 에러로 Crashed됩니다.

원인: buildpack을 지정하지 않으면 Cloud Foundry가 자동 감지를 시도하는데, 프로젝트 구조가 표준과 다르거나 루트에 필요한 파일(package.json, pom.xml 등)이 없으면 감지에 실패합니다. 또한 SAP BTP에서 제공하는 buildpack 버전과 런타임 버전 간 호환성 문제도 빈번합니다.

해결법:

# manifest.yml — buildpack 명시 지정
applications:
- name: my-node-app
  buildpacks:
    - nodejs_buildpack        # Node.js
  # 또는
  # buildpacks:
  #   - java_buildpack        # Java / Spring Boot
  #   - sap_java_buildpack    # SAP Java Buildpack (SAP BTP 전용)
  #   - staticfile_buildpack  # HTML5 정적 파일
  #   - python_buildpack      # Python

6. 흔한 실수 / 트러블슈팅

FAQ 1: cf push는 성공이라고 나오는데 앱이 Crashed입니다. 왜 그렇습니까?

cf push의 "성공"은 Staging(droplet 생성)까지의 성공을 의미할 수 있습니다. Starting 단계에서의 실패는 별도로 확인해야 합니다. cf push 직후 cf app APP_NAME으로 상태를 반드시 확인하고, Crashed라면 cf logs APP_NAME --recent를 즉시 실행하세요.

FAQ 2: Trial 계정에서 메모리 한도를 늘릴 수 없습니다. 어떻게 해야 합니까?

SAP BTP Trial은 일반적으로 Space당 총 메모리가 제한됩니다(2024~2025년 기준 약 4GB). 실행 중인 다른 앱을 cf stop으로 중지하거나, 불필요한 앱을 cf delete하여 메모리를 확보하세요. cf org-usage 또는 BTP Cockpit에서 현재 메모리 사용량을 확인할 수 있습니다.

FAQ 3: cf logs에 아무것도 나오지 않습니다.

앱이 Staging 단계에서 실패한 경우 런타임 로그가 남지 않습니다. cf push 명령의 터미널 출력 자체를 확인하세요. 또한 --recent 플래그 없이 cf logs APP_NAME을 실행하면 실시간 스트리밍 모드가 되므로, 다른 터미널에서 cf restart APP_NAME을 실행하며 동시에 로그를 관찰하는 방법이 효과적입니다.

FAQ 4: cf restagecf restart의 차이가 무엇입니까?

cf restart는 기존 droplet(빌드 결과물)을 그대로 사용하여 컨테이너만 재시작합니다. cf restage는 소스부터 다시 빌드(Staging)하여 새 droplet을 생성합니다. 환경변수 변경이나 서비스 바인딩 변경 후에는 cf restage가 필요합니다.

7. 다음 단계 / 관련 주제

8. 참고 자료