🤖

インフラエンジニアもClineを触ってみたい!

2025/03/12に公開

きっかけ

最近Clineが界隈をにぎわせているので使ってみたいな~と思ったのがきっかけです。
普段はアプリケーション開発ではなく、インフラメインなのでterraformをClineで書いてみることにしました。

お題は何でもよかったので、Azureアーキテクチャセンターの「基本的な Web アプリケーション」を作ってもらいました。
https://learn.microsoft.com/ja-jp/azure/architecture/web-apps/app-service/architectures/basic-web-app

結果

作れました。

利用したモデルは以下の通りで、約2ドルくらいで生成してくれました。

Mode Model
Plan claude3.7-sonnet
Act genimi-2.0-flash-001※

※無料枠のレートリミットが来たので、少しだけclaudeを投入しました。

生成されたコードのフォルダ構成はこんな感じです。

やったこと

clinerulesの作成

モジュール分割や命名規則、テスト計画等をClineに渡すためにclinerulesを作成しました。
このルールは公式が出しているterraform Style GuideとGoogleCloudの一般的なスタイルと構造に関するベスト プラクティスをClaudeに食わせて生成しました。

clinerules
clinerules
# Terraformコーディングプラクティス

## 原則

### DRY原則(Don't Repeat Yourself)

- ローカル変数を活用し、反復を避ける
- モジュールを使用して共通コードを抽象化(モジュールはサービス単位で作成(例:azurevm、appservice等))
- 変数とoutputsを適切に使用
- for_eachとcountを活用して類似リソースをまとめる

### 可読性とメンテナンス性

- 一貫したコードフォーマット
- 明確な命名規則
- 適切なコメントと文書化
- モジュールの分割と再利用

## 実装パターン

### ファイル構成


├── env/                # 環境別設定
│   ├── dev/
│   │   └── terraform.tfvars    # 開発環境変数
│   ├── test/
│   │   └── terraform.tfvars    # テスト環境変数
│   └── prod/
│       └── terraform.tfvars    # 本番環境変数
├── main.tf             # リソース定義
├── variables.tf        # 入力変数
├── outputs.tf          # 出力変数
├── locals.tf           # ローカル変数
├── providers.tf        # プロバイダー設定
├── backend.tf          # バックエンド設定
├── terraform.tf        # Terraformバージョン等の設定
├── README.md           # プロジェクト説明と使用方法
└── modules/            # 再利用可能なモジュール
    └── <module_name>/
        ├── main.tf
        ├── variables.tf
        └── outputs.tf


### リソース命名

リソースには読みやすく一貫性のある名前を付けます。単語はアンダースコアで区切り、リソースタイプはリソース識別子に含めません。

# 悪い例
resource "azurerm_virtual_network" "vnet-prod-eastus" {...}

# 良い例
resource "azurerm_virtual_network" "sys_vnet" {...}


### タグ付け

Azureリソースには常に以下のタグを設定します。Nameタグはリソースごとに適切な名称を設定します:


resource "azurerm_resource_group" "example" {
  # ...
  tags = {
    Name   = "example-resource-group"  # リソースごとに適切な名称
    System = var.system_name
    Env    = var.environment
  }
}

resource "azurerm_virtual_network" "example" {
  # ...
  tags = {
    Name   = "example-vnet"  # リソースごとに適切な名称
    System = var.system_name
    Env    = var.environment
  }
}


### 変数定義

すべての変数には型と説明を必ず含めます。オプションの変数には適切なデフォルト値を設定します。

variable "location" {
  type        = string
  description = "The Azure region where resources will be created"
  default     = "eastus"
}

variable "environment" {
  type        = string
  description = "Environment name (dev, test, prod)"
  
  validation {
    condition     = contains(["dev", "test", "prod"], var.environment)
    error_message = "Environment must be one of: dev, test, prod."
  }
}


### 出力変数

出力変数にも必ず説明を含めます。


output "resource_group_id" {
  description = "The ID of the created resource group"
  value       = azurerm_resource_group.main.id
}


### ローカル変数

ローカル変数を使用して、コード内で複数回使用される式や値を定義します。


locals {
  name_suffix     = "${var.environment}-${var.location}"
  resource_prefix = "${var.system_name}-${local.name_suffix}"
}


### シークレット管理

シークレット情報(パスワード、APIキー、接続文字列など)は決してコード内にハードコードしないでください。以下の方法を使用してください:

- リソース構築時にランダム文字を生成し、Azure Key Vaultに格納


# 悪い例 - ハードコード
resource "azurerm_sql_server" "example" {
  administrator_login_password = "SuperSecret123!"  # 避けるべき
}

# 良い例
resource "azurerm_sql_server" "example" {
  administrator_login_password = var.sql_admin_password  # 変数として渡す
}

### PJ固有情報
system_nameはsysを格納してください。
リソースの命名規約はsys_[環境略称]_[リソース略称]_[役割]としてください。
リソース略称は以下のドキュメントから引用してください。
https://learn.microsoft.com/ja-jp/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations

## Terraformの使い方

### AzureRMプロバイダー設定


# providers.tf
provider "azurerm" {
  features {}
}

# terraform.tf
azurermのバージョンは最新メジャーバージョンを設定してください。
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 4.0.0"
    }
  }
}


