メインコンテンツまでスキップ

plantpulse-server (ウェブコンソール + IIoTエンジン)

役割​

プラットフォームの顔であり頭脳に相当する中核モジュールです。オペレーターが閲覧するウェブコンソール、外部システムが呼び出すREST API、そして産業データを実際に処理するIIoTエンジンが、すべてこの1つのモジュール内で動作します。

項目値
モジュール名plantpulse-server
コンテナplantpulse-server-web (自己イメージ、自己コンテナ)
コンテナ内パス/opt/kopens/plantpulse-platform/plantpulse-server/
ユーザー接続80 / 443 — plantpulse-proxy が受け取ってこのコンテナへ渡します。管理コンソールも同じアドレスです
ホストポートなし — プロキシの背後でのみ動作します
メモリ上限DOCKER_SERVER_MEMORY デフォルト 14g / ヒープ DOCKER_SERVER_HEAP デフォルト 8g
ランタイムApache Tomcat 10.1 + Java 21
処理量毎秒40,000件メッセージ (36スレッドパイプライン)
このコンテナはホストポートを開きません

ユーザートラフィックは常に plantpulse-proxy(80/443) を経由します。そのため、バックエンドが移動したり名前が変わったりしても、ユーザー・設備設定を変更する必要がありません。コンテナの状態は bin/status.sh、ログは bin/logs.sh plantpulse-server-web で確認します。

責務領域​

ディレクトリ構造​

plantpulse-server/
├── config/ # 서버 관리 설정 (외부화 — 배포해도 유지)
│ ├── plantpulse-engine.properties # IIoT 엔진 튜닝
│ ├── plantpulse-storage.properties # DB 연결
│ ├── plantpulse-mq.properties # 메시징 연결
│ └── log4j2.xml # 로깅 설정 (자가 시딩 — 최초 기동 시 생성)
├── bin/
│ ├── start.sh
│ ├── stop.sh
│ └── log-viewer.sh
├── logs/
│ └── system.log
├── path/ # 경로 매핑
└── server/ # 내장 Tomcat
├── conf/
│ ├── server.xml # 커넥터 / 포트
│ ├── context.xml # 컨텍스트 / 데이터소스
│ ├── catalina.properties
│ ├── logging.properties
│ ├── tomcat-users.xml
│ ├── web.xml
│ └── Catalina/localhost/
│ └── ROOT.xml # 컨텍스트 설정 (sessionCookieName 등)
└── webapps/
├── ROOT.war # 웹 애플리케이션 (WAR 통배포)
└── ROOT/ # Tomcat 이 unpack 한 디렉토리 (수정 금지)

デプロイ方式: ウェブアプリは server/webapps/ROOT.war 差し替え方式でデプロイします (WAR一括デプロイ、移行中)。既存の app/plantpulse-server-web explodedディレクトリ方式は廃止予定であり、server.xml の Context docBase オーバーライドは削除されました。ROOT/ 内のファイルを直接修正すると次のデプロイ時に消えるため、設定変更は常に config/ で行ってください。

主要設定ファイル​

設定ファイルはモジュールの config/ ディレクトリにあり、サーバーは -Dpp.conf.dir → ${catalina.base}/../config → クラスパス(fallback) の順で探索します。外部設定がロードされると、起動ログに Properties loaded from external conf: が出力されます。

application.properties は削除されました (2026.06)。テーマ / ホームページなどコンソール動作設定はコンソールのシステム > 設定管理 (mm_config テーブル) で管理し、alarm.duplicate.check.minutes は plantpulse-engine.properties に移管されました。

plantpulse-engine.properties​

IIoTエンジンパイプラインのチューニング。

項目デフォルト値説明
engine.pipeline.threads36並列処理スレッド数
engine.pipeline.ratelimit40000毎秒最大メッセージ数
engine.pipeline.batch.size1000バッチサイズ
engine.pipeline.queue.size1200000キュー容量
engine.dedup.enabledtrue重複除去の有効化

