Ichigo Notes

個人開発アプリ 5 つを Google Cloud から Oracle Cloud へ移行した話

更新 約 15 分で読めます

エンジニアにとって、個人アプリケーション開発はとても楽しいものですよね。ただ、利用者がほとんどいない個人開発のアプリであっても、クラウドの請求は毎月来ます。私が以前利用していた Google Cloud は、非常に使いやすく、サービスや機能も豊富です。それでも料金は、個人で払い続けるには重いと感じていました。アクセスがなくてもデータベースの料金はかかり続け、Web ゲームのように通信の多いアプリでは、遊ばれた分だけ下りの通信料(サーバから利用者へ送るデータの料金)もかさみます。

そこで目を付けたのが、Oracle Cloud Infrastructure(OCI)の無料枠(Always Free)です。Arm の VM、200GB のディスク、月 10TB の下りの通信が、期限なしで無料で使えます。Google Cloud の無料枠と比べると、個人開発にはかなり気前のよい枠です。2026 年 10 月、個人開発のアプリ 5 つを Google Cloud(Cloud Run + Cloud SQL)から OCI の Arm の VM 2 台へ移しました。準備をしておいたので、切り替えそのものは 1 日で終わりました。それでも、詰まったところは少なくありませんでした。

この記事では、Google Cloud の料金と OCI の無料枠を比べたうえで、構成図、移行の手順のサンプル、詰まりやすいところの直し方をまとめます。

この記事でわかること

  • Google Cloud の料金が、個人開発で重くなりやすいところ
  • OCI の無料枠の中身と注意点
  • Cloud Run + Cloud SQL から OCI の VM へ移す手順(構成図・コマンド例つき)
  • 移行で詰まりやすいところと、その直し方

予備知識:この記事に出てくる用語

クラウドでアプリを動かす方法は、大きく 2 つあります。サーバの準備や台数の調整をクラウド側に任せるマネージドサービスと、自分専用のサーバを借りる VM(仮想マシン)です。移す前は前者、移した後は後者が中心です。

用語どんなものか
Cloud RunGoogle Cloud のマネージドサービス。アプリを入れたコンテナを預けると、リクエストに応じて台数を自動で増減する(0 台まで減らせる)
Cloud SQLGoogle Cloud のマネージドなデータベース。PostgreSQL などを、バックアップや更新込みで貸してくれる
Always FreeOCI の無料枠。期限なしで、決まった量まで無料で使える
Ampere A1(A1)OCI の Arm の CPU の VM。無料枠の中心。CPU の数は OCPU で数え、A1 では 1 OCPU が 1 コア
ホームリージョンOCI のアカウントを作ったときに選ぶ拠点。A1 の無料枠はここでしか使えない
BastionVM へ安全に SSH するための、OCI の中継(踏み台)のサービス
下り通信料サーバから利用者へ送ったデータの量でかかる料金。OCI の資料では「外向きの通信」
Cloudflareサイトの手前で通信の中継・キャッシュ・攻撃の防御をするサービス
Docker・コンテナアプリと動作に必要なものをひとまとめにして、どこでも同じように動かす仕組み

Google Cloud の料金は、個人開発には重い

Cloud Run は、リクエストがないときは 0 台まで減らせるので、アクセスの少ないアプリならほぼ無料で動きます。重かったのは、次の 2 つです。

  • データベースは、使っていなくても料金がかかる。 Cloud SQL には、ずっと使える無料枠がありません(30 日の試用のみ)。インスタンスが動いている時間に課金されるので、アクセスがなくても請求が来ます。アプリを 1 つ作るたびに、毎月の固定費が 1 つ増えていきます。
  • 下り通信料に上限がない。 Cloud Run からインターネットへの下りの通信は量に比例して課金され、無料分は北米からの月 1GB だけです。Web ゲームのように WebSocket で状態を送り続けるアプリでは、遊ばれるほど請求が伸びます。しかも WebSocket はつながっている間ずっと「処理中のリクエスト」として扱われるので、誰か 1 人が画面を開いているだけで Cloud Run の課金も続きます。

夜間だけ止める、通信量が急に増えたら止める、といった節約もできます。ただ、どれも機能を削る方向の工夫で、「人気が出るほど費用が心配になる」形は変わりませんでした。

OCI の無料枠は、個人開発にはとても優秀

両社の無料枠を並べると、差がよくわかります(2026 年 10 月時点の公式ドキュメントから)。

項目Google Cloud の Free TierOCI の Always Free
VMe2-micro 1 台(米国のリージョンのみ。メモリ 1GB)A1 で合計 2 OCPU・メモリ 12GB(東京・大阪でも可)
ディスク30GB200GB
マネージドのデータベースなし(30 日の試用のみ)Autonomous Database が 2 つ
下りの通信製品ごとに北米から月 1GB など月 10TB

2 コア・12GB あれば、利用者の少ないアプリを Docker でいくつも動かせます。データベースも VM の中に置けば、アプリを増やしても費用は増えません。そして下りの通信が月 10TB まで無料なので、通信の多いゲームでも請求を気にせずに済みます。

実際の月額(移す前の Google Cloud と、移した後の OCI)は、請求が締まったあとでこの記事に追記します。

ただし、注意点もあります。

  • A1 の枠は 2026 年 6 月に半分になった。 以前は 4 OCPU / 24GB でした(InfoQ の記事)。今も古い数字の記事が多いので、公式のドキュメントで確かめてください。この記事の構成は、今の枠を前提にしています。
  • A1 は作れないことがある。 空きがないと「Out of host capacity」になります。ホームリージョンでしか無料にならないので、時間をおいて作り直すしかありません。
  • 使われていない VM は回収されることがある。 Always Free のインスタンスは、7 日間の CPU・ネットワーク・メモリの使用率がどれも 20% 未満だと回収される場合があります。一般に、従量課金(Pay As You Go)のアカウントで作った VM は対象外とされています。枠の中の分は、従量課金にしても無料のままです。

移す前と後の構成

移したのは、私が個人開発している棋譜蔵・minotake・Meooow・LUDORA・このブログの 5 つです。どれも Go のサーバと PostgreSQL の組み合わせです。

移行前の構成図。利用者から Cloudflare を通って Google Cloud 上の Cloud Run の各アプリへつながり、アプリごとに別の Cloud SQL のインスタンスを使う。ファイルは Cloud Storage、定期処理は Cloud Scheduler と Cloud Run Jobs

移す前は、アプリごとに Cloud Run と Cloud SQL を持つ、個人開発ではよくある構成でした。

移行後の構成図。利用者から Cloudflare を通って OCI の VCN 内の VM 2 台へつながる。Web アプリ用の VM では Caddy が各アプリへ振り分け、PostgreSQL のデータベースはアプリごとに分けている。ゲーム用の VM は WebSocket だけ直接受ける。ファイルは Object Storage、管理用の SSH は Bastion、バックアップは Cloudflare R2

移した後は、A1 の無料枠(合計 2 OCPU / 12GB)を、1 OCPU / 6GB ずつの VM 2 台に分けています。

  • Web アプリ用の VM
    通信の少ない Web アプリを、それぞれ別のコンテナで動かします。入口の Caddy(リバースプロキシ)が、ドメインごとに振り分けます。データベースは PostgreSQL で、アプリごとに分けています。
  • ゲーム用の VM
    通信と CPU を使うゲームは、ほかのアプリに影響しないよう別の VM にしました。

VM の 22 番(SSH)はインターネットに開けず、管理は Bastion 越しに行います。Web アプリ用の VM の 443 番は Cloudflare の IP 範囲だけに開けています。データベースとファイルは、毎日 Cloudflare R2 へバックアップしています。

今まで Google Cloud のマネージドサービスに任せていた自動スケール・バックアップ・OS やデータベースの更新は、自前の仕組みで引き受けました。

移行の手順

大事な方針は、本番の動きを変えない準備を先に全部済ませ、最後に短い停止で切り替えることです。アプリ名は app-a のような仮のものです。

1. Google Cloud への依存を洗い出す

Google Cloud移した後の例
Cloud RunVM の中の Docker(arm64 のイメージが要る)
Cloud SQLVM の中の PostgreSQL(バックアップは自分で)
Cloud StorageOCI Object Storage(S3 互換の API で読み書き)
Cloud Schedulersystemd タイマー

Google Cloud 専用のライブラリを使っている所は、設定で切り替えられるようにしておきます。既定を今までのままにしておけば、Google Cloud の本番の動きは変わりません。

2. OCI 側を用意する

ホームリージョン(東京か大阪)でアカウントを作り、VCN(仮想ネットワーク)・A1 の VM・Bastion を作って、VM に Docker を入れます。443 番は Cloudflare の IP 範囲だけに開けます。

3. arm64 のイメージを作る

A1 は Arm の CPU なので、amd64 向けのイメージは動きません。docker buildx で両方を作れば、同じタグを Cloud Run でも A1 でも使えます。Go のようにクロスコンパイルできる言語なら、ビルドの段を手元のアーキテクチャで動かすと、エミュレータ(QEMU)なしで速く作れます。

FROM --platform=$BUILDPLATFORM golang:1.27.3 AS build
ARG TARGETOS TARGETARCH
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /server ./cmd/server

# 実行の段には RUN を置かない(置くと QEMU が必要になる)
FROM gcr.io/distroless/static-debian12
COPY --from=build /server /server
ENTRYPOINT ["/server"]
# 複数のアーキテクチャを作れるビルダー
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t <レジストリ>/app-a:<タグ> --push .

4. データの移行を練習する

Cloud SQL Auth Proxy でつなぎ、pg_dump で書き出して、VM の PostgreSQL(Bastion 越しの SSH トンネル)へ pg_restore で入れます。

./cloud-sql-proxy --port 15432 <プロジェクト>:<リージョン>:<インスタンス> &
pg_dump -h 127.0.0.1 -p 15432 -U app_a -d app_a -Fc --no-acl -f app_a.dump
pg_restore -h 127.0.0.1 -p 5432 -U app_a -d app_a --no-owner --no-acl app_a.dump

入れたら、両側の全テーブルの行数を比べて一致を確かめます。psql の \gexec で、テーブルごとの count(*) をまとめて流せます。

SELECT format('SELECT %L AS table_name, count(*) FROM %I.%I', table_name, table_schema, table_name)
FROM information_schema.tables
WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
ORDER BY table_name
\gexec

ファイルは rclone sync で Cloud Storage から Object Storage へ写せます(Object Storage は「顧客秘密キー」を作ると S3 互換で使えます)。逆向きの移行と、バックアップから戻す練習もしておくと、何かあったときに戻せます。

5. 定期処理を systemd タイマーへ移す

今まで Cloud Scheduler が担ってくれていたメール送信タスクなどの定期実行処理を、 systemd タイマーに記述する形に変更します。cron を使用する方法もあります。

# /etc/systemd/system/app-a-cleanup.timer(同名の .service で処理を書く)
[Timer]
# VM の時計は UTC が既定なので、タイムゾーンを書く
OnCalendar=*-*-* 04:30:00 Asia/Tokyo
Persistent=true

[Install]
WantedBy=timers.target

6. 切り替えて、片付ける

  1. Google Cloud への書き込みを止める(Cloud Run の公開を外し、Cloud Scheduler を止める)
  2. データを移し、行数の一致を確かめる
  3. Cloudflare の DNS を VM へ向ける(プロキシ越しなら数十秒〜数分で切り替わる)
  4. OCI 側のタイマーを動かし、ログイン・書き込みなどを目で確かめる
  5. しばらく様子を見てから、Google Cloud の資源を消す

停止は、アプリ 1 つあたり数十分を見込んでおけば十分でした。

トラブルシューティング

症状よくある原因対処
A1 の VM が「Out of host capacity」で作れないホームリージョンに空きがない時間をおいて作り直す。別の可用性ドメインを試す
コンテナが exec format error で起動しないamd64 のイメージを arm64 で動かしたarm64 を含めて作り直す
Cloudflare のエラー 521・522443 番が閉じているセキュリティリストと VM の中の iptables の両方を確かめる
Cloudflare のエラー 526証明書が Full (strict) で通らないCloudflare の Origin CA などの証明書を置く
PostgreSQL 18 のコンテナが起動直後に止まるボリュームを /var/lib/postgresql/data に付けた18 からは /var/lib/postgresql に付ける
定期処理が 9 時間ずれるVM の時計が UTCOnCalendar にタイムゾーンを書く
更新したのに古い JS・CSS が返るCloudflare のキャッシュURL に版(?v=...)を付ける
Google Cloud の資源が消せない削除保護・VPC のピアリングが残っているTerraform の deletion_protection を外す。ピアリングを先に消す

ファイアウォールは 2 段ある

OCI では、VCN のセキュリティリストと、VM の中の iptables の 2 段で通信を絞っています。OCI の Ubuntu のイメージには、INPUT の最後で通信を断る規則が最初から入っています。Docker で公開したポートは Docker の規則で通りますが、VM で直接待ち受けるソフトは届きません。その場合は、/etc/iptables/rules.v4 の REJECT の行の前に 443 番を通す規則を書き足します。

利用者の IP が、すべて Cloudflare のものになる

Caddy は、信頼するプロキシを設定していないと、届いた X-Forwarded-For を直前の接続相手(Cloudflare)の IP で作り直します。すると、レート制限やアクセス解析が Cloudflare の拠点ごとにまとめて数えられてしまいます。Cloudflare が付ける CF-Connecting-IP で置き換えます。

https://app-a.example.com {
	reverse_proxy app-a:8080 {
		header_up X-Forwarded-For {http.request.header.CF-Connecting-IP}
	}
}

このヘッダは偽装できるので、443 番を Cloudflare の IP 範囲だけに開けておくことが前提です。

新旧の環境から、同じメールが 2 通届く

練習で本番のデータを OCI 側へ写すと、OCI 側の定期処理も本番のデータを見て動き出し、Google Cloud と合わせて同じメールが 2 通届いてしまいます。切り替えまでは OCI 側のタイマーを止めておきます。目印のファイルがあるときだけ動くようにしておくと確実です。

# タイマーから起動する .service の [Unit] に足す
ConditionPathExists=/srv/app/live

まとめ

  • Google Cloud は使いやすいが、Cloud SQL の固定費と上限のない下り通信料が、個人開発には重い
  • OCI の無料枠は、Arm の VM(合計 2 OCPU / 12GB)・200GB のディスク・月 10TB の下りの通信が期限なしで無料。個人開発にはとても優秀
  • 移行は、本番を変えない準備を先に済ませ、データの移行と復元を練習してから、短い停止で切り替える
  • 詰まりやすいのは、arm64 のイメージ、2 段のファイアウォール、Cloudflare 越しの IP、新旧の環境の二重送信

自動スケールや止まらない運用が要るなら、マネージドサービスの料金は払う価値があります。一方で「月々の請求をできるだけ 0 に近づけたい」「通信量を気にせずに作りたい」個人開発なら、OCI の無料枠は第一の候補になると思います。実際の費用や運用してわかったことは、あとで追記します。

参考