### for_eachとcountの使用

複数の類似リソースを作成する場合は、for_eachまたはcountを使用します。


# for_eachの例
variable "subnets" {
  type = map(object({
    address_prefix = string
    service_endpoints = list(string)
  }))
  default = {
    web = {
      address_prefix = "10.0.1.0/24"
      service_endpoints = ["Microsoft.Web"]
    },
    app = {
      address_prefix = "10.0.2.0/24"
      service_endpoints = ["Microsoft.Sql"]
    },
    data = {
      address_prefix = "10.0.3.0/24"
      service_endpoints = ["Microsoft.Sql", "Microsoft.Storage"]
    }
  }
}

resource "azurerm_subnet" "example" {
  for_each = var.subnets
  
  name                 = each.key
  resource_group_name  = azurerm_resource_group.main.name
  virtual_network_name = azurerm_virtual_network.main.name
  address_prefixes     = [each.value.address_prefix]
  service_endpoints    = each.value.service_endpoints
}


## モジュール設計

### モジュールの基本構造


modules/
└── virtual_machine/
    ├── main.tf       # リソース定義
    ├── variables.tf  # 入力変数
    └── outputs.tf    # 出力変数

### モジュールの呼び出し

module "web_server" {
  source = "./modules/virtual_machine"
  
  name           = "web"
  vm_size        = "Standard_B2s"
  admin_username = var.admin_username
  location       = var.location
  
  resource_group_name  = azurerm_resource_group.main.name
  subnet_id            = azurerm_subnet.main.id
  
  system_name  = var.system_name
  environment  = var.environment
}

## コード品質とワークフロー

### terraform fmt

コミット前に必ず `terraform fmt` を実行して、一貫したコードフォーマットを維持します。

### terraform validate

`terraform validate` を使用して、構文エラーや一般的な問題を検出します。

### セキュリティチェック

`checkov` を使用してInfrastructure as Codeのセキュリティとコンプライアンスのベストプラクティスをスキャンします。

checkov -d .

### .gitignore

以下のファイルはバージョン管理から除外します:

.terraform/
.terraform.lock.hcl

### 実装手順

1. **設計から始める**
   - 必要なリソースを特定
   - 環境変数とモジュール設計

2. **段階的実装**
   - 基本インフラから開始
   - セキュリティ設定を追加
   - アプリケーションリソースを追加

3. **コード品質確保**
   - terraform fmt で整形
   - terraform validate で検証
   - checkov でセキュリティチェック
   - terraform plan で内容確認

4. **ドキュメント作成**
   - README.mdに使用方法を記載
   - 変数の説明を充実させる
   - 例を提供

いざClineに依頼

Clineの初期セットアップを終え、いざ実行です。
どこまでざっくりな依頼で対応してもらえるのか気になったので、プロンプトはすごくざっくりです。
基本的な Web アプリケーションの構成図部分のスクショを提供して、その通り作ってという雑なお願いです。

(システムプロンプトに「Speak in Japanese」と書いているのですが、英語で話されることがあったのでプロンプトにも含めています。)

Planで実行計画を立ててくれ、Actに変更するとコードを書き始め、コードが書き終わったら、terraform init/plan/applyまで実行してくれました。

やはり、ローカル環境でClineが動いてコマンド実行し、エラーが出ればプロジェクトを見渡してトラブルシューティングをするさまを見ていると隔世の感がありました…!

うまくいかなかったこと

Clineすげ~となった一方で、私のCline力の低さからきているのか、いくつか思い通りにいかないポイントもありましたのでご紹介します。
改善提案あればコメントいただけますと幸いです。

clinerulesをちゃんと読んでくれない

最初のプロンプトを投げた後、↓のようにclinerulesを読んでくれます。

そのあとplanの結果が表示されたのですが、ファイル構造がclinerulesと違う…
モジュールも分割されていない…

加えて、シークレットもランダム生成してKeyVaultに格納するように指示しているのにユーザからの情報提供を求める…

ただし、間違っている個所を指摘したうえできちんと読み込みなおすように指示すると改善することができました。
もっと強制力を持たせられるような書き方があるのか模索していきます。

checkovの結果をインテリジェンスに取り込めない

checkovで出来上がったコードの品質をチェックするように定めています。
今回は20項目程度Failedになり、Clineが自発的にFailedをつぶしてってくれました。
「さすがだな~」と思って眺めていたのですがよくよく見ると、今回VnetがないアーキテクチャなのにPrivate Endpointを作ろうとしていたり、むやみにパブリックアクセスをブロックしたりしていました…
この辺りはActで利用していたモデルの性能かもしれませんが、アーキテクチャを理解して指摘の取り込み有無を一次判断し、方針を問い合わせる みたいな動きをしてくれたらうれしいなと思いました。

まとめ

とりあえずClineを初めて触ってみた感想でした。
良かった点としては、ざっくりとした指示からある程度機能するコードを生成し、エラーを検出して修正までしてくれるところは噂にたがわぬ実力・可能性を感じました!

一方で、clinerulesの遵守やcheckovの結果の適切な取り込みなど、まだ改善の余地がある部分もありました。
より強制力のあるルール設定方法や、アーキテクチャの理解に基づいた判断ができるような仕組みができるようなプロンプトやclinerulesを試していこうと思います。

Discussion