plantpulse-storage.properties​

データストア接続。

# Cassandra
cassandra.host=${PP_CASSANDRA_HOST}
cassandra.port=${PP_CASSANDRA_PORT}
cassandra.keyspace=${PP_KEYSPACE}
cassandra.user=${PP_CASSANDRA_USER}
cassandra.password=${PP_CASSANDRA_PASSWORD}

# PostgreSQL (Spring DataSource)
postgres.url=jdbc:postgresql://${PP_POSTGRES_HOST}:${PP_POSTGRES_PORT}/${PP_DB_NAME}
postgres.user=${PP_PG_USER}
postgres.password=${PP_PG_PASSWORD}

# Valkey
redis.host=${PP_REDIS_HOST}
redis.port=${PP_REDIS_PORT}
redis.password=${PP_REDIS_PASSWORD}

このアプリは設定をレンダリングしません。 コンテナに分かれた後、ウェブサーバーはデータレイクの設定レンダラーなしで起動し、値を3つの場所から読み取ります — ① オペレーターが置いた外部ファイル → ② WAR に内蔵されたデフォルト値 → ③ compose が渡す環境変数。この3つのうち、環境変数が内蔵デフォルト値を上書きします。

そのためアプリが見る値の定義元は compose/docker-compose.yml の1つだけです。データレイク側にのみ存在し compose に無い名前は、このアプリに届きません — データレイク側だけで識別子を変更したサイトで、アプリ5つが古い名前を使い続けた事故がそれです(2026-08-29)。

ウェブアプリ内部(server/webapps/ROOT/)のファイルは修正しないでください — デプロイ時に消えます。

server/conf/server.xml​

Tomcatコネクタ設定。ポート変更 / TLS / 圧縮 / スレッドプール。

<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="500"
acceptCount="200"
URIEncoding="UTF-8"
compression="on"
compressibleMimeType="text/html,text/css,application/json,application/javascript" />

<Connector port="443" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
SSLEnabled="true"
maxThreads="500"
sslEnabledProtocols="TLSv1.3,TLSv1.2">
<SSLHostConfig>
<Certificate certificateKeystoreFile="/var/security/plantpulse/server.jks"
certificateKeystorePassword="${PP_TLS_KEYSTORE_PASSWORD}" />
</SSLHostConfig>
</Connector>

運用コマンド​

ホストから — コンテナ単位​

コンテナを再起動することが、すなわちこのモジュールの再起動です。インフラや他のアプリには影響しません。

cd /opt/kopens/plantpulse-platform-docker

# 서버만 재시작
docker compose -f compose/docker-compose.yml restart plantpulse-server-web

# 상태 · 로그
bin/status.sh
bin/logs.sh plantpulse-server-web -n 200

コンテナ内に入る​

cd /opt/kopens/plantpulse-platform-docker/bin
./shell.sh plantpulse-server-web
データレイクの restart-server.sh では再起動されません

そのスクリプトは各アプリの自己コンテナ内でそのモジュールのランチャーを呼ぶ薄い委譲です。データレイクコンテナにはウェブサーバー実行ファイルが無いため、「モジュールが無い」というエラーで終了します。上記のコンテナ単位再起動を使用してください。

ホットリロード (再起動なしで設定反映)​

一部の設定はコンソールのシステム > 設定管理メニューからホットリロードが可能です。config/ のプロパティファイルや server.xml など起動時設定は再起動が必要です。

ログ​

ログパス内容
メインログlogs/system.logアプリケーションロジック、エラー
Tomcat catalinaserver/logs/catalina.outTomcat標準出力
アクセスログserver/logs/localhost_access_log.YYYY-MM-DD.txtHTTPリクエストログ
エンジンログlogs/engine.logIIoTエンジン処理詳細
スロークエリlogs/slow.log200ms以上のクエリ

