1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GarageHQを建てて閉じようか悩んでる話

Last updated at Posted at 2025-12-01

minioの件から・・・

多分このアドベントカレンダーを見てる皆様ならご存知かと思いますが、
minioのUIが廃止されたり、Dockerイメージの提供が停止したり、と色々ありました・・・

WebUIはともかく、Dockerイメージの提供が停止し、ソースだけ、有志がビルド、という状況は今後のことも踏まえてminio脱退のきっかけになりました

そんなこんなで、当方セルフホスト環境で色々遊んでいることもあり、minioをやめて別のものに移行しようぜ!ということでGarageHQを選択。

タイトルからお察しの通り、止めることを検討中なのですが、
悪くはなかったということで興味があればぜひ!

GarageHQの注意点

GarageHQの導入

環境構成

この記事で立てる環境はローカルPC用にしておきます。

  • ノード数: 1
  • OS: macOS Sequoia 15.6.1
  • deploy: Docker compose
  • storage: local(10GB)

なお、セルフホスト環境は下記のようになっております

  • ノード数: 4
  • Server(2つ)
    • 1つ目(node * 2)
      • OS: Debian GNU/Linux bullseye 11.11 aarch64
      • deploy: Docker compose
      • storage: 2TB, 2TB
    • 2つ目(node * 2)
      • OS: Debian GNU/Linux bookworm 12.12 x86_64
      • deploy: Docker compose
      • storage: 2TB, 3TB

サーバー2つに対して、2つずつノードを立てることで、HDDの故障に対してのリカバリ、サーバー自体の故障でも読み取りはできるように・・・という考えのもとです。

セットアップ

compose.ymlgarage.toml.envを準備します。

Garage WebUIはアクセスキーをログインなしで、時間が経っても後から確認できます。
今回はローカル環境のため認証情報は追加しませんが、認証を追加する場合はREADMEをご確認ください。
https://github.com/khairul169/garage-webui?tab=readme-ov-file#authentication

ローカル環境だけで利用できる、traefikも活用したリポジトリを用意しました。
各種ポートは非表示のため、本手順のwebアクセスは一部読み替えてもらう必要がありますが、webポートも解放しているので、簡易利用にはお勧めです:star:
https://github.com/sinsky/garage-sample

番外編でも追加で紹介しているので、最初のセットアップはRepoからの設定をお勧めしときます!

compose.yml
services:
  garage:
    image: dxflrs/garage:v2.1.0
    container_name: garage
    restart: always
    ports:
      - 3900:3900 # S3 endpoint
      # - 3901:3901 # RPC endpoint(複数ノードによる連携時に必要)
      # - 3902:3902 # S3 Web endpoint
      - 3903:3903 # admin endpoint
    environment:
      GARAGE_RPC_SECRET: ${GARAGE_RPC_SECRET}
      GARAGE_ADMIN_TOKEN: ${GARAGE_ADMIN_TOKEN}
      GARAGE_METRICS_TOKEN: ${GARAGE_METRICS_TOKEN}
    volumes:
      - ./garage.toml:/etc/garage.toml
      # 全てカレントディレクトリ直下に作成
      - ./meta:/var/lib/garage/meta
      - ./data:/var/lib/garage/data
  webui:
    image: khairul169/garage-webui
    container_name: garage-webui
    restart: unless-stopped
    volumes:
      - ./garage.toml:/etc/garage.toml:ro
    ports:
      - 3909:3909
    environment:
      API_BASE_URL: http://garage:3903
      API_ADMIN_KEY: ${GARAGE_RPC_SECRET}
      S3_ENDPOINT_URL: http://garage:3900
      S3_REGION: garage
garage.toml
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "lmdb"
metadata_auto_snapshot_interval = "6h"

replication_factor = 1

compression_level = 2

## 使わないのでコメントアウト
# rpc_bind_addr = "[::]:3901"
# rpc_public_addr = "localhost:3901"
## rpc_secret = "" # .envで指定

