こんにちは、HolyShehe AI技術ブログへようこそ。私は普段インフラ管理工作をしているエンジニアですが、を使ったIaC(Infrastructure as Code)に最近本格的に移行しました。本日は、PulumiとHolyShehe AIのAPIを組み合わせたインフラ管理の世界を、API経験が全くない初心者の方に向けてゼロから解説いたします。

なぜPulumiなのか?

従来のTerraformなどのIaCツールは独自のDSL(Domain Specific Language)を学ぶ必要がありました。一方、PulumiはTypeScript、Python、Go、C#などの、普段使っているプログラミング言語でインフラを定義できます。これにより、条件分岐やループを使った柔軟なインフラ管理が可能になります。

さらに、HolyShehe AIのAPIを組み合わせることで、インフラ構成の最適化提案や自動コード生成,甚至是被災時の自動復旧スクリプトの作成まで、AIの力で自動化できます。HolyShehe AIの2026年価格はGPT-4.1 $8/MTokClaude Sonnet 4.5 $15/MTokDeepSeek V3.2 $0.42/MTokと、コストパフォーマンスに優れています。

必要な環境の準備

Step 1: Pulumi CLIのインストール

まず、PulumiのCLIをインストールします。macOSの場合はHomebrew、Windowsの場合はChocolateyまたはMSIインストーラーを使います。

# macOS
brew install pulumi

Windows (Chocolatey)

choco install pulumi

Linux

curl -fsSL https://get.pulumi.com | sh

インストール確認

pulumi version

出力: v3.x.x

Step 2: Node.jsとTypeScriptの準備

PulumiをTypeScriptで使うので、Node.js环境を構築します。

# Node.jsバージョン確認(v18以上を推奨)
node --version

v20.10.0

プロジェクトフォルダの作成

mkdir pulumi-ai-infra cd pulumi-ai-infra

初期化

pulumi new typescript

必要なパッケージインストール

npm install @pulumi/pulumi @pulumi/aws

Step 3: HolyShehe AI APIキーの取得

HolyShehe AIにログインして、APIキーを取得します。ダッシュボードの「API Keys」セクションから生成できます。HolyShehe AIは¥1=$1の超優遇レート(中国語ベースの海外サービスを避けるなら注目の選択肢)で、WeChat PayやAlipayにも対応しています。登録すれば無料クレジットもらえます!

実践:AI APIを呼び出すPulumiリソースを作成

infraestructura設計

今回の目標は、EC2インスタンス上にAI APIを呼び出すLambda関数をデプロイすることです。以下の構成を作成します:

Pulumiプロジェクト的文件の作成

// index.ts
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// 設定値の取得
const config = new pulumi.Config();
const openaiApiKey = config.requireSecret("holySheepApiKey");
const environment = config.get("environment") || "development";

// ========================================
// 1. VPCの作成
// ========================================
const vpc = new aws.ec2.Vpc("ai-api-vpc", {
    cidrBlock: "10.0.0.0/16",
    enableDnsHostnames: true,
    enableDnsSupport: true,
    tags: {
        Name: ai-api-vpc-${environment},
        Environment: environment,
    },
});

// サブネットの作成
const subnet = new aws.ec2.Subnet("ai-api-subnet", {
    vpcId: vpc.id,
    cidrBlock: "10.0.1.0/24",
    availabilityZone: "us-east-1a",
    mapPublicIpOnLaunch: false,
    tags: {
        Name: ai-api-subnet-${environment},
    },
});

// インターネットゲートウェイ
const igw = new aws.ec2.InternetGateway("ai-api-igw", {
    vpcId: vpc.id,
    tags: { Name: ai-api-igw-${environment} },
});

// ルートテーブル
const routeTable = new aws.ec2.RouteTable("ai-api-rt", {
    vpcId: vpc.id,
    routes: [
        {
            cidrBlock: "0.0.0.0/0",
            gatewayId: igw.id,
        },
    ],
});

new aws.ec2.RouteTableAssociation("ai-api-rta", {
    subnetId: subnet.id,
    routeTableId: routeTable.id,
});

