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?

macのローカルディレクトリをrcloneを使ってGoogleドライブへ退避する

1
Posted at

やろうと思ったきっかけ

Ubuntu ServerにGoogle Driveをマウント(rclone)のように、Linuxだとわりと簡単にできるGoogleドライブのmountがmacOSでもできるはずなので、ためしてみたかった
かつ、QiitaにもZennにもまとめている人が見当たらなかったため、残してみようとおもい、記事にしました

いきなりのハードル

macOSでGoogleドライブをmountするには、仮想ファイルシステム機能をOSに認識・統合させるためにFUSE(Filesystem in Userspace)という仕組みを導入しないといけないが、そのパッケージであるmacFUSEをインストールするには、OSレベルでの設定変更が必要(起動セキュリティユーティリティで低セキュリティを選択して確認済みの開発元からのインストールを許可)になるため(参考リンク)、正直インストールしたくない。

じゃあどうするか

やってみたい。諦めきれない(長考)

・・・ubuntuなコンテナをたてて、そこにrcloneでGoogleドライブとホスト側の特定ディレクトリをそれぞれmountさせればいいんだ!
ただ、そういうトリッキーなことを行なっている人はQiitaにもZennにもXにも見当たらないので、生成AIと戯れながらやってみました

システム構成

こんな構成にしました(最終系)

実際のコード

ほとんどをClaudeCodeに書かせましたが、こんな感じのコードにしています
ただ、これだけで動くわけではなく、コンテナ上で動かしたrcloneからGoogleへの認証をうまく通すことがキモでした

  • Dockerfile
FROM ubuntu:22.04

