CLOVER🍀

That was when it all began.

Amazon S3互換のオブゞェクトストレヌゞ、MinIOを詊す

これは、なにをしたくお曞いたもの

前々から1床詊しおおきたかった、Amazon S3互換のオブゞェクトストレヌゞMinIOを扱っおみようかなず。

MinIOずは

MinIOは、Amazon S3互換のオブゞェクトストレヌゞです。

MinIO | High Performance, Kubernetes Native Object Storage

Goで実装されおいたす。

GitHub - minio/minio: High Performance, Kubernetes Native Object Storage

3぀のラむセンス圢態があるようですが、サポヌトに差があるみたいですね。

Pricing

ドキュメントは、ベアメタル環境向け、Kubernetes環境向け、VMware Cloud Fundation環境向けのものがありたすが、
今回はベアメタル環境向けのものを参照したす。

MinIO High Performance Object Storage — MinIO Baremetal Documentation

MinIO Object Storage for Hybrid Cloud — MinIO Hybrid Cloud Documentation

機胜に぀いおは、こちら。

MinIO Server Features — MinIO Baremetal Documentation

Notification、バヌゞョニング、耐障害性、レプリケヌションを備えたす。

ちなみに、これらのドキュメントは珟圚䜜成䞭で、レガシヌ扱いずなったドキュメントもありたす。珟圚のドキュメントに
蚘茉がないものに぀いおは、レガシヌドキュメントの方を参照する必芁があるようです。

MinIO | The MinIO Quickstart Guide

たずえば、AWS CLIや各皮プログラミング蚀語向けのクラむアントラむブラリなどはレガシヌドキュメントにしか
ありたせん。

MinIO | AWS CLI with MinIO - Cookbook/Recipe

MinIO | Java Client Quickstart Guide

Amazon S3互換ずいうこずで、AWS CLIやAWS SDKが䜿えるわけですが、専甚のクラむアントコマンドや管理コマンド、
クラむアントラむブラリも備えおいたす。

MinIO Client (mc) — MinIO Baremetal Documentation

MinIO Admin (mc admin) — MinIO Baremetal Documentation

今回は、ずりあえずスタンドアロンでMinIOサヌバヌを立おお、クラむアントコマンドやAWS CLIでアクセスしお
みたいず思いたす。

環境

今回の環境は、こちら。Ubuntu Linux 20.04 LTSです。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.3 LTS
Release:    20.04
Codename:   focal


$ uname -srvmpio
Linux 5.4.0-84-generic #94-Ubuntu SMP Thu Aug 26 20:27:37 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

AWS CLIもむンストヌルしおおきたした。

$ aws --version
aws-cli/2.2.36 Python/3.8.8 Linux/5.4.0-84-generic exe/x86_64.ubuntu.20 prompt/off

MinIOサヌバヌをむンストヌルする

たずは、MinIOサヌバヌをむンストヌルしたす。

MinIO | Code and downloads to create high performance object storage

むンストヌル方法は実行バむナリ、rpmパッケヌゞ、debパッケヌゞ、そしおDockerむメヌゞがありたすが、今回は
debパッケヌゞのものを䜿うこずにしたす。

debパッケヌゞをダりンロヌドしお

$ curl -O https://dl.min.io/server/minio/release/linux-amd64/minio_20210903035613.0.0_amd64.deb

むンストヌル。

$ sudo dpkg -i minio_20210903035613.0.0_amd64.deb

バヌゞョン。

$ minio --version
minio version RELEASE.2021-09-03T03-56-13Z

実行方法に぀いおはこちらに蚘茉がありたすが、

MinIO Server — MinIO Baremetal Documentation

ヘルプも確認。

$ minio --help
NAME:
  minio - High Performance Object Storage

DESCRIPTION:
  Build high performance data infrastructure for machine learning, analytics and application data workloads with MinIO

USAGE:
  minio [FLAGS] COMMAND [ARGS...]

COMMANDS:
  server   start object storage server
  gateway  start object storage gateway
  
FLAGS:
  --certs-dir value, -S value  path to certs directory (default: "/home/vagrant/.minio/certs")
  --quiet                      disable startup information
  --anonymous                  hide sensitive information from logging
  --json                       output server logs and startup information in json format
  --help, -h                   show help
  --version, -v                print the version
  
VERSION:
  RELEASE.2021-09-03T03-56-13Z

起動方法にserverずgatewayがあるようです。

MinIO Gatewayは、AWSやAzureのオブゞェクトストレヌゞをバック゚ンドにするプロセスです。

今回は、serverの方を䜿いたす。

$ minio server --help
NAME:
  minio server - start object storage server

USAGE:
  minio server [FLAGS] DIR1 [DIR2..]
  minio server [FLAGS] DIR{1...64}
  minio server [FLAGS] DIR{1...64} DIR{65...128}

