慣性聚合 関心のあるブログ、ニュース、テクノロジーを効率的に追跡
原文を読む 慣性聚合で開く

おすすめ購読元

V
V2EX
博客园 - 叶小钗
Y
Y Combinator Blog
大猫的无限游戏
大猫的无限游戏
博客园 - 【当耐特】
酷 壳 – CoolShell
酷 壳 – CoolShell
D
Docker
WordPress大学
WordPress大学
Blog — PlanetScale
Blog — PlanetScale
博客园 - Franky
G
Google Developers Blog
爱范儿
爱范儿
Google DeepMind News
Google DeepMind News
Stack Overflow Blog
Stack Overflow Blog
云风的 BLOG
云风的 BLOG
Engineering at Meta
Engineering at Meta
aimingoo的专栏
aimingoo的专栏
V
Visual Studio Blog
M
MIT News - Artificial intelligence
Hugging Face - Blog
Hugging Face - Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
私はテラフォーマー・スパゲッティの47,000行を相続した—ここに、生産環境を燃焼させずに解きほぐした方法
S, Sanjay · 2026-05-22 · via DEV Community

月曜日を台無しにしたSlackのメッセージ

「前のプラットフォームチームが去りました。リポジトリはこちらです。頑張ってください 🫡」

私はGitリポジトリを見つめていました。 47,000行のTerraformコード。x temp2一つの状態ファイル。ゼロのモジュール。変数名はDO_NOT_TOUCH_ask_raj、__JHSNS_SEG_d25198f1_8__、そして私の大好きなもの——__JHSNS_SEG_d25198f1_9__。ラージは2年前に会社を去りました。

一年以上のシニアデボップエンジニアであれば、こんなものを引き継いでいます。47K行とはいかなくても、main.tfを開いて、キャリア選択を疑問に思ったことはあります。

これは「Terraformのベストプラクティス」に関する記事ではありません。それらは、運用する必要がなかった人によって書かれています。terraform plan は午前2時、3,000リソースの状態ファイルで、エンジニアリングのVPが見守っている間に起こりました。

これは生存ガイドです。


反パターン #1: モノリス状態ファイル(通称「キャリアの単一ポイント失敗」)

私が発見したこと

# main.tf — 8,400 lines
# "Managed" networking, compute, databases, DNS, IAM, monitoring,
# and somehow... a CloudFront distribution for a marketing site
# that was decommissioned in 2023.

resource "aws_vpc" "main" { ... }
resource "aws_instance" "api_server_1" { ... }
resource "aws_instance" "api_server_2" { ... }
# ... 200 more instances ...
resource "aws_rds_instance" "prod_db" { ... }
resource "aws_iam_role" "god_mode" { ... }  # yes, really

フルスクリーンモードに入る フルスクリーンモードから退出する

単一の terraform apply すべてを触りました ネットワーキング、データベース、コンピュート、DNS — すべてが1月のクリスマスライトのように絡み合っている。セキュリティグループルールの1つのタイプミス?おめでとう、あなたの plan が847のリソースを評価する必要があることを示し、TerraformはあなたのRDSインスタンスを交換する必要があると決定しました。

本当の危険

これはただの乱雑さではなく — これは 運用上の破滅です。以下が起こることです:

  • terraform plan14 分 かかります。開発者はそれを停止しました。
  • 状態ファイルロックは一度に一人しか作業できないことを意味します。
  • どのミスもその影響範囲はインフラ全体です。
  • 新しいチームメンバーは何かを触るのを恐れています(適切にです)。

どうやって解決したか(ダウンタイムなしで)

ステップ 1: 状態手術でterraform state mv

# First, I mapped resource dependencies visually
terraform graph | dot -Tsvg > infra-dependency-map.svg

# Then, split by domain boundaries
terraform state mv 'aws_vpc.main' -state-out=networking/terraform.tfstate
terraform state mv 'aws_subnet.public[0]' -state-out=networking/terraform.tfstate
terraform state mv 'aws_subnet.public[1]' -state-out=networking/terraform.tfstate