// ========================================
// 2. S3バケット(ログ保存用)
// ========================================
const logBucket = new aws.s3.Bucket("ai-api-log-bucket", {
    bucket: ai-api-logs-${environment}-${pulumi.getStack()},
    acl: "private",
    versioning: {
        enabled: true,
    },
    lifecycleRule: [{
        enabled: true,
        expiration: 365,
        transitions: [{
            days: 30,
            storageClass: "STANDARD_IA",
        }],
    }],
    tags: {
        Environment: environment,
    },
});

// ========================================
// 3. IAMロール(Lambda用)
// ========================================
const lambdaRole = new aws.iam.Role("ai-api-lambda-role", {
    name: ai-api-lambda-role-${environment},
    assumeRolePolicy: JSON.stringify({
        Version: "2012-10-17",
        Statement: [{
            Action: "sts:AssumeRole",
            Effect: "Allow",
            Principal: {
                Service: "lambda.amazonaws.com",
            },
        }],
    }),
});

new aws.iam.RolePolicyAttachment("lambda-basic-exec", {
    role: lambdaRole.name,
    policyArn: "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
});

new aws.iam.RolePolicy("lambda-s3-policy", {
    role: lambdaRole.id,
    policy: logBucket.id.apply(id => JSON.stringify({
        Version: "2012-10-17",
        Statement: [{
            Effect: "Allow",
            Action: [
                "s3:PutObject",
                "s3:GetObject",
            ],
            Resource: arn:aws:s3:::ai-api-logs-${environment}-${pulumi.getStack()}/*,
        }],
    })),
});

// ========================================
// 4. Lambda関数(HolyShehe AI API呼び出し)
// ========================================
const apiHandler = new aws.lambda.Function("ai-api-handler", {
    functionName: ai-api-handler-${environment},
    role: lambdaRole.arn,
    runtime: "nodejs18.x",
    handler: "index.handler",
    timeout: 30,
    memorySize: 256,
    code: new pulumi.asset.AssetArchive({
        "index.js": new pulumi.asset.StringAsset(`
const https = require('https');

exports.handler = async (event) => {
    const apiKey = process.env.HOLY_SHEEP_API_KEY;
    
    // HolyShehe AI APIへのリクエスト
    const payload = JSON.stringify({
        model: "gpt-4.1",
        messages: [
            { role: "system", content: "あなたはインフラ管理の助手です。" },
            { role: "user", content: event.prompt || "インフラの最適化提案をしてください。" }
        ],
        max_tokens: 500,
        temperature: 0.7,
    });

    const options = {
        hostname: 'api.holysheep.ai',
        port: 443,
        path: '/v1/chat/completions',
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': \Bearer \${apiKey}\,
            'Content-Length': Buffer.byteLength(payload),
        },
    };

    return new Promise((resolve, reject) => {
        const req = https.request(options, (res) => {
            let data = '';
            res.on('data', (chunk) => data += chunk);
            res.on('end', () => {
                try {
                    const result = JSON.parse(data);
                    resolve({
                        statusCode: 200,
                        body: JSON.stringify({ success: true, data: result }),
                    });
                } catch (e) {
                    reject(new Error('Failed to parse API response'));
                }
            });
        });

        req.on('error', reject);
        req.write(payload);
        req.end();
    });
};
        `),
    }),
    environment: {
        variables: {
            HOLY_SHEEP_API_KEY: openaiApiKey,
            LOG_BUCKET: logBucket.id,
            ENVIRONMENT: environment,
        },
    },
});

// Lambda関数のARNを出力
export const lambdaArn = apiHandler.arn;
export const vpcId = vpc.id;
export const logBucketName = logBucket.id;
export const apiEndpoint = apiHandler.invokeArn;

Pulumi設定ファイルの作成

# Pulumi..yaml に設定を保存

config:
  pulumi-ai-infra:holySheepApiKey:
    secure: AAABBBCCCDDDEEEFFF...
  pulumi-ai-infra:environment: production

ヒント:APIキーは「pulumi config set --secret pulumi-ai-infra:holySheepApiKey YOUR_API_KEY」で安全に保存してください。secretオプションを使うことで、KMSで暗号化されます。

デプロイの実行

# プレビュー(変更内容の確認)
pulumi preview

デプロイ

pulumi up

出力例:

Previewing update (production)

View Live: https://app.pulumi.com/...

Resources:

+ 8 to create

Do you want to proceed? [Yes] yes

Updating (production)

Duration: 2m45s

Outputs:

lambdaArn: "arn:aws:lambda:us-east-1:123456789:function:ai-api-handler-production"

vpcId: "vpc-0a1b2c3d4e5f6g7h8"

logBucketName: "ai-api-logs-production-abc123"

Resources:

8 created

AIを活用したインフラ最適化の実例

HolyShehe AIのAPIを使って、インフラコストを自動最適化するスクリプトを作成しました。以下のコードは、月の利用コストを分析して最適化の提案を生成するものです。

// optimizer.ts - AIを活用したインフラ最適化
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const config = new pulumi.Config();

interface CostReport {
    service: string;
    monthlyCost: number;
    utilization: number;
    recommendations: string[];
}

const HOLY_SHEEP_API_KEY = config.requireSecret("holySheepApiKey");

// コストデータを取得する関数
async function fetchCostData(): Promise {
    // 実際の実装ではCost Explorer APIを使用
    return [
        { service: "EC2", monthlyCost: 450, utilization: 0.35, recommendations: [] },
        { service: "RDS", monthlyCost: 280, utilization: 0.45, recommendations: [] },
        { service: "CloudWatch", monthlyCost: 85, utilization: 0.80, recommendations: [] },
        { service: "S3", monthlyCost: 120, utilization: 0.60, recommendations: [] },
    ];
}

// HolyShehe AI APIを呼び出して最適化提案を取得
async function getOptimizationFromAI(costData: CostReport[]): Promise<string> {
    const apiUrl = new URL("https://api.holysheep.ai/v1/chat/completions");
    
    const requestBody = {
        model: "deepseek-v3.2",
        messages: [
            {
                role: "system",
                content: `あなたはAWSコスト最適化の専門家です。
以下のコストデータに基づき、具体的な改善案をJSON形式で提案してください。
{
  "actions": [
    {
      "priority": "high|medium|low",
      "service": "サービス名",
      "action": "取るべきアクション",
      "estimatedSavings": "USD/月",
      "risk": "低|中|高"
    }
  ],
  "summary": "全体の要約"
}`
            },
            {
                role: "user",
                content: AWSコストデータを分析してください:${JSON.stringify(costData, null, 2)}
            }
        ],
        max_tokens: 1500,
        temperature: 0.3,
    };

    const response = await fetch(apiUrl.toString(), {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            "Authorization": Bearer ${HOLY_SHEEP_API_KEY},
        },
        body: JSON.stringify(requestBody),
    });

    if (!response.ok) {
        throw new Error(API request failed: ${response.status});
    }

    const result = await response.json();
    return result.choices[0].message.content;
}

// メイン処理
export async function runCostOptimization() {
    console.log("コストデータの取得中...");
    const costData = await fetchCostData();
    
    const totalCurrentCost = costData.reduce((sum, item) => sum + item.monthlyCost, 0);
    console.log(現在の月間コスト: $${totalCurrentCost});
    
    console.log("AIによる最適化提案を取得中...");
    const aiSuggestions = await getOptimizationFromAI(costData);
    
    console.log("=== AI最適化提案 ===");
    console.log(aiSuggestions);
    
    // 提案をS3に保存
    const timestamp = new Date().toISOString();
    console.log(推奨事項は logs/suggestions-${timestamp}.json に保存されます);
    
    return {
        currentCost: totalCurrentCost,
        suggestions: aiSuggestions,
        timestamp,
    };
}

HolyShehe AIの具体的な活用メリット

私が実際にHolyShehe AIを使って感じているメリットは他にもたくさんあります:

よくあるエラーと対処法

エラー1: APIキー認証エラー (401 Unauthorized)

// エラー内容
Error: Request failed with status code 401
{
  "error": {
    "message": "Invalid authentication credentials",
    "type": "invalid_request_error",
    "code": "invalid_api_key"
  }
}

// 原因:APIキーが無効または期限切れ
// 解決方法

// 1. キーが正しく設定されているか確認
pulumi config get holySheepApiKey

// 2. キーがsecretで保存されているか確認(再設定)
pulumi config set --secret pulumi-ai-infra:holySheepApiKey YOUR_ACTUAL_API_KEY

// 3. スタックによって異なるキーを使用する場合
pulumi config set --secret pulumi-ai-infra:holySheepApiKey YOUR_KEY --stack production

// 4. 環境変数として直接設定(開発時のみ)
export HOLY_SHEEP_API_KEY=YOUR_API_KEY

// 5. コードでの正しい読み込み方
const config = new pulumi.Config();
const apiKey = config.requireSecret("holySheepApiKey");
// 絶対にハードコードしないこと!

エラー2: レートリミットExceeded (429 Too Many Requests)

// エラー内容
Error: Request failed with status code 429
{
  "error": {
    "message": "Rate limit exceeded for gpt-4.1",
    "type": "rate_limit_error",
    "retry_after": 5
  }
}

// 原因:短時間に大量のリクエストを送信した
// 解決方法

// 1. リトライロジックを実装(指数バックオフ)
async function retryWithBackoff(fn, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            return await fn();
        } catch (error) {
            if (error.response?.status === 429 && i < maxRetries - 1) {
                const waitTime = Math.pow(2, i) * 1000;
                console.log(Retry after ${waitTime}ms...);
                await new Promise(resolve => setTimeout(resolve, waitTime));
            } else {
                throw error;
            }
        }
    }
}

// 2. 安いモデルに変更してコストも節約
const requestBody = {
    model: "deepseek-v3.2",  // $0.42/MTok - コスト効率最高
    messages: [...],
    max_tokens: 500,  // 必要最低限に設定
};

// 3. バッチ処理でリクエストをまとめる
const batchPrompts = ["prompt1", "prompt2", "prompt3"];
const batchRequest = {
    model: "deepseek-v3.2",
    messages: batchPrompts.map(p => ({ role: "user", content: p })),
};

エラー3: Pulumiリソースの依存関係エラー

// エラー内容
Error: Resource 'lambda-function' is missing required property 'role'
and depends on 'lambda-role' which was created with errors.

Diagnostics:
  aws:lambda/function:Function resource 'lambda-function' has a problem:
  "role": one value does not match regular expression...

// 原因:Lambda関数がIAMロールを作成するのを待つ前に実行された
// 解決方法

// 1. 明示的な依存関係を追加
const lambdaFunction = new aws.lambda.Function("api-handler", {
    // ... other options
    role: lambdaRole.arn,  // pulumiが自動的に依存関係を解決
});

// 2. apply()を使って非同期依存関係を処理
const s3Bucket = new aws.s3.Bucket("log-bucket", {...});

const lambdaWithBucket = new aws.lambda.Function("handler", {
    // ...
    environment: {
        variables: {
            BUCKET_NAME: s3Bucket.id,  // pulumiのOutputは自動的に解決
        },
    },
});

// 3. カスタムリソースで複雑な依存関係を管理
const customDeps = pulumi.all([vpc.id, subnet.id]).apply(([vpcId, subnetId]) => {
    return { vpcId, subnetId };
});

// 4. スタック参照を使った跨スタック依存関係
const infraStack = new pulumi.StackReference("acmecorp/infra/production");
const vpcId = infraStack.getOutput("vpcId");
const subnetId = infraStack.getOutput("subnetId");

エラー4: TypeScriptコンパイルエラー

// エラー内容
error TS2322: Type 'Output<string>' is not assignable to type 'string'

// 原因:PulumiのOutput型を直接文字列として使用した
// 解決方法

// ❌ 間違い
const vpcId: string = vpc.id;  // vpc.idはOutput

// ✅ 正しい方法1: apply()を使用
const securityGroup = new aws.ec2.SecurityGroup("sg", {
    vpcId: vpc.id,  // Pulumiが自動的に処理
});

// ✅ 正しい方法2: apply()で値を変換
vpc.id.apply(id => {
    console.log(VPC ID: ${id});
    return id;
});

// ✅ 正しい方法3: 出力先での使用
new aws.ec2.SecurityGroupRule("rule", {
    type: "ingress",
    fromPort: 443,
    toPort: 443,
    protocol: "tcp",
    sourceSecurityGroupId: securityGroup.id,  // 自動的に解決
});

// ✅ 正しい方法4: エクスポートでの使用
export const vpcId = vpc.id;  // スタック出力で自動的に文字列化

次のステップ

今回の記事を基に、以下のことにチャレンジしてみてください:

  1. 複数環境の構築:staging、production環境を Pulumi Stack で管理
  2. CI/CD統合:GitHub Actionsと組み合わせて自動デプロイ
  3. コスト監視ダッシュボード:CloudWatchとHolyShehe AIで異常検知

    関連リソース

    関連記事