DIR:
  DIR points to a directory on a filesystem. When you want to combine
  multiple drives into a single large system, pass one directory per
  filesystem separated by space. You may also use a '...' convention
  to abbreviate the directory arguments. Remote directories in a
  distributed setup are encoded as HTTP(s) URIs.

FLAGS:
  --address value              bind to a specific ADDRESS:PORT, ADDRESS can be an IP or hostname (default: ":9000")
  --console-address value      bind to a specific ADDRESS:PORT for embedded Console UI, ADDRESS can be an IP or hostname
  --certs-dir value, -S value  path to certs directory (default: "/home/vagrant/.minio/certs")
  --quiet                      disable startup information
  --anonymous                  hide sensitive information from logging
  --json                       output server logs and startup information in json format
  --help, -h                   show help
  
EXAMPLES:
  1. Start minio server on "/home/shared" directory.
     $ minio server /home/shared

  2. Start single node server with 64 local drives "/mnt/data1" to "/mnt/data64".
     $ minio server /mnt/data{1...64}

  3. Start distributed minio server on an 32 node setup with 32 drives each, run following command on all the nodes
     $ export MINIO_ROOT_USER=minio
     $ export MINIO_ROOT_PASSWORD=miniostorage
     $ minio server http://node{1...32}.example.com/mnt/export{1...32}

  4. Start distributed minio server in an expanded setup, run the following command on all the nodes
     $ export MINIO_ROOT_USER=minio
     $ export MINIO_ROOT_PASSWORD=miniostorage
     $ minio server http://node{1...16}.example.com/mnt/export{1...32} \
            http://node{17...64}.example.com/mnt/export{1...64}

デヌタを保存するためのディレクトリが必芁なようなので、䜜成しお

$ mkdir data

起動。

$ minio server data
API: http://192.168.121.136:9000  http://192.168.33.10:9000  http://127.0.0.1:9000     
RootUser: minioadmin 
RootPass: minioadmin 

Console: http://192.168.121.136:42799 http://192.168.33.10:42799 http://127.0.0.1:42799   
RootUser: minioadmin 
RootPass: minioadmin 

Command-line: https://docs.min.io/docs/minio-client-quickstart-guide
   $ mc alias set myminio http://192.168.121.136:9000 minioadmin minioadmin

Documentation: https://docs.min.io

WARNING: Console endpoint is listening on a dynamic port (42799), please use --console-address ":PORT" to choose a static port.
WARNING: Detected default credentials 'minioadmin:minioadmin', we recommend that you change these values with 'MINIO_ROOT_USER' and 'MINIO_ROOT_PASSWORD' environment variables

特に指定しないず、Web Consoleのポヌトがランダムに決たるようなので、指定しおおきたす。ドキュメントに習っお
9001にしおおきたした。

$ minio server data --console-address ":9001"
API: http://192.168.121.136:9000  http://192.168.33.10:9000  http://127.0.0.1:9000     
RootUser: minioadmin 
RootPass: minioadmin 

Console: http://192.168.121.136:9001 http://192.168.33.10:9001 http://127.0.0.1:9001   
RootUser: minioadmin 
RootPass: minioadmin 

Command-line: https://docs.min.io/docs/minio-client-quickstart-guide
   $ mc alias set myminio http://192.168.121.136:9000 minioadmin minioadmin

Documentation: https://docs.min.io
WARNING: Detected default credentials 'minioadmin:minioadmin', we recommend that you change these values with 'MINIO_ROOT_USER' and 'MINIO_ROOT_PASSWORD' environment variables

起動時に衚瀺されおいるのは、MinIOの管理ナヌザヌの名前ずパスワヌドでもあり、AWS SDKのクレデンシャルでも
ありたす。

これは、MINIO_ROOT_USERおよびMINIO_ROOT_PASSWORD環境倉数で指定するこずができたす。

$ MINIO_ROOT_USER=admin MINIO_ROOT_PASSWORD=password minio server data --console-address ":9001"
API: http://192.168.121.136:9000  http://192.168.33.10:9000  http://127.0.0.1:9000     
RootUser: admin 
RootPass: password 

Console: http://192.168.121.136:9001 http://192.168.33.10:9001 http://127.0.0.1:9001   
RootUser: admin 
RootPass: password 

Command-line: https://docs.min.io/docs/minio-client-quickstart-guide
   $ mc alias set myminio http://192.168.121.136:9000 admin password

Documentation: https://docs.min.io

今回は、デフォルトのminioadmin / minioadminをそのたた䜿うこずにしたす。

$ minio server data --console-address ":9001"

MinIOクラむアントをむンストヌルする

続いおは、MinIOクラむアントをむンストヌルしたしょう。