フルスクリーンモードを開始 フルスクリーンモードを終了

ステップ 2: バースト半径で状態の境界を紹介

私は変化頻度バースト半径に基づいて五つの状態ファイルに分けました

レイヤー コンテンツ 変化頻度 爆発半径
foundation VPC、サブネット、ルートテーブル 月次 重大
security IAM、KMS、セキュリティグループ 週次 重大
data RDS、ElastiCache、S3 稀少 災害的
compute ECS/EKS、ASGs、ALBs 日次 高い
edge CloudFront、Route53、WAF 週間 中級

ステップ3: リモート状態データソースでそれらを接続します

# In compute/main.tf
data "terraform_remote_state" "networking" {
  backend = "s3"
  config = {
    bucket = "company-terraform-state"
    key    = "foundation/terraform.tfstate"
    region = "us-east-1"
  }
}

resource "aws_ecs_service" "api" {
  # Reference networking outputs safely
  network_configuration {
    subnets = data.terraform_remote_state.networking.outputs.private_subnet_ids
  }
}

フルスクリーンモードを開始します フルスクリーンモードを終了します

結果: terraform plan 14分から45秒に短縮されました。チームのスピードが3倍になりました。深夜2時の状態ロックに関するページの通知を受け取るのをやめました。


反パターン#2: コピペ帝国(別名「家にモジュールがある」)

私が発見したこと

environments/
├── dev/
│   └── main.tf      # 1,200 lines
├── staging/
│   └── main.tf      # 1,200 lines (95% identical to dev)
├── prod/
│   └── main.tf      # 1,200 lines (90% identical... with 47 "hotfixes")
└── dr/
    └── main.tf      # 1,200 lines (copied from prod 8 months ago, never updated)

全画面表示モードに入る 全画面表示モードから退出する

同じインフラストラクチャのコピーが4つあり、微妙なずれがあった。ステージングにはセキュリティグループルールがあり、プロダクションにはなかった。DRは3つのサービスが完全に欠けていた。誰も意図的にどの違いがあるか知らなかった。

なぜこれがシニアエンジニアを殺しているのか

あなたはできませんdiffこの問題から抜け出す方法です。ファイルは意図的(prodにはより大きなインスタンスがある)および偶然(誰かがdevでバグを修正したが、それを広めるのを忘れた)の両方の方法で分岐しています。あなたは真実の源がない.

実際に機能するリファクタリング戦略

一度にすべてを統合しようとしないこと.失敗した「ビッグバン」リファクタリングで3つのスプリントかけてステージングを1週間壊したから学んだ.

代わりに、ストラングラー・フィグパターンを使え.

# modules/api-platform/main.tf
variable "environment" {
  type = string
  validation {
    condition     = contains(["dev", "staging", "prod", "dr"], var.environment)
    error_message = "Environment must be dev, staging, prod, or dr."
  }
}

variable "config" {
  type = object({
    instance_type    = string
    min_capacity     = number
    max_capacity     = number
    enable_waf       = bool
    multi_az         = bool
    backup_retention = number
  })
}

locals {
  # Environment-specific defaults that document WHY they differ
  env_config = {
    dev = {
      instance_type    = "t3.medium"
      min_capacity     = 1
      max_capacity     = 2
      enable_waf       = false
      multi_az         = false
      backup_retention = 1
    }
    prod = {
      instance_type    = "m5.xlarge"
      min_capacity     = 3
      max_capacity     = 20
      enable_waf       = true
      multi_az         = true
      backup_retention = 35
    }
  }
}

フルスクリーンモードに入る. フルスクリーンモードから退出する.

鍵となる洞察は:すべての環境の違いはコードで意図的に文書化され、1200行のファイルに無意識の逸脱として隠されていません


。 反パターン#3: terraform apply -auto-approve YOLO パイプライン

.gitlab-ci.yml

