一覧に戻る
    本番デプロイ当日の記録 — Canary SG作成・ECS SG更新・Pulumiデプロイまでの一部始終
    開発ラボ
    PRこの記事には広告が含まれています

    本番デプロイ当日の記録 — Canary SG作成・ECS SG更新・Pulumiデプロイまでの一部始終

    17 分で読める

    前回の記事では、Canary 用のセキュリティグループ(SG)管理を Pulumi から Terraform へ段階的に移行する設計について書きました。

    今回はその続きで、実際に本番環境へデプロイした当日の記録です。

    設計フェーズとは違い、当日はいくつか予期しない細かいハマりもありました。特に .yml vs .yaml の拡張子まわりは、知っていて損のない話だったので残しておきます。

    前提:作業の全体像

    この作業はいくつかのフェーズに分かれています。

    Phase 1: Canary用SGを手動作成(ingress無し、egress 80/443のみ)
    Phase 2: 複数のECS SGにCanary SGからのingressルールを追加
    Phase 3: Pulumi.prod.ymlのcanarySecurityGroupIdを実IDに差し替え → commit & push
    Phase 4: PRをdevにマージ
    Phase 5: Jenkinsでpreview → deploy
    Phase 6: Canary動作確認(RUNNING/PASSED確認、SNSサブスクリプション承認)
    Phase 7: snsEnabled: true化、その他後処理(別PR)

    今回の記録は主に Phase 1〜3 と、途中で発生したいくつかのやり直しについてです。

    作業開始前:読み取りだけでシミュレーションする

    実際に操作を始める前に、読み取り専用のコマンドだけで事前確認を行いました。

    これは「本番でやってはじめて気づく」を減らすためのステップです。

    確認したこと:

    • AWS プロファイルで正しいアカウントにログインできているか
    • VPC が存在するか
    • Canary 用 SG がすでに存在していないか(重複作成のリスク)
    • Phase 2 で操作対象となる ECS SG が全件存在するか
    • Git ブランチの状態
    • Pulumi.prod.yml のプレースホルダーがまだ書き換えられていないか
    # プロファイル確認
    aws sts get-caller-identity --profile <prod-profile>
    
    # VPC存在確認
    aws ec2 describe-vpcs --vpc-ids <vpc-id> --profile <prod-profile> --region us-west-2
    
    # Canary SG重複チェック
    aws ec2 describe-security-groups \
      --filters "Name=group-name,Values=<canary-sg-name>" \
                "Name=vpc-id,Values=<vpc-id>" \
      --profile <prod-profile> --region us-west-2
    
    # ECS SG一覧取得
    for NAME in <ecs-sg-name-1> <ecs-sg-name-2> ...; do
      SG_ID=$(aws ec2 describe-security-groups \
        --filters "Name=group-name,Values=$NAME" \
        --query 'SecurityGroups[0].GroupId' --output text \
        --profile <prod-profile> --region us-west-2)
      echo "$NAME = $SG_ID"
    done

    結果として「Canary SG は未作成、ECS SG は全件存在、Pulumi.prod.yml はまだプレースホルダー」を確認できたので、安心して Phase 1 に進めました。

    シミュレーション自体は 5 分もかからないのですが、「実行していいよ」と言える状態を作るという意味で、心理的な効果が大きいです。

    Phase 1: Canary SG作成

    # SGを作成
    MSYS_NO_PATHCONV=1 aws ec2 create-security-group \
      --group-name <canary-sg-name> \
      --description "Security group for Synthetics Canary" \
      --vpc-id <vpc-id> \
      --tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=<canary-sg-name>}]' \
      --profile <prod-profile> --region us-west-2
    
    # デフォルトのegress(全開放)を削除
    MSYS_NO_PATHCONV=1 aws ec2 revoke-security-group-egress \
      --group-id <canary-sg-id> \
      --ip-permissions '[{"IpProtocol":"-1","IpRanges":[{"CidrIp":"0.0.0.0/0"}]}]' \
      --profile <prod-profile> --region us-west-2
    
    # HTTP(80)を許可
    MSYS_NO_PATHCONV=1 aws ec2 authorize-security-group-egress \
      --group-id <canary-sg-id> \
      --ip-permissions '[{"IpProtocol":"tcp","FromPort":80,"ToPort":80,"IpRanges":[{"CidrIp":"0.0.0.0/0"}]}]' \
      --profile <prod-profile> --region us-west-2
    
    # HTTPS(443)を許可
    MSYS_NO_PATHCONV=1 aws ec2 authorize-security-group-egress \
      --group-id <canary-sg-id> \
      --ip-permissions '[{"IpProtocol":"tcp","FromPort":443,"ToPort":443,"IpRanges":[{"CidrIp":"0.0.0.0/0"}]}]' \
      --profile <prod-profile> --region us-west-2

    MSYS_NO_PATHCONV=1 が必須なのは Git Bash 特有の問題です。

    Git Bash は Windows のパス変換を自動でやろうとするので、0.0.0.0/0 のような文字列も変換対象になってしまいます。この環境変数を設定することで変換を無効化できます。

    作成後は ingress が空、egress が HTTP/HTTPS のみ — 意図通りの状態を確認して次へ。

    Phase 2: 既存ECS SGへのingressルール追加

    Canary SG の ID が確定したので、監視対象となる複数の ECS SG に対して、「Canary SG からの TCP/80」 ingress ルールを追加します。

    MSYS_NO_PATHCONV=1 aws ec2 authorize-security-group-ingress \
      --group-id <ecs-sg-id> \
      --ip-permissions '[{
        "IpProtocol":"tcp",
        "FromPort":80,
        "ToPort":80,
        "UserIdGroupPairs":[{
          "GroupId":"<canary-sg-id>",
          "Description":"Allow from Synthetics Canary SG"
        }]
      }]' \
      --profile <prod-profile> --region us-west-2

    これを対象の ECS SG 分だけ繰り返しました(今回は 6 件)。

    最後に逆引きで確認。「Canary SG からの ingress を許可している SG を検索」するフィルターが便利です。

    MSYS_NO_PATHCONV=1 aws ec2 describe-security-groups \
      --filters "Name=ip-permission.group-id,Values=<canary-sg-id>" \
      --profile <prod-profile> --region us-west-2 \
      --query 'SecurityGroups[*].GroupName'

    6 件全件ヒットを確認して Phase 3 へ。

    Phase 3: Pulumi.prod.ymlの更新とcommit

    Pulumi.prod.yml のプレースホルダーを、Phase 1 で作成した Canary SG の ID に書き換えます。

    # 変更前
    cm-iac-monitoring:canarySecurityGroupId: sg-xxxxxxxxxxxxxxxxx
    
    # 変更後
    cm-iac-monitoring:canarySecurityGroupId: <作成したCanary SG ID>

    commit → push して、PR を Ready for review に変更。

    ここで発生したやり直し:.yml vs .yaml 問題

    Phase 5 の Jenkins preview 実行後、こんなエラーが出ました。

    error: Missing required configuration variable 'cm-iac-monitoring:vpcSubnetIds'
        please set a value using the command `pulumi config set cm-iac-monitoring:vpcSubnetIds <value>`

    「あれ、vpcSubnetIds は Pulumi.prod.yml に書いてあるはず…」と思ったら、原因はファイルのリネームでした。

    作業の途中で「.yml よりも .yaml の方が正式では?」という話になり、Pulumi.prod.ymlPulumi.prod.yaml にリネームしていたのですが、それがエラーの原因でした。

    Pulumiのスタック設定ファイル探索ルール

    Pulumi はプロジェクトファイル(Pulumi.yml)と同じ拡張子でスタック設定ファイルを探します。

    ✅ Pulumi.yml + Pulumi.prod.yml     → 動作する
    ✅ Pulumi.yaml + Pulumi.prod.yaml   → 動作する
    ❌ Pulumi.yml + Pulumi.prod.yaml    → config が読まれずエラー

    このリポジトリのプロジェクトファイルは Pulumi.yml(.yml)だったので、スタックファイルも .yml でなければなりませんでした。.yaml にリネームしたことで Pulumi が設定を見失い、「vpcSubnetIds が無い」という形でエラーになりました。

    ステートに保存されているのはリソース情報であって、config の値ではありません。そのため「ステートに入っているから大丈夫」という判断は機能しない、というのも確認になりました。

    .yml と .yaml — なぜ両方あるのか

    ついでに、.yml.yaml が両方存在する背景も整理しておきます。

    .yaml が YAML 仕様(yaml.org)の推奨です。一方 .yml は、かつての Windows の 8.3 ファイル名制約(FAT16 時代、拡張子は最大 3 文字)の名残です。.htm vs .html.jpg vs .jpeg と同じ事情です。

    8.3 制約はとっくに廃止されていますが、普及済みのプロジェクトや慣習が残り、両方が共存し続けています。今後新規に作るなら .yaml を使う方が仕様的には正しいのですが、既存プロジェクトを変えるコストは高い。今回はそれを実感しました。

    後半の追加作業:snsEnabled の有効化

    デプロイ後、各エンドポイントで snsEnabled: false になっていた設定を true に変更しました。初回デプロイ時は意図的に false にしており(まず動作確認を優先)、問題ないことを確認してから有効化するという手順です。

    # 変更前
    - name: <endpoint-name>
      ...
      snsEnabled: false
    
    # 変更後
    - name: <endpoint-name>
      ...
      snsEnabled: true

    全エンドポイントに対して変更して commit & push。

    振り返り

    当日の作業を通じてあらためて感じたこと。

    事前シミュレーションは省略しない方がいい。 読み取りだけで 5〜10 分かけてでも、「実行前に全件確認できた」という状態は精神的に全然違います。本番操作中に「そういえばこの SG 存在するっけ」となるのを防げます。

    Pulumi のスタック設定ファイルは拡張子を揃える。 これは知らないとハマります。エラーメッセージも「config が無い」という形で出るので、原因がファイル名だとすぐには気づきにくい。

    命名規則の変更は、影響範囲を正しく見積もってから。 .yml → .yaml の変更は「単なるリネーム」に見えますが、Pulumi のように拡張子の一致を前提とするツールでは動作に影響します。今回は monitoring 配下のみでも、他にも同じパターンがあるなら一括で変えないとかえって混乱します。

    今回は一部作業で Claude Code を使って操作しました。AWS の操作手順を事前に読み込んでもらい、フェーズごとに確認しながら進める形です。コマンドを手で打つよりも、「今この操作は何をしているか」「何を確認すべきか」をセットで確認しながら進められるのが良かったです。

    次のステップは、今回まだ手動で行った SG 管理を Terraform に移行することです。それはまた別の記事で。

    参考

    AWS の運用手順やトラブル対処を体系的に学びたい方には、以下の書籍が参考になります。本記事のような事前確認や CLI 操作の作法を整理するのに役立ちます。

    この記事は役に立ちましたか?

    Coffee cup

    この記事が、何かの整理につながったら

    コーヒー1杯分の応援をもらえると嬉しいです。

    ※ これは応援とは別の話ですが、

    同じようなテーマを自分の文脈で整理したい場合は、 (文章だけだと詰まりやすい人向けに) 思考整理の壁打ちという形で対話の時間も取っています。

    対話の時間について