こちらも、debパッケヌゞでむンストヌルしたす。ダりンロヌドしお

$ curl -O https://dl.min.io/client/mc/release/linux-amd64/mcli_20210902092127.0.0_amd64.deb

むンストヌル。

$ sudo dpkg -i mcli_20210902092127.0.0_amd64.deb

バヌゞョン。

$ mcli --version
mcli version RELEASE.2021-09-02T09-21-27Z

ちなみに、実行可胜ファむルでむンストヌルするずmcコマンドずなり、rpmパッケヌゞやdebパッケヌゞでむンストヌル
するずmcliコマンドになりたす。

MinIO | Code and downloads to create high performance object storage

どちらにせよ、むンストヌルされるのは単䞀バむナリだけですが。

$ dpkg -L mcli
/usr
/usr/local
/usr/local/bin
/usr/local/bin/mcli

ダりンロヌドペヌゞに蚘茉されおいるコマンドに埓い、myminioずいう名前にロヌカルのMinIOを゚むリアスずしお
蚭定したす。この時、ナヌザヌ名ずパスワヌドも必芁です。

$ mcli alias set myminio http://localhost:9000 minioadmin minioadmin

MinIOサヌバヌの情報を確認。

$ mcli admin info myminio
●  localhost:9000
   Uptime: 6 minutes 
   Version: 2021-09-03T03:56:13Z
   Network: 1/1 OK 

いく぀かコマンドを詊しおみたす。

バケットの䜜成。

$ mcli mb myminio/my-bucket
Bucket created successfully `myminio/my-bucket`.

確認。

$ mcli ls myminio
[2021-09-10 22:58:17 JST]     0B my-bucket/

ロヌカルでファむルを䜜成しお

$ echo 'Hello World' > hello.txt

アップロヌド。

$ mcli cp hello.txt myminio/my-bucket/hello.txt

ダりンロヌド。

$ mcli cp myminio/my-bucket/hello.txt hello-copy.txt


$ cat hello-copy.txt
Hello World

ファむル削陀。

$ mcli rm myminio/my-bucket/hello.txt
Removing `myminio/my-bucket/hello.txt`.

バケット削陀。

$ mcli rb myminio/my-bucket
Removed `myminio/my-bucket` successfully.

もう1床バケットの䜜成ずファむルアップロヌド、そしおバケットをもうひず぀䜜成したす。

$ mcli mb myminio/my-bucket
$ mcli cp hello.txt myminio/my-bucket/hello.txt


$ mcli mb myminio/my-bucket2

起動時に--console-address ":9001"を指定したので、http://[MinIOサヌバヌのIPアドレス]:9001でWeb Consoleに
アクセスできたす。

MinIO Console — MinIO Baremetal Documentation

ログむンアカりントは、起動時に衚瀺されたナヌザヌ名ずパスワヌドです。

Web Consoleでは、Minioサヌバヌの情報を参照したり、バケットぞのアクセス、ナヌザヌ管理などができたりしたす。

f:id:Kazuhira:20210910230530p:plain

f:id:Kazuhira:20210910230550p:plain

AWS CLIでアクセスする

続いお、AWS CLIでアクセスしおみたしょう。

クレデンシャルずリヌゞョンは、環境倉数で指定するこずにしたす。

$ export AWS_ACCESS_KEY_ID=minioadmin
$ export AWS_SECRET_ACCESS_KEY=minioadmin
$ export AWS_DEFAULT_REGION=ap-northeast-1

AWS CLIでアクセスする際は、--endpoint-url http://[MinIOサヌバヌのIPアドレス]:9000を指定したす。

$ aws --endpoint-url http://localhost:9000 s3 ls
2021-09-10 23:03:54 my-bucket
2021-09-10 23:04:19 my-bucket2

先ほど、MinIOのクラむアントツヌルで䜜成したバケットが芋えおいたす。

ファむルのダりンロヌド。

$ aws --endpoint-url http://localhost:9000 s3 cp s3://my-bucket/hello.txt -
Hello World

こちらもOKそうですね。

systemdでMinIOサヌバヌを起動する

ずころで、MinIOサヌバヌのパッケヌゞを芋るず、どうやらsystemdの定矩ファむルが含たれおいるようです。

$ dpkg -L minio
/usr
/usr/local
/usr/local/bin
/usr/local/bin/minio
/etc
/etc/systemd
/etc/systemd/system
/etc/systemd/system/minio.service

systemdのナニット定矩ファむルは、こんな感じでした。

/etc/systemd/system/minio.service

[Unit]
Description=MinIO
Documentation=https://docs.min.io
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/bin/minio

[Service]
WorkingDirectory=/usr/local

User=minio-user
Group=minio-user
ProtectProc=invisible

