> ## Documentation Index
> Fetch the complete documentation index at: https://ayakaleaf-pro.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# S3

> Kubernetes デプロイで、プロジェクトのファイルと履歴を S3 互換ストレージに保存します。

プロジェクトのファイルとその履歴は **history-v1** サービスが、テンプレートファイルは **filestore** サービスが保存します。どちらもすべての Ayakaleaf Pro Pod 内で動作します。デフォルトではデータボリュームに書き込みますが、S3 を使うとバケットに書き込みます。必要なバケットと権限については [S3](https://ayakaleaf-pro.mintlify.site/ja/on-premises/configuration/overleaf-toolkit/s3.md) で説明しています。

| | |
| - | - |
| サービス | history-v1（プロジェクトのファイルと履歴）、filestore（テンプレートファイル）、すべての Ayakaleaf Pro Pod 内 |
| Pod → S3 | S3 エンドポイント。ファイルの読み書きのたび |
| 必須となる場合 | [複数のレプリカ](https://ayakaleaf-pro.mintlify.site/ja/on-premises/configuration/kubernetes/horizontal-scaling.md)を使う場合: データボリュームは共有されないが、バケットは共有される |
| 定期ジョブ | なし |

> [!WARNING]
>
> ユーザーがプロジェクトを作成する前に S3 を選択してください。すでにボリュームにファイルを保存しているインスタンスでは、先に [S3 への移行](https://ayakaleaf-pro.mintlify.site/ja/on-premises/maintenance/s3-migration.md)が必要です。

### 設定

**1. バケットとキー**

[S3 のセットアップ](https://ayakaleaf-pro.mintlify.site/ja/on-premises/configuration/overleaf-toolkit/s3.md#s3-setup)の説明に従って、S3 サービスで 3 つのバケット `overleaf-template-files`、`overleaf-project-blobs`、`overleaf-chunks` と、権限を制限した 2 つのユーザーを作成するか、以下に示すようにクラスター内で Garage を実行します。4 つのキーを Secret に格納します。

```bash wrap theme={null}
kubectl -n overleaf create secret generic overleaf-s3 \
  --from-literal=OVERLEAF_FILESTORE_S3_ACCESS_KEY_ID=<filestore key> \
  --from-literal=OVERLEAF_FILESTORE_S3_SECRET_ACCESS_KEY=<filestore secret> \
  --from-literal=OVERLEAF_HISTORY_S3_ACCESS_KEY_ID=<history key> \
  --from-literal=OVERLEAF_HISTORY_S3_SECRET_ACCESS_KEY=<history secret>
```

**2. ConfigMap**

```yaml title="30-config.yaml (additions)" wrap theme={null}
  OVERLEAF_FILESTORE_BACKEND: s3
  OVERLEAF_FILESTORE_TEMPLATE_FILES_BUCKET_NAME: overleaf-template-files
  OVERLEAF_FILESTORE_S3_REGION: eu-west-1
  OVERLEAF_HISTORY_BACKEND: s3
  OVERLEAF_HISTORY_PROJECT_BLOBS_BUCKET: overleaf-project-blobs
  OVERLEAF_HISTORY_CHUNKS_BUCKET: overleaf-chunks
  OVERLEAF_HISTORY_S3_REGION: eu-west-1
  # a self-hosted S3 service also needs its endpoint and path-style addressing
  # OVERLEAF_FILESTORE_S3_ENDPOINT: http://garage:3900
  # OVERLEAF_FILESTORE_S3_PATH_STYLE: "true"
  # OVERLEAF_HISTORY_S3_ENDPOINT: http://garage:3900
  # OVERLEAF_HISTORY_S3_PATH_STYLE: "true"
```

**3. Secret を Pod に追加して再起動する**

Deployment（または StatefulSet）で、他の Secret の隣にこの Secret を追加します。

```yaml theme={null}
          envFrom:
            - configMapRef: {name: overleaf-env}
            - secretRef: {name: overleaf-secrets}
            - secretRef: {name: overleaf-s3}
```

```bash theme={null}
kubectl apply -f 30-config.yaml -f 40-overleaf.yaml
kubectl -n overleaf rollout restart deployment/overleaf     # or statefulset/overleaf
```

### クラスター内の Garage

S3 サービスがない場合、[Garage](https://garagehq.deuxfleurs.fr/) はクラスター内で動作する小型の S3 サーバーです。[水平スケーリング](https://ayakaleaf-pro.mintlify.site/ja/on-premises/configuration/kubernetes/horizontal-scaling.md)の構成はこれを使ってテストしました。以下のコマンドはキーの生成と Secret `overleaf-s3` の作成まで行うため、手順 1 の Secret コマンドの代わりにこちらを使用してください。

> [!NOTE]
>
> Overleaf のサンプルで使われている MinIO は、コンテナイメージを公開しなくなりました。`minio/minio` は Docker Hub と quay.io から削除されています。

```yaml title="50-garage.yaml" wrap theme={null}
apiVersion: v1
kind: ConfigMap
metadata:
  name: garage-config
  namespace: overleaf
data:
  garage.toml: |
    metadata_dir = "/var/lib/garage/meta"
    data_dir = "/var/lib/garage/data"
    db_engine = "lmdb"
    replication_factor = 1
    rpc_bind_addr = "[::]:3901"
    rpc_public_addr = "127.0.0.1:3901"
    # rpc_secret and admin_token come from GARAGE_RPC_SECRET / GARAGE_ADMIN_TOKEN
    [s3_api]
    s3_region = "garage"          # Overleaf's OVERLEAF_*_S3_REGION must match
    api_bind_addr = "[::]:3900"
    [admin]
    api_bind_addr = "[::]:3903"
---
apiVersion: v1
kind: Service
metadata:
  name: garage
  namespace: overleaf
spec:
  selector:
    app: garage
  ports:
    - name: s3
      port: 3900
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: garage
  namespace: overleaf
spec:
  serviceName: garage
  replicas: 1
  selector:
    matchLabels:
      app: garage
  template:
    metadata:
      labels:
        app: garage
    spec:
      containers:
        - name: garage
          image: dxflrs/garage:v2.5.0
          env:
            - name: GARAGE_RPC_SECRET
              valueFrom: {secretKeyRef: {name: garage-secrets, key: rpc_secret}}
            - name: GARAGE_ADMIN_TOKEN
              valueFrom: {secretKeyRef: {name: garage-secrets, key: admin_token}}
          ports:
            - containerPort: 3900
          readinessProbe:
            tcpSocket:
              port: 3900
          resources:
            requests: {cpu: 50m, memory: 64Mi}
            limits: {memory: 512Mi}
          volumeMounts:
            - {name: config, mountPath: /etc/garage.toml, subPath: garage.toml}
            - {name: data, mountPath: /var/lib/garage}
      volumes:
        - name: config
          configMap:
            name: garage-config
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: [ReadWriteOnce]
        resources:
          requests:
            storage: 10Gi
```

シークレットを生成して Garage を起動し、レイアウト、バケット、権限を制限した 2 つのキーを作成します。Garage のキー ID は `GK` に 16 進数 24 文字を加えたもの、シークレットは 16 進数 64 文字です。

```bash wrap theme={null}
kubectl -n overleaf create secret generic garage-secrets \
  --from-literal=rpc_secret="$(openssl rand -hex 32)" \
  --from-literal=admin_token="$(openssl rand -base64 32)"
kubectl -n overleaf create secret generic overleaf-s3 \
  --from-literal=OVERLEAF_FILESTORE_S3_ACCESS_KEY_ID="GK$(openssl rand -hex 12)" \
  --from-literal=OVERLEAF_FILESTORE_S3_SECRET_ACCESS_KEY="$(openssl rand -hex 32)" \
  --from-literal=OVERLEAF_HISTORY_S3_ACCESS_KEY_ID="GK$(openssl rand -hex 12)" \
  --from-literal=OVERLEAF_HISTORY_S3_SECRET_ACCESS_KEY="$(openssl rand -hex 32)"
kubectl apply -f 50-garage.yaml
kubectl -n overleaf rollout status statefulset/garage

g() { kubectl -n overleaf exec garage-0 -- /garage "$@"; }
s() { kubectl -n overleaf get secret overleaf-s3 -o jsonpath="{.data.$1}" | base64 -d; }
g layout assign -z dc1 -c 8G "$(g status 2>/dev/null | awk '/^[0-9a-f]{16}/{print $1; exit}')"
g layout apply --version 1
for b in overleaf-template-files overleaf-project-blobs overleaf-chunks; do g bucket create "$b"; done
g key import --yes -n overleaf-filestore "$(s OVERLEAF_FILESTORE_S3_ACCESS_KEY_ID)" "$(s OVERLEAF_FILESTORE_S3_SECRET_ACCESS_KEY)"
g key import --yes -n overleaf-history "$(s OVERLEAF_HISTORY_S3_ACCESS_KEY_ID)" "$(s OVERLEAF_HISTORY_S3_SECRET_ACCESS_KEY)"
g bucket allow --read --write overleaf-template-files --key overleaf-filestore
g bucket allow --read overleaf-project-blobs --key overleaf-filestore
g bucket allow --read --write overleaf-project-blobs --key overleaf-history
g bucket allow --read --write overleaf-chunks --key overleaf-history
```

権限は [S3](https://ayakaleaf-pro.mintlify.site/ja/on-premises/configuration/overleaf-toolkit/s3.md#access-policies) のポリシーと一致しています。Garage はリージョンをチェックします。ここでは `garage` であり、`OVERLEAF_*_S3_REGION` も同じである必要があります。

Garage を使う場合は、[水平スケーリング](https://ayakaleaf-pro.mintlify.site/ja/on-premises/configuration/kubernetes/horizontal-scaling.md)の `60-config.yaml` と同様に、ConfigMap で両方のサービスにエンドポイント、`PATH_STYLE: "true"`、リージョン `garage` を設定してください。

### 複数のレプリカ

すべてのレプリカが同じバケットとキーを使用する必要があります。バケットは S3 プロバイダーのツールでバックアップしてください。そうすれば、レプリカ自身のディスクにはバックアップが必要なデータは残りません。

### Kubernetes でのテスト

Kubernetes 1.37 上でレプリカ 3 つ、上記の Garage を使用した状態で、これらのページにあるエンドツーエンドテストのうち、プロジェクトの作成、ファイルのアップロード、履歴の使用、テンプレートの公開を行うものはすべて合格しました。その後、バケット `overleaf-project-blobs`、`overleaf-chunks`、`overleaf-template-files` にはオブジェクトが保存されており、レプリカ自身の `/var/lib/overleaf/data/history` は空のままでした。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.