deploy_prod:
  stage: deploy
  script:
    - terraform init
    - terraform apply -auto-approve  # 🚨 WHAT
  only:
    - main

で見つけたこと__Enter fullscreen mode Exit fullscreen mode

計画のアーティファクトがない。承認のゲートがない。差分レビューがない。mainにプッシュ → プロダクションでのインフラストラクチャの変更。コミット履歴は恐怖のストーリーを語っていた:

fix: revert the revert of the fix
fix: actually fix prod this time
fix: ok THIS one fixes it
revert: revert everything from today

フルスクリーンモードに入る フルスクリーンモードから退出する

実際にシニアエンジニアが必要とするもの

# .github/workflows/terraform.yml
name: "Terraform"

on:
  pull_request:
    paths: ['infrastructure/**']
  push:
    branches: [main]
    paths: ['infrastructure/**']

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Terraform Plan
        id: plan
        run: |
          terraform init
          terraform plan -no-color -out=tfplan \
            -detailed-exitcode 2>&1 | tee plan_output.txt
        continue-on-error: true

      - name: Comment Plan on PR
        uses: actions/github-script@v7
        if: github.event_name == 'pull_request'
        with:
          script: |
            const fs = require('fs');
            const plan = fs.readFileSync('plan_output.txt', 'utf8');
            const truncated = plan.length > 60000 
              ? plan.substring(0, 60000) + '\n\n... truncated ...' 
              : plan;
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## Terraform Plan Output\n\`\`\`\n${truncated}\n\`\`\``
            });

      - name: Upload Plan Artifact
        uses: actions/upload-artifact@v4
        with:
          name: tfplan
          path: tfplan

  apply:
    needs: plan
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    environment: production  # Requires manual approval
    steps:
      - uses: actions/checkout@v4

      - name: Download Plan
        uses: actions/download-artifact@v4
        with:
          name: tfplan

      - name: Terraform Apply
        run: terraform apply tfplan  # Apply ONLY the reviewed plan

フルスクリーンモードに入る フルスクリーンモードから退出する

交渉不可能なルール:

  1. プランはPRで生成され、アーティファクトとして添付されます。
  2. 人間がプロダクション適用前に差分をレビューします。
  3. 適用は、レビューされた正確なプランを使用します(新しいプランではありません)。
  4. production環境には、上級エンジニアからの手動承認が必要です。

アンチパターン #4: セキュリティの秘密 (時限爆弾的なコンプライアンス)

私が発見したこと

resource "aws_db_instance" "prod" {
  engine               = "postgres"
  instance_class       = "db.r5.2xlarge"
  username             = "admin"
  password             = "Pr0d_P@ssw0rd_2022!"  # I wish I was joking
  publicly_accessible  = true                    # I really wish I was joking
}

フルスクリーンモードに入る フルスクリーンモードから抜ける

パスワードは.tfファイル、状態ファイル、計画の出力、Gitの履歴にありました。漏洩する可能性のある場所が4つありました。そしてpublicly_accessible = trueは、このクズのアイスクリームサンデーの最後のトッピングでした。

The Fix (That Also Passes Audit)

# Use a data source to pull secrets at plan/apply time
data "aws_secretsmanager_secret_version" "db_password" {
  secret_id = "prod/rds/master-password"
}

resource "aws_db_instance" "prod" {
  engine              = "postgres"
  instance_class      = "db.r5.2xlarge"
  username            = "admin"
  password            = data.aws_secretsmanager_secret_version.db_password.secret_string
  publicly_accessible = false

  # Prevent Terraform from detecting password "drift"
  lifecycle {
    ignore_changes = [password]
  }
}

フルスクリーンモードに入る フルスクリーンモードから退出する

しかし、それだけでは不十分です。 ステートファイルまだ機密情報を含んでいます。完全な解決策:

# backend.tf
terraform {
  backend "s3" {
    bucket         = "company-terraform-state"
    key            = "prod/data/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true                          # SSE-KMS encryption
    kms_key_id     = "arn:aws:kms:us-east-1:xxx:key/yyy"
    dynamodb_table = "terraform-state-lock"
  }
}

