開発

ステージング環境とは?本番・検証環境との違いと差分を抑えるIaC・データマスキングの構成例

ステージング環境とは?本番・検証環境との違いと差分を抑えるIaC・データマスキングの構成例

ステージング環境は、本番に出す直前のビルドを、本番と同じ構成のサーバー・設定・データ規模の上で動かして最終確認する環境です。検証環境が「機能が正しく動くか」を確かめる場所だとすれば、ステージング環境は「本番に出しても同じように動くか」を確かめる場所にあたります。この記事では、開発・検証・本番環境との違いを一次情報で整理したうえで、Terraformで本番との差分を変数だけに閉じ込める構成、PostgreSQLで本番データをマスキングして持ち込む手順、GitHub Actionsで同じ成果物をステージングから本番へ昇格させるワークフローを、コード付きで解説します。

まとめ:ステージング環境で本番と揃える範囲と揃えない範囲の結論

本番と必ず揃えるのは、デプロイする成果物、ミドルウェアの種類と版、インフラの定義の3点です。ビルドは1回だけにして、ステージングで確かめたコンテナイメージをそのまま本番へ出します。インフラはTerraformなどのコードで1つの定義を共有し、環境ごとに違うのはサーバーの大きさや台数といった変数だけにします。

揃えなくてよいのは、台数・性能、決済やメール送信などの外部連携、ドメインです。データは本番をそのまま複製せず、個人情報をマスキングしてから持ち込みます。本番の写しとして保てないステージングは、手間とコストだけがかかるので、常設するかどうかは外部連携とDBの変更の多さで決めます。

ステージング環境の役割と開発・検証・本番環境との違いを表で整理

環境の呼び名は会社やプロジェクトで揺れますが、役割で分けると混乱しません。

ステージング環境で確かめることと検証環境で済ませることの線引き

AWSの規範ガイダンスは、ステージング環境を「本番環境と同じになるように設定」し、データの範囲とサイズも本番に近づける環境と定義しています。ビルドの手順は「なし」で、テスト環境で使ったのと同じアーティファクトを再利用する、という点がこの定義の芯です。

環境 主な目的 データ 使う人
開発環境 実装中の動作確認 手元の少量データ 開発者
検証環境 機能・結合テスト テスト用の合成データ 開発者・QA
ステージング 本番相当での最終確認 本番規模のマスク済みデータ QA・発注者・承認者
本番環境 利用者へのサービス提供 実データ 利用者

検証環境で落ちる不具合は、ステージングまで持ち込まないのが原則です。ステージングで見つけたいのは、データ量で遅くなるSQL、本番と同じネットワーク構成でだけ起きるタイムアウト、マイグレーションの所要時間のように、構成と規模に依存する問題に絞ります。

ステージングで本番と揃えるべき差分と揃えなくてよい差分の優先順位

Twelve-Factor Appの「開発/本番一致」は、開発と本番のずれを時間・人・ツールの3つのギャップで説明し、開発・ステージング・本番のすべてで「同じ種類かつ同じバージョンのバックエンドサービス」を使うべきだとしています。PostgreSQLの16系で検証して本番が17系、という組み合わせでは、ステージングの確認結果をそのまま信じられません。

一方で、すべてを揃える必要はありません。Firebaseの環境の解説も、ステージングでは副作用を起こす機能や外部連携が省かれる場合があると書いています。実務で揃える順は次のとおりです。

  1. 成果物(コンテナイメージやビルド済みファイル)を同一にする
  2. DB・キャッシュ・キューの種類と版を本番と同じにする
  3. 設定の項目(環境変数の名前と構造)を揃え、値だけ変える
  4. データの件数と分布を本番に近づける

台数やインスタンスの大きさは縮めて構いません。決済は各サービスのテストモード、メールは送信先を固定した検証用の設定に差し替えます。設定値の受け渡し方は環境変数の設定方法とDocker・CIでの受け渡しで扱っています。

Terraformで本番とステージングの差分を変数だけに閉じ込める構成例

本番とステージングの構成が手作業でずれていく現象(構成ドリフト)を防ぐには、インフラをコードで1つの定義にまとめます。IaCそのものの考え方はIaCの仕組みと導入判断にまとめています。

環境別ディレクトリとモジュール共有で作るTerraformのファイル構成

リソースの定義はmodules/appに1つだけ置き、環境ごとのディレクトリからは値を変えて呼び出します。

