目次
Koupleless 概要
Koupleless はモジュール型の Serverless 技術ソリューションで、通常のアプリケーションを比較的低いコストで Serverless 開発モデルへ移行できます。コードとリソースを疎結合にして独立に保守しやすくし、秒単位のビルド・デプロイ、統合デプロイ、動的スケーリングにも対応します。これにより、優れた開発・運用体験を提供できます。
適用シーン
- アプリのビルド・リリースが遅い、SDK の更新が煩雑:従来のアプリケーションではビルドとリリースに 6-10 分かかり、Koupleless なら 10 秒級に短縮できます
- ロングテールなアプリケーションでリソースが無駄になる:企業では 80% のアプリケーションの CPU 使用率が 10% 未満であり、統合デプロイによりリソースコストを大幅に削減できます
- 開発・共同作業の効率が低い:複数人で 1 つのアプリケーションを開発する場合、リリース时机をそろえる必要があります。Koupleless ならモジュールを個別に更新できます
- ミドルプラットフォームのアプリケーションで業務資産を蓄積しにくい:ベースで共通機能を蓄積し、モジュールで具体的な業務ロジックを実装できます
- マイクロサービスへの移行コストが高い:アプリケーションをモノリolith、モジュール型、マイクロサービス型のアーキテクチャ間でスムーズに移行できます
統合デプロイの概要
統合デプロイとは
統合デプロイとは、独立した複数のアプリケーション(Koupleless では「モジュール」と呼びます)を同じ JVM プロセスにデプロイし、ベースのリソースと依存関係を共有しながら、コードと実行時の分離を維持する方式です。
統合デプロイの利点
- リソース削減:複数モジュールがベース的记忆領域(Metaspace と Heap)を共有し、CPU 使用率も効率よく引き上げます
- 起動の迅速化:モジュールのビルド成果物を数百 MB から数十 MB に小型化し、起動時間を大幅に短縮します
- 運用の簡素化:複数モジュールをまとめて管理でき、保守コストを削減します
- 柔軟な拡張:モジュールを動的に追加・削除でき、ベースの再起動は不要です
アーキテクチャの原理
Koupleless は SOFAArk フレームワークを基盤に、クラス分離と統合デプロイを実現しています。
- ベース(Base):SpringBoot フレームワーク、ミドルウェア SDK などの共通依存関係と基礎機能を提供します
- モジュール(Biz):業務機能のモジュールです。ベースが提供する共通機能に依存します
- クラスローディング方式:モジュールはまず自身の ClassLoader でクラスを探し、見つからない場合はベースの ClassLoader に委譲します
環境準備
前提条件
- JDK 8 以上
- Maven 3.6+
- SpringBoot 2.x または 3.x
- 利用可能な IDE(IntelliJ IDEA、Eclipse など)
バージョンの選択
現在の Koupleless の主なバージョンは次のとおりです。
<koupleless.runtime.version>0.5.6</koupleless.runtime.version>
<sofa.ark.version>2.2.14</sofa.ark.version>
ツールの準備
Arkctl ツール(モジュールデプロイ用)をダウンロードします。
ベースの改修
1. 依存関係を追加
ベースの pom.xml に Koupleless のベース依存関係を追加します。
2. アプリケーション名を設定
application.properties または application.yml でアプリケーション名を設定します。
# application.properties
spring.application.name=base-application
3. ベースのビルドプラグインを設定
pom.xml の build セクションにベースのビルドプラグインを追加します。
4. 依存関係用 Starter を生成
次のコマンドを実行して、ベースの依存関係用 Starter を生成します。
mvn com.alipay.sofa.koupleless:koupleless-base-build-plugin::packageDependency -f pom.xml
このコマンドは ${baseAppName}-dependencies-starter という依存関係パッケージを生成します。モジュールプロジェクトではこれを parent として指定することで、ベースのすべての依存関係を継承できます。
5. ベースを起動
上記の設定が完了したら、IDE またはコマンドラインから直接ベースを起動できます。
mvn spring-boot:run
モジュールの改修
1. モジュールプロジェクトを作成
モジュールは既存の SpringBoot アプリケーションでも、新しく作成したプロジェクトでも構いません。複数のモジュールを管理するには、Maven のマルチモジュール構成を使うことをおすすめします。
2. モジュールの依存関係を設定
モジュールの pom.xml にモジュールの依存関係とパッケージングプラグインを追加します。
3. パッケージングプラグインを設定
モジュールの pom.xml に SOFAArk パッケージングプラグインを追加します。
4. モジュールの小型化を設定
自動除外設定ファイル rules.txt をダウンロードし、モジュールの conf/ark/ ディレクトリに配置します。
rules.txt の内容は次のようになります。
5. モジュールコードを開発
たとえば、次のような REST Controller を作成してモジュールの機能を実装します。
6. アプリケーション名を設定
モジュールの application.properties でアプリケーション名を設定します。
spring.application.name=module1
モジュールの小型化
なぜモジュールを小型化するのか
モジュールの小型化には次の利点があります。
- モジュールパッケージのサイズを削減:数百 MB から数十 MB に縮小できます
- メモリ使用量を削減:Metaspace の使用量を抑え、ベースにより多くのモジュールを導入できます
- 起動速度を向上:モジュールの起動時間を数分級から秒級に短縮できます
- デプロイ効率を向上:小さなパッケージは転送もデプロイも容易です
小型化の原理
モジュール小型化の中心となる考え方は次のとおりです。モジュールとベースが重複する依存関係を取り除き、モジュールがベースのクラスを再利用できるようにする
次の方法で実現します。
- ベースの依存関係 Starter を継承:モジュールで
${baseAppName}-dependencies-starterを parent に指定します - 依存関係を自動除外:
rules.txt設定ファイルで不要な依存関係を除外します - 依存関係を委譲:モジュールの依存関係を
providedスコープに設定し、ロードをベースへ委譲します
設定方法
方法1:ベースの依存関係 Starter を継承(推奨)
モジュールの pom.xml に次の設定を追加します。
これにより、モジュールはベースのすべての依存関係を自動的に継承し、バージョンを手動で設定する必要がなくなります。
方法2:依存関係のスコープを手動設定
モジュールの pom.xml で、ベースが既に持っている依存関係を provided スコープに設定します。
方法3:除外設定を利用
sofa-ark-maven-plugin に除外項目を設定します。
小型化の効果を確認
モジュールをビルドし、パッケージサイズを確認します。
結果可以看到、スライミング後の ark-biz.jar は 180M から 15M に減少しており、効果が大きことが分かります。
デプロイと検証
1. ベースを起動
まずベースアプリケーションを起動します。
cd base-application
mvn spring-boot:run
または、IDE からメインクラスを起動します。
2. モジュールをビルド
モジュールプロジェクトでビルドを実行します。
cd module1
mvn clean package
ビルドが成功すると、2 つの jar パッケージが生成されます。
module1-1.0.0.jar:通常の SpringBoot fat jar で、単独実行できますmodule1-1.0.0-ark-biz.jar:統合デプロイ用の Koupleless モジュールパッケージです
3. Arkctl でモジュールをデプロイ
Arkctl ツールを使ってモジュールをベースへデプロイします。
4. デプロイを検証
デプロイが成功したら、次の方法で検証できます。
モジュールの状態を確認
arkctl status
出力例です。
Biz count: 1
bizName: module1
bizVersion: 1.0.0
bizState: ACTIVATED
mainClass: com.example.module1.Module1Application
webContextPath: /module1
モジュールの API にアクセス
# 访问模块1的接口
curl http://localhost:8080/module1/
# 输出: hello to module1 deploy
curl http://localhost:8080/module1/health
# 输出: OK
ログを確認
ベースコンソールでモジュールの起動ログを確認できます。
[INFO] Install biz: module1, version: 1.0.0, state: ACTIVATED
[INFO] Module module1 started successfully
5. 複数モジュールをデプロイ
同じ手順を繰り返して module2 をデプロイします。
cd module2
mvn clean package
arkctl deploy target/module2-1.0.0-ark-biz.jar
複数モジュールのデプロイを検証します。
# 查看所有模块
arkctl status
# 访问不同模块
curl http://localhost:8080/module1/
curl http://localhost:8080/module2/
6. モジュールをアンインストール
よくある質問と解決策
1. クラス競合の問題
問題:モジュールとベースに同名のクラスがあり、クラス競合が発生します。
解決策:
- クラス分離机制を利用し、モジュールが自分のクラスを優先して読み込むようにします
- 共通クラスをベースへ移し、モジュールは依存関係の委譲によって再利用します
- モジュールとベースで同じパッケージ名・クラス名のクラスを定義しないようにします
2. 静的フィールドを共有する問題
問題:複数モジュールが静的フィールドを共有し、データが混在します。
解決策:
StaticFieldMapWrapper を使って静的フィールドをラップします。
3. Dubbo の互換性問題
問題:モジュール内で Dubbo のジェネリック呼び出しを使用すると問題が発生します。
解決策:
- Dubbo 関連の依存関係がベースにあることを確認します
- Dubbo に適切な ClassLoader 切り替えを設定します
- 公式 adapter リポジトリの解決策を参照します
4. Nacos のスレッド数が多い問題
問題:各モジュールの起動時に Nacos クライアントが作成され、スレッド数が多くなります。
解決策:
ベース内で Nacos クライアントをキャッシュします。
5. モジュールの起動順序の問題
問題:モジュール間に依存関係があり、順番대로起動する必要があります。
解決策:
- ベースでモジュールの起動順序を設定します
- 依存関係を使って起動順序を制御します
- 循環依存を避けます
6. メモリリーク
問題:モジュールをアンロードした後もメモリが解放されず、Metaspace が増え続けます。
解決策:
- モジュールをアンロードする際に、スレッドプールや接続などすべてのリソースを解放するようにします
- キャッシュの管理に弱参照を使います
- 定期的にベースを再起動するか、メモリを整理します
7. Spring コンテキストの競合
問題:モジュールとベースの Spring Bean が競合します。
解決策:
- 異なる Bean 名を使います
- モジュール内で
@Primaryアノテーションを使って優先順位を明示します - モジュールとベースで同じ Bean を定義しないようにします ---
本番環境へのデプロイ
1. デプロイアーキテクチャ
本番環境で推奨するデプロイ構成です。
2. K8s のデプロイ設定
ベースの Deployment
モジュールのリリースパイプライン
3. モジュールの動的デプロイ
方式1:OSS 監視モード
ベースが OSS ディレクトリの変更を監視し、新しいモジュールを自動的にデプロイします。
方式2:設定センターモード
設定センターでモジュールのデプロイを制御します。
ベースが設定変更を監視します。
最後に、チュートリアルでは詳しく 다루らなかった次の 2 点をまとめて説明します。
- 静的統合デプロイ(Static Packaged Deployment)――ベースと N 個のモジュールを一度に実行可能な Fat Jar へパッケージし、起動と同時に全モジュールを利用可能にします。
- ポート分離――各モジュールが実際に独自のポートをリッスンし、1 プロセス内で複数 WebServer を実現します。
------------------------------------------------
方式3:静的統合デプロイ(Static Packaged Deployment)
適用シーン
- リリースフローを極限まで簡略化し、運用担当者に arkctl deploy を実行させない場合。
- コンテナイメージで起動するプロセスが 1 つだけで、K8s の liveness/readiness プローブからベースを直接調べればよい場合。
- モジュールバージョンが固定で、ホットアンロードやホットロードが不要な場合。
パッケージングの考え方
ベースの pom で各モジュールの ark-biz.jar をリソースとして BOOT-INF/lib ディレクトリに一緒に含めます。
ベース起動時に SOFAArk の「static-biz」機構借助し、これらの ark-biz.jar をベースのライフサイクルに合わせて install と start で導入します。実践手順
ステップ1:モジュール側で通常どおりmvn packageを実行し、moduleX-1.0.0-ark-biz.jar を取得します。
ステップ2:ベースの pom に profile を追加します(静的パッケージを作成する-business場合のみ有効化)。
ステップ3:ベースの起動クラスに @StaticBiz アノテーション(0.5.6 以降)を追加し、SOFAArk に classpath 配下のすべての ark-biz.jar を静的にインストールするよう指示します。
ステップ4:静的パッケージを作成します。
mvn clean package -Pstatic-pack
生成される base-application-1.0.0-exec.jar には、module1-ark-biz.jar と module2-ark-biz.jar が同時に含まれます。java -jar base-application-1.0.0-exec.jar で起動すると、arkctl status で 2 つのモジュールがすでに ACTIVATED になっていることが確認でき、deploy の再実行は不要です。
モジュールが独自のポートをリッスンするようにする
既定の動作
- 全モジュールが同じ組み込み Tomcat(ポート 8080)を共有し、webContextPath だけで区別します。
- 利点:スレッドとメモリを節約できます。
- 欠点:「ポート単位」の分離ができず、「モジュール単位の管理エンドポイント」も用意できません。
Koupleless 0.5.6 から「複数 WebServer モード」がサポートされ、各モジュールが独立した Netty や Tomcat を起動し、それぞれのポートに実際に bind できるようになりました。
- モジュール側に依存関係を追加
- ポートとコンテキストを設定
# module1/application.yml
server:
port: 8081 # 模块独占
servlet:
context-path: / # 可以为 /
spring:
application:
name: module1
- パッケージングプラグインを宣言
- デプロイを検証
ベースは引き続き 8080 を使い、module1 は 8081 もリッスンします。module2 にはさらに 8082 を設定でき、互いに干渉しません。curl http://localhost:8081/を実行すると直接モジュール 1 のレスポンスが返り、プレフィックスは不要です。
注意
- ポートが n 個多く必要になり、メモリやスレッドも相应的に増えるため、用途に応じてトレードオフを検討してください。
- 本番環境では、K8s Service に 8081、8082… も宣言するか、Istio のマルチポート機能を利用してください。
参考資料
- 公式ドキュメント:https://koupleless.io/docs/
- GitHub リポジトリ:https://github.com/koupleless/koupleless
- サンプルコード:https://github.com/koupleless/samples
- コミュニティサポート:https://github.com/koupleless/koupleless/issues