ログレベル変更 — ロギング設定(log4j2.xml)はモジュール config/ に外部化されています (自己シーディング: 初回起動時にWARデフォルト値が config/log4j2.xml にコピーされ、適用時に起動ログへ Logging reconfigured from external conf: 出力):

# 웹 서버 컨테이너 안에서
cd /opt/kopens/plantpulse-platform-docker/bin
./shell.sh plantpulse-server-web
vi /opt/kopens/plantpulse-platform/plantpulse-server/config/log4j2.xml
# <Logger name="plantpulse" level="DEBUG"/> 등 수정 후 exit

# 호스트에서 그 컨테이너만 재시작
cd /opt/kopens/plantpulse-platform-docker
docker compose -f compose/docker-compose.yml restart plantpulse-server-web

外部ファイルなのでWAR再デプロイでも永続的に保持されます。ウェブアプリ内部(server/webapps/ROOT/WEB-INF/classes/log4j2.xml)は修正しないでください — デプロイ時に消えます。

パフォーマンスチューニング​

JVMヒープ​

# server/bin/setenv.sh (없으면 생성)
export CATALINA_OPTS="-Xms16g -Xmx32g \
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/log/plantpulse/heap/ \
-Xlog:gc*:file=/var/log/plantpulse/gc.log:time,uptime:filecount=10,filesize=100M"

Tomcatスレッドプール​

server.xml の Connector で maxThreads / acceptCount を調整。大規模同時接続環境では以下を推奨します。

同時接続数maxThreadsacceptCount
~ 100200100
~ 500500200
500+1000500

IIoTエンジン処理量​

plantpulse-engine.properties の engine.pipeline.threads をホストコア数の70~80%に設定。メッセージ滞留時は engine.pipeline.queue.capacity も合わせて増やしてください。

詳細なチューニングはパフォーマンスチューニングページを参照してください。

アップロード物の保存先 — RustFS​

設備文書 · 設備画像 · プロフィール画像はオブジェクトストア(RustFS) に保存されます。データベースには本体の代わりに s3://<버킷>/<key> が入ります。

項目値
バケットPP_S3_UPLOAD_BUCKET (デフォルト upload) — データレイクが使用する plantpulse バケットとは異なります
接続PP_S3_HOST · PP_S3_PORT · PP_S3_USER · PP_S3_PASSWORD
配置先plantpulse-server-web のみに配置されます。ワーカーには行きません

バケットを分けた理由は、片方の保存ルールがもう片方に影響しないようにするためです。

バケットが事前に存在している必要があります

2026.09 は起動時にバケットを作成しません。 存在しないバケットを指すとアップロードが失敗します。クリーンインストールでは移行プロセスでバケットが作成されますが、値を手動で変更して別のバケットを指す場合は、そのバケットを先に作成しておいてください。

環境が設定されている必要があります

接続値が空の場合はオブジェクトストアを作成できず、アップロードパスが表示されません。コンテナ環境は作成時点で固定されるため、値を追加したら docker restart ではなくコンテナを再作成する必要があります。

アップロード上限 — 一行では書き表せません​

上限は2層あり、実際に先に引っかかるのはほぼ常に下層(エンドポイント)です。

エンドポイント別ガード — 先に引っかかる​

アップロード対象エンドポイント上限
設備文書POST /asset/tree/document/upload50 MiB
設備文書 (API v5)POST /api/v5/assets/{asset_id}/documents50 MiB
設備画像POST /asset/image/upload10 MiB
キャンバスSVGPOST /canvas/svgupload10 MiB
「アップロード上限50 MiB」とだけ案内すると画像で誤ります

設備画像とキャンバスSVGは10 MiBで拒否されます。文書のみ50 MiBです。

上限を超えた場合に表示されるもの​

4つのエンドポイントは同じ検証関数を使用し、メッセージにはバイト数だけが表示されます。

file_size: 12582912 > max 10485760

12 MiBの画像をアップロードした場合の例です — 10485760 が10 MiB、52428800 が50 MiBです。

単位もファイル名もありません