# 必要なパッケージのインストール
# socat: rcloneのOAuth待受サーバー(127.0.0.1限定bind)を
#        コンテナ外部から到達可能にするための中継用(rclone config時のみ使用)
RUN apt-get update && apt-get install -y \
    curl \
    unzip \
    fuse3 \
    socat \
    && rm -rf /var/lib/apt/lists/*

# Rcloneのインストール
RUN curl https://rclone.org/install.sh | bash

# エントリーポイント用スクリプトの配置
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
  • docker-compose.yml
services:
  rclone-backup:
    build: .
    container_name: rclone-backup
    privileged: true 
    volumes:

      # GCPのJSONキーとrclone設定ファイルの配置
      - ./conf.d:/root/.config/rclone
      
      # コンテナ内の動作確認用(必要に応じて)
      - ./entrypoint.sh:/entrypoint.sh
    ports:
      # ▼ コンテナの認証用ポートをホストに公開する
      - "53682:9999"
    command: ["tail", "-f", "/dev/null"] # 手動実行やcron用にあえて常駐させる場合
  • docker-compose.override.yml ※こんなことできるんだと感心
services:
  rclone-backup:
    volumes:
      # B: ホストOS側の特定ディレクトリをRO(読込専用)でマウント
      # 実際のパスに書き換えたうえで docker-compose.override.yml として保存する
      - /path/to/your/source/dir:/source:ro
    environment:
      # rclone sync の同期先(entrypoint.sh から参照)。実際の値に書き換える
      - BACKUP_DEST=gdrive:path/to/your/dest
  • entrypoint.sh
#!/bin/bash

rclone about gdrive:

: "${BACKUP_DEST:?BACKUP_DEST is not set (define it in docker-compose.override.yml)}"
echo "Backup started at $(date)"
rclone copy /source "$BACKUP_DEST" --progress
echo "Backup finished at $(date)"

exec "$@"

実際の手順

上記のコードにもとづいて、Podman コンテナ上で rclone を動かし、macOS ホストの特定ディレクトリを Google Drive にバックアップする構成を組んでいたところ、OAuth再認証で Error 401: Invalid Credentials にハマりました。原因究明から解決までの流れをまとめます。

発生した問題

rclone で Google Drive にアクセスしようとすると以下のエラーが発生。

Error 401: Request had invalid authentication credentials ... Reason: authError, Message: Invalid Credentials

原因調査

設定ファイル(rclone.conf)の中身を確認すると、token の access_token が実際には "dummy" というプレースホルダ文字列のままでした。

token = {"access_token": "dummy", "token_type": "Bearer", "refresh_token": "4/0AT...", "expiry": "2026-08-14T17:25:00Z"}

expiry が未来時刻だったため、rclone は「まだ有効」と判断してリフレッシュせず、そのまま dummy を Google API に送信 → 401、という流れでした。

client_id / client_secret / refresh_token 自体は本物の値が入っていたため、OAuth再認証を1回行い、本物の access_token を取得し直せば解消するはずでした。ところが、ここからが本題です。

ハマった点:127.0.0.1 bind と Podman(macOS/VM) のポート公開が噛み合わない

rclone の OAuth 認可は、認可用の一時Webサーバー(デフォルトポート 53682)に対するブラウザからのコールバックを待つ仕組みです。しかしこのWebサーバーはコンテナ内の 127.0.0.1(ループバック)にしかbindしない仕様になっています。

macOS の Podman は Linux VM 上でコンテナを動かしており、ports: - "53682:53682" のような通常のポート公開は「Mac → VM → コンテナの外部インターフェース(NAT)」という経路になります。この経路は、コンテナが 0.0.0.0 等でbindしている場合は届きますが、127.0.0.1 限定bindのプロセスにはNAT越しに届きません。

その結果:

  • nc/ブラウザからの接続は(Podman側のプロキシが受け付けるため)TCP接続自体は成立する
  • しかしコンテナ内の実サービスまでは届かず、ERR_EMPTY_RESPONSE / curl: (52) Empty reply from server になる

これは docker-compose.yml のポート設定の書き方の問題ではなく、rclone側の認可サーバーが 127.0.0.1 固定bindであり、CLIフラグでの変更手段が無いことに起因します。さらに厄介なことに、Google側のOAuth(installed app向けクライアント)は redirect_uri を http://127.0.0.1:/ 固定にするため、ブラウザは常に「自分自身(=Mac)」のループバックにアクセスしようとします。つまり最終的に Mac の 127.0.0.1:53682 に何かが応答してくれないと、原理的に成立しません。

解決策:コンテナ内で socat による中継を挟む

コンテナ内に socat を追加し、外部から到達可能なポート(9999)でLISTENしてコンテナ内ループバック 127.0.0.1:53682 へ中継します。docker-compose.yml 側は Macの 53682 → コンテナの 9999 で公開します(rclone自身の待受ポート53682はそのまま。Google側に見せる redirect_uri とも矛盾しません)。

  • docker-compose.yml
ports:
  - "53682:9999"
  • Dockerfile
RUN apt-get update && apt-get install -y curl unzip fuse3 socat && rm -rf /var/lib/apt/lists/*

再認証手順

再認証には rclone config reconnect を使います。既存 remote([gdrive])の client_id/client_secret を再利用しつつ、認可が成功すると同じ設定ファイルの token = を自動的に書き換えてくれるため、トークンJSONの手動コピペは不要です。

  • 1.コンテナ起動
podman compose up -d --build
  • 2.socat中継を起動(バックグラウンド)
podman exec -d ubuntu-rclone-backup socat TCP-LISTEN:9999,fork,reuseaddr TCP:127.0.0.1:53682
  • 3.再認証を対話実行
podman exec -it ubuntu-rclone-backup rclone config reconnect gdrive:

対話プロンプトの流れは以下の通りです。

  1. Token already configured - replace it? → y
  2. Use web browser to automatically authenticate rclone with remote? → y
  3. コンテナにはブラウザがないため自動オープンは失敗し、認可URL(例: http://127.0.0.1:53682/auth?state=...)がログに表示される
  4. ホストOS側のブラウザでそのURLを開き、Googleアカウントでログイン・許可する(socat中継のおかげでここが到達可能になっている)
  5. Google側の同意完了後、ブラウザは http://127.0.0.1:53682/?state=...&code=... にリダイレクトされる。ここに正常にアクセスできれば rclone が conf.d/rclone.conf の token を実トークンで上書きして終了する
  6. コンテナ側の rclone config reconnect プロセスは最終確認プロンプトで残ることがあるので、対話ターミナル側で応答して終了させる

まとめ

ここまで行なって、ようやく快適にmacOSから余計な設定をいれることなくGoogleドライブへデータをコピーできるようになりました。

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?