クラウド・ネイティブ Java アプリケーション用の Liberty InstantOn 始動
この記事は、Liberty InstantOnがまだベータ版だったときに公開されました。Liberty InstantOnは、Liberty 23.0.0.6リリースの時点でベータ版から移行しました。Liberty InstantOnに関する最新情報は、Open LibertyドキュメントのOpen Liberty InstantOnによるコンテナ型アプリケーションの高速起動を参照してください。
ほんの数ミリ秒で起動するクラウドネイティブ Java アプリケーションがあったらいいな、と思いませんか? それも、スループット、メモリ、環境設定、Javaの機能などの妥協をせずに実現できたら。Open Liberty 22.0.0.11-beta は、MicroProfile および Jakarta EE アプリケーションの起動時間を高速化するエキサイティングな新機能 InstantOn を提供します!
サーバーレス環境では、アプリケーションの起動時間が重要です。アプリケーションが使用されていない場合、InstantOnアプリケーションのインスタンスはゼロになります。進行中のリクエストがないときにアプリケーションのインスタンスの総数を減らすことで、デプロイされたアプリケーションの全体的なクラウド・コストを削減できます。アプリケーションの活動が回復すると、ユーザーを待たせることなく、新しいインスタンスをすばやく起動できます。
Open Liberty が InstantOn 始動を可能にする方法
InstantOnを有効にするためには、Open Libertyは、OpenJ9 JVM とLinux テクノロジーの、「チェックポイント/リストア イン ユーザースペース」(Checkpoint/Restore In Userspace)または、CRIU を使用して、アプリケーション開始時に、プロセスのチェックポイントを取得します。このチェックポイントは、実行中のアプリケーション プロセスのスナップショットであり、永続化してすぐに復元し、アプリケーション プロセスをチェックポイント取得時の状態に戻すことができます。このプロセスにより、Liberty インスタンスを、構成済みのアプリケーションとともに、アプリケーションの別個のインスタンスに複数回、復元できます。
InstantOn の起動速度を確認するには、「どのくらい速い?」セクションに進んでください。このアプローチの利点の詳細については、https://blog.openj9.org/2022/09/26/fast-jvm-startup-with-openj9-criu-support/[Fast JVM startup with OpenJ9 CRIU Support] と、Open Libertyのこのブログを参照してください。Java アプリケーションの起動を高速化するための CRIU の可能性について、最初に説明したものです。
Open Liberty InstantOn 機能は、既存のOpen Liberty サーバー構成に対して実行できる新しい「チェックポイント」アクションを提供するので、簡単に試していただくことができます。checkpoint
アクションでは、Liberty 始動プロセスを停止してチェックポイントを保存するフェーズを指定します。Liberty が起動されると、保存されたチェックポイント プロセスが検出され、checkpoint
アクション中に保存された状態からプロセスが再開されます。
サンプル アプリケーション プロジェクトをセットアップする
checkpoint
アクションがどのように機能するかの詳細に入る前に、実際のサンプルアプリケーションで動作を見てみましょう。この例では、Open Liberty の開始 ガイドを参照します。先に進みたい場合は、このガイドのGit リポジトリ をクローンすることから始め、このガイドの中で提供されているプロジェクトを使用します。
git clone https://github.com/openliberty/guide-getting-started.git
cd guide-getting-started
このデモでは、finish/
ディレクトリ内で作業します。アプリケーションを試すには、次の Maven ゴールを実行してアプリケーションをビルドし、Open Liberty にデプロイします。
cd finish
mvn liberty:run
次のメッセージが表示されたら、アプリケーション サーバーの準備は完了です。
The defaultServer server is ready to run a smarter planet.
ブラウザーから http://localhost:9080/dev/system/properties で、サービスが動いていることを確認してください。アプリケーションが動いていることを確認したら、サーバーを実行したコマンド行セッションで CTRL+C を押して、Open Liberty サーバーを停止します。
アプリケーションの WAR をビルドするには、次を実行します。
mvn package
このコマンドは、target/guide-getting-started.war
アーカイブを作ります。これで、InstantOn 機能を使用するコンテナー・イメージにこの WAR を含めることができます。
アプリケーションのコンテナ化
アプリケーションで Open Liberty InstantOn サポートを使用するには、最初に Open Liberty ベータ版 InstantOn イメージを使用してコンテナー化する必要があります。 Open Liberty を使用してアプリケーションをコンテナー化する方法に関する一般的な情報については、Containerizing microservices guide または Containerizing microservices with Podman guide を参照してください。 Podman に慣れていない場合は、最初に Podman ガイドに従ってください。現在、Open Liberty InstantOn のサポートには Podman を使用する必要があるためです。 Docker のサポートは、Docker が CRIU が必要とする機能をサポートするようになると、後で提供されるはずです。
Open Liberty Betaバージョンの InstantOn イメージを使用してアプリケーションをコンテナー化する
Liberty InstantOn ベータ・バージョンには、チェックポイント・サーバー・プロセスを使って、アプリのコンテナー・イメージを作成する機能が含まれています。アプリは、Liberty InstantOn ベータ イメージをベースとして使い、独自のアプリケーション コンテナー イメージを構築します。そこからチェックポイント プロセスを使用して独自のアプリケーション コンテナー イメージを作成できます。これには、次の手順が含まれます。
コンテナー化されたアプリケーションをチェックポイント/復元するための前提条件
現在、Open Liberty InstantOn のベータ版は、x86-64/amd64 アーキテクチャーでの実行のみをサポートしています。 criu
を使用するコンテナー イメージをビルドして実行するには、ホスト オペレーティング システムにいくつかの前提条件がインストールされている必要があります。すべてのテストは RHEL 8.6 および RHEL 9.0 で行われました。必要な前提条件があれば、他の Linux ディストリビューションおよびバージョンも使用できる可能性があります。次の条件が必要です。
-
カーネルは、Linux CAP_CHECKPOINT_RESTORE 機能 をサポートする必要があります。この機能はカーネル バージョン 5.9 で導入されましたが、RHEL 8.6 で使用される RHEL カーネル バージョンにバックポートされました。
-
Linux ディストリビューション用の Podman の最新バージョンをインストールする必要があります。
-
Podman は、
crun
またはrunc
コンテナー ランタイムを使用するように構成する必要があります。 -
runc
コンテナ ランタイムを使用する場合、最新のrunc
のfix を取得するには、バージョン 1.1.3 以降が必要です。この修正により、コンテナー内の/proc/sys/kernel/ns_last_pid
の正常なマウントが可能になります。
アプリケーションの Dockerfile を作成する
Open Liberty の使用を開始する の例では、最初のステップは、アプリケーションをコンテナー化するために Dockerfile
を作成することです。 podman
では、コンテナ イメージを作るための Containerfile
形式もサポートしています。
この例では、IBM Container Registry (ICR) の公式イメージ icr.io/appcafe/open-liberty:beta
を親イメージとして使用します。このイメージには beta
というタグが付けられており、full
イメージの Liberty 機能だけでなく、Liberty のベータ版機能もすべて含まれています。このイメージには instanton
というタグが付いており、必要な criu
バイナリファイルなど、チェックポイントプロセスのイメージを作成するためのすべての前提条件が含まれています。
起動中のアプリケーションの Dockerfile
は既に finish/Dockerfile
に存在しています。既存の finish/Dockerfile
を編集し、FROM
命令を変更して icr.io/appcafe/open-liberty:beta
の親イメージを使用するようにします。Dockerfile`を保存すると、以下のようになります。
FROM icr.io/appcafe/open-liberty:beta
ARG VERSION=1.0
ARG REVISION=SNAPSHOT
LABEL \
org.opencontainers.image.authors="Your Name" \
org.opencontainers.image.vendor="IBM" \
org.opencontainers.image.url="local" \
org.opencontainers.image.source="https://github.com/OpenLiberty/guide-getting-started" \
org.opencontainers.image.version="$VERSION" \
org.opencontainers.image.revision="$REVISION" \
vendor="Open Liberty" \
name="system" \
version="$VERSION-$REVISION" \
summary="The system microservice from the Getting Started guide" \
description="This image contains the system microservice running with the Open Liberty runtime."
COPY --chown=1001:0 src/main/liberty/config/ /config/
COPY --chown=1001:0 target/*.war /config/apps/
RUN configure.sh
アプリケーション コンテナー イメージをビルドする
criu
がチェックポイントを取得してプロセスを復元できるようにするには、criu
バイナリに追加の Linux 機能 付与する必要があります。特に、Open Liberty の場合、cap_checkpoint_restore
、cap_net_admin
、および`cap_sys_ptrace` を付与する必要があります。 Open Liberty InstantOn ベータ イメージには、必要な機能が既に criu
バイナリ ファイルに付与されている criu
バイナリが含まれています。 criu バイナリが実行時に割り当てられた機能にアクセスできるようにするには、criu を実行しているコンテナーにも、起動時に必要な機能を付与する必要があります。これらの機能をコンテナーに付与するには、次の 2 つの方法のいずれかを使用します。
-
--privileged
オプションを使用して特権コンテナを使用する -
--cap-add
オプションを使用して特定の機能を割り当てる
Docker を使用する場合、通常、デーモンには root 権限があります。この権限により、コンテナーを起動するときに要求された機能を付与できます。 Podman にはデーモンがないため、コンテナーを起動するユーザーは、必要な Linux 機能をコンテナーに付与する権限を持っている必要があります。 root として実行するか、sudo
を使用して podman
コマンドを実行すると、この権限が付与されます。この例では、root ユーザーとして podman
コマンドを実行していることにします。
root
権限で実行したとすると、podman build
コマンドを使用してコンテナー イメージをビルドできます。 finish/
ディレクトリから次のコマンドを実行して、アプリケーションのコンテナー イメージをビルドします。
podman build -t getting-started .
このコマンドは、getting-started
コンテナー イメージを作成します。ただし、このコンテナー イメージには、InstantOn の起動に使用できるチェックポイント イメージ ファイルは含まれていません。次のコマンドを使用して、このアプリケーション コンテナー イメージを実行できます。
podman run --name getting-started --rm -p 9080:9080 getting-started
Liberty が開始されたことを示すメッセージが表示されるまでにかかる時間を記録して、コンテナーで実行されているサービスが立ち上がっているのを http://localhost:9080/dev/system/properties で確認してください。アプリケーションが動いているのが確認できたら、 podman run
コマンドを実行したコマンドライン セッションで CTRL+C を押して、実行中のコンテナーを停止します。
コンテナー内のアプリケーションのチェックポイント
Open Liberty には、始動プロセス中にチェックポイントが発生する可能性のある 3 つのフェーズがあります。
-
features
- これはチェックポイントが発生する最も早いフェーズです。 チェックポイントは、設定されたすべてのOpen Liberty機能が開始された後に発生しますが、インストールされたアプリケーションの処理が発生する前に発生します。New enhancements for Liberty InstantOn in 23.0.0.2-betaを参照してください。 -
beforeAppStart
- チェックポイントは設定されたアプリケーションのメタデータを処理した後に行われます。 アプリケーションの開始時に実行されるコンポーネントがある場合、チェックポイントはアプリケーションのコードを実行する前に行われます。 -
afterAppStart
- これはチェックポイントが発生する最後のフェーズであるため、アプリケーションインスタンスのリストア時に最速の起動時間を提供する可能性があります。チェックポイントは、設定されたすべてのアプリケーションが開始されたとレポートされた後に行われます。 このフェーズは、アプリケーションの着信要求を受け付けるポートを開く前に行われます。
afterAppStart`フェーズは通常、アプリケーションに最も早い起動時間を提供しますが、サーバプロセスのチェックポイントが行われる前にアプリケーションコードが実行される可能性もあります。 このため、チェックポイントプロセスのリストア時に、アプリケーションが複数の同時実行インスタンスにリストアされるべきでない状態を保持していると、望ましくない動作が発生する可能性があります。 例えば、チェックポイントが行われる前にデータベースなどの外部リソースに接続すると、以降、同じ接続を複数回リストアしようとするため、そのようなプロセスの多くのインスタンスのリストアに不具合が生じます。しかし、アプリケーションの初期化でデータベース接続を開くなどの操作を行わない場合は、チェックポイントに `afterAppStart
フェーズを使用することができます。
アプリケーションコンテナイメージがビルトインされた後、先に説明したチェックポイントフェーズ (features
、beforeAppStart
、afterAppStart
) のいずれかでアプリケーションプロセスをチェックポイントするために使用できます。podman run` の --env
オプションで WLP_CHECKPOINT
の値を利用可能なチェックポイントフェーズのいずれかに設定することで、チェックポイントのフェーズを指定することができます。この例では、次の podman
コマンドを実行して afterAppStart
フェーズを使用します
podman run \
--name getting-started-checkpoint-container \
--privileged \
--env WLP_CHECKPOINT=afterAppStart \
getting-started
-
コンテナー内で
criu
チェックポイントを実行するには、--privileged
オプションが必要です。 -
WLP_CHECKPOINT
環境変数はチェックポイントフェーズを指定するために使用されます。get-started の例では、afterAppStart
チェックポイントフェーズが最も早いリストア時間を提供します。
これにより、Open Liberty で実行されているアプリケーションでコンテナーが開始されます。 Open Liberty の開始後、WLP_CHECKPOINT
環境変数で指定されたフェーズでチェックポイントが実行されます。コンテナ プロセス データが永続化された後、コンテナは停止し、チェックポイント プロセス データを含む停止中のコンテナが残ります。出力は次のようになります。
Performing checkpoint --at=afterAppStart
Launching defaultServer (Open Liberty 22.0.0.11-beta/wlp-1.0.69.cl221020220912-1100) on Eclipse OpenJ9 VM, version 17.0.5-ea+2 (en_US)
CWWKE0953W: This version of Open Liberty is an unsupported early release version.
[AUDIT ] CWWKE0001I: The server defaultServer has been launched.
[AUDIT ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/checkpoint.xml
[AUDIT ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml
[AUDIT ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/open-default-port.xml
[AUDIT ] CWWKZ0058I: Monitoring dropins for applications.
[AUDIT ] CWWKT0016I: Web application available (default_host): http://f5edff273d9c:9080/ibm/api/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://f5edff273d9c:9080/metrics/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://f5edff273d9c:9080/health/
[AUDIT ] CWWKT0016I: Web application available (default_host): http://f5edff273d9c:9080/dev/
[AUDIT ] CWWKZ0001I: Application guide-getting-started started in 0.986 seconds.
[AUDIT ] CWWKC0451I: A server checkpoint was requested. When the checkpoint completes, the server stops.
現在、このプロセスは podman build
ステップの一部として実行できません。これは、Podman (および Docker) が、criu
がプロセス チェックポイントを実行するために必要な Linux 機能をコンテナー イメージ ビルドに付与する方法を提供していないためです。
アプリケーション チェックポイント イメージを作成する
ここまでで、getting-started-checkpoint-container という名前の停止済みコンテナーに、getting-started アプリケーションのチェックポイント プロセス データを作成して保存しました。最後の手順は、チェックポイント プロセス データを含む新しいコンテナー イメージを作成することです。このコンテナー イメージが開始されると、チェックポイントが作成された時点からアプリケーション プロセスが再開され、InstantOn アプリケーションが作成されます。次の podman commit
を実行して、新しいイメージを作成できます。
podman commit getting-started-checkpoint-container getting-started-instanton
これで、getting-started
と getting-started-instanton
という名前の 2 つのアプリケーション イメージが作成されました。 getting-started-instanton
コンテナー イメージを使用してコンテナーを開始すると、元の getting-started
イメージよりも起動時間が大幅に短縮されます。
Instanton アプリケーション イメージの実行
通常、アプリケーション コンテナーは、次のようなコマンドを使用してアプリケーション コンテナー イメージから開始できます
podman run --rm -p 9080:9080 getting-started-instanton
ただし、このコマンドは失敗します。これは、criu
がコンテナー内のプロセスを復元できるようにするために昇格された特権が必要になるためです。 Liberty がチェックポイント プロセスの復元に失敗すると、チェックポイント イメージなしで起動することによって回復し、次のメッセージをログに記録します。
CWWKE0957I: Restoring the checkpoint server process failed. Check the /logs/checkpoint/restore.log log to determine why the checkpoint process was not restored. Launching the server without using the checkpoint image.
--privileged
オプションで実行
利用可能なすべての必要な特権を付与するには、次のコマンドで特権コンテナーを起動することを選択できます。
podman run --rm --privileged -p 9080:9080 getting-started-instanton
成功すると、次のような出力が表示されます。
[AUDIT ] CWWKZ0001I: Application guide-getting-started started in 0.059 seconds.
[AUDIT ] CWWKC0452I: The Liberty server process resumed operation from a checkpoint in 0.088 seconds.
[AUDIT ] CWWKF0012I: The server installed the following features: [cdi-3.0, checkpoint-1.0, concurrent-2.0, distributedMap-1.0, jndi-1.0, json-1.0, jsonb-2.0, jsonp-2.0, monitor-1.0, mpConfig-3.0, mpHealth-4.0, mpMetrics-4.0, restfulWS-3.0, restfulWSClient-3.0, servlet-5.0, ssl-1.0, transportSecurity-1.0].
[AUDIT ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 0.098 seconds.
特権のないコンテナーで実行する
上記では、--privileged`で、完全に特権のあるコンテナーの例をご紹介しましたが、実は、コンテナーに全部の特権を与えることはお勧めしません。ベスト プラクティスは、昇格された特権をコンテナーの実行に必要なものだけに減らすことです。次のコマンドを使用して、完全な `--privileged
コンテナを実行せずに、コンテナに必要な権限を付与できます:
podman run \
--rm \
--cap-add=CHECKPOINT_RESTORE \
--cap-add=NET_ADMIN \
--cap-add=SYS_PTRACE \
--security-opt seccomp=unconfined \
--security-opt systempaths=unconfined \
--security-opt apparmor=unconfined \
-p 9080:9080 \
getting-started-instanton
--cap-add
オプションは、criu
が必要とする 3 つの Linux 機能をコンテナーに付与します。 --security-opt
オプションは、必要なシステム コールへの criu
アクセスと、ホストからの /proc/sys/kernel/ns_last_pid
へのアクセスを許可するために必要です。
セキュリティが制限された非特権コンテナーでの実行
unconfined
を使用する --security-opt
オプションの必要性を減らすと、チェックポイント プロセスをさらに簡素化できます。デフォルトでは、podman
は criu
が必要とするすべてのシステム コールへのアクセスを許可していません。 (ファイル /usr/share/containers/seccomp.json
にデフォルトの値が指定されています) まず、criu
がコンテナーに必要とするすべてのシステム コールを許可するような、追加の構成ファイルを作る必要があります。次に、ホスト /proc/sys/kernel/ns_last_pid
をマウントする必要があります。次のコマンドを使用して、これらの両方の手順を実行できます。
podman run \
--rm \
--cap-add=CHECKPOINT_RESTORE \
--cap-add=NET_ADMIN \
--cap-add=SYS_PTRACE \
--security-opt seccomp=criuRequiredSysCalls.json \
-v /proc/sys/kernel/ns_last_pid:/proc/sys/kernel/ns_last_pid \
-p 9080:9080 \
getting-started-instanton
--security-opt seccomp=
オプションは、criuRequiredSysCalls.json
というファイルを参照します。このファイルは、criu
が必要とするシステム コールを指定します。
-v
オプションは、コンテナによるアクセスのためにホスト /proc/sys/kernel/ns_last_pid
をマウントします。
Linux ディストリビューションによっては、Podman はデフォルトで runc
または crun
を使用する場合があります。 Podman インストール用に構成されているコンテナー ランタイムを確認するには、コマンド podman info
を実行し、ociRuntime
セクションを確認します。 runc
を使用する場合は、バージョン 1.1.3 以降を使用していることを確認してください。この方法が機能するには、1.1.3 以降のバージョンの runc
が必要です。
RHEL 8.6 または RHEL 9.0 インストールがどの程度最新のものであるかによっては、criuRequiredSysCalls.json
を指定するための --security-opt
が必要でない場合があります。執筆時点では、RHEL 8.6 および RHEL 9.0 の最新バージョンには、デフォルトで起動するコンテナーに必要なシステム コールを許可する Podman が含まれています。このデフォルトにより、--security-opt seccomp=criuRequiredSysCalls.json
の指定が不要になります。
{
"defaultAction": "SCMP_ACT_ERRNO",
"defaultErrnoRet": 1,
"archMap": [
{
"architecture": "SCMP_ARCH_X86_64",
"subArchitectures": [
"SCMP_ARCH_X86",
"SCMP_ARCH_X32"
]
},
{
"architecture": "SCMP_ARCH_AARCH64",
"subArchitectures": [
"SCMP_ARCH_ARM"
]
},
{
"architecture": "SCMP_ARCH_MIPS64",
"subArchitectures": [
"SCMP_ARCH_MIPS",
"SCMP_ARCH_MIPS64N32"
]
},
{
"architecture": "SCMP_ARCH_MIPS64N32",
"subArchitectures": [
"SCMP_ARCH_MIPS",
"SCMP_ARCH_MIPS64"
]
},
{
"architecture": "SCMP_ARCH_MIPSEL64",
"subArchitectures": [
"SCMP_ARCH_MIPSEL",
"SCMP_ARCH_MIPSEL64N32"
]
},
{
"architecture": "SCMP_ARCH_MIPSEL64N32",
"subArchitectures": [
"SCMP_ARCH_MIPSEL",
"SCMP_ARCH_MIPSEL64"
]
},
{
"architecture": "SCMP_ARCH_S390X",
"subArchitectures": [
"SCMP_ARCH_S390"
]
},
{
"architecture": "SCMP_ARCH_RISCV64",
"subArchitectures": null
}
],
"syscalls": [
{
"names": [
"accept",
"accept4",
"access",
"adjtimex",
"alarm",
"bind",
"brk",
"capget",
"capset",
"chdir",
"chmod",
"chown",
"chown32",
"clock_adjtime",
"clock_adjtime64",
"clock_getres",
"clock_getres_time64",
"clock_gettime",
"clock_gettime64",
"clock_nanosleep",
"clock_nanosleep_time64",
"close",
"close_range",
"connect",
"copy_file_range",
"creat",
"dup",
"dup2",
"dup3",
"epoll_create",
"epoll_create1",
"epoll_ctl",
"epoll_ctl_old",
"epoll_pwait",
"epoll_pwait2",
"epoll_wait",
"epoll_wait_old",
"eventfd",
"eventfd2",
"execve",
"execveat",
"exit",
"exit_group",
"faccessat",
"faccessat2",
"fadvise64",
"fadvise64_64",
"fallocate",
"fanotify_mark",
"fchdir",
"fchmod",
"fchmodat",
"fchown",
"fchown32",
"fchownat",
"fcntl",
"fcntl64",
"fdatasync",
"fgetxattr",
"flistxattr",
"flock",
"fork",
"fremovexattr",
"fsetxattr",
"fstat",
"fstat64",
"fstatat64",
"fstatfs",
"fstatfs64",
"fsync",
"ftruncate",
"ftruncate64",
"futex",
"futex_time64",
"futex_waitv",
"futimesat",
"getcpu",
"getcwd",
"getdents",
"getdents64",
"getegid",
"getegid32",
"geteuid",
"geteuid32",
"getgid",
"getgid32",
"getgroups",
"getgroups32",
"getitimer",
"getpeername",
"getpgid",
"getpgrp",
"getpid",
"getppid",
"getpriority",
"getrandom",
"getresgid",
"getresgid32",
"getresuid",
"getresuid32",
"getrlimit",
"get_robust_list",
"getrusage",
"getsid",
"getsockname",
"getsockopt",
"get_thread_area",
"gettid",
"gettimeofday",
"getuid",
"getuid32",
"getxattr",
"inotify_add_watch",
"inotify_init",
"inotify_init1",
"inotify_rm_watch",
"io_cancel",
"ioctl",
"io_destroy",
"io_getevents",
"io_pgetevents",
"io_pgetevents_time64",
"ioprio_get",
"ioprio_set",
"io_setup",
"io_submit",
"io_uring_enter",
"io_uring_register",
"io_uring_setup",
"ipc",
"kill",
"landlock_add_rule",
"landlock_create_ruleset",
"landlock_restrict_self",
"lchown",
"lchown32",
"lgetxattr",
"link",
"linkat",
"listen",
"listxattr",
"llistxattr",
"_llseek",
"lremovexattr",
"lseek",
"lsetxattr",
"lstat",
"lstat64",
"madvise",
"membarrier",
"memfd_create",
"memfd_secret",
"mincore",
"mkdir",
"mkdirat",
"mknod",
"mknodat",
"mlock",
"mlock2",
"mlockall",
"mmap",
"mmap2",
"mprotect",
"mq_getsetattr",
"mq_notify",
"mq_open",
"mq_timedreceive",
"mq_timedreceive_time64",
"mq_timedsend",
"mq_timedsend_time64",
"mq_unlink",
"mremap",
"msgctl",
"msgget",
"msgrcv",
"msgsnd",
"msync",
"munlock",
"munlockall",
"munmap",
"nanosleep",
"newfstatat",
"_newselect",
"open",
"openat",
"openat2",
"pause",
"pidfd_open",
"pidfd_send_signal",
"pipe",
"pipe2",
"poll",
"ppoll",
"ppoll_time64",
"prctl",
"pread64",
"preadv",
"preadv2",
"prlimit64",
"process_mrelease",
"pselect6",
"pselect6_time64",
"pwrite64",
"pwritev",
"pwritev2",
"read",
"readahead",
"readlink",
"readlinkat",
"readv",
"recv",
"recvfrom",
"recvmmsg",
"recvmmsg_time64",
"recvmsg",
"remap_file_pages",
"removexattr",
"rename",
"renameat",
"renameat2",
"restart_syscall",
"rmdir",
"rseq",
"rt_sigaction",
"rt_sigpending",
"rt_sigprocmask",
"rt_sigqueueinfo",
"rt_sigreturn",
"rt_sigsuspend",
"rt_sigtimedwait",
"rt_sigtimedwait_time64",
"rt_tgsigqueueinfo",
"sched_getaffinity",
"sched_getattr",
"sched_getparam",
"sched_get_priority_max",
"sched_get_priority_min",
"sched_getscheduler",
"sched_rr_get_interval",
"sched_rr_get_interval_time64",
"sched_setaffinity",
"sched_setattr",
"sched_setparam",
"sched_setscheduler",
"sched_yield",
"seccomp",
"select",
"semctl",
"semget",
"semop",
"semtimedop",
"semtimedop_time64",
"send",
"sendfile",
"sendfile64",
"sendmmsg",
"sendmsg",
"sendto",
"setfsgid",
"setfsgid32",
"setfsuid",
"setfsuid32",
"setgid",
"setgid32",
"setgroups",
"setgroups32",
"setitimer",
"setpgid",
"setpriority",
"setregid",
"setregid32",
"setresgid",
"setresgid32",
"setresuid",
"setresuid32",
"setreuid",
"setreuid32",
"setrlimit",
"set_robust_list",
"setsid",
"setsockopt",
"set_thread_area",
"set_tid_address",
"setuid",
"setuid32",
"setxattr",
"shmat",
"shmctl",
"shmdt",
"shmget",
"shutdown",
"sigaltstack",
"signalfd",
"signalfd4",
"sigprocmask",
"sigreturn",
"socket",
"socketcall",
"socketpair",
"splice",
"stat",
"stat64",
"statfs",
"statfs64",
"statx",
"symlink",
"symlinkat",
"sync",
"sync_file_range",
"syncfs",
"sysinfo",
"tee",
"tgkill",
"time",
"timer_create",
"timer_delete",
"timer_getoverrun",
"timer_gettime",
"timer_gettime64",
"timer_settime",
"timer_settime64",
"timerfd_create",
"timerfd_gettime",
"timerfd_gettime64",
"timerfd_settime",
"timerfd_settime64",
"times",
"tkill",
"truncate",
"truncate64",
"ugetrlimit",
"umask",
"uname",
"unlink",
"unlinkat",
"utime",
"utimensat",
"utimensat_time64",
"utimes",
"vfork",
"vmsplice",
"wait4",
"waitid",
"waitpid",
"write",
"writev",
"arch_prctl",
"chroot",
"clone",
"clone3",
"fallocate",
"fanotify_init",
"fsconfig",
"fsmount",
"fsopen",
"guarded_storage",
"kcmp",
"lseek",
"mmap",
"mount",
"open",
"open_by_handle_at",
"openat",
"pivot_root",
"preadv",
"process_vm_readv",
"ptrace",
"readdir",
"s390_runtime_instr",
"setns",
"sigaction",
"signal",
"syscall",
"umount",
"umount2",
"unshare",
"userfaultfd",
"wait"
],
"action": "SCMP_ACT_ALLOW"
},
{
"names": [
"process_vm_readv",
"process_vm_writev",
"ptrace"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"minKernel": "4.8"
}
},
{
"names": [
"personality"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 0,
"op": "SCMP_CMP_EQ"
}
]
},
{
"names": [
"personality"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 8,
"op": "SCMP_CMP_EQ"
}
]
},
{
"names": [
"personality"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 131072,
"op": "SCMP_CMP_EQ"
}
]
},
{
"names": [
"personality"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 131080,
"op": "SCMP_CMP_EQ"
}
]
},
{
"names": [
"personality"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 4294967295,
"op": "SCMP_CMP_EQ"
}
]
},
{
"names": [
"sync_file_range2",
"swapcontext"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"arches": [
"ppc64le"
]
}
},
{
"names": [
"arm_fadvise64_64",
"arm_sync_file_range",
"sync_file_range2",
"breakpoint",
"cacheflush",
"set_tls"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"arches": [
"arm",
"arm64"
]
}
},
{
"names": [
"arch_prctl"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"arches": [
"amd64",
"x32"
]
}
},
{
"names": [
"modify_ldt"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"arches": [
"amd64",
"x32",
"x86"
]
}
},
{
"names": [
"s390_pci_mmio_read",
"s390_pci_mmio_write",
"s390_runtime_instr"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"arches": [
"s390",
"s390x"
]
}
},
{
"names": [
"riscv_flush_icache"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"arches": [
"riscv64"
]
}
},
{
"names": [
"open_by_handle_at"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_DAC_READ_SEARCH"
]
}
},
{
"names": [
"bpf",
"clone",
"clone3",
"fanotify_init",
"fsconfig",
"fsmount",
"fsopen",
"fspick",
"lookup_dcookie",
"mount",
"mount_setattr",
"move_mount",
"name_to_handle_at",
"open_tree",
"perf_event_open",
"quotactl",
"quotactl_fd",
"setdomainname",
"sethostname",
"setns",
"syslog",
"umount",
"umount2",
"unshare"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYS_ADMIN"
]
}
},
{
"names": [
"clone"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 2114060288,
"op": "SCMP_CMP_MASKED_EQ"
}
],
"excludes": {
"caps": [
"CAP_SYS_ADMIN"
],
"arches": [
"s390",
"s390x"
]
}
},
{
"names": [
"clone"
],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 1,
"value": 2114060288,
"op": "SCMP_CMP_MASKED_EQ"
}
],
"comment": "s390 parameter ordering for clone is different",
"includes": {
"arches": [
"s390",
"s390x"
]
},
"excludes": {
"caps": [
"CAP_SYS_ADMIN"
]
}
},
{
"names": [
"clone3"
],
"action": "SCMP_ACT_ERRNO",
"errnoRet": 38,
"excludes": {
"caps": [
"CAP_SYS_ADMIN"
]
}
},
{
"names": [
"reboot"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYS_BOOT"
]
}
},
{
"names": [
"chroot"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYS_CHROOT"
]
}
},
{
"names": [
"delete_module",
"init_module",
"finit_module"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYS_MODULE"
]
}
},
{
"names": [
"acct"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYS_PACCT"
]
}
},
{
"names": [
"kcmp",
"pidfd_getfd",
"process_madvise",
"process_vm_readv",
"process_vm_writev",
"ptrace"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYS_PTRACE"
]
}
},
{
"names": [
"iopl",
"ioperm"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYS_RAWIO"
]
}
},
{
"names": [
"settimeofday",
"stime",
"clock_settime"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYS_TIME"
]
}
},
{
"names": [
"vhangup"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYS_TTY_CONFIG"
]
}
},
{
"names": [
"get_mempolicy",
"mbind",
"set_mempolicy"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYS_NICE"
]
}
},
{
"names": [
"syslog"
],
"action": "SCMP_ACT_ALLOW",
"includes": {
"caps": [
"CAP_SYSLOG"
]
}
}
]
}
どのくらい速い?
InstantOnで起動時間がどのように短縮されるかを示すために、複数のアプリケーションをテストしましたか?
-
Pingperf は、一つのREST エンドポイントをもつ非常に単純な ping タイプのアプリケーションです。
-
Rest crud は、 もう少し複雑なアプリで、JPA とリモート データベースを扱います。
-
AcmeAir Microservice Main は、MicroProfile 機能を利用します。
これらの実験は、24コアのシステムで実行されました。taskset -c
を使用して、コンテナ内で実行されている Liberty プロセスに 4 CPU を割り当てました。InstantOnの時間は、`afterAppStart`チェックポイントフェーズを使用して計測しました。起動時間は、Libertyサーバーの起動が開始されてから、サーバーがリクエストを受け付ける準備が整うまでの時間を計測したもので、messages.logに"The <server name> server is ready to run a smarter planet. "というメッセージが表示さ れます。コンテナ自体の起動にかかる時間はフィルタリングされていません。これらのアプリケーションの InstantOn と通常の起動時間をミリ秒単位で示します。成果は、お使いの環境、システムにインストールされているハードウェアとソフトウェア、およびその他の要因によって異なる場合があります。低い数値(短い時間で立ち上がる)ほうが、良いパフォーマンスだと評価できます。
InstantOn は、アプリケーションに応じて最大 90% の大幅なスタートアップ節約を提供します。すべてのアプリケーションが同じではないため、アプリケーションによって結果は異なります。
次はどんな機能が期待できるでしょうか?
このブログ投稿では、Open Liberty InstantOn ベータ版を使用して、InstantOn 起動時間でアプリケーション コンテナー イメージを生成する方法について詳しく説明しました。このサポートは現在、Liberty webProfile-8.0、webProfile-9.1、microProfile-4.1、および microProfile-5.0 の機能の一部として組み込まれている Open Liberty 機能のみでサポートされています。これを拡張して webProfile と microProfile の将来のバージョンを含め、Jakarta フル プロファイル機能 (jakarta-8.0、jakarta-9.1、jakarta-10.0 など) まで、サポートを拡張したいと考えています。
InstantOn を使用すると、オプションとして scale-to-zero を使用してデプロイできる非常に高速な起動アプリケーション コンテナーを構築できます。 Knative などのアプリケーションをゼロに自動スケーリングできるテクノロジーを使用して、Red Hat OpenShift Container Platform (OCP) や Kubernetes (k8s) などのクラウド環境に Open Liberty InstantOn をデプロイすることができます。今後のブログ記事で、みなさんにご説明するのを楽しみにしています。