少し間が空きましたが、AlluxioをS3ストレージとして使ってみたいと思います。
S3 Client - Docs | Alluxio Open Source
Alluxioは、すべてのS3の機能をサポートしているわけではないので、注意が必要です。
ドキュメントには、curlでアクセスするサンプルが記載されています。
こちらを参考に、ちょっと遊んでみましょう。
なお、書いている人はAWS S3を使ったことがありません。
環境
使ったAlluxioのバージョンは、1.7.0です。また、AlluxioのIPアドレスは「172.17.0.2」とし、ローカルモードでMasterもWorkerも単一のホストで
動作しているものとします。
REST APIでアクセス
curlを使って、REST APIにアクセスしてみます。使うにあたって、特にAccessKeyやSecretKeyの設定は不要です。
アクセスするURLは、「http://[IPアドレス]:[ポート(デフォルト39999)/api/v1/s3」となります。
39999ポートというのは、AlluxioのProxy Web Serviceのものになります。
Bucketの作成。
$ curl -i -XPUT http://172.17.0.2:39999/api/v1/s3/test-bucket HTTP/1.1 200 OK Date: Wed, 21 Mar 2018 14:41:55 GMT Content-Length: 0 Server: Jetty(9.2.z-SNAPSHOT)
オブジェクトの登録。
$ curl -i -XPUT http://172.17.0.2:39999/api/v1/s3/test-bucket/test-object -d 'Hello Alluxio!!' HTTP/1.1 200 OK Date: Wed, 21 Mar 2018 14:42:23 GMT ETag: "10d9c68bbf10a8b8cdef7f304d2f3055" Content-Length: 0 Server: Jetty(9.2.z-SNAPSHOT)
オブジェクトの取得。
$ curl -i http://172.17.0.2:39999/api/v1/s3/test-bucket/test-object HTTP/1.1 200 OK Date: Wed, 21 Mar 2018 14:43:43 GMT Last-Modified: Wed, 21 Mar 2018 14:42:24 GMT Content-Type: application/xml Content-Length: 15 Server: Jetty(9.2.z-SNAPSHOT) Hello Alluxio!!
オブジェクトの削除。
$ curl -i -XDELETE http://172.17.0.2:39999/api/v1/s3/test-bucket/test-object HTTP/1.1 204 No Content Date: Wed, 21 Mar 2018 14:46:27 GMT Server: Jetty(9.2.z-SNAPSHOT)
Bucketの削除。
$ curl -i -XDELETE http://172.17.0.2:39999/api/v1/s3/test-bucket HTTP/1.1 204 No Content Date: Wed, 21 Mar 2018 14:46:52 GMT Server: Jetty(9.2.z-SNAPSHOT)
とりあえずは、こんなところでしょうか。
AWSクライアントライブラリでアクセス
続いて、AWSのクライアントライブラリを使ってアクセスしていこうと思います。対象には、Java(というかGroovy)とNode.jsを選択。
いやぁ、てこずりました。
最終的に、以下の点に注意しておけばなんとかアクセスできるようになりました。
- AccessKeyとSecretKeyは、ダミーでいいので設定する
- エンドポイントのURLをAlluxioのものに設定して、かつPath Styleでのアクセスとする
- Bucket作成時のContent-Typeがapplication/octet-streamだとAlluxioが受け付けないため、Content-Typeの設定を外す(Node.jsは諦めた)
- Content-MD5の検証に失敗するのでオフにする(Javaのみ)
では、いってみます。
Java/Groovy
環境。
$ groovy -v
Groovy Version: 2.4.14 JVM: 1.8.0_151 Vendor: Oracle Corporation OS: Linux
とりあえず、このあたりを参考にaws-sdk-s3を使ってみます。
Amazon S3 バケットの作成、一覧表示、削除 - AWS SDK for Java
AWS SDK for Java を使用したオブジェクトのアップロード - Amazon Simple Storage Service
AWS SDK for Java を使用したオブジェクトの取得 - Amazon Simple Storage Service
AWS 認証情報の使用 - AWS SDK for Java
できあがったプログラムは、こちら。
alluxio-s3-client-example.groovy
@Grab('com.amazonaws:aws-java-sdk-s3:1.11.298') import com.amazonaws.ClientConfiguration import com.amazonaws.auth.AWSStaticCredentialsProvider import com.amazonaws.auth.BasicAWSCredentials import com.amazonaws.services.s3.AmazonS3ClientBuilder import com.amazonaws.services.s3.model.DeleteObjectRequest import com.amazonaws.services.s3.model.GetObjectRequest import com.amazonaws.services.s3.model.ObjectMetadata import com.amazonaws.services.s3.model.PutObjectRequest import com.amazonaws.client.builder.AwsClientBuilder // Content-MD5とEtagの検証を飛ばす System.setProperty('com.amazonaws.services.s3.disableGetObjectMD5Validation', 'false') System.setProperty('com.amazonaws.services.s3.disablePutObjectMD5Validation', 'false') // access-keyとsecret-access-keyはなんでもいい def awsCreds = new BasicAWSCredentials('test-access-key-id', 'test-secret-access-key') def s3Client = AmazonS3ClientBuilder .standard() .withCredentials(new AWSStaticCredentialsProvider(awsCreds)) // Alluxioのエンドポイントを設定 .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration('http://172.17.0.2:39999/api/v1/s3', null)) // Path Styleでのアクセスとする .withPathStyleAccessEnabled(true) .withChunkedEncodingDisabled(true) // Content-Typeがapplication/octet-streamだとBucketの作成で失敗するので切る .withClientConfiguration(new ClientConfiguration().withHeader('Content-Type', null)) .build() def bucketName = 'groovy-bucket' if (s3Client.doesBucketExist(bucketName)) { println("alredy exists bucket[$bucketName]") } else { s3Client.createBucket(bucketName) println("bucket[$bucketName] created") } def objectName = 'message' if (s3Client.doesObjectExist(bucketName, objectName)) { // no-op } else { // PUT object def message = 'Hello Groovy!!' def metadata = new ObjectMetadata() metadata.contentLength = message.getBytes('UTF-8').length def data = new ByteArrayInputStream(message.getBytes('UTF-8')) s3Client.putObject(new PutObjectRequest(bucketName, objectName, data, metadata)) println("put object[$objectName], [$message]") } // GET object def s3Object = s3Client.getObject(new GetObjectRequest(bucketName, objectName)) def content = s3Object.objectContent def message = content.getText('UTF-8') println("get object[$message]") // DELETE object s3Client.deleteObject(new DeleteObjectRequest(bucketName, objectName)) assert s3Client.doesObjectExist(bucketName, objectName) == false
だいたい先頭の方に書いていますが、このあたりが注意点そのままです。
// Content-MD5とEtagの検証を飛ばす System.setProperty('com.amazonaws.services.s3.disableGetObjectMD5Validation', 'false') System.setProperty('com.amazonaws.services.s3.disablePutObjectMD5Validation', 'false') // access-keyとsecret-access-keyはなんでもいい def awsCreds = new BasicAWSCredentials('test-access-key-id', 'test-secret-access-key') def s3Client = AmazonS3ClientBuilder .standard() .withCredentials(new AWSStaticCredentialsProvider(awsCreds)) // Alluxioのエンドポイントを設定 .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration('http://172.17.0.2:39999/api/v1/s3', null)) // Path Styleでのアクセスとする .withPathStyleAccessEnabled(true) .withChunkedEncodingDisabled(true) // Content-Typeがapplication/octet-streamだとBucketの作成で失敗するので切る .withClientConfiguration(new ClientConfiguration().withHeader('Content-Type', null)) .build()
Path Styleにしてあげないと、そもそもアクセスできません。また、Content-Typeをつぶしておかないと、Bucketが作れません。そして、オブジェクトを
登録する際にContent-MD5の検証にどうしても失敗するのでオフに。
なんなのでしょう…。
実行すると、こんな感じに。
## 1回目 $ groovy alluxio-s3-client-example.groovy bucket[groovy-bucket] created put object[message], [Hello Groovy!!] get object[Hello Groovy!!] ## 2回目(Bucket存在済み) $ groovy alluxio-s3-client-example.groovy alredy exists bucket[groovy-bucket] put object[message], [Hello Groovy!!] get object[Hello Groovy!!]
Node.js
環境。
$ node -v v9.8.0 $ npm -v 5.6.0
$ npm i --save aws-sdk
確認は、Jestで行うことにします。
$ npm i --save-dev jest
依存関係。
"dependencies": { "aws-sdk": "^2.212.1" }, "devDependencies": { "jest": "^22.4.2" }
"scripts": { "test": "jest" },
なお、AWSのJavaScriptクライアントライブラリでは、Bucketを作るのが厳しかった(Content-Typeの変更が苦しい)ので先に作っておくことにしました…。
$ curl -i -XPUT http://172.17.0.2:39999/api/v1/s3/nodejs-bucket
プログラムは、このあたりを参考に。
Node.js 内の AWS SDK for JavaScript | AWS
Class: AWS.S3 — AWS SDK for JavaScript
Class: AWS.Config — AWS SDK for JavaScript
できあがったコードは、こんな感じです。
test/alluxio-s3.test.js
const AWS = require("aws-sdk"); AWS.config.update({ accessKeyId: "access-key-id", secretAccessKey: "secret-access-key", s3: { endpoint: "http://172.17.0.2:39999/api/v1/s3" }, s3ForcePathStyle: true }); const s3 = new AWS.S3(); const bucketName = "nodejs-bucket"; const objectName = "nodejs-object"; const message = "Hello Node.js!!"; test("put-get object", done => { s3.putObject({ Bucket: bucketName, Key: objectName, Body: message }, (err, data) => { s3.getObject({ Bucket: bucketName, Key: objectName}, (err, data) => { expect(data.Body.toString('utf-8')).toEqual(message); done(); }); }); });
Node.jsの方だと、Content-MD5の検証には失敗しないんですよね…なんででしょう…?
とりあえず、動かすところまではなんとかなりました…。