[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.garage"

## 使わないのでコメントアウト
# [s3_web]
# bind_addr = "[::]:3902"
# root_domain = ".web.garage"
# index = "index.html"

[admin]
api_bind_addr = "[::]:3903"
# admin_token="" # .envで指定
# metrics_token = "" # .envで指定

.envはShellで作成

cat > .env << EOF
GARAGE_RPC_SECRET="$(openssl rand -hex 32)"
GARAGE_ADMIN_TOKEN="$(openssl rand -base64 32)"
GARAGE_METRICS_TOKEN="$(openssl rand -base64 32)"
EOF

こんなファイルが生成されると思います

.env
GARAGE_RPC_SECRET="279f0def4bbe3fc117a418ed2210fbc95c7c07c9a71d5d6658e854f1ae1d198f"
GARAGE_ADMIN_TOKEN="Nqd8of4qLpYkWyBigN1PagaxbNoAJ74UkoV3kN0+vew="
GARAGE_METRICS_TOKEN="gvmqD3rO05yT+7cwn3Mt1y3bFju78fK1yFO4nR1RS7o="

立ち上げとWebUIの表示

  1. docker compose up -dで立ち上げ
  2. WebUI(http://localhost:3909)へアクセス(repo版: http://webui.127.0.0.1.traefik.me/
    CleanShot 2025-11-23 at 21.50.48.png

GarageHQのセットアップ

GarageHQはLayoutという設定をしないと使えません。
WebUIからの設定と、CUIからの設定、どちらも利用できます。
説明は手軽なWebUIからのみ。CUIはドキュメント見てください笑

なおこの記事では省きますが、2Way以上はノード同士の接続をする必要がありますので、
その場合についても上記のドキュメントからノードの接続を行ってください。

  1. Cluster画面から、表示されているNodeの「...」からAssignを選択
    CleanShot 2025-11-23 at 21.51.45.png
  2. ZoneやCapacityなど、必要なものを入力。
    実際のストレージサイズとは別に、Capacityで必要な分だけ割り当てる、ということが可能です。
    タグは作らなくてもいいです。
    CleanShot 2025-11-23 at 21.55.34.png
  3. Saveを押下するとApply/Revertボタンが出てくるので、Applyを押下
    CleanShot 2025-11-23 at 21.56.58.png
  4. レイアウト変更するぞ?と出るのでOK
    CleanShot 2025-11-23 at 21.57.44.png
  5. 実際にレイアウトを変更すると、ログが表示されます。ノードもZoneやCapacityが設定したものが表示されるのでご確認ください
    CleanShot 2025-11-23 at 21.57.57.png

これでセットアップは完了です。

レイアウトはバージョン管理されており、後からの変更も対応しています。
が、もちろんサイズを小さくしたりノードを増やすと多分面倒なので、その辺はドキュメント見てください

https://garagehq.deuxfleurs.fr/documentation/operations/layout/

バケットの作成とキーの作成

バケットの作成

  1. 左のメニューからBucketを選択し、Create Bucketを押下
    CleanShot 2025-11-23 at 22.05.08.png
  2. バケットの名前を決めてSubmitを押下
    CleanShot 2025-11-23 at 22.05.43.png
  3. バケットが作成されました。
    Manageを押下すると、色々みれます(Browseでも)
    ただし、アクセスキーを作成しないと何もできないので、作成していきます。
    CleanShot 2025-11-23 at 22.06.25.png
    CleanShot 2025-11-23 at 22.08.48.png

アクセスキーの作成

  1. 左のメニューからKeysを選択し、Create Keyを押下
    CleanShot 2025-11-23 at 22.10.03.png
  2. キーの名前を入力して、Submit
    CleanShot 2025-11-23 at 22.10.48.png
  3. Key IDとKey Secretが確認できます
    CleanShot 2025-11-23 at 22.11.27.png

アクセスキーとバケットの紐付け

アクセスキーを作成しただけではアクセスできません。バケットと紐付けましょう

  1. Bucketsからアクセスを許可したいバケットのManageを押下
    CleanShot 2025-11-23 at 22.15.35.png
  2. Permissionsのタブに移動して、Allow Keyを押下
    CleanShot 2025-11-23 at 22.16.20.png
  3. 許可するアクセスキーと、許可する権限を選択してSubmit
    CleanShot 2025-11-23 at 22.17.11.png
  4. 許可されたことを確認する
    CleanShot 2025-11-23 at 22.20.11.png
  5. Browseから操作可能
    CleanShot 2025-11-23 at 22.20.16.png

あとはrcloneなどからアップロードなどができるようになっていますので、設定後rclone lsd garage:/などでご確認ください

GarageHQを止めようとしている理由

割とセットアップ簡単じゃん!と思われたでしょう。ハイ、簡単でした。

なんならWebUIもTinyAuthで保護しながら、s3のサブドメインで1週間ほど使っておりました...

CleanShot 2025-11-23 at 22.28.58.png

CleanShot 2025-11-23 at 22.29.44.png

そして、そんなある日・・・
restic(profile)で日次バックアップをしていたのですが、スナップショットの一覧を見ようとしたら、エラーが出てスナップショットの確認ができないではありませんか・・・

resticprofile -n default snapshots
rclone: 2025/11/23 00:12:51 ERROR : locks/83b73ba7f4b3683e920ce5973bcadeed57c3c122f2cdbab30c3b6280d7516edb: Post request put error: operation error S3: PutObject, exceeded maximum number of attempts, 1, https response error StatusCode: 502, RequestID: , HostID: , api error BadGateway: Bad Gateway
rclone: 2025/11/23 00:12:51 ERROR : locks/83b73ba7f4b3683e920ce5973bcadeed57c3c122f2cdbab30c3b6280d7516edb: Post request rcat error: operation error S3: PutObject, exceeded maximum number of attempts, 1, https response error StatusCode: 502, RequestID: , HostID: , api error BadGateway: Bad Gateway
Save(<lock/83b73ba7f4>) returned error, retrying after 745.565906ms: unexpected HTTP response (500): 500 Internal Server Error
rclone: 2025/11/23 00:12:51 ERROR : locks/83b73ba7f4b3683e920ce5973bcadeed57c3c122f2cdbab30c3b6280d7516edb: Post request put error: operation error S3: PutObject, exceeded maximum number of attempts, 1, https response error StatusCode: 502, RequestID: , HostID: , api error BadGateway: Bad Gateway
rclone: 2025/11/23 00:12:51 ERROR : locks/83b73ba7f4b3683e920ce5973bcadeed57c3c122f2cdbab30c3b6280d7516edb: Post request rcat error: operation error S3: PutObject, exceeded maximum number of attempts, 1, https response error StatusCode: 502, RequestID: , HostID: , api error BadGateway: Bad Gateway
Save(<lock/83b73ba7f4>) returned error, retrying after 1.055820677s: unexpected HTTP response (500): 500 Internal Server Error
rclone: 2025/11/23 00:12:52 ERROR : locks/83b73ba7f4b3683e920ce5973bcadeed57c3c122f2cdbab30c3b6280d7516edb: Post request put error: operation error S3: PutObject, exceeded maximum number of attempts, 1, https response error StatusCode: 502, RequestID: , HostID: , api error BadGateway: Bad Gateway
rclone: 2025/11/23 00:12:52 ERROR : locks/83b73ba7f4b3683e920ce5973bcadeed57c3c122f2cdbab30c3b6280d7516edb: Post request rcat error: operation error S3: PutObject, exceeded maximum number of attempts, 1, https response error StatusCode: 502, RequestID: , HostID: , api error BadGateway: Bad Gateway
Save(<lock/83b73ba7f4>) returned error, retrying after 4.894215255s: unexpected HTTP response (500): 500 Internal Server Error

rclone lsd garage:/restic-backupで確認する感じ、接続はできている・・・
しかし、copyコマンドでコピーするとエラーになったので、書き込みで問題が発生していた・・

ノードのログを確認すると、データの破損で問題が起きていた模様

garage-node1  | 2025-11-22T17:31:44.120974Z  INFO garage_api_common::generic_server: 172.100.0.1 (via [::ffff:172.100.0.2]:56042) (key GK74c642553fa47075b0badf6f) HEAD /restic-backup/locks/d85f4c4951bddcf194d9e156090c26a944c51269dd239f3a6f1d277853f0b1c4
garage-node1  | 2025-11-22T17:31:44.124106Z  INFO garage_api_common::generic_server: Response: error 404 Not Found, Key not found
garage-node1  | 2025-11-22T17:33:41.939079Z  INFO garage_block::resync: Resync block 1f6e7205ce9e3de4: fetching absent but needed block (refcount > 0)
garage-node1  | 2025-11-22T17:33:41.942512Z  WARN garage_block::resync: Could not fetch needed block 1f6e7205ce9e3de4, no node returned valid data. Checking that refcount is correct.
garage-node1  | 2025-11-22T17:33:41.942662Z ERROR garage_block::resync: Error when resyncing 1f6e7205ce9e3de4: Missing block 1f6e7205ce9e3de4: no node returned a valid block
garage-node1  | 2025-11-22T17:33:42.013632Z  INFO garage_block::resync: Resync block 3baf8a5e012332da: fetching absent but needed block (refcount > 0)
garage-node1  | 2025-11-22T17:33:42.018354Z  WARN garage_block::resync: Could not fetch needed block 3baf8a5e012332da, no node returned valid data. Checking that refcount is correct.
garage-node1  | 2025-11-22T17:33:42.018502Z ERROR garage_block::resync: Error when resyncing 3baf8a5e012332da: Missing block 3baf8a5e012332da: no node returned a valid block
garage-node1  | 2025-11-22T17:33:42.083633Z  INFO garage_block::resync: Resync block 07f9d00d352f8d1e: fetching absent but needed block (refcount > 0)
garage-node1  | 2025-11-22T17:33:42.089358Z  WARN garage_block::resync: Could not fetch needed block 07f9d00d352f8d1e, no node returned valid data. Checking that refcount is correct.
garage-node1  | 2025-11-22T17:33:42.089746Z ERROR garage_block::resync: Error when resyncing 07f9d00d352f8d1e: Missing block 07f9d00d352f8d1e: no node returned a valid block
garage-node1  | 2025-11-22T17:33:42.178459Z  INFO garage_block::resync: Resync block 3b90be5385c0828b: fetching absent but needed block (refcount > 0)
garage-node1  | 2025-11-22T17:33:42.184076Z  WARN garage_block::resync: Could not fetch needed block 3b90be5385c0828b, no node returned valid data. Checking that refcount is correct.
garage-node1  | 2025-11-22T17:33:42.184453Z ERROR garage_block::resync: Error when resyncing 3b90be5385c0828b: Missing block 3b90be5385c0828b: no node returned a valid block
garage-node1  | 2025-11-22T17:33:42.289532Z  INFO garage_block::resync: Resync block 589e043d75261153: fetching absent but needed block (refcount > 0)
garage-node1  | 2025-11-22T17:33:42.293945Z  WARN garage_block::resync: Could not fetch needed block 589e043d75261153, no node returned valid data. Checking that refcount is correct.
garage-node1  | 2025-11-22T17:33:42.294343Z ERROR garage_block::resync: Error when resyncing 589e043d75261153: Missing block 589e043d75261153: no node returned a valid block
garage-node1  | 2025-11-22T17:34:04.229131Z  INFO garage_block::resync: Resync block dde2b95f5fd41739: fetching absent but needed block (refcount > 0)

そして何もわからないまま、再び使えるようになりました・・・
ログを見る感じネットワークの問題?各ノードの再起動で治ったみたいではある
その前にほかのバケットで色々遊んで消したりしたのが原因・・・?

ホストしているデバイス自体は起動し続けていたし、ほかのログも見当たらない。ディスクなども問題なし。
データの破損もぱっと見、大丈夫そうだったのでとりあえず使い続けていますが、
minioに戻るか、ほかのFSを選ぼうか悩み中・・・

最後に

Garageの紹介は以上です!いかがでしたでしょうか。

セットアップの簡単さや軽量性、分散ストレージとしての設計思想など、魅力的な面は多いかと思います。
ライセンスやら、データの整合性による問題など、悩ましい点もあったりなかったりしますが、
手軽に使える良いものかなと思います!
WebUIも公式が提供していないとはいえ、使いやすいものを提供してくださっていたので、
シンプルな構成でいきたい!って場合は結構おすすめです。

付録

自宅で利用中の環境

Garage WebUIのみPublicに公開(ただしTinyAuthによるOIDCを挟んでアクセス制御)

他のGarageノード間、およびWebUIの通信はTailscaleネットワークに参加させて通信させています。

PCのバックアップなどは全てTailscaleネットワークに入らないと利用できない構成なので、セキュリティ的にも安全な・・・はず!

my-network.png

ちなみに構成がデカくなるので記載していませんが、ForgejoEnteLinkwardenなど色々たてております。
TailscaleTraefikに感謝!Let's Encryptの管理もいらないからね!

使用率とか

こちらもお勧めしたいのですが、Beszelによるリソースの監視も行われております。(目的が変わってきている)

resticのバックアップやEnteによる画像のアップロードを行ってましたが、使用量的にはこんなもん(初回のresticスナップショットが40GBちょい)
メモリやCPUもそんなに高性能である必要はないので、良さげです

CleanShot 2025-11-23 at 23.46.26.png

あとはS3のバックアップということで、GoogleのCloudStorageにrestic経由でバックアップを予定
(Google Developer Programに参加しているのでクレジット消費も兼ねて)

クレジットがなかったらR2にしてたかな〜笑

番外編(traefik.meを使ったローカルのリバースプロキシ環境とwebの利用)

時間があったので、ローカルで活用できるリポジトリも用意しました!

web portもtraefikで公開しているので、http://*.web.127.0.0.1.traefik.me でアクセスできます!

docker compose up -dでコンテナを立ち上げ、バケットの作成とアクセスキーの割り当てまで終わってる前提で、
バケットのWebsite Accessを有効化して、index.htmlをアップロード。

CleanShot 2025-11-24 at 01.21.27.png
CleanShot 2025-11-24 at 01.22.25.png

Website Accessに記載のあるバケット名をサブドメインのリンクを開く
demo bucket --> http://demo.web.127.0.0.1.traefik.me/

見える!!(Claude作成)

CleanShot 2025-11-24 at 01.23.23.png

ぱぱっと動かすには、やはりちょうどいい(褒めすぎ)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?