infra/
├── modules/
│   └── app/            # 本番とステージングで共有する定義
│       ├── main.tf
│       └── variables.tf
└── envs/
    ├── staging/
    │   ├── backend.tf
    │   └── main.tf
    └── production/
        ├── backend.tf
        └── main.tf
# envs/staging/main.tf
module "app" {
  source = "../../modules/app"

  env            = "staging"
  db_engine_ver  = "17"              # 本番と同じ版を必ず指定する
  instance_class = "db.t4g.medium"   # 性能は縮めてよい
  min_tasks      = 1
  db_multi_az    = false
}

本番側のmain.tfは、env・instance_class・min_tasks・db_multi_azの値だけが違う形にします。差分がこの4行に収まっていることは、次のコマンドでいつでも確かめられます。

diff envs/staging/main.tf envs/production/main.tf

# 環境ごとに初期化して計画を確認してから適用する
cd envs/staging
terraform init
terraform plan -out=stg.tfplan
terraform apply stg.tfplan

diffの結果に版番号やリソースの種類が出てきたら、ステージングが本番の写しではなくなった合図です。環境が増えて同じ記述の繰り返しが気になる場合は、Terragruntでの環境別の構成も選択肢になります。

Terraformのworkspacesで本番とステージングを分けない理由

HashiCorpのワークスペースの解説は、同じ作業ディレクトリのCLIワークスペースは同じバックエンドを使うため「分離の仕組みとして適さない」と明記しています。認証情報やアクセス制御を環境ごとに分けたい構成では、別の方法を勧めています。

# envs/staging/backend.tf(本番は別のバケットと別のアカウントに置く)
terraform {
  backend "s3" {
    bucket = "example-tfstate-staging"
    key    = "app/terraform.tfstate"
    region = "ap-northeast-1"
  }
}

ワークスペースで切り替える運用は、terraform workspace selectを1回忘れるだけでステージング向けの変更が本番に当たります。stateの置き場所をディレクトリごとに分けておけば、ステージングの権限しか持たない人は本番のstateに触れません。

ステージングと本番のクラウドアカウントを分ける判断と権限の線引き

Firebaseが推奨しているのは、環境ごとに別のプロジェクトを使う構成です。AWSやGoogle Cloudでも同じ考え方で、ステージングと本番をアカウントやプロジェクトの単位で分けます。アカウントが別なら、ステージングで広い権限を持つ開発者も本番のリソースを削除できず、費用も環境別に集計できます。

分離するかどうかの判断基準は、本番に個人情報や決済データがあるかどうかです。同じアカウントの中でタグやIAMの条件で分ける方法は、設定の誤り1つで境界が崩れます。複数アカウントの束ね方はAWS Organizationsのマルチアカウント管理で解説しています。

PostgreSQLで本番データをステージングへ移すときのマスキング手順

本番に近いデータ量で試したい一方、個人情報をそのまま持ち込むと、ステージングが漏えいの経路になります。

ステージングで本番コピーをそのまま使わない理由と合成データで足りる場面

ステージングは本番より多くの人が触り、監視も緩くなりがちです。本番のメールアドレスが残ったままだと、通知処理のテストで実在の顧客にメールが届く事故も起きます。

画面やAPIの確認だけであれば、用意するのは合成データで十分です。本番の複製が要るのは、件数や偏りに依存する確認、つまり重いSQLの実行計画、マイグレーションの所要時間、データ移行のリハーサルの3つにほぼ限られます。この場合も、複製したら外に開く前にマスキングを済ませます。

SQLの静的マスキングとPostgreSQL Anonymizerの宣言的ルール

小さなスキーマなら、本番のスナップショットから復元した複製DBで、次のようなSQLを実行するだけで済みます。必ず複製側に接続していることを確かめてから流します。

-- 本番スナップショットから復元した複製DBでだけ実行する
BEGIN;
UPDATE customers
SET    name    = '顧客' || id,
       email   = concat('user', id, '@', 'example.invalid'),
       phone   = '000-0000-' || lpad((id % 10000)::text, 4, '0'),
       address = '(マスク済み)';
UPDATE payment_methods SET card_token = NULL;
TRUNCATE TABLE sessions, password_reset_tokens;
COMMIT;

テーブルが増えると、どの列を隠したかの管理が追いつかなくなります。その段階ではPostgreSQL Anonymizerのように、列ごとのマスキング規則をDBに宣言しておく拡張が向いています。

CREATE EXTENSION IF NOT EXISTS anon CASCADE;
SELECT anon.init();