フルスクリーンモードに入る フルスクリーンモードを終了

より厳格なS3バケットポリシー、アクセスログ、そして決して開発者に直接状態ファイルへのアクセスを与えない。terraform outputを使用する代わりに.


反パターン#5: 200行のネストされたブロックを持つ「神のリソース」

私が発見したこと

resource "aws_ecs_task_definition" "api" {
  family                   = "api"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = 1024
  memory                   = 2048
  execution_role_arn       = aws_iam_role.ecs_execution.arn
  task_role_arn            = aws_iam_role.ecs_task.arn

  container_definitions = jsonencode([
    {
      name  = "api"
      image = "company/api:latest"  # 🚨 LATEST TAG IN PROD
      portMappings = [{ containerPort = 8080 }]
      environment = [
        { name = "DB_HOST", value = "prod-db.cluster-xxx.us-east-1.rds.amazonaws.com" },
        { name = "DB_NAME", value = "production" },
        { name = "REDIS_URL", value = "prod-redis.xxx.cache.amazonaws.com:6379" },
        # ... 45 more environment variables hardcoded here ...
      ]
      logConfiguration = {
        logDriver = "awslogs"
        options = {
          "awslogs-group"         = "/ecs/api"
          "awslogs-region"        = "us-east-1"
          "awslogs-stream-prefix" = "api"
        }
      }
      # ... 80 more lines of health checks, mount points, ulimits ...
    }
  ])
}

フルスクリーンモードを開始 フルスクリーンモードを終了

問題が複雑化する:

  • 環境変数がハードコードされている(SSM/Secrets Managerから取得していない)。
  • latestタグはデプロイが再現不能であることを意味する。
  • jsonencodeバルクはPRレビューでテスト不可能で差分比較もできない。
  • 環境変数の変更一つで完全なタスク定義の置き換えがトリガーされる。

リファクタリングされたバージョン

# Use templatefile for complex JSON — it's testable and readable
resource "aws_ecs_task_definition" "api" {
  family                   = "api-${var.environment}"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = var.task_cpu
  memory                   = var.task_memory
  execution_role_arn       = aws_iam_role.ecs_execution.arn
  task_role_arn            = aws_iam_role.ecs_task.arn

  container_definitions = templatefile("${path.module}/templates/api-container.json.tpl", {
    image_tag     = var.image_tag  # Pinned, passed from CI/CD
    environment   = var.environment
    db_host       = data.aws_ssm_parameter.db_host.value
    redis_url     = data.aws_ssm_parameter.redis_url.value
    log_group     = aws_cloudwatch_log_group.api.name
    aws_region    = data.aws_region.current.name
  })
}

フルスクリーンモードを開始 フルスクリーンモードを終了


リファクタリング・プレイブック(月曜日にこれをする)

この三年間の混乱を解きほぐした後、ここに有効な手順があります

第1週:分類と保護

# 1. Enable state file encryption and locking NOW
# 2. Add branch protection — no direct pushes to main
# 3. Run terraform plan and SAVE the output as your baseline
terraform plan -no-color > baseline_plan_$(date +%Y%m%d).txt

# 4. Enable detailed audit logging on your state bucket

フルスクリーンモードを開始 フルスクリーンモードを終了

第2週~第4週:モノリシスを分割

# Use terraform state list to inventory everything
terraform state list > all_resources.txt
wc -l all_resources.txt  # Mine had 2,847 resources

# Group by service domain
grep "aws_vpc\|aws_subnet\|aws_route" all_resources.txt > networking.txt
grep "aws_iam\|aws_kms" all_resources.txt > security.txt
grep "aws_rds\|aws_elasticache\|aws_s3" all_resources.txt > data.txt
grep "aws_ecs\|aws_alb\|aws_autoscaling" all_resources.txt > compute.txt

フルスクリーンモードに入る フルスクリーンモードから退出する