EnvironmentFile=-/etc/default/minio
ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/default/minio\"; exit 1; fi"
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES

# Let systemd restart this service always
Restart=always

# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=65536

# Specifies the maximum number of threads this process can create
TasksMax=infinity

# Disable timeout logic and wait until process is stopped
TimeoutStopSec=infinity
SendSIGKILL=no

[Install]
WantedBy=multi-user.target

# Built for ${project.name}-${project.version} (${project.name})

有効化しお

$ sudo systemctl enable minio
Created symlink /etc/systemd/system/multi-user.target.wants/minio.service → /etc/systemd/system/minio.service.

起動しようずするず、倱敗したす。

$ sudo systemctl start minio
Job for minio.service failed because the control process exited with error code.
See "systemctl status minio.service" and "journalctl -xe" for details.

ログを芋るず、クレデンシャルに問題があるようです。

 9月 10 23:18:28 server systemd[1]: Starting MinIO...
 9月 10 23:18:28 server systemd[1989]: minio.service: Failed to determine user credentials: No such process
 9月 10 23:18:28 server systemd[1989]: minio.service: Failed at step USER spawning /bin/bash: No such process

ナニット定矩のナヌザヌおよびグルヌプ指定を芋るず、存圚しないナヌザヌずグルヌプが指定されおいたす。

User=minio-user
Group=minio-user

このたただず起動しないので、ナヌザヌを远加したす。

$ sudo useradd minio-user

これでもただ倱敗したす。

$ sudo systemctl start minio
Job for minio.service failed because the control process exited with error code.
See "systemctl status minio.service" and "journalctl -xe" for details.

゚ラヌメッセヌゞを確認するず、/etc/default/minioずいうファむルに環境倉数の定矩がないず蚀っおいたす。

 9月 10 23:19:44 server systemd[1]: Starting MinIO...
 9月 10 23:19:44 server bash[2030]: Variable MINIO_VOLUMES not set in /etc/default/minio

これは、ExecStartPreおよびExecStartを芋るず理由がわかりたす。

ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/default/minio\"; exit 1; fi"
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES

起動時の蚭定をしなければいけないようです。

では、デヌタを保存するディレクトリを䜜成しお

$ sudo mkdir -p /var/lib/minio/data
$ sudo chown -R minio-user:minio-user /var/lib/minio

/etc/default/minioファむルも䜜成したす。ここで、起動時のオプションずデヌタの保存先を指定したす。

/etc/default/minio

MINIO_OPTS=--console-address :9001
MINIO_VOLUMES=/var/lib/minio/data

今床は起動するようになりたす。

$ sudo systemctl start minio

デフォルトのクレデンシャルだず譊告が出るので

 9月 10 23:26:00 server minio[2273]: WARNING: Detected default credentials 'minioadmin:minioadmin', we recommend that you change these values with 'MINIO_ROOT_USER' and 'MINIO_ROOT_PASSWORD' environment variables

奜みに応じお、MINIO_ROOT_USERおよびMINIO_ROOT_PASSWORDを蚭定しおクレデンシャルを指定するず
よいでしょう。

/etc/default/minio

MINIO_OPTS=--console-address :9001
MINIO_VOLUMES=/var/lib/minio/data
MINIO_ROOT_USER=root-user
MINIO_ROOT_PASSWORD=password

たずめ

Amazon S3互換のオブゞェクトストレヌゞ、MinIOを詊しおみたした。

MinIOのクラむアントコマンドは最初は戞惑ったりしたしたが、あずはそれほど困りたせんでしたね。

お手軜に䜿えそうなので、Amazon S3の代わりが欲しい時はLocalStackず䜿い分けおいこうかなず思いたす。

Infinispan Server 12.1で、Hot Rod ClientRemoteCacheManagerAdminからCacheを䜜成する

これは、なにをしたくお曞いたもの

InfinispanのHot Rod Clientには、Cacheの䜜成、削陀などを行う管理APIがありたす。

今たでも䜕回か䜿っおいたのですが、よく忘れるので単䜓でメモしおおくこずにしたした。

RemoteCacheManagerAdminむンタヌフェヌス

RemoteCacheManagerAdminずいうむンタヌフェヌスを䜿うこずで、Infinispan ServerにおけるCacheの䜜成、削陀などが
できたす。

RemoteCacheManagerAdmin (Infinispan JavaDoc 12.1.10.Final API)

クラスタ構成のInfinispan Serverであっおも、各Nodeに䞀気にCacheを䜜れたりするので䟿利です。
各Nodeそれぞれに察しお、XMLファむルを修正しなくおすみたすからね。
もっずもCLIで操䜜した堎合も同じように各NodeにCacheの定矩を反映しおくれるのですが、APIで曞けた方が
䟿利な時もあるかな、ず。

