目次
- ストレージは「どうやってアクセスするか」で3種類に分かれる
- ブロックストレージ:OSから見た「1本のディスク」
- ファイルストレージ:複数サーバーで共有できる「フォルダ」
- オブジェクトストレージ:HTTP APIで出し入れする「倉庫」
- 用途別の使い分け:DB・OS用/共有ファイル/画像・バックアップ
- DBのデータとOSのルートはブロックストレージ一択
- 複数台で同じファイルを見たいならファイルストレージ
- 画像・動画・バックアップ・ログはオブジェクトストレージ
- クラウド3社の対応サービスとコスト・性能の見方
- 課金の軸が種類ごとに違う
- 性能は「レイテンシ」と「並列度」で見る
- アプリ設計の原則:ローカルディスクに保存しない
- なぜローカル保存が問題になるのか
- 実装例:署名付きURLでS3に直接アップロードする
- 既存アプリを最小限の変更で複数台化する:EFSのマウント
- トラブル事例:2台目を追加したら画像が「たまに」表示されない
- 症状
- 原因
- 対処
- まとめ
「アップロードされた画像はどこに置けばいいのか」「S3とEBSとEFSは何が違うのか」「サーバーを2台にしたらファイルが片方にしかない」――クラウドでアプリを動かし始めると、ストレージの選択で必ず一度は迷います。コードは書けても、ストレージの種類ごとの性格を知らないと、後からの移行が非常に高くつく設計になりがちです。
この記事では、オブジェクト・ブロック・ファイルという3種類のストレージを「アクセス方式」という一本の軸で整理し、DB・OS用、共有ファイル、画像やバックアップといった用途ごとの使い分けを解説します。AWS・GCP・Azureの対応サービス表、コストと性能の傾向、そしてアプリ設計で守るべき「ローカルディスクに保存しない」原則まで、実務で判断できるところまで持っていきます。
ストレージは「どうやってアクセスするか」で3種類に分かれる
ストレージの違いは容量や価格よりも、まず「プログラムやOSがどのインターフェースでデータに触るか」で決まります。この軸で見ると、3種類の性格がはっきりします。
ブロックストレージ:OSから見た「1本のディスク」
ブロックストレージは、データを固定長のブロック(一般に4KBなど)の並びとして扱い、OSに対して「ディスク(ブロックデバイス)」として見えるストレージです。OSはその上にext4やXFSなどのファイルシステムを作り、パーティションを切り、通常のディスクとして使います。AWSのEBS(Elastic Block Store)が代表で、EC2インスタンスに「アタッチ」して使います。
特徴は低レイテンシとランダムアクセス性能です。データベースのデータファイルやOSのルートボリュームのように、小さなブロックを高頻度に読み書きする用途に向きます。一方で原則として1台のサーバーにしかアタッチできず(マルチアタッチは限定的)、ネットワーク越しに複数台から共有する用途には向きません。
ファイルストレージ:複数サーバーで共有できる「フォルダ」
ファイルストレージは、NFSやSMBといったプロトコルでネットワーク越しにディレクトリ階層をそのまま提供するストレージです。OSからは/mnt/sharedのようにマウントして、通常のファイルと同じようにopen・read・writeで扱えます。AWSではEFS(Elastic File System)、Windows向けにはFSxが該当します。
最大の特徴は「複数のサーバーから同時に同じファイルツリーを見られる」ことです。既存のアプリがローカルファイル前提で書かれていて、コードを大きく変えずにサーバーを複数台にしたい場合の現実的な選択肢になります。ただしネットワークを経由するため、ブロックストレージよりレイテンシは大きく、小さなファイルを大量に読み書きする処理は遅くなりがちです。
オブジェクトストレージ:HTTP APIで出し入れする「倉庫」
オブジェクトストレージは、ファイルを「キー(名前)+データ+メタデータ」のオブジェクトとして扱い、HTTP(S)のAPIでPUT・GET・DELETEするストレージです。OSにマウントするのではなく、SDKやCLIからAPIを呼んで使います。AWS S3、Google Cloud Storage(GCS)、Azure Blob Storageが該当し、S3のAPIは事実上の業界標準になっています。
フラットな名前空間にほぼ無制限にオブジェクトを置け、容量を事前に確保する必要がなく、耐久性がきわめて高く設計されています。一方でオブジェクトの一部だけを書き換える「部分更新」はできず、書き換えは丸ごと置き換えになります。ファイルの一部を頻繁に更新する用途(DBのデータファイルなど)には根本的に向きません。
| 種類 | アクセス方式 | 共有 | 得意な用途 | 苦手な用途 |
|---|---|---|---|---|
| ブロック | ブロックデバイスとしてOSにアタッチ | 基本1台 | OSのルート、DBデータ、低レイテンシI/O | 複数台での共有、無制限の容量 |
| ファイル | NFS/SMBでマウント | 複数台で同時 | 共有ディレクトリ、既存アプリの複数台化、ホームディレクトリ | 小さなファイルの大量高速I/O |
| オブジェクト | HTTP APIでPUT/GET | どこからでも | 画像・動画・バックアップ・ログ・静的サイト | 部分更新、ファイルシステム前提の処理 |
用途別の使い分け:DB・OS用/共有ファイル/画像・バックアップ
3種類の性格がわかると、「何をどこに置くか」はかなり機械的に決まります。迷いやすいポイントを用途別に整理します。
DBのデータとOSのルートはブロックストレージ一択
データベースは数KB単位のページをランダムに読み書きし、書き込みの順序と永続性(fsync)を厳密に扱います。これはブロックデバイスの上のファイルシステムを前提とした動きで、オブジェクトストレージはもちろん、NFSの上でDBを動かすのも(不可能ではありませんが)ロックやレイテンシの問題を抱えやすく、一般には推奨されません。EC2上で自前運用するならEBSの汎用SSD(gp3)が起点で、IOPSが足りなければプロビジョンドIOPS(io2)を検討します。マネージドDB(RDSなど)を使う場合は内部でブロックストレージが使われており、利用者はストレージ種別とIOPSを選ぶだけです。RDSの選び方はAWS RDSの実務ガイドを参照してください。
複数台で同じファイルを見たいならファイルストレージ
典型例は、WordPressのようにアップロードファイルをローカルディレクトリに書く設計のアプリを、ロードバランサー配下で複数台にしたいケースです。EFSを各サーバーのwp-content/uploadsにマウントすれば、どのサーバーが受けたアップロードも全台から見えます。コードの改修なしで水平展開できるのがメリットで、CIのビルドキャッシュや、複数コンテナで共有する設定ファイルにも使えます。
ただし「とりあえず全部EFS」は禁物です。EFSは1ファイルあたりのアクセスにネットワークの往復が乗るため、PHPのソースコード全体やnode_modulesをEFSに置くと、起動やリクエスト処理が目に見えて遅くなります。共有が必要なデータだけをマウントするのが原則です。
画像・動画・バックアップ・ログはオブジェクトストレージ
ユーザーがアップロードした画像や動画、生成したPDF、DBのダンプ、アプリケーションログの長期保管は、オブジェクトストレージが最適です。理由は3つあります。容量を気にしなくてよいこと、耐久性が高く冗長化を自分で考えなくてよいこと、そしてCDNと組み合わせて配信を直接任せられることです。CloudFrontとS3の組み合わせは、アプリサーバーを経由せずに画像を配信する定番構成です。
新規に設計するアプリでは、「アップロードされたファイルはアプリサーバーを経由せず、署名付きURLでブラウザから直接S3に置く」構成が推奨されます。サーバーのディスクもメモリも消費せず、大きなファイルでもアプリの負荷になりません。
クラウド3社の対応サービスとコスト・性能の見方
AWS・GCP・Azureはいずれも3種類すべてを提供しており、名前が違うだけで役割はほぼ対応します。
| 種類 | AWS | Google Cloud | Azure |
|---|---|---|---|
| ブロック | EBS | Persistent Disk / Hyperdisk | Managed Disks |
| ファイル | EFS(NFS)、FSx(Windows/Lustre など) | Filestore(NFS) | Azure Files(SMB/NFS) |
| オブジェクト | S3 | Cloud Storage(GCS) | Blob Storage |
課金の軸が種類ごとに違う
コスト比較で最初に押さえるべきは、「何に対して課金されるか」が異なる点です。ブロックストレージは「確保した容量」に対して課金されるため、100GBのボリュームを作れば10GBしか使っていなくても100GB分の料金がかかります。加えてIOPSやスループットを上げると追加料金が発生します。ファイルストレージは実際に使った容量が基本で、スループットモードによって課金が変わります。オブジェクトストレージは「使った容量」に加えて「リクエスト数」と「外部へのデータ転送量」に課金があり、GB単価はもっとも安い一方、大量の小さなオブジェクトを頻繁にGETする使い方ではリクエスト料金が効いてきます。
一般的な傾向として、GBあたりの保管単価はオブジェクト<ブロック<ファイルの順に高くなることが多く、特にファイルストレージは共有の利便性と引き換えに単価が高めです。「大容量だがめったに読まない」データをEFSやEBSに置いたままにしていると、コストの無駄が大きくなります。オブジェクトストレージにはライフサイクルポリシーで低頻度アクセス層やアーカイブ層に自動で移す仕組みがあり、S3の具体的な設定はAWS S3の実務活用ガイドで解説しています。
性能は「レイテンシ」と「並列度」で見る
性能面では、ブロックストレージは1回のI/Oのレイテンシがミリ秒未満から数ミリ秒と小さく、DBのような直列的な処理に強い一方、1ボリュームの上限スループットは決まっています。オブジェクトストレージは1リクエストのレイテンシは数十ミリ秒とやや大きいものの、並列にリクエストを投げれば実質的に上限なくスケールします。「1つのファイルを素早く」ならブロック、「大量のファイルを並列で」ならオブジェクト、と覚えておくと設計判断がぶれません。
アプリ設計の原則:ローカルディスクに保存しない
ここまでの内容を設計原則として一言にすると、「アプリケーションサーバーのローカルディスクに、消えて困るデータを置かない」となります。この原則の背景と実装方法を説明します。
なぜローカル保存が問題になるのか
クラウドやコンテナ環境では、サーバーは「いつでも入れ替わるもの」として扱われます。オートスケールで台数が増減し、デプロイのたびにコンテナは作り直され、障害があればインスタンスは別のホストで起動し直します。ローカルディスクに置いたアップロード画像は、次のデプロイで消えるか、台数を増やした瞬間に「どのサーバーにあるか」が不定になります。コンテナのファイルシステムがなぜ揮発的なのかはコンテナの内部構造で仕組みから解説しています。
逆に言えば、状態(データ)をすべて外部のストレージやDBに追い出し、サーバー自体をステートレスにしておけば、台数を増やすのもサーバーを捨てるのも自由になります。ストレージの選択は、この「ステートレス化」を実現するための手段です。
実装例:署名付きURLでS3に直接アップロードする
Node.js(AWS SDK v3)で、ブラウザが直接S3にPUTするための署名付きURLを発行する例です。サーバーはURLを発行するだけで、ファイル本体は通りません。
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const s3 = new S3Client({ region: "ap-northeast-1" });
export async function createUploadUrl(userId, fileName, contentType) {
const key = `uploads/${userId}/${Date.now()}-${fileName}`;
const command = new PutObjectCommand({
Bucket: process.env.UPLOAD_BUCKET,
Key: key,
ContentType: contentType,
});
// 5分だけ有効なアップロード用URL
const url = await getSignedUrl(s3, command, { expiresIn: 300 });
return { url, key };
}
フロントエンドは返ってきたurlに対してfetch(url, { method: "PUT", body: file })を実行し、完了後にkeyをアプリのAPIに送ってDBに紐づけます。ローカルディスクはまったく使いません。
既存アプリを最小限の変更で複数台化する:EFSのマウント
すでにローカルディレクトリへの書き込み前提で動いているアプリを、コード改修なしで複数台にしたい場合は、そのディレクトリだけをEFSにします。Amazon Linux 2023での手順は次のとおりです。
- EFSファイルシステムを作成し、EC2と同じVPC・サブネットにマウントターゲットを作る。セキュリティグループでEC2からのNFS(TCP 2049)を許可する。
- EC2側に
amazon-efs-utilsをインストールし、マウントポイントを作ってマウントする。 - 動作確認後、
/etc/fstabに追記して再起動後も自動でマウントされるようにする。
sudo dnf install -y amazon-efs-utils
sudo mkdir -p /var/www/app/shared/uploads
sudo mount -t efs -o tls fs-0123456789abcdef0:/ /var/www/app/shared/uploads
# 永続化(TLS付き・起動時にネットワーク待ち)
echo "fs-0123456789abcdef0:/ /var/www/app/shared/uploads efs _netdev,tls 0 0" | sudo tee -a /etc/fstab
df -hT /var/www/app/shared/uploads
Docker Composeで動かしている場合は、ホスト側でマウントしたディレクトリをボリュームとしてコンテナに渡すだけで済みます。
services:
app:
image: myapp:latest
volumes:
- /var/www/app/shared/uploads:/app/public/uploads
トラブル事例:2台目を追加したら画像が「たまに」表示されない
実際によく起きる事故を、症状から原因、対処まで追ってみます。
症状
負荷対策でアプリサーバーをロードバランサー配下に2台に増やしたところ、「アップロードした直後は画像が見えるのに、リロードすると404になることがある」という報告が上がりました。再現は不規則で、同じ画像が見えたり見えなかったりします。
原因
アプリはアップロード画像をpublic/uploadsというローカルディレクトリに保存していました。アップロードを受けたのがサーバーAなら画像はAのディスクにしかなく、次のリクエストがロードバランサーによってサーバーBに振られると、Bには該当ファイルが存在しないため404になります。「たまに」なのは、ロードバランサーの振り分け先がリクエストごとに変わるからです。
対処
短期的には、ロードバランサーのスティッキーセッションを有効にして同じユーザーを同じサーバーに固定すれば症状は緩和しますが、根本解決にはなりません(サーバーが落ちれば画像ごと消えます)。恒久対策は2択で、即日で対応するならpublic/uploadsをEFSに載せ替え、中期的にはアップロード先をS3に変更して画像配信をCloudFrontに任せる構成に移行しました。移行時は、既存ファイルをaws s3 sync public/uploads s3://bucket/uploadsでコピーし、DBに保存している画像パスをS3のキーに書き換えるスクリプトを用意しています。
# 既存ファイルをS3へ同期(差分のみ・削除は反映しない)
aws s3 sync /var/www/app/public/uploads s3://myapp-uploads/uploads \
--exclude "*.tmp" --storage-class STANDARD
まとめ
ストレージはアクセス方式で3種類に分かれ、それぞれ得意分野がはっきりしています。ブロックストレージ(EBS)はDBとOSのように低レイテンシのランダムI/Oが必要なもの、ファイルストレージ(EFS)は複数台で同じディレクトリを共有したいもの、オブジェクトストレージ(S3)は画像・動画・バックアップ・ログのように大量に溜まり、部分更新が不要なもの、と覚えておけば迷いません。コストはブロックが「確保容量」、オブジェクトが「使用量+リクエスト+転送」と課金軸が違う点に注意してください。
そして設計上もっとも大事なのは、アプリサーバーのローカルディスクに消えて困るデータを置かず、サーバーをステートレスに保つことです。新規開発ならS3への直接アップロード、既存アプリの複数台化ならEFSのマウントから始めるのが現実的な一手です。
ストレージ構成の見直しやクラウド移行で、自社の要件にどの組み合わせが合うか判断に迷う場合は、Harmonic Societyのシステム開発・インフラ支援にお気軽にご相談ください。
Harmonic Society
この記事の内容、自社の業務でも活かせそうですか?
ローカルLLM・AI・クラウドなどの技術導入を、要件整理からPoC・社内展開まで代表エンジニアが伴走します。オンライン対応・全国OK。まずは30分の無料相談から。売り込みはしません。
関連記事
Related / 9 articles
Notes & Insights
- プログラミング
DDoS攻撃の仕組みと対策入門|レイヤー別の防御とCDN・クラウドの活用
DDoS攻撃をボリューム型・プロトコル型・アプリ層に分けて仕組みを解説し、自前サーバーで防げない理由、CloudflareやAWS Shieldの標準防御、オリジンIPの隠し方、レートリミットとBot対策、攻撃を受けたときの初動、費用が跳ね上がるDenial of Walletへの備えまでわかります。
- プログラミング
WAFとは?仕組み・導入パターン・誤検知対策|Webアプリを攻撃から守る実践ガイド
WAFがファイアウォールやIDSと何が違うのか、シグネチャとマネージドルールの仕組み、Cloudflare WAF・AWS WAF・ModSecurityの比較、フォーム送信がブロックされる誤検知の調査と例外設定、ログ監視、WAFが代替できないことまで実践的に解説します。
- プログラミング
セキュリティヘッダー入門|CSP・HSTS・X-Frame-Optionsの設定と効果を実践解説
CSP・HSTS・X-Frame-Options・X-Content-Type-Optionsなど主要セキュリティヘッダーが防ぐ攻撃と、CSPのReport-Onlyからの段階導入、nonce/hash、HSTS preloadの不可逆リスク、Nginx・Next.js・Astroでの設定例、確認方法を解説します。
- プログラミング
クラウドの通信費(Egress)入門|データ転送量課金の仕組みと転送コストを抑える設計
クラウドの「受信無料・送信有料」の原則、AZ間・リージョン間・インターネット向けの単価差、NATゲートウェイ処理料の罠、CDNで転送量を減らす方法、バックアップやログ転送の見落とし、請求書で転送料を特定する手順を解説。想定外の請求を防げます。
- プログラミング
秘密情報をGitに入れない仕組み|.gitignore・git-secrets・履歴から漏れた鍵の削除
APIキーや.envをGitにコミットしてしまう典型経路と、.gitignore・.env.exampleの運用、pre-commitでのgitleaks検知、GitHub secret scanningの活用、漏れた鍵の無効化と履歴書き換え(git filter-repo)の手順を解説。仕組みで再発を防げます。
- プログラミング
開発・ステージング・本番環境の分離設計|環境差分をなくす構成とアクセス制御
開発・ステージング・本番それぞれの目的と、構成をコードで揃える方法、環境別の設定注入、本番データを使わないテストデータ戦略、ステージングの保護(Basic認証・IP制限・noindex)、コストを抑える運用までを解説。環境差分による本番障害を防げます。
- プログラミング
ngrok・Cloudflare Tunnelでローカルを公開|Webhook開発とデモ環境の作り方
NAT内のローカル環境にStripeやLINEのWebhookを届けるトンネリングの仕組みを解説。ngrok・Cloudflare Tunnel・localtunnelの比較、固定ドメインと認証、リクエスト検査、公開時のセキュリティ、自宅サーバー公開への応用までわかります。
- プログラミング
ローカル開発環境のHTTPS化|mkcert・hostsファイル・自己署名証明書の正しい使い方
ローカル開発をHTTPS前提にすべき理由(Secure Cookie・Service Worker・OAuth)と、mkcertでローカルCAを作りhostsで独自ドメインを割り当ててVite・Next.js・Dockerで使う手順を解説。証明書警告を無視する癖の危険も理解できます。
- プログラミング
localhost・0.0.0.0・127.0.0.1の違い|ポートとUnixソケットを理解して「つながらない」を解決
localhost・127.0.0.1・0.0.0.0の意味の違い、Dockerで外から接続できない原因、host.docker.internal、ポート競合の調べ方、Unixソケットの利点と権限、1024未満ポートの制約を解説。「つながらない」を仕組みから解決できます。
Harmonic Society
「読んで終わり」にせず、自社の業務で試してみませんか?
AI・ローカルLLM・クラウドの導入を、要件整理からPoC・社内展開まで代表エンジニアが伴走します。オンライン対応・全国OK・売り込みなし。
無料・30分・オンラインOK|1営業日以内に返信します