メッセージに単位がないため、オペレーターがバイト数を暗算する必要があり、どのファイルが引っかかったのかも表示されません。複数ファイルを一度にアップロードして拒否された場合、サイズを直接測って特定する必要があります。

コンテナ上限 — その上の天井​

対象値設定場所
1ファイル50 MiBweb.xml の <max-file-size>
マルチパートリクエスト全体52 MiBweb.xml の <max-request-size>
フォームパラメータ(ファイルパートを除く)2 MiBTomcatデフォルト値 — 両コネクタとも maxPostSize を宣言していません
2 MiB は「ファイル」上限ではありません — プロキシ経由でも大きなファイルは届きます

maxPostSize はTomcatがリクエストパラメータに変換するバイトの上限です。x-www-form-urlencoded はボディ全体を、multipart/form-data はファイル以外のパートのみをカウントします。JSONのようなrawボディは対象外です。

実測(2026-09-18): プロキシ経由で3 MiBマルチパートを送信すると、ボディ全体が送信されアプリケーション認証層まで到達します(サイズではなく 401 で終了します)。転送経路に2 MiBの壁はなく、nginx は client_max_body_size 200m です。

2026-09-18以前は443コネクタのみ maxPostSize="-1" であり、同じサーバーがポートによって異なる上限を強制していました。現在は80 · 443とも同じです。

ヘルスチェック​

# 표준 헬스체크 (익명, readiness — 엔진이 전 단계 기동을 완료(RUNNING)했을 때만 UP. 배포 자동검증 / 모니터링용)
curl -fsS http://127.0.0.1/api/health
# 준비 완료: 200 {"status":"UP","service":"plantpulse-server-web","ts":1765500000000,"checks":{"engine":"RUNNING"}}
# 기동 중: 503 {"status":"STARTING",...} / 기동 실패·중지: 503 {"status":"DEGRADED",...}
# 경로는 /api/health 다 — «/api/v5/health» 는 없다. 인증도 필요 없다(익명 허용 경로).

# 콘솔 ping
curl -fsS http://127.0.0.1/api/v5/ping

# 공개 상태 페이지의 데이터 (익명 — 24시간 가용성·p99·엔드포인트별 상태)
curl -fsS http://127.0.0.1/api/v5/public/status

# WebSocket 핸드셰이크 확인
curl -i -N \
-H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==" \
-H "Sec-WebSocket-Version: 13" \
http://127.0.0.1:8000/ws

頻発する問題​

症状原因対処
OutOfMemoryErrorヒープ不足setenv.sh で -Xmx を増量 + GCログ分析
Too many open filesファイルディスクリプタ上限/etc/security/limits.conf の nofile 65535以上
コンソール応答遅延DBスロークエリPostgreSQL slow queryログ、Valkeyキャッシュヒット率確認
ログイン無限ループセッション / クッキー問題ブラウザキャッシュ削除、server/conf/Catalina/localhost/ROOT.xml の sessionCookieName 確認
502 / 504 (リバースプロキシ)バックエンド応答時間超過nginx proxy_read_timeout を増加
WebSocket切断ファイアウォールidle timeoutファイアウォールtimeout > 60s、tomcat.websocket.session.timeout 調整

詳細な診断は問題解決ページを参照してください。

セキュリティチェックリスト​

  • デフォルトadminパスワード変更 (admin / admin123!)
  • tomcat-users.xml のmanagerアカウント削除または強力なパスワード設定
  • server.xml の shutdown port (7000) 外部アクセス遮断
  • HTTPS証明書適用 (plantpulse-certs が焼き込んだ pp-security ボリュームの資材または外部CA)
  • X-Frame-Options / CSP / HSTSヘッダー設定確認
  • API Bearer Tokenを運用vaultに保存
  • config/ プロパティファイルのデバッグオプション無効化および権限制限 (chmod 600)

詳細なセキュリティ設定はセキュリティ設定ページを参照してください。

関連ドキュメント​