ちなみに、CLIであっおも管理APIであっおも、䜜成したCacheの情報はクラスタに新しいNodeが参加した堎合、
そのCacheの情報もコピヌされたす。この点でも䟿利です。

ドキュメントずしおは、このあたりに蚘茉がありたす。

Deploying and Configuring Infinispan Servers / Creating Remote Caches with Hot Rod Clients

Hot Rod Java Clients / Creating Remote Caches with Hot Rod Clients

曞かれおいる内容は同じなのですが。

RemoteCacheManagerAdminではなく、RemoteCacheConfigurationBuilder#configurationでCacheの定矩を行う方法も
玹介されおいるのですが、こちらはパスしたす 。

RemoteCacheConfigurationBuilder (Infinispan JavaDoc 12.1.10.Final API)

環境

今回の環境は、こちらです。

$ java --version
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.8.2 (ea98e05a04480131370aa0c110b8c54cf726c06f)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.11, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-81-generic", arch: "amd64", family: "unix"

Infinispan Serverは12.1.7.Finalを䜿い、172.17.0.2〜4の3 Node甚意したす。

準備

各Nodeには、adminグルヌプに属するナヌザヌず、applicationグルヌプに属するナヌザヌをそれぞれ䜜成しおおきたす。

$ bin/cli.sh user create -g admin -p password admin-user
$ bin/cli.sh user create -g application -p password app-user

各グルヌプは、ClusterRoleMapperを意識しおいたす。

Deploying and Configuring Infinispan Servers / User Roles and Permissions

Cacheの定矩などは行いたせん。

Maven䟝存関係などはこちら。

    <dependencies>
        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-client-hotrod</artifactId>
            <version>12.1.7.Final</version>
        </dependency>

        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-core</artifactId>
            <version>12.1.7.Final</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.7.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.7.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.20.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
        </plugins>
    </build>

今回のお題には、最䜎限infinispan-client-hotrodが必芁です。infinispan-coreはなくおもRemoteCacheManagerAdminを
䜿うこずはできるのですが、あった方がCacheの定矩をするには䟿利かなず思いたす。理由は埌述したす。

動䜜確認はテストコヌドで行うので、テスト甚のラむブラリも远加しおおきたす。

テストコヌドの雛圢

テストコヌドの雛圢は、こちら。

src/test/java/org/littlewings/remote/admin/CreateCacheTest.java

package org.littlewings.remote.admin;

import java.util.stream.IntStream;
import java.util.stream.Stream;

import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.client.hotrod.RemoteCacheManagerAdmin;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class CreateCacheTest {

    private static String createUri(String userName, String password) {
        return String.format("hotrod://%s:%s@172.17.0.2:11222,172.17.0.3:11222,172.17.0.4:11222", userName, password);
    }

    // ここに、テストコヌドを曞く
}

createUriずいうメ゜ッドは、接続するナヌザヌ名ずパスワヌドを䜿っお、Infinispan Serverぞ接続するためのURIを
䜜成するメ゜ッドです。こちらを接続情報ずしたす。

RemoteCacheManagerAdminを䜿っおCacheを䜜成しおみる

では、RemoteCacheManagerAdminを䜿っおCacheを䜜成しおみたす。

䜿甚䟋はこちら。

    @Test
    public void createCacheByAdminUser() {
        String uri = createUri("admin-user", "password");

        try (RemoteCacheManager manager = new RemoteCacheManager(uri)) {
            RemoteCacheManagerAdmin admin = manager.administration();

            org.infinispan.configuration.cache.Configuration cacheConfiguration =
                    new org.infinispan.configuration.cache.ConfigurationBuilder()
                            .clustering()
                            .cacheMode(org.infinispan.configuration.cache.CacheMode.DIST_SYNC)
                            .encoding().key().mediaType("application/x-protostream")
                            .encoding().value().mediaType("application/x-protostream")
                            .build();

            RemoteCache<String, String> cache = admin.createCache("distCache", cacheConfiguration);

            IntStream.rangeClosed(1, 100).forEach(i -> cache.put("key" + i, "value" + i));
            assertThat(cache.size()).isEqualTo(100);

            admin.removeCache("distCache");
        }
    }

