🦆

オープンソースの S3 互換オブジェクトストレージ MinIO を DuckDB で使う

2024/11/07に公開

前提

  • DuckDB が使える環境
  • Docker Compose が使える環境

まとめ

DuckDB から S3 互換オブジェクトストレージを利用する際、MinIO を使う事で、ローカルに気軽に S3 互換オブジェクトストレージ環境を用意できる。

DuckDB とは

こちらをどうぞ。

DuckDB雑紹介(1.1対応版)@DuckDB座談会 - Speaker Deck

MinIO とは

MinIO はオープンソースの S3 互換オブジェクトストレージです。

DuckDB は S3 API 機能を持っており、S3 互換オブジェクトストレージとの相性がとても良いです。
ローカルで試したい時などは Docker Compose で MinIO を用意して利用すると、とても便利です。

Docker Compose

  • ローカルということでセキュリティは一切考慮していません
  • MinIO のイメージを pull して起動します
  • ~/minio/data にデータを保存する設定にしています
  • 起動時にヘルスチェックをして、起動が完了するまで待ちます
  • MinIO にアクセスするための mc コマンドを使って、ユーザーを追加し、バケットを作成しています

以下を compose.yaml ファイルとして保存してください。

services:
  minio:
    image: minio/minio:latest
    ports:
      - "9000:9000"
      - "9001:9001"
    # environment:
    #   MINIO_ROOT_USER: root
    #   MINIO_ROOT_PASSWORD: root
    volumes:
      - ~/minio/data:/data
    command: server /data --console-address ":9001"
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 5s

  init-minio:
    image: minio/mc:latest
    depends_on:
      minio:
        condition: service_healthy
    entrypoint: >
      /bin/sh -c "
      /usr/bin/mc alias set myminio http://minio:9000 minioadmin minioadmin;
      /usr/bin/mc admin user add myminio duckdb-local duckdb-local;
      /usr/bin/mc admin policy attach myminio readwrite --user=duckdb-local;
      if /usr/bin/mc ls myminio/duckdb-local > /dev/null 2>&1; then
        /usr/bin/mc rm -r --force myminio/duckdb-local;
      fi;
      if ! /usr/bin/mc ls myminio/duckdb-local > /dev/null 2>&1; then
        /usr/bin/mc mb myminio/duckdb-local;
      fi;
      exit 0;"

使い方

$ docker compose up
[+] Running 3/3
 ✔ Network duckdb-minio_default         Created                                                           0.0s
 ✔ Container duckdb-minio-minio-1       Created                                                           0.0s
 ✔ Container duckdb-minio-init-minio-1  Created                                                           0.0s
Attaching to init-minio-1, minio-1
minio-1       | MinIO Object Storage Server
minio-1       | Copyright: 2015-2024 MinIO, Inc.
minio-1       | License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html
minio-1       | Version: RELEASE.2024-10-29T16-01-48Z (go1.22.8 linux/arm64)
minio-1       |
minio-1       | API: http://172.18.0.2:9000  http://127.0.0.1:9000
minio-1       | WebUI: http://172.18.0.2:9001 http://127.0.0.1:9001
minio-1       |
minio-1       | Docs: https://docs.min.io
minio-1       | WARN: Detected default credentials 'minioadmin:minioadmin', we recommend that you change these values with 'MINIO_ROOT_USER' and 'MINIO_ROOT_PASSWORD' environment variables
init-minio-1  | Added `myminio` successfully.
init-minio-1  | Added user `duckdb-local` successfully.
init-minio-1  | Attached Policies: [readwrite]
init-minio-1  | To User: duckdb-local
init-minio-1 exited with code 0

DuckDB で MinIO を利用する準備

DuckDB で MinIO を利用するためには、Secret Manager 機能を利用します。

  • TYPE は S3 を指定します
  • KEY_ID と SECRET は compose.yaml ファイルで指定した値を指定します
  • ENDPOINT はローカルの値を指定します
  • USE_SSL は false を指定します
  • URL_STYLE は path を指定します
% duckdb
v1.1.3 19864453f7
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
D CREATE SECRET minio (
    TYPE S3,
    KEY_ID 'duckdb-local',
    SECRET 'duckdb-local',
    ENDPOINT '127.0.0.1:9000',
    USE_SSL false,
    URL_STYLE 'path'
  );

これで DuckDB から MinIO を利用する準備が整いました。

MinIO に保存する

https://github.com/voluntas/duckdb-wasm-parquet こちらで後悔している Parquet ファイルを DuckDB に読み込ませて、何もせずに MinIO に保存してみます。

D COPY (SELECT * FROM parquet_scan('https://duckdb-wasm.shiguredo.jp/P78BHZM3MD3MV47JDZG47PB8PW.parquet')) TO "s3://duckdb-local/spam.parquet" (FORMAT parquet, compression zstd);

これで、 MinIO に Parquet ファイルが保存されました。

