S3 AWS SDK for JavaでMinIOのバケットとオブジェクトを操作する
はじめに
前回の記事でMiniIOを動かしてみたのですが、Javaのクライアントをいくつか試して見たいと思って、この記事ではAamazon SDKを使ってみようと思います。
前回同様MiniIOはDockerを用いて立てます。
使ってみる
環境
今回のプログラムを動かす環境は以下の通りです。
$ java --version openjdk 15 2020-09-15 OpenJDK Runtime Environment (build 15+36-1562) OpenJDK 64-Bit Server VM (build 15+36-1562, mixed mode, sharing) $ mvn -v Apache Maven 3.6.3 Maven home: /usr/share/maven Java version: 15, vendor: Oracle Corporation, runtime: /home/yuya-hirooka/.sdkman/candidates/java/15-open Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-65-generic", arch: "amd64", family: "unix" $ lsb_release -a LSB Version: core-11.1.0ubuntu2-noarch:security-11.1.0ubuntu2-noarch Distributor ID: Ubuntu Description: Ubuntu 20.04.2 LTS Release: 20.04 Codename: focal $ uname -srvmpio Linux 5.4.0-65-generic #73-Ubuntu SMP Mon Jan 18 17:25:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Lin
MiniIOを立てて置く
前述の通り、MiniIOをDockerで起動します。
以下のコマンドを実行します。
$ docker run -p 9000:9000 minio/minio server /data You are running an older version of MinIO released 2 days ago Update: Run `mc admin update` Endpoint: http://172.17.0.2:9000 http://127.0.0.1:9000 Browser Access: http://172.17.0.2:9000 http://127.0.0.1:9000 Object API (Amazon S3 compatible): Go: https://docs.min.io/docs/golang-client-quickstart-guide Java: https://docs.min.io/docs/java-client-quickstart-guide Python: https://docs.min.io/docs/python-client-quickstart-guide JavaScript: https://docs.min.io/docs/javascript-client-quickstart-guide .NET: https://docs.min.io/docs/dotnet-client-quickstart-guide Detected default credentials 'minioadmin:minioadmin', please change the credentials immediately using 'MINIO_ROOT_USER' and 'MINIO_ROOT_PASSWORD'
localhost:9000にアクセスし、ログインすると(アクセスキーとシークレットキーは両方共minioadmin
)以下のUIが開かれます。
プロジェクトを作成する
適当にMavenプロジェクトを作成し、Pomに以下の依存を追加します。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>aws-s3</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>15</maven.compiler.source> <maven.compiler.target>15</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-s3</artifactId> </dependency> <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>2.3.2</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-bom</artifactId> <version>1.11.327</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
AWS SDKにはBOMが用意されており、複数モジュール導入する場合でも互換性のあるバージョンを利用することができます。上記のように、dependencyManagementに
aws-java-sdk-bom`を追加してやることでこのBOMを利用することができます。
最新のバージョンのBOMはここ
からご確認ください。
AWSのSDKは利用するモジュールを個別に指定出来るため今回はs3のモジュールだけを依存に追加しています。
もし、すべてのモジュールを依存に追加したい場合はBOMを利用せずに以下の依存をPomに追加することで行なうことができます。
<dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk</artifactId> <version>1.11.327</version> </dependency> </dependencies>
AWS SDKはJava7以上で利用することが可能です。環境のところでも示しましたが、今回はJava15でSDKクラアントを試してみようと思います。
Java9以降に関しては、JAXBも入れる必要があるようなので依存に追加しています。
クレデンシャル情報をセットする
AWS 認証情報の設定には以下のような方法があります。
環境変数(
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY
)として設定する認証情報の明示的な指定を行なう
BasicAWSCredentials awsCreds = new BasicAWSCredentials("access_key_id", "secret_key_id"); AmazonS3 s3Client = AmazonS3ClientBuilder.standard() .withCredentials(new AWSStaticCredentialsProvider(awsCreds)) .build();
~/.aws/credentials
(WindowsはC:\Users\USERNAME\.aws\credentials
)に以下のようなクレデンシャルファイルを置く
[default] aws_access_key_id = your_access_key_id aws_secret_access_key = your_secret_access_key
今回は認証情報の明示的な指定
して利用するやり方を試してみようと思います。
バケットを操作する
ここまでで諸々の設定は終わったので早速SDKを用いてバケットを操作していきたいと思います。
今回は以下のようなイメージファイルを対象にして、バケットにアップロードダウンロード削除等々をやってみたいと思います。
S3クライアントの作成
まずは、ASKのS3クライアントを作成します。
public static void main(String[] args) { AmazonS3ClientBuildern endpointConfiguration = new AwsClientBuilder.EndpointConfiguration("http://localhost:9000/", Regions.DEFAULT_REGION.name()); AWSCredentials credentials = new BasicAWSCredentials("minioadmin", "minioadmin"); final AmazonS3 s3Client = AmazonS3ClientBuilder.standard() .withEndpointConfiguration(endpointConfiguration) .withPathStyleAccessEnabled(true) .withCredentials(new AWSStaticCredentialsProvider(credentials)) .build(); }
S3のクライアントを作成するためにはAmazonS3ClientBuilder
を利用します。withRegion()
メソッドにリージョンを指定しますが、今回はローカルのMinIOにつなぎに行きたいため、AwsClientBuilder.EndpointConfiguration
を利用して、エンドポイントの設定を行います(ちょっと、ドキュメント見つけられ無かったんですが、ここで指定するリージョンに関してはなんでも良さそうな感じがします)。
クレデンシャルの情報はBasicAWSCredentials
で作成することができます。MinIOのデフォルトのACCESS_KEY_ID/SECRET_ACCESS_KEY
はそれぞれminioadmin
なのでその設定を行っています。
これで、クライアントの作成ができました。今後は特に明示時なければここでインスタンス化したクライアント
バケットを作成してオブジェクトをアップロードする
それでは、まずはバケットを作成してオブジェクトをアップロードしてみます。
bucket01
という名前のバケットを作成して前述の画像をアップロードを行なうには以下のようなコードを書きます。
public class Main { //クライアント作成は省略 String bucketName = "bucket01"; if (!s3Client.doesBucketExistV2(bucketName)) { Bucket bucket = s3Client.createBucket(bucketName); } s3Client.putObject(bucketName, "henoheno.png", new File("/path/to/imageDir/henoheno.png")); } }
エラーハンドリングなどは省略していますがS3クライアントのcreateBucket
とputObject
メソッドを用いることで、バケットの作成と画像のアップロードが行えます。
コードを実行するとMinIOのUIから作成されたバケットとアップロードされた画像を確認することができます。
バケットにポリシーを適用する
ポリシーを作成して、クレデンシャル無しで画像をダウンロード出来るようにしてみます。
現状ではcURL等を用いた画像のダウンロードを行おうとすると、以下のように403の認可エラーが返ってきます。
$ curl http://localhost:9000/bucket01/henoheno.png -v * Trying 127.0.0.1:9000... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 9000 (#0) > GET /bucket01/henoheno.png HTTP/1.1 > Host: localhost:9000 > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 403 Forbidden < Accept-Ranges: bytes < Content-Length: 303 < Content-Security-Policy: block-all-mixed-content < Content-Type: application/xml < Server: MinIO < Vary: Origin < X-Amz-Request-Id: 16643FECF975B0A1 < X-Xss-Protection: 1; mode=block < Date: Tue, 16 Feb 2021 14:14:13 GMT < <?xml version="1.0" encoding="UTF-8"?> * Connection #0 to host localhost left intact <Error><Code>AccessDenied</Code><Message>Access Denied.</Message><Key>henoheno.png</Key><BucketName>bucket01</BucketName><Resource>/bucket01/henoheno.png</Resource><RequestId>16643FECF975B0A1</RequestId><HostId>7f44b0c0-57d7-4511-ac50-bc78b99478aa</HostId></Error>y
AWS SDK を用いてPolicyを設定する場合S3クライアントのsetBucketPolicy
メソッドを利用すると実行行えます。この場合、以下の2つの方法が取れます。
今回は後者のPolicyクラスを用いるやり方を試してみようと思います。
具体的には以下のようなコードを記述します。
public static void main(String[] args) { //クライアントの作成とバケット&オブジェクトの作成省略 String bucketName = "bucket01"; Statement statement = new Statement(Statement.Effect.Allow) .withPrincipals(Principal.AllUsers) .withActions(S3Actions.GetObject) .withResources(new Resource( "arn:aws:s3:::" + bucketName + "/*")); s3Client.setBucketPolicy(bucketName, new Policy().withStatements(statement).toJson()); }
上記のコードで作成されているポリシーはすべてのユーザに対して、Getのリクエストを許可しています。
再度、cURLで画像をダウンロードすると今度はきちんと画像がダウンロード出来ることが確認できます。
$ curl http://localhost:9000/bucket01/henoheno.png -v --output henoheno.ping % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 127.0.0.1:9000... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 9000 (#0) > GET /bucket01/henoheno.png HTTP/1.1 > Host: localhost:9000 > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Accept-Ranges: bytes < Content-Length: 18968 < Content-Security-Policy: block-all-mixed-content < Content-Type: image/png < ETag: "6524a1d06fc27ef8a835abd32bb7c34c" < Last-Modified: Tue, 16 Feb 2021 14:07:52 GMT < Server: MinIO < Vary: Origin < X-Amz-Request-Id: 166440FB47A5C193 < X-Xss-Protection: 1; mode=block < Date: Tue, 16 Feb 2021 14:33:34 GMT < { [18968 bytes data] 100 18968 100 18968 0 0 3704k 0 --:--:-- --:--:-- --:--:-- 3704k * Connection #0 to host localhost left intact $ ls henoheno.ping