Alibaba Cloud Jindo CLI は、OSS-HDFS サービスを管理するためのコマンドラインインターフェイス (CLI) です。このトピックでは、Java Spring Boot を使用して Jindo CLI コマンドを API 操作としてラップし、OSS-HDFS サービスをプログラムで管理する方法について説明します。このトピックでは、集中型デプロイメントと分離型デプロイメントの 2 つのアーキテクチャについて説明します。これらのアーキテクチャは、運用保守 (O&M) 制御システム、自動化スクリプト、継続的インテグレーションと継続的デリバリー (CI/CD) ツールなどのシナリオに適しています。
デプロイメントオプション
オプション 1: 集中型デプロイメント
業務アプリケーションと Jindo CLI ツールは同じサーバーにデプロイされ、ローカル呼び出しを介して統合されます。次の図に示すように、業務アプリケーションは業務サーバー上の Jindo CLI を直接呼び出して OSS-HDFS サービスにアクセスします。
利点: ネットワークオーバーヘッドがなく、実装がシンプルです。
欠点: CLI の実行は、主要な業務アプリケーションのリソースを消費します。
シナリオ: このオプションは、迅速な検証、内部自動化スクリプト、および単一の管理プラットフォームに適しています。
オプション 2: 分離型デプロイメント
業務アプリケーション (サーバー A) は Jindo CLI (サーバー B) から分離されています。CLI は独立した HTTP Agent サービスとしてラップされ、2 つのコンポーネントは RESTful API を介して通信します。次の図に示すように、業務アプリケーションは HTTP Agent をリモートで呼び出します。その後、Agent は Jindo CLI を呼び出して OSS-HDFS サービスにアクセスします。
利点: AccessKey はツールサーバー上で分離されます。業務アプリケーションとツールは分離されています。これにより、独立したアップグレードとクロス言語呼び出しがサポートされます。このツールは、複数の業務プラットフォームに同時にサービスを提供できます。
欠点: このオプションでは、Agent サービスの追加のメンテナンスが必要になり、ネットワークオーバーヘッドが発生します。RESTful API 呼び出しには、デフォルトで認証がありません。認証トークンメカニズムなど、独自のセキュリティチェックを実装する必要があります。
シナリオ: このオプションは、本番環境、特に拡張性の要件が高いシステムや、複数の業務プラットフォームにサービスを提供するシナリオに適しています。
準備
開始する前に、次の前提条件が満たされていることを確認してください:
OSS-HDFS サービス: OSS-HDFS サービスが有効になっているバケット。詳細については、「OSS-HDFS サービスを有効にする」をご参照ください。
権限: Resource Access Management (RAM) ユーザーは、OSS-HDFS サービスにアクセスするための権限を持っている必要があります。最小権限の原則に従ってください。たとえば、読み取り権限のみが必要な場合は、書き込み権限や削除権限を付与しないでください。詳細については、「OSS-HDFS サービスへのアクセス権限を付与する」をご参照ください。
サーバー環境: ECS インスタンスや自己管理サーバーなど、少なくとも 1 台のサーバーが必要です。このサーバーは、バケットと同じリージョンにあり、内部ネットワーク経由で OSS にアクセスでき、Java 開発キット (JDK) がインストールされている必要があります。
Jindo SDK: Jindo ソフトウェア開発キット (SDK) がインストールされ、構成されている必要があります。
集中型デプロイメント: SDK を業務サーバーにインストールします。
分離型デプロイメント: SDK は Agent サーバー (サーバー B) にのみインストールします。
オプション 1: 集中型デプロイメント
業務アプリケーションと Jindo CLI は同じサーバー上にあります。業務アプリケーションは Jindo CLI コマンドを直接呼び出します。このオプションは、迅速な検証に適しています。
ステップ 1: バックエンド API 操作の開発
Spring Boot API 操作を作成して jindo fs -ls コマンドをラップします。
メインコマンドは Jindo SDK のバージョンによって異なる場合があります。たとえば、一部の新しいバージョンでは jindo を使用し、一部の古いバージョンでは jindofs を使用します。
コードをコピーする前に、サーバーのコマンドラインで jindo -v または jindofs -v を実行して、環境に適した正しいコマンドを決定してください。このトピックの例では jindo を使用しています。
package com.example.jindotest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
@RestController
public class JindoController {
@PostMapping("/jindo-ls")
public ResponseEntity<String> executeJindoLs(@RequestParam("path") String path) {
// パス形式を検証
if (path == null || !path.startsWith("oss://")) {
return ResponseEntity.badRequest().body("Invalid OSS path");
}
try {
// Jindo CLI コマンドをビルド
ProcessBuilder processBuilder = new ProcessBuilder("jindo", "fs", "-ls", path);
processBuilder.redirectErrorStream(true);
// プロセスを開始
Process process = processBuilder.start();
// コマンド出力を読み取り
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line).append("\n");
}
// プロセスの終了を待機し、終了コードを確認
int exitCode = process.waitFor();
if (exitCode == 0) {
// コマンド実行結果を返す
return ResponseEntity.ok(result.toString());
} else {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Command failed with exit code: " + exitCode);
}
} catch (IOException | InterruptedException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Error executing command: " + e.getMessage());
}
}
}ステップ 2: 結果の検証
デプロイメントが完了したら、次のいずれかの方法で統合を検証できます。
Web インターフェイスでの検証:
サンプル Web インターフェイスコードについては、「付録」をご参照ください。コード内のリクエストパスを
/jindo-lsに変更します。http://<業務サーバーのパブリック IP>:8080にアクセスして統合をテストできます。業務サーバーでインバウンドトラフィックに対してポート 8080 を開く必要があります。oss://my-bucket.cn-hangzhou.oss-dls.aliyuncs.com/などのファイルパスを入力し、「List Files」ボタンをクリックします。インターフェイスに OSS ファイルリストが表示された場合、統合は成功です。
API 操作を使用した検証 (代替)
フロントエンドをデプロイできない場合は、curl を使用してバックエンド API 操作をテストできます。
curl -X POST "http://localhost:8080/jindo-ls?path=oss://bucket.endpoint/"ファイルリストが返された場合、統合は成功です。
検証が成功したら、他のコマンドをシステムに統合できます。詳細については、付録の「一般的な Jindo CLI コマンド」をご参照ください。
オプション 2: 分離型デプロイメント
このオプションは、本番環境に推奨されます。このアーキテクチャでは、Jindo CLI は独立した Agent サービスとしてラップされ、責任を分離します。このアーキテクチャは、内部ネットワーク環境やセキュリティ要件が比較的低いシナリオに適しています。セキュリティ要件が高いシナリオでは、独自の API アクセス検証メカニズムを実装する必要があります。
ステップ 1: サーバー B で Agent サービスを開始する
Agent スクリプトの作成
JindoCliHttpAgent.pyファイルを作成します。スクリプトは Python 3 で実装されています。他の技術スタックでも同様のアプローチを使用できます。#!/usr/bin/env python3 # -*- coding: utf-8 -*- import http.server import json import subprocess import socketserver import shlex class CommandHandler(http.server.SimpleHTTPRequestHandler): def do_POST(self): if self.path == '/execute': # リクエスト本文を読み取り content_length = int(self.headers.get('Content-Length', 0)) post_data = self.rfile.read(content_length) try: # JSON リクエストを解析 data = json.loads(post_data) command = data.get('command', '') # command パラメーターを検証 if not command: self.send_response(400) self.send_header('Content-Type', 'application/json') self.end_headers() self.wfile.write(json.dumps({'error': 'Missing "command" parameter'}).encode('utf-8')) return # コマンドを安全に実行 command_list = shlex.split(command) output = subprocess.check_output(command_list, stderr=subprocess.STDOUT) output_str = output.decode('utf-8').strip() # 実行結果を返す self.send_response(200) self.send_header('Content-Type', 'application/json') self.end_headers() self.wfile.write(json.dumps({'output': output_str}).encode('utf-8')) except Exception as e: # エラーメッセージを返す self.send_response(500) self.send_header('Content-Type', 'application/json') self.end_headers() self.wfile.write(json.dumps({'error': str(e)}).encode('utf-8')) else: self.send_error(404, 'Not Found') # マルチスレッド HTTP サーバー class ThreadedHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer): pass if __name__ == '__main__': # HTTP Agent サービスを開始 server_address = ('0.0.0.0', 8000) httpd = ThreadedHTTPServer(server_address, CommandHandler) print('Starting secure HTTP Agent on port 8000...') httpd.serve_forever()ファイアウォールの構成
サーバー B のインバウンドトラフィックに対してポート 8000 を開きます。業務サーバー (サーバー A) のプライベート IP アドレスからのアクセスのみを許可し、パブリックネットワークアクセスを拒否します。
実行権限の追加
chmod +x JindoCliHttpAgent.pyHTTP Agent サービスの開始
python3 JindoCliHttpAgent.pyサービスが開始されると、ポート 8000 でリクエストをリッスンします。次の図は、起動結果の例を示しています。