SECURITY LABEL FOR anon ON COLUMN customers.name
  IS 'MASKED WITH FUNCTION anon.dummy_last_name()';
SECURITY LABEL FOR anon ON COLUMN customers.phone
  IS 'MASKED WITH FUNCTION anon.partial(phone,2,$$******$$,2)';

-- 宣言した規則で全テーブルを書き換える(元データは戻せない)
SELECT anon.anonymize_database();
ANALYZE;

公式の説明どおり、静的マスキングは元データを破壊します。本番のDBでは実行しない前提で、複製の作成とマスキングを1本のスクリプトにまとめ、人の手順を挟まないようにします。

本番データのマスキング漏れを検出する確認クエリと外部送信の遮断

マスキングの後は、残っていないことを数で確かめます。0件でなければ、その時点で公開を止める仕組みにします。

SELECT count(*) AS unmasked
FROM   customers
WHERE  email NOT LIKE '%example.invalid';

データを消しても、アプリの設定が本番のままなら外部へ送信される状態です。メール送信は送信先を検証用の受信箱に固定し、決済はテストモードのキー、Webhookの送信先はステージング用のURLに差し替えます。新しい列を足したときにマスキングの規則も追加する、という手順をレビューの確認項目に入れておくと漏れが減ります。

GitHub Actionsで同じ成果物をステージングから本番へ昇格させる流れ

ステージングで確かめた物と本番に出す物が違えば、確認の意味がなくなります。ビルドは1回だけにして、同じイメージを順に流します。

ビルドを1回だけにして同じイメージを両環境へ流すワークフロー例

コミットのSHAをタグにしたイメージを作り、ステージング、本番の順に同じタグを渡します。レジストリへのログインとクラウドの認証は省略しています。

name: deploy
on:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      image: ${{ steps.meta.outputs.image }}
    steps:
      - uses: actions/checkout@v7
      - id: meta
        run: echo "image=registry.example.com/app:${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
      - run: |
          docker build -t "${{ steps.meta.outputs.image }}" .
          docker push "${{ steps.meta.outputs.image }}"

  deploy-staging:
    needs: build
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/checkout@v7
      - run: ./scripts/deploy.sh "${{ needs.build.outputs.image }}"
      - run: ./scripts/smoke_test.sh "${{ vars.BASE_URL }}"

  deploy-production:
    needs: [build, deploy-staging]
    runs-on: ubuntu-latest
    environment: production   # 必須レビュー担当者の承認でだけ先へ進む
    steps:
      - uses: actions/checkout@v7
      - run: ./scripts/deploy.sh "${{ needs.build.outputs.image }}"

environmentに名前を書くと、環境ごとの変数・シークレットと保護ルールが効きます。GitHubのドキュメントによると、必須レビュー担当者は最大6人まで指定でき、そのうち1人の承認でジョブが進みます。GitHub Freeではパブリックリポジトリでしか環境を構成できない点に注意してください。承認ゲートや環境別シークレットの設計はGitHub ActionsのEnvironmentsの解説が詳しく扱っています。

ステージングで実施するテストと承認者が本番へ進める合格条件の決め方

AWSの規範ガイダンスでは、ステージングへのデプロイの中でDBのバージョニングとIaCの適用を行い、統合テストと負荷テストは任意としています。全部を毎回回すと時間がかかるため、毎回と節目で分けます。

  • 毎回:主要画面とAPIのスモークテスト、マイグレーションの成否と所要時間
  • リリース前:主要な業務の流れを通すE2Eテスト、発注者の受け入れ確認
  • 大きな変更時:負荷テスト、データ移行のリハーサル

合格条件は「スモークテストがすべて成功し、マイグレーションが想定時間内に終わる」のように、承認者が数字で判断できる形で書いておきます。E2Eテストの組み方はE2Eテストと結合テストの違い、本番への切り替えで停止をなくす方法はBlue/Greenデプロイの実装を参照してください。

ステージング環境を常設する場面と置かずに済ませる場面の判断基準

ステージングは作るより保つ方が難しい環境です。常設の費用に見合うかどうかを、先に判断します。

常設のステージングが要る条件とPRごとの一時環境で足りる条件

常設すべきなのは、決済・会計・外部APIとの連携が多いシステム、DBのマイグレーションが頻繁なシステム、受託開発で発注者がリリース前に受け入れ確認をするシステムです。これらは本番に近いデータと連携先がそろった場所でしか確かめられません。