RemoteCacheManagerAdminは、RemoteCacheManager#administrationで取埗できたす。
なお、接続にはadminグルヌプに属しおいるナヌザヌを䜿甚しおいたす。

        try (RemoteCacheManager manager = new RemoteCacheManager(uri)) {
            RemoteCacheManagerAdmin admin = manager.administration();

Cacheの䜜成はRemoteCacheManagerAdmin#createCacheで行えばよいのですが

            RemoteCache<String, String> cache = admin.createCache("distCache", cacheConfiguration);

この時に䜜成するCacheの定矩情報が必芁です。

Cacheの定矩情報はStringずXMLStringConfigurationから䜜成でき、䟝存関係もinfinispan-client-hotrodだけで枈みたすが
Cacheの定矩を文字列で甚意するこずになり、たあ面倒です。この䜜り方は、最埌に茉せたいず思いたす。

もうひず぀は、Embedded CacheでのConfigurationを䜿う方法です。こちらを䜿うずAPIでCache定矩を組み立おられるの
ですが、infinispan-coreが必芁になりたす。䟝存関係にinfinispan-coreを远加したのはこれが理由ですね。

こんな感じでCacheの定矩情報を䜜成したす。infinispan-client-hotrodの範囲倖であるこずがわかるようにFQCNで
クラス名を曞いおいたす。

            org.infinispan.configuration.cache.Configuration cacheConfiguration =
                    new org.infinispan.configuration.cache.ConfigurationBuilder()
                            .clustering()
                            .cacheMode(org.infinispan.configuration.cache.CacheMode.DIST_SYNC)
                            .encoding().key().mediaType("application/x-protostream")
                            .encoding().value().mediaType("application/x-protostream")
                            .build();

Cacheの皮類ずしおは、Distributed Cacheずしたした。

これでクラスタに参加する各NodeにCacheが䜜成され、すぐに䜿うこずができたす。

            IntStream.rangeClosed(1, 100).forEach(i -> cache.put("key" + i, "value" + i));
            assertThat(cache.size()).isEqualTo(100);

RemoteCacheManagerAdminを䜿うず、Cacheの削陀も可胜です。

            admin.removeCache("distCache");

なお、Cacheの䜜成にはADMIN暩限が必芁です。このため、applicationグルヌプに属したナヌザヌでは
RemoteCacheManagerAdmin#createCacheの呌び出しに倱敗したす。

    @Test
    public void createCacheByApplicationUser() {
        String uri = createUri("app-user", "password");

        try (RemoteCacheManager manager = new RemoteCacheManager(uri)) {
            RemoteCacheManagerAdmin admin = manager.administration();

            org.infinispan.configuration.cache.Configuration cacheConfiguration =
                    new org.infinispan.configuration.cache.ConfigurationBuilder()
                            .clustering()
                            .cacheMode(org.infinispan.configuration.cache.CacheMode.DIST_SYNC)
                            .encoding().key().mediaType("application/x-protostream")
                            .encoding().value().mediaType("application/x-protostream")
                            .build();

            assertThatThrownBy(() -> admin.createCache("distCache", cacheConfiguration))
                    .hasMessageContaining("org.infinispan.commons.CacheException: java.lang.SecurityException: ISPN000287: Unauthorized access: subject 'Subject with principal(s): [app-user, RolePrincipal{name='application'},")
                    .hasMessageContaining("' lacks 'ADMIN' permission")
                    .isInstanceOf(HotRodClientException.class);
        }
    }

ClusterRoleMapperでADMIN暩限が䜿えるのは、ALLが割り圓おられおいるadminグルヌプしかありたせん。

RemoteCacheManagerAdmin#getOrCreateCacheを䜿う

RemoteCacheManagerAdmin#createCacheでCacheの䜜成が可胜なこずはわかりたしたが、䜜成察象のCacheがすでに
存圚しおいる堎合は䟋倖がスロヌされたす。

    @Test
    public void recreateCache() {
        String uri = createUri("admin-user", "password");

        try (RemoteCacheManager manager = new RemoteCacheManager(uri)) {
            RemoteCacheManagerAdmin admin = manager.administration();

            org.infinispan.configuration.cache.Configuration cacheConfiguration =
                    new org.infinispan.configuration.cache.ConfigurationBuilder()
                            .clustering()
                            .cacheMode(org.infinispan.configuration.cache.CacheMode.DIST_SYNC)
                            .encoding().key().mediaType("application/x-protostream")
                            .encoding().value().mediaType("application/x-protostream")
                            .build();

            assertThat(admin.createCache("distCache", cacheConfiguration))
                    .isNotNull()
                    .isInstanceOf(RemoteCache.class);

            assertThatThrownBy(() -> admin.createCache("distCache", cacheConfiguration))
                    .hasMessage("org.infinispan.commons.CacheConfigurationException: ISPN000507: Cache distCache already exists")
                    .isInstanceOf(HotRodClientException.class);

            admin.removeCache("distCache");
        }
    }

これを避ける堎合は、RemoteCacheManagerAdmin#getOrCreateCacheを䜿えばOKです。

    @Test
    public void createOrGetCache() {
        String uri = createUri("admin-user", "password");

        try (RemoteCacheManager manager = new RemoteCacheManager(uri)) {
            RemoteCacheManagerAdmin admin = manager.administration();

            org.infinispan.configuration.cache.Configuration cacheConfiguration =
                    new org.infinispan.configuration.cache.ConfigurationBuilder()
                            .clustering()
                            .cacheMode(org.infinispan.configuration.cache.CacheMode.DIST_SYNC)
                            .encoding().key().mediaType("application/x-protostream")
                            .encoding().value().mediaType("application/x-protostream")
                            .build();

            assertThat(admin.createCache("distCache", cacheConfiguration))
                    .isNotNull()
                    .isInstanceOf(RemoteCache.class);
            assertThat(admin.getOrCreateCache("distCache", cacheConfiguration))
                    .isNotNull()
                    .isInstanceOf(RemoteCache.class);

            admin.removeCache("distCache");

            assertThat(admin.getOrCreateCache("distCache", cacheConfiguration))
                    .isNotNull()
                    .isInstanceOf(RemoteCache.class);

            admin.removeCache("distCache");
        }
    }

察象のCacheがなければ䜜成し、すでに存圚しおいればそれを䜿うずいう動䜜になりたす。

最初からこれを䜿ったらいいのでは、ずいう話もありたすね。

耇数のCacheを䜜成しおみる

ここたでDistributed Cacheばかり䜜っおいたしたが、さらにReplicated Cacheも䜜っおみたしょう。

    @Test
    public void createVariousCache() {
        String uri = createUri("admin-user", "password");

        try (RemoteCacheManager manager = new RemoteCacheManager(uri)) {
            RemoteCacheManagerAdmin admin = manager.administration();

            org.infinispan.configuration.cache.Configuration distCacheConfiguration =
                    new org.infinispan.configuration.cache.ConfigurationBuilder()
                            .clustering()
                            .cacheMode(org.infinispan.configuration.cache.CacheMode.DIST_SYNC)
                            .encoding().key().mediaType("application/x-protostream")
                            .encoding().value().mediaType("application/x-protostream")
                            .build();

            org.infinispan.configuration.cache.Configuration replCacheConfiguration =
                    new org.infinispan.configuration.cache.ConfigurationBuilder()
                            .clustering()
                            .cacheMode(org.infinispan.configuration.cache.CacheMode.REPL_SYNC)
                            .encoding().key().mediaType("application/x-protostream")
                            .encoding().value().mediaType("application/x-protostream")
                            .build();


            RemoteCache<String, String> distCache = admin.getOrCreateCache("distCache", distCacheConfiguration);
            RemoteCache<String, String> replCache = admin.getOrCreateCache("replCache", replCacheConfiguration);

            IntStream.rangeClosed(1, 100).forEach(i -> distCache.put("key" + i, "value" + i));
            assertThat(distCache.size()).isEqualTo(100);

            IntStream.rangeClosed(1, 100).forEach(i -> replCache.put("key" + i, "value" + i));
            assertThat(replCache.size()).isEqualTo(100);

            admin.removeCache("distCache");
            admin.removeCache("replCache");
        }
    }

たあ、ちょっずしたオマケ的な感じですが 。

で、ここたでCacheを䜜成しおきたしたが、Infinispan Server偎にどのように存圚するかは特に曞いおきたせんでした。

Cacheを䜜成しおも、infinispan.xmlそのものは倉わりたせん。

server/conf/infinispan.xml

   <cache-container name="default" statistics="true">
      <transport cluster="${infinispan.cluster.name:cluster}" stack="${infinispan.cluster.stack:tcp}" node-name="${infinispan.node.name:}"/>
      <security>
         <authorization/>
      </security>
   </cache-container>

動的に䜜成したCacheは、server/data/caches.xmlファむルに蚘茉されたす。

server/data/caches.xml

<?xml version="1.0"?>
<infinispan xmlns="urn:infinispan:config:12.1">
    <cache-container>
        <replicated-cache mode="SYNC" remote-timeout="17500" name="replCache" statistics="true">
            <encoding>
                <key media-type="application/x-protostream"/>
                <value media-type="application/x-protostream"/>
            </encoding>
            <locking concurrency-level="1000" acquire-timeout="15000" striping="false"/>
            <state-transfer timeout="60000"/>
        </replicated-cache>
        <distributed-cache mode="SYNC" remote-timeout="17500" name="distCache" statistics="true">
            <encoding>
                <key media-type="application/x-protostream"/>
                <value media-type="application/x-protostream"/>
            </encoding>
            <locking concurrency-level="1000" acquire-timeout="15000" striping="false"/>
            <state-transfer timeout="60000"/>
        </distributed-cache>
    </cache-container>
</infinispan>

ConfigurationBuilderでCacheの定矩を行った時はほが最䜎限の蚭定しか行っおいなかったのに、いろいろず
デフォルト倀が埋め蟌たれおいたすね。

たた、最初にも曞きたしたが、クラスタに新しいNodeが参加した堎合は、このファむルも新しいNodeに展開されたす。

文字列でCache定矩を行う

最埌に、Cacheの定矩を文字列で䜜成したす。ドキュメントに蚘茉されおいたのは、この方法ですね。

    @Test
    public void createCacheByString() {
        String uri = createUri("admin-user", "password");

        try (RemoteCacheManager manager = new RemoteCacheManager(uri)) {
            RemoteCacheManagerAdmin admin = manager.administration();

            String cacheConfigurationAsString =
                    "        <distributed-cache name=\"distCache\">\n" +
                            "            <encoding>\n" +
                            "                <key media-type=\"application/x-protostream\"/>\n" +
                            "                <value media-type=\"application/x-protostream\"/>\n" +
                            "            </encoding>\n" +
                            "        </distributed-cache>";

            org.infinispan.commons.configuration.XMLStringConfiguration cacheConfiguration =
                    new org.infinispan.commons.configuration.XMLStringConfiguration(cacheConfigurationAsString);

            RemoteCache<String, String> distCache = admin.getOrCreateCache("distCache", cacheConfiguration);

            IntStream.rangeClosed(1, 100).forEach(i -> distCache.put("key" + i, "value" + i));
            assertThat(distCache.size()).isEqualTo(100);

            admin.removeCache("distCache");

            assertThatThrownBy(() -> admin.getOrCreateCache("distributedCache", cacheConfiguration))
                    .hasMessageContaining("org.infinispan.commons.CacheConfigurationException: ISPN005031: The supplied configuration for cache 'distributedCache' is missing a named configuration for it:")
                    .isInstanceOf(HotRodClientException.class);
        }
    }

ポむントはこちらで、Cache定矩の断片をXMLStringConfigurationずしお䜜成したす。

            String cacheConfigurationAsString =
                    "        <distributed-cache name=\"distCache\">\n" +
                            "            <encoding>\n" +
                            "                <key media-type=\"application/x-protostream\"/>\n" +
                            "                <value media-type=\"application/x-protostream\"/>\n" +
                            "            </encoding>\n" +
                            "        </distributed-cache>";

            org.infinispan.commons.configuration.XMLStringConfiguration cacheConfiguration =
                    new org.infinispan.commons.configuration.XMLStringConfiguration(cacheConfigurationAsString);

これをRemoteCacheManagerAdmin#createCacheやRemoteCacheManagerAdmin#getOrCreateCacheに枡せば
OKです。

            RemoteCache<String, String> distCache = admin.getOrCreateCache("distCache", cacheConfiguration);

この方法であればinfinispan-client-hotrodの䟝存関係に含たれる、infinispan-commonsがあれば䟝存関係ずしおは
十分です。぀たり、Hot Rod Clientのみで実行するこずができたす。

ちなみに、XML定矩のCache名ず䜜成するCacheの名前が異なる堎合は、䟋倖がスロヌされるので泚意したしょう。。

            assertThatThrownBy(() -> admin.getOrCreateCache("distributedCache", cacheConfiguration))
                    .hasMessageContaining("org.infinispan.commons.CacheConfigurationException: ISPN005031: The supplied configuration for cache 'distributedCache' is missing a named configuration for it:")
                    .isInstanceOf(HotRodClientException.class);

これでひずずおり確認できた感じですね。

こちらのチュヌトリアルを芋おいるず、Configuration Templateも定矩できそうですが、今回はパスしたす。

https://github.com/infinispan/infinispan-simple-tutorials/tree/main/infinispan-remote/cache-admin-api

Embedded CacheのConfigurationは、どう䜿われおいるの

オマケ的にですが。

こちらがRemoteCacheManagerAdminむンタヌフェヌスの実装です。

https://github.com/infinispan/infinispan/blob/12.1.7.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/RemoteCacheManagerAdminImpl.java

Embedded CacheのConfigurationを枡した時にはどうなるのかなず思ったのですが、結局文字列に倉換されおいるので
最終的にはXML定矩をInfinispan Serverに送っおCacheを䜜成するみたいですね。

https://github.com/infinispan/infinispan/blob/12.1.7.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/RemoteCacheManagerAdminImpl.java#L61

たずめ

InfinispanのHot Rod ClientのRemoteCacheManagerAdminを䜿っお、Infinispan Server䞊にCacheを動的に䜜成しお
みたした。

時々䜿っおいるのですが、本圓によく忘れるのでいい機䌚かな、ず。

今回䜜成した゜ヌスコヌドは、こちらに眮いおいたす。

https://github.com/kazuhira-r/infinispan-getting-started/tree/master/remote-create-cache