Agent サービスの検証
新しいターミナルを開き、Agent が正しく動作しているかテストします。 と を実際の値に置き換えます。例:
oss://my-bucket.cn-hangzhou.oss-dls.aliyuncs.com/curl -X POST http://localhost:8000/execute \ -H "Content-Type: application/json" \ -d '{"command": "jindo fs -ls oss://<Bucketname>.<EndPoint>/"}'次の図に示すように、JSON 形式のファイルリストが返された場合、Agent は正常にデプロイされています。

ステップ 2: サーバー A に業務システムを統合する
メインコマンドは Jindo SDK のバージョンによって異なる場合があります。たとえば、一部の新しいバージョンでは jindo を使用し、一部の古いバージョンでは jindofs を使用します。
サーバーのコマンドラインで jindo -v または jindofs -v を実行して、環境に適した正しいコマンドを確認してください。このトピックのすべての例では jindo を使用しています。
Java API 操作を作成して Agent サービスを呼び出します。コード内の <サーバー B のプライベート IP> をサーバー B の実際のプライベート IP アドレスに置き換えます。
package com.example.jindotest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
@RestController
public class JindoAgentController {
@PostMapping("/jindo-agent-ls")
public ResponseEntity<String> executeJindoLs(@RequestParam String path) {
// パス形式を検証
if (path == null || !path.startsWith("oss://")) {
return ResponseEntity.badRequest().body("Invalid OSS path");
}
try {
// JSON リクエスト本文を構築
String requestBody = String.format("{\"command\": \"jindo fs -ls %s\"}", path);
// curl を使用して Agent サービスを呼び出し
ProcessBuilder processBuilder = new ProcessBuilder(
"curl", "-X", "POST", "http://<サーバー B のプライベート IP>:8000/execute",
"-H", "Content-Type: application/json",
"-d", requestBody
);
// プロセスを開始
Process process = processBuilder.start();
// 出力ストリームを読み取り
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line).append("\n");
}
// 実行結果を確認
int exitCode = process.waitFor();
if (exitCode == 0) {
return ResponseEntity.ok(result.toString());
} else {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Command failed with exit code: " + exitCode);
}
} catch (IOException | InterruptedException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error executing command: " + e.getMessage());
}
}
}本番環境では、パフォーマンスとエラー処理を向上させるために、curl の代わりに RestTemplate や WebClient などの HTTP クライアントライブラリを使用してください。
ステップ 3: 結果の検証
ネットワーク接続の確認
分離型デプロイメントを使用する場合、サーバーが相互に接続できることを確認してください。サーバー A で
ping <サーバー B のプライベート IP>を実行できます。パケット損失なしで安定した ping 応答を受信した場合、2 つのサーバーは接続されています。
Web インターフェイスでの検証
サンプル Web インターフェイスコードについては、「付録」をご参照ください。コード内のリクエストパスを
/jindo-agent-lsに変更します。http://<サーバー A のパブリック IP>:8080にアクセスして統合をテストできます。サーバー A でインバウンドトラフィックに対してポート 8080 を開く必要があります。oss://my-bucket.cn-hangzhou.oss-dls.aliyuncs.com/などのファイルパスを入力し、「List Files」ボタンをクリックします。インターフェイスに OSS ファイルリストが表示された場合、統合は成功です。
API 操作を使用した検証 (代替)
フロントエンドをデプロイできない場合は、curl を使用してバックエンド API 操作をテストできます。
curl -X POST "http://localhost:8080/jindo-agent-ls?path=oss://<bucket>.<Endpoint>/"ファイルリストが返された場合、統合は成功です。
検証が成功したら、他のコマンドをシステムに統合できます。詳細については、付録の「一般的な Jindo CLI コマンド」をご参照ください。
セキュリティに関する推奨事項
Jindo CLI は、OSS-HDFS サービスの構成管理とデータ削除機能を提供します。不適切な使用は深刻な結果を招く可能性があります。本番環境にサービスをデプロイする前に、テスト環境で徹底的なテストを実施する必要があります。
コア原則
最小権限: タスクを完了するために必要な最小限の権限のみを付与します。過剰な権限付与は避けてください。
アクセス制御: クライアント側で厳格な ID 検証と権限付与メカニズムを実装します。
同時実行制御: 同時操作の数を制限して、構成の競合やデータ管理の問題を防ぎます。
ネットワークセキュリティ
分離型デプロイメント: 分離型デプロイメントでは、Agent サーバーへのアクセスを業務サーバーのプライベート IP アドレスからのみ許可します。Agent サーバーをインターネットに公開しないでください。
ポート管理: セキュリティグループまたはファイアウォールを使用して、ポートへのアクセスを正確に制御します。
リファレンス
付録
一般的な Jindo CLI コマンド
コマンド | 説明 | 例 |
stat | ファイルのステータスを表示します。 |
|
ls | ディレクトリ内のファイルを一覧表示します。オプションの -R パラメーターは再帰的な一覧表示を示します。 |
|
du | ディレクトリ内のすべてのファイルのサイズを表示します。次のパラメーターはオプションです:
|
|
count | ファイルサイズとファイル数を表示します。オプションの -h パラメーターは、ファイルサイズを人間が読める形式で表示します。 |
|
listUserGroupsMappings | すべてのユーザーとグループの関係を一覧表示します。 |
|
dumpInventory | ファイルメタデータをエクスポートします。 |
|
putConfig | ディレクトリ保護などのサービス属性を設定します。 |
|
getConfig | ディレクトリ保護情報などの構成情報を取得します。 |
|
サンプル Web インターフェイスコード
次のコードを index.html として保存し、Spring Boot プロジェクトの src/main/resources/static/ ディレクトリに配置します:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Jindo CLI 管理インターフェイス</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1000px;
margin: 50px auto;
padding: 20px;
background-color: #f5f5f5;
}
.container {
background-color: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
text-align: center;
border-bottom: 2px solid #007bff;
padding-bottom: 10px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #555;
}
input[type="text"] {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
box-sizing: border-box;
}
button {
background-color: #007bff;
color: white;
padding: 12px 24px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin-right: 10px;
}
button:hover {
background-color: #0056b3;
}
button:disabled {
background-color: #6c757d;
cursor: not-allowed;
}
.result {
margin-top: 20px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #f8f9fa;
min-height: 100px;
font-family: monospace;
white-space: pre-wrap;
font-size: 14px;
}
.loading {
color: #007bff;
font-style: italic;
}
.error {
color: #dc3545;
background-color: #f8d7da;
border-color: #f5c6cb;
}
.success {
color: #155724;
background-color: #d4edda;
border-color: #c3e6cb;
}
</style>
</head>
<body>
<div class="container">
<h1> Jindo CLI 管理インターフェイス</h1>
<div class="form-group">
<label for="ossPath">OSS パス:</label>
<input type="text" id="ossPath"
value="oss://your-bucket-name.cn-hangzhou.oss-dls.aliyuncs.com/"
placeholder="OSS パスを入力 (例: oss://bucket-name.endpoint/)">
</div>
<div class="form-group">
<button onclick="listFiles()">ファイルの一覧表示 (ls)</button>
<button onclick="clearResult()">結果をクリア</button>
</div>
<div id="result" class="result">
Jindo CLI コマンドを実行する準備ができました...
</div>
</div>
<script>
function listFiles() {
const path = document.getElementById('ossPath').value;
const resultDiv = document.getElementById('result');
if (!path || !path.startsWith('oss://')) {
resultDiv.innerHTML = 'エラー: "oss://" で始まる有効な OSS パスを入力してください';
resultDiv.className = 'result error';
return;
}
// ロード中を表示
resultDiv.innerHTML = 'ロード中... お待ちください';
resultDiv.className = 'result loading';
// バックエンド API を呼び出し
fetch('/jindo-ls', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'path=' + encodeURIComponent(path)
})
.then(response => {
if (response.ok) {
return response.text();
} else {
throw new Error('HTTP ' + response.status + ': ' + response.statusText);
}
})
.then(data => {
resultDiv.innerHTML = '成功:\n\n' + data;
resultDiv.className = 'result success';
})
.catch(error => {
resultDiv.innerHTML = 'エラー:\n\n' + error.message;
resultDiv.className = 'result error';
});
}
function clearResult() {
document.getElementById('result').innerHTML = 'Jindo CLI コマンドを実行する準備ができました...';
document.getElementById('result').className = 'result';
}
// Enter キーで listFiles をトリガーできるようにする
document.getElementById('ossPath').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
listFiles();
}
});
</script>
</body>
</html>