개요와 이 글에서 얻게 될 것
CAP(SAP Cloud Application Programming Model) 프로젝트를 로컬에서 cds watch로 개발하다가 BTP HANA Cloud로 전환하는 순간 대다수 개발자가 "connection refused" 혹은 "no such table" 오류에 직면합니다. 원인은 대부분 한 가지, 바로 cds deploy --to hana 단계 누락입니다. 이 글은 개발자가 SQLite로 만든 스키마를 HANA Cloud의 HDI 컨테이너로 배포하는 3단계 흐름을 실전 코드와 함께 정리합니다.
- CAP 프로젝트가 HANA Cloud에 접근하는 내부 매커니즘 이해
cds deploy --to hana가 생성하는 hdbtable/hdbview 아티팩트 구조 파악- BTP Cloud Foundry에서 HDI 컨테이너 바인딩 실전 수행
- SalesOrder/PurchaseOrder 시나리오로 전체 배포 파이프라인 재현
- 흔한 배포 실패 원인 3가지와 진단 명령어 습득
이 글을 이해하려면 알고 있으면 좋은 것
Node.js 16 이상 환경과 npm 사용 경험, CAP 프로젝트 초기화(cds init) 경험, CDS 스키마 정의 문법(entity, association) 기초 지식이 필요합니다. 또한 BTP Cockpit에서 서브계정/스페이스 개념을 이해하고 있어야 하며, Cloud Foundry CLI(cf) 명령어를 한 번이라도 실행해본 경험이 있으면 흐름을 따라가기 수월합니다. HDI(HANA Deployment Infrastructure)와 스키마 격리 개념도 알아두면 좋습니다.
환경 구성과 사전 준비물
이 글은 다음 환경 기준으로 작성됩니다. 버전이 다를 경우 명령어 옵션이 달라질 수 있으므로 반드시 자신의 환경을 확인하는 것을 권장합니다.
- Node.js 20.x LTS (CAP 8.x 대응)
- @sap/cds-dk 8.2.x 이상 (전역 설치)
- @sap/hana-client 2.20.x
- @cap-js/hana 1.4.x (신규 HANA 어댑터)
- BTP Trial 또는 Enterprise 서브계정에 HANA Cloud 인스턴스 provisioning 완료
- Cloud Foundry CLI 8.x 및
cf login완료 상태 - MTA Build Tool(mbt) 1.2.x (선택, 4단계 확장 시)
npm install -g @sap/cds-dk
cds --version
# @sap/cds-dk: 8.2.1
# @sap/cds-compiler: 5.3.0
cf --version
# cf version 8.7.0+
HANA Cloud 인스턴스는 프로비저닝에 약 15~30분 소요되며, 인스턴스 상태가 RUNNING이어야 이후 단계 진행이 가능합니다. Trial 계정의 경우 하루 8시간 후 자동 중지되므로 실습 전 재시작을 확인하세요.
핵심 개념과 동작 원리
CAP은 개발 단계에서 SQLite 인메모리 DB를 기본값으로 사용합니다. cds watch는 매번 재시작 시 스키마를 새로 만들고 mock 데이터를 로드하기 때문에 개발자는 "그냥 되는 것"에 익숙해집니다. 그러나 HANA Cloud는 영속 DB이며, HDI라는 별도 레이어를 통해서만 스키마를 정의하고 관리할 수 있습니다.
비유하자면 SQLite는 "화이트보드"입니다. 지웠다 다시 쓰면 됩니다. 반면 HANA Cloud + HDI는 "인쇄기와 도장"에 가깝습니다. 스키마를 만들려면 도장(hdbtable 아티팩트)을 파고, 인쇄기(HDI Deployer)에 넣어 찍어야만 실제 테이블이 생성됩니다.
이 인쇄 과정을 자동화해주는 명령어가 바로 cds deploy --to hana입니다. 내부적으로는 다음 세 가지가 순차적으로 일어납니다.
- 컴파일:
db/폴더의.cds파일을gen/db/src/gen/하위의.hdbtable,.hdbview,.hdbindex아티팩트로 변환합니다. - 바인딩 확보:
default-env.json또는 Cloud Foundry에서 바인딩된hana/hdi-shared서비스 인스턴스의 자격증명(credentials)을 읽어옵니다. - HDI Deploy 호출:
@sap/hdi-deploy모듈을 통해 컴파일된 아티팩트를 HDI 컨테이너에 밀어 넣고, HANA에 실제 테이블/뷰를 생성합니다.
여기서 자주 오해되는 점은 cds deploy가 애플리케이션 코드가 아니라 스키마만 배포한다는 것입니다. 즉, 이 명령어를 실행해도 서비스 엔드포인트가 열리지는 않으며, 오직 DB 레이어의 물리적 구조만 생성됩니다. Application Router와 CAP 서비스 배포는 별도 cf push 또는 mbt build + cf deploy가 필요합니다.
1단계 — HANA Cloud 인스턴스와 HDI 컨테이너 준비
가장 먼저 BTP Cloud Foundry 스페이스에 HDI 컨테이너를 만들어야 합니다. SalesOrder와 PurchaseOrder를 관리하는 orderdb 프로젝트를 예시로 사용합니다.
cf login -a https://api.cf.eu10.hana.ondemand.com
cf target -o my_trial -s dev
# 사용 가능한 서비스 확인
cf marketplace -e hana-cloud
cf marketplace -e hana
# HDI 컨테이너 생성 (약 2~3분 소요)
cf create-service hana hdi-shared orderdb-hdi-container
# 상태 확인 (create succeeded 확인 필수)
cf service orderdb-hdi-container
여기서 서비스 플랜 이름이 환경에 따라 hdi-shared 또는 schema로 다를 수 있습니다. Trial 계정에서는 hana-cloud 서비스 대신 hana 서비스에 hdi-shared 플랜을 사용하는 것이 일반적입니다.
다음으로 로컬 CAP 프로젝트를 준비합니다.
// 프로젝트 초기화
// cds init orderdb --add hana
// cd orderdb
// db/schema.cds
namespace com.acme.orders;
using { cuid, managed, Currency } from '@sap/cds/common';
entity SalesOrders : cuid, managed {
orderNumber : String(20) @mandatory;
customerName : String(80);
totalAmount : Decimal(15,2);
currency : Currency;
status : String(20) default 'OPEN';
items : Composition of many SalesOrderItems on items.parent = $self;
}
entity SalesOrderItems : cuid {
parent : Association to SalesOrders;
productCode : String(40);
quantity : Integer;
unitPrice : Decimal(15,2);
}
entity PurchaseOrders : cuid, managed {
poNumber : String(20);
supplier : String(80);
totalAmount : Decimal(15,2);
currency : Currency;
}
2단계 — 프로필과 requires 설정, 로컬 바인딩
CAP은 프로필(--profile) 개념으로 개발/프로덕션 DB를 분리합니다. package.json의 cds 구성에 hana 프로필을 추가하고, 필요 시 .cdsrc.json으로 세분화합니다.
{
"name": "orderdb",
"version": "1.0.0",
"dependencies": {
"@sap/cds": "^8.2.0",
"@cap-js/hana": "^1.4.0",
"express": "^4.19.0"
},
"cds": {
"requires": {
"db": {
"[development]": { "kind": "sqlite", "credentials": { "url": ":memory:" } },
"[production]": { "kind": "hana", "impl": "@cap-js/hana" }
}
},
"hana": {
"deploy-format": "hdbtable"
}
}
}
로컬 개발자 머신에서 원격 HANA Cloud로 직접 배포하려면 서비스 키를 만들어 로컬 환경에 바인딩해야 합니다. cds bind 명령이 이 과정을 크게 단순화합니다.
# 서비스 키 생성 (한 번만)
cf create-service-key orderdb-hdi-container SERVICE_KEY_ORDERDB
# 로컬 프로젝트에 바인딩 정보 저장
cds bind -2 orderdb-hdi-container:SERVICE_KEY_ORDERDB
# 실제 배포 시 이 프로필로 실행
cds env get requires.db --profile hybrid
대안으로 default-env.json을 프로젝트 루트에 두는 전통적 방식도 여전히 유효합니다.
{
"VCAP_SERVICES": {
"hana": [{
"name": "orderdb-hdi-container",
"label": "hana",
"tags": ["hana", "database", "relational"],
"credentials": {
"host": "xxx.hana.prod-eu10.hanacloud.ondemand.com",
"port": "443",
"user": "USER_ORDERDB",
"password": "***",
"schema": "ORDERDB_1",
"hdi_user": "USER_ORDERDB_DT",
"hdi_password": "***"
}
}]
}
}
3단계 — cds deploy 실행과 스키마 검증
준비가 끝났다면 실제 배포 명령을 실행합니다. --to hana 뒤에는 인스턴스 이름을 지정할 수 있고, 생략하면 바인딩된 첫 번째 인스턴스를 사용합니다.
# 컴파일 결과 미리보기 (실제 배포 없이)
cds compile db --to hana --dry > gen-preview.hdbtable
# 실제 배포 (약 30초~2분)
cds deploy --to hana:orderdb-hdi-container --profile hybrid --auto-undeploy
# 상세 로그
DEBUG=deploy cds deploy --to hana
성공 시 다음과 유사한 출력이 나타납니다.
> building db content...
> deploying to HDI container 'ORDERDB_1'...
[hdi-deploy] Making 8 HDI Deployer calls...
[hdi-deploy] MAKE succeeded: 8 files deployed
- COM_ACME_ORDERS_SALESORDERS.hdbtable
- COM_ACME_ORDERS_SALESORDERITEMS.hdbtable
- COM_ACME_ORDERS_PURCHASEORDERS.hdbtable
✓ deployed to hana
배포 결과를 검증하려면 SAP HANA Database Explorer 또는 다음 CLI 스니펫으로 스키마를 조회합니다.
-- HANA Database Explorer의 SQL 콘솔에서 실행
SELECT TABLE_NAME, RECORD_COUNT
FROM SYS.M_TABLES
WHERE SCHEMA_NAME = 'ORDERDB_1'
AND TABLE_NAME LIKE 'COM_ACME_ORDERS%'
ORDER BY TABLE_NAME;
프로덕션 파이프라인에서는 CI/CD에 다음과 같이 통합하는 것이 일반적입니다.
# .github/workflows/deploy-db.yml (발췌)
- name: Install CAP tools
run: npm install -g @sap/cds-dk@8.2
- name: Deploy schema to HANA Cloud
env:
VCAP_SERVICES: ${{ secrets.HANA_VCAP_SERVICES }}
run: |
npm ci
cds deploy --to hana --auto-undeploy --profile production
timeout-minutes: 10
--auto-undeploy 옵션은 CDS 모델에서 제거된 아티팩트를 HDI에서도 자동 삭제하도록 하며, 프로덕션 초기 도입 시에는 데이터 손실 방지를 위해 주의해서 사용하는 것을 권장합니다.
배포 실패 시 진단 체크리스트와 FAQ
Q1. "Error: No service matches hana" 오류가 발생합니다.
바인딩 정보가 CAP 런타임에 전달되지 않았을 때 나타납니다. cds env get requires.db로 실제 로드되는 설정을 확인하고, 프로필을 명시적으로 지정(--profile hybrid)했는지 점검하세요. default-env.json이 .gitignore에 있어야 하지만 로컬에는 존재해야 합니다.
Q2. "HDI make failed: insufficient privilege" 권한 오류.
HDI 컨테이너의 hdi_user(design-time 사용자)가 아니라 user(runtime 사용자) 자격으로 배포를 시도할 때 발생합니다. 서비스 키를 재발급하고 credentials.hdi_user가 실제로 존재하는지 확인하세요. 또한 다른 개발자가 동시에 같은 컨테이너에 배포 중이면 lock 충돌이 발생할 수 있습니다.
Q3. 배포는 성공했는데 애플리케이션에서 "table not found"가 뜹니다.
스키마 접두어 문제일 가능성이 큽니다. CAP의 네이밍 규칙은 namespace.Entity → NAMESPACE_ENTITY로 변환하며, 코드에서 SELECT.from('com.acme.orders.SalesOrders')가 아니라 raw SQL로 접근한다면 "COM_ACME_ORDERS_SALESORDERS"처럼 대문자와 언더스코어를 정확히 맞춰야 합니다.
추가로 자주 놓치는 지점을 정리합니다.
@cap-js/hana가 아니라 구형hana-client만 설치한 경우 CAP 8.x에서 연결 실패- Trial HANA Cloud 인스턴스가 중지 상태(stopped)일 때 배포 시 timeout
- 회사 프록시 환경에서
HTTPS_PROXY미설정으로 HDI Deployer가 HANA에 도달 못함 db/data/*.csv초기 데이터가 있을 때 헤더 컬럼명이 CDS 필드와 정확히 일치하지 않으면 데이터만 실패하고 스키마는 성공
이후 확장할 만한 주제
스키마 배포까지 마쳤다면 다음은 CAP 서비스 자체의 클라우드 배포입니다. cds add mta로 MTA descriptor를 생성해 mbt build && cf deploy 파이프라인으로 전환하면 App Router, XSUAA, HDI를 한 번에 관리할 수 있습니다. 또한 프로덕션 성능 튜닝 관점에서 HANA 전용 기능(Calculation View, Fuzzy Search)을 CDS에서 어떻게 노출하는지 학습하는 것을 권장합니다. 대용량 데이터가 있다면 hdbtabledata 아티팩트로 초기 데이터를 전달하는 방식도 살펴볼 가치가 있습니다.
추가로 볼만한 링크
- CAP Docs — Using SAP HANA Cloud
- CAP Docs — Deploy to Cloud Foundry
- SAP Help — SAP HANA Cloud 공식 문서
- SAP Help — HANA Cloud Administration Guide
- SAP Help — BTP Cloud Foundry Environment
댓글 0
아직 댓글이 없습니다.