第5週~第8週:段階的にモジュール化する

一つずつサービスをモジュールに移動させる。それぞれの移動後:

  1. terraform planを実行する——それには変更がゼロであると表示されるべきです。
  2. 計画に変更が示されている場合、バグがあります。進める前に修正してください。
  3. 他のシニアエンジニアからPRのレビューを取得してください。
  4. 適用し、24時間監視してください。

第9週~第12週:パイプラインを強化

  • CIにterraform validatetflintを追加します。
  • セキュリティスキャンのため、checkovまたはtfsecを追加します。
  • ずれ検知の実装(差異を通知するスケジュールされた計画).
  • コスト見積もりをinfracostで追加.

Drift Detection Cron が私たちを救った

これは誰も話さないことです。完璧なリファクタリングの後でも、ずれが起こりますコンソールでクリックされました。自動修復ツールが変更を行います。Lambdaがセキュリティグループを修正します.

# .github/workflows/drift-detection.yml
name: "Drift Detection"

on:
  schedule:
    - cron: '0 6 * * 1-5'  # Every weekday at 6 AM

jobs:
  detect-drift:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        layer: [foundation, security, data, compute, edge]
    steps:
      - uses: actions/checkout@v4

      - name: Terraform Plan (Drift Check)
        id: plan
        working-directory: infrastructure/${{ matrix.layer }}
        run: |
          terraform init
          terraform plan -detailed-exitcode -no-color > plan.txt 2>&1
          echo "exitcode=$?" >> $GITHUB_OUTPUT
        continue-on-error: true

      - name: Alert on Drift
        if: steps.plan.outputs.exitcode == '2'
        run: |
          # Exit code 2 = changes detected (drift!)
          curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
            -H 'Content-type: application/json' \
            -d "{\"text\":\"🚨 Drift detected in *${{ matrix.layer }}* layer. Check the plan output.\"}"

フルスクリーンモードに入力 フルスクリーンモードから退出

最初の週だけで3件の不正なコンソール変更を検知しました.


混乱に直面した若手エンジニアへのアドバイス

  1. すべてを一度にリファクタリングしないでください。 物事を壊して信用を失うことになる。

  2. 修正する前に、見つけたことを文書化する。 悪いことのスクリーンショットを取る。後日検証と評価のため必要になる。

  3. 開始する前に、リーダーシップの承認を得る。 "技術的負債のために3つのスプリントが必要です"は難しい販売です。"現在の設定では、インフラストラクチャの変更がインシデントを引き起こす可能性が40%あります"は予算を承認されます.

  4. すべてのterraform state mvは別々の、レビューされたPRであるべきです. それは技術的に必要だからではなく、50のステップのうち37番目で何かが壊れたときに、クリーンなgit履歴でバイセクションしたいからです。

  5. 目標は完璧なTerraformではない。目標は、チームが午後2時(2 AM)に安全に運用できるTerraformだ。若若ジュニアエンジニアが実行できませんterraform plan恐れず、リファクタリングは完了していない。


スクローラー用のTL;DR

反パターン 直す 優先順位
モノリス状態ファイル 爆発半径で分割し、頻度を変更 P0
環境のコピー&ペースト モジュール+環境設定 P1
-auto-approveCI内 アーティファクトの計画+手動承認ゲート P0
状態/コード内のシークレット シークレットマネージャー+暗号化された状態+ignore_changes P0
ゴッドリソースとインラインJSON templatefile + SSMパラメータ P2
ドリフト検知なし スケジュールplanアラートあり P1

Terraformのコードベースを見て「誰がこれをしたんだろう?!」と空虚に囁いたことがあるなら、あなたは一人じゃない。私たちは皆そこにいた。良いニュースは?直せる。一つずつ状態を移動して。


この情報が役に立ったですか?もっと本番で試されたDevOpsのコンテンツを見るためにフォローしてください。私はドキュメントのハッピー・パスではなく、実際に本番で起こることについて書きます。