MinIO を確認する

http://127.0.0.1:9001 にアクセスして、 minioadmin / minioadmin でログインしてください。

Image from Gyazo

spam.parquet が保存されていれば成功です。

Image from Gyazo

MinIO から取得してみる

parquet_scan に MinIO の URL を指定して読み込んでみます。

D SELECT * FROM parquet_scan("s3://duckdb-local/spam.parquet");
┌──────────────────────┬──────────────────────┬─────────────────┬───┬──────────────────────┬───────────────────┬─────────────────────┐
│    connection_id     │          id          │      label      │ … │        rtc_id        │   rtc_timestamp   │      rtc_type       │
│       varchar        │       varchar        │     varchar     │   │       varchar        │      double       │       varchar       │
├──────────────────────┼──────────────────────┼─────────────────┼───┼──────────────────────┼───────────────────┼─────────────────────┤
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ AP                   │ 1726394702721.481 │ media-playout       │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ CF9A:6C:31:80:50:F…  │ 1726394702721.481 │ certificate         │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ CFAF:51:8E:09:37:2…  │ 1726394702721.481 │ certificate         │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ COTdata1_109_maxpl…  │ 1726394702721.481 │ codec               │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ COTdata1_120_profi…  │ 1726394702721.481 │ codec               │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ CP/NH8cQqe_eL6zYNON  │ 1726394702721.481 │ candidate-pair      │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ CP08b8N49i_eL6zYNON  │ 1726394702721.481 │ candidate-pair      │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ CPBDwwCTaU_eL6zYNON  │ 1726394702721.481 │ candidate-pair      │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ CPYLu975lS_eL6zYNON  │ 1726394702721.481 │ candidate-pair      │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ CPki/8xp1m_eL6zYNON  │ 1726394702721.481 │ candidate-pair      │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ CPki/8xp1m_eYTJlek6  │ 1726394702721.481 │ candidate-pair      │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ D5                   │ 1726394702721.481 │ data-channel        │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ D6                   │ 1726394702721.481 │ data-channel        │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ D7                   │ 1726394702721.481 │ data-channel        │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ D8                   │ 1726394702721.481 │ data-channel        │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ I/NH8cQqe            │ 1726394702721.481 │ local-candidate     │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ I08b8N49i            │ 1726394702721.481 │ local-candidate     │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ I4uDdiSuP            │ 1726394702721.481 │ local-candidate     │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ IBDwwCTaU            │ 1726394702721.481 │ local-candidate     │
│ F6WJ4SY2HD63Z25XD3…  │ DE5MC2JG3H2PK667ZG…  │ WebRTC SFU Sora │ … │ IT0OYEKLy            │ 1726394702721.481 │ local-candidate     │
│          ·           │          ·           │        ·        │ · │     ·                │         ·         │       ·             │
│          ·           │          ·           │        ·        │ · │     ·                │         ·         │       ·             │
│          ·           │          ·           │        ·        │ · │     ·                │         ·         │       ·             │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ CPp2HkMADY_vKxy9BYC  │ 1726403015487.149 │ candidate-pair      │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ D5                   │ 1726403015487.149 │ data-channel        │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ D6                   │ 1726403015487.149 │ data-channel        │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ D7                   │ 1726403015487.149 │ data-channel        │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ D8                   │ 1726403015487.149 │ data-channel        │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ ITdata1A2376627921   │ 1726403015487.149 │ inbound-rtp         │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ ITdata1A3686590866   │ 1726403015487.149 │ inbound-rtp         │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ ITdata1V3657862824   │ 1726403015487.149 │ inbound-rtp         │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ ITdata1V494618204    │ 1726403015487.149 │ inbound-rtp         │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ OTdata1A3589631305   │ 1726403015487.149 │ outbound-rtp        │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ OTdata1V886471106    │ 1726403015487.149 │ outbound-rtp        │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ RIA3589631305        │   1726403011612.0 │ remote-inbound-rtp  │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ RIV886471106         │   1726403014647.0 │ remote-inbound-rtp  │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ ROA2376627921        │   1726403013580.0 │ remote-outbound-rtp │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ ROA3686590866        │   1726403011612.0 │ remote-outbound-rtp │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ ROV3657862824        │   1726403015068.0 │ remote-outbound-rtp │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ ROV494618204         │   1726403014750.0 │ remote-outbound-rtp │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ SA3                  │ 1726403015487.149 │ media-source        │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ SV4                  │ 1726403015487.149 │ media-source        │
│ ZVWETDA641527D2A6T…  │ S31C88V2SX7M76DD6M…  │ WebRTC SFU Sora │ … │ Tdata1               │ 1726403015487.149 │ transport           │
├──────────────────────┴──────────────────────┴─────────────────┴───┴──────────────────────┴───────────────────┴─────────────────────┤
│ 83911 rows (40 shown)                                                                                         20 columns (6 shown) │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

参考

Discussion