逆に、静的なサイトやDBを持たないフロントエンドなら、プルリクエストごとに作る一時的なプレビュー環境で足ります。小さなAPIで、段階的に公開して異常なら戻す仕組みが整っているなら、カナリアリリースで本番の一部に出す方が確認の精度は上がります。この場合、常設のステージングは過剰です。

ステージングが形骸化する失敗パターンと稼働時間によるコストの抑え方

よくある失敗は3つあります。管理画面からの手作業の変更が積み重なって本番と構成がずれる、データが半年前の複製のまま古くなる、誰も確認しないままデプロイだけが自動で流れる、の3つです。前の2つはIaCとマスキングの自動化で防げますが、3つ目は合格条件と承認者を決めない限り直りません。

費用は、平日の日中だけ動かす運用にすると、常時稼働の週168時間に対して週50時間ほどになり、稼働時間を約3割に減らせます。夜間の停止と翌朝の起動もパイプラインに組み込むことが可能です。既存システムにステージングと自動デプロイの流れを後から組み込みたい場合は、DevOps・CI/CD導入支援で構成の見直しから相談を受け付けています。

よくある質問

ステージング環境について、構築や運用の場面でよく出る質問に答えます。

ステージング環境と検証環境は同じものですか?

同じ意味で使う現場もありますが、役割で分けると別物です。検証環境は機能が仕様どおりに動くかを確かめる場所で、テスト用の合成データを使います。ステージング環境は、本番と同じ構成と規模で、本番に出す直前の成果物を最終確認する場所です。チームの中で呼び名が混ざっている場合は、「どの成果物を、どのデータで、誰が確認するか」を環境ごとに書き出して揃えると混乱が減ります。

ステージング環境の英語表記や略称は何ですか?

英語ではstaging environmentで、設定ファイルやブランチ名ではstgやstagingと略すのが一般的です。本番の直前という意味でpre-production(プレプロダクション)と呼ぶ組織もあります。本番環境の英語表記はproductionで、略称はprodやprdです。略称は変数名やリソース名に入るので、プロジェクトの最初に1つに決めておきます。

ステージング環境にも本番と同じドメインやSSL証明書が必要ですか?

本番と同じドメインは使わず、割り当てるのはstg.example.comのようなサブドメインです。SSL証明書は本番と同じくHTTPSで動かすために用意し、Cookieの設定や混在コンテンツの問題を本番と同じ条件で確かめます。外部から見られないよう、IPアドレスの制限かBasic認証を掛けておくと、検索エンジンへの掲載や第三者のアクセスも防げます。

WordPressのサイトでもステージング環境は作るべきですか?

本体やプラグイン、PHPの版を上げる前の確認には作る価値があります。レンタルサーバーやマネージドホスティングの多くはステージングの複製機能を持っており、ボタン操作で本番の写しを作ることが可能です。注意点は、複製した会員情報や問い合わせ履歴がそのまま残ることで、会員サイトでは個人情報の扱いを決めてから使います。更新の進め方はWordPressのバージョンアップ手順で扱っています。

ステージングで確認したのに本番で不具合が出るのはなぜですか?

原因の多くは、本番とステージングの差分です。よく見つかるのは、ミドルウェアの版の違い、データの件数と偏り、外部連携の設定、本番だけに入っている手作業の変更の4つです。不具合が出たら、まず差分の一覧(Terraformのdiff、環境変数の名前、DBの版)を突き合わせ、ステージングに再現できなかった理由を特定して、次のリリースまでに差分を1つ減らします。

関連記事

お気に入りに入れた記事の一覧

一創の公式 SNS

X では毎朝の新着記事と IT ニュースの速報を、YouTube・TikTok・Instagram・LinkedIn・Facebook では記事の解説動画を配信しています。

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.11.11 テックブログ Microsoft 2026年11月の月例更新:Outlookの悪用済みCVE-2026-124194と修正版の確認方法
  2. 2026.11.13 テックブログ 宝くじ公式サイト不正アクセス:4,436名の対象確認とパスワード再設定、変更された仕組み
  3. 2026.11.13 テックブログ KARTEの不正アクセス:全機能停止で利用企業がタグ・配信・データ連携を確かめる手順
  4. 2026.11.13 テックブログ ignica不正アクセス:6万4,003件の氏名とメールアドレス流出の可能性と対象確認
  5. 2026.11.11 テックブログ JANISの不正アクセス:最大11,652名の医療機関情報と情報窃取プログラムの検知設定

RELATED POSTS 関連記事

目次