はじめに
この記事では、CAP (Java) のアプリケーションでBTPのPostgreSQLをデータベースとして使用する方法について紹介します。
過去の記事でコミュニティ開発のモジュールであるcds-pg
およびcds-dbm
を使用した方法を紹介しましたが、cds 7.xから@cap-js/postgresが登場してPostgreSQLの使用が公式にサポートされるようになりました。これにともない、cds-pg
とcds-dbm
はdeprecatedとなっています。
関連ブログ
- Run and Deploy SAP CAP (Node.js or Java) with PostgreSQL on SAP BTP Cloud Foundry
- Run and Deploy SAP CAP (Java) with PostgreSQL using Official Database Adapter @cap-js/postgres
実施すること
- ローカル実行にはインメモリデータベース(H2)を使用する
- Cloud FoundryではPostreSQLを使用する
※ハイブリッド実行でPostgreSQLに接続できないか試してみましたが、うまくいきませんでした(「ハイブリッド実行で試したこと」を参照)。
バージョン
@sap/cds: 8.6.1
@sap/cds-dk: 8.4.2
開発環境
SAP Business Application Studio
ステップ
- プロジェクトの作成
- サンプルサービスの設定
- PostgreSQLを追加
- デプロイのための設定
- ビルド、デプロイ
- 動作確認
1. プロジェクトの作成
CAP (Java) のプロジェクトを作成します。
cds init cap-java-postgresql --add java
2. サンプルサービスの設定
サンプルサービスを追加します。
cds add tiny-sample
以下のコマンドでサービスを実行します。
mvn spring-boot:run
3. PostgreSQLを追加
以下のコマンドでPostgreSQLのための設定を追加します。
cds add postgres
この結果、以下の設定が追加されます。
<dependency>
<groupId>com.sap.cds</groupId>
<artifactId>cds-feature-postgresql</artifactId>
<scope>runtime</scope>
</dependency>
"dependencies": {
"@cap-js/postgres": "^1"
}
---
spring:
datasource:
password: postgres
embedded-database-connection: none
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/postgres
username: postgres
config:
activate:
on-profile: default
application.yamlの設定を元に戻す
application.yaml
がローカル実行時もローカルのPostgreSQLに接続する設定に変更されたので、このままmvn spring-boot:run
を実行するとDBに接続できずにエラーになります。ローカル実行時にはこれまで通りH2データベースに接続するため、デフォルトのプロファイルを元に戻します。
application.yaml
の全体は以下のようになります。
---
spring:
config.activate.on-profile: default
sql.init.schema-locations: classpath:schema-h2.sql
cds:
data-source.auto-config.enabled: false
4. デプロイのための設定
mta.yamlを追加します。
cds add mta
mta.yamlファイルを開き、サービスのproperties
に以下の設定を追加します。<POSTGRESQL_SERVICE_NAME>
には、PostgreSQLのサービス名(mta.yamlのresourcesセクション参照)を設定します。
CFENV_SERVICE_<POSTGRESQL_SERVICE_NAME>_ENABLED: false
設定の意味
デフォルトではjava_buildpack
がPostgreSQLデータソースを初期化します。CAPで動かすためにはPostreSQLのデータソースはCAP Javaランタイムが作成する必要があるため、ビルドパックによるデータソースの初期化を無効化しています。(参考:Provisioning a DB Instance)
以下は設定例です。
modules:
- name: cap-java-postgresql2-srv
type: java
path: srv
parameters:
buildpack: sap_java_buildpack_jakarta
readiness-health-check-type: http
readiness-health-check-http-endpoint: /actuator/health/readiness
properties:
SPRING_PROFILES_ACTIVE: cloud,sandbox
JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']"
JBP_CONFIG_SAP_MACHINE_JRE: '{ version: 21.+ }'
CFENV_SERVICE_CAP-JAVA-POSTGRESQL-POSTGRES_ENABLED: false #追加
ビルドの設定
postgresqlのデプロイヤーはgen/pg
フォルダ配下にあるビルド結果を使用しますが、生成されたmta.yamlにはビルドのためのコマンドがありません。そこで、mta.yamlの先頭に以下の設定を追加します。cds build --production
コマンドによりgen/pg
フォルダが生成されます。
build-parameters:
before-all:
- builder: custom
commands:
- npx cds build --production
先頭部分は全体で以下のようになります。
_schema-version: 3.3.0
ID: cap-java-postgresql2
version: 1.0.0-SNAPSHOT
description: "A simple CAP project."
parameters:
enable-parallel-deployments: true
build-parameters:
before-all:
- builder: custom
commands:
- npx cds build --production
application.yamlの設定
デプロイしたサービスからPostgreSQLに接続できるよう、application.yamlに以下の設定を追加します。(参考:Run and Deploy SAP CAP (Java) with PostgreSQL using Official Database Adapter @cap-js/postgres)
---
spring:
config.activate.on-profile: cloud
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://${vcap.services.<POSTGRESQL_SERVICE_NAME>.credentials.hostname}:${vcap.services.<POSTGRESQL_SERVICE_NAME>.credentials.port}/${vcap.services.<POSTGRESQL_SERVICE_NAME>.credentials.dbname}
username: ${vcap.services.<POSTGRESQL_SERVICE_NAME>.credentials.username}
password: ${vcap.services.<POSTGRESQL_SERVICE_NAME>.credentials.password}
---
spring:
config.activate.on-profile: cloud
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://${vcap.services.cap-java-postgresql-postgres.credentials.hostname}:${vcap.services.cap-java-postgresql-postgres.credentials.port}/${vcap.services.cap-java-postgresql-postgres.credentials.dbname}
username: ${vcap.services.cap-java-postgresql-postgres.credentials.username}
password: ${vcap.services.cap-java-postgresql-postgres.credentials.password}
※ドキュメントには記載がなかったのですが、この設定がないとBooksエンティティを照会しようとしたときに以下のエラーが返されました。
{
"error": {
"code": "50003009",
"message": "Failed to start a new transaction"
}
}
postgresql-dbサービスプランを変更(トライアルアカウントの場合)
resources
セクションに追加されたpostgresql-dbサービスには、デフォルトではdevelopment
プランが設定されています。トライアルアカウントを使用している場合はサービスプランをtrial
に変更します。
resources:
- name: cap-java-postgresql2-postgres
type: org.cloudfoundry.managed-service
parameters:
service: postgresql-db
service-plan: development
トライアルアカウントの場合、作成できるサービスインスタンスは1つまでです。
5. ビルド、デプロイ
以下のコマンドでビルド、デプロイします。
mbt build -t gen --mtar mta.tar
cf deploy gen/mta.tar
6. 動作確認
デプロイされたサービスにアクセスし、データが取得できることを確認します。
ハイブリッド実行で試したこと
BASからBTPのPostgreSQLに接続しようと以下のことを行いましたが、接続できませんでした。
- PostgreSQLのインスタンスをバインド
cds bind db --to cap-java-postgresql-postgres
-
application.yaml
にハイブリッド用の設定を追加
---
spring:
config.activate.on-profile: hybrid
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://${vcap.services.cap-java-postgresql-postgres.credentials.hostname}:${vcap.services.cap-java-postgresql-postgres.credentials.port}/${vcap.services.cap-java-postgresql-postgres.credentials.dbname}
username: ${vcap.services.cap-java-postgresql-postgres.credentials.username}
password: ${vcap.services.cap-java-postgresql-postgres.credentials.password}
- ハイブリッドモードで実行
cds bind --exec -- mvn spring-boot:run \
-Dspring-boot.run.profiles=default,hybrid
結果、"vcap.services.cap-java-postgresql.credentials.hostname
が見つからない"というエラーになりました。
java.lang.IllegalArgumentException: Could not resolve placeholder 'vcap.services.cap-java-postgresql.credentials.hostname' in value "jdbc:postgresql://${vcap.services.cap-java-postgresql.credentials.hostname}...
以下のコマンドで、環境変数VCAP_SERVICES
がBTP環境と同じように設定されていることを確認しました。
cds bind --exec -- node -e 'console.log(process.env.VCAP_SERVICES)'