Article

クラウドの利用料金を40%削減する運用テクニック

高田晃太郎
クラウドの利用料金を40%削減する運用テクニック

Flexera 2024の調査ではクラウド支出の約28%が無駄と報告されています¹。加えて、AWS Savings Plans(長期コミットによる割引)はオンデマンド比で公式に最大66%、RI(Reserved Instances、特定リソースの予約割引)は条件により**最大72%の割引が公表されています²³。スポットインスタンス(中断前提の割安リソース)の活用はワークロード次第で最大70〜90%のレート低減が見込めることも広く知られています⁴。一般に、測定とルール化が伴えば、3カ月で10〜20%、半年で30〜40%**程度の削減に到達した事例が複数報告されています(あくまで目安であり環境依存)。課題は「どれから着手し、どの順序で数値化し、どう恒常運用に落とすか」です。本稿では、可視化、即効テクニック、恒常運用の仕組み化という順で、具体クエリやスクリプト、ポリシー例を交えながら、中級〜上級のCTO/エンジニアリングリーダーが即日着手できる手順へ落とし込みます。

可視化と単位経済で「ムダ」を特定する

コスト削減は測定から始まります。粗い合計額ではなく、タグ(リソースに付与するメタデータ)/アカウント/プロダクト/環境/リージョンといった軸での明細化、さらに「1リクエスト/1ジョブあたりの原価」といった単位経済(unit economics)への分解が不可欠です。タグの欠落は分析を不可能にするため、作成時点での強制が最短距離です。初期目標は単純で、直近30日と直近90日の移動平均を比較し、上昇傾向の費目と無負荷時間帯を把握すること。データは、AWSならCost and Usage Report(CUR、利用明細)をAthena(サーバレスのSQLクエリサービス)で、GCPならBilling Export(課金明細)をBigQueryで扱うと俊敏です。

たとえばEC2のCPU使用率が低い時間帯を抽出し、停止やサイズ変更の候補を機械的に洗い出します。以下はAthenaでCURとCloudWatchメトリクスを結合し、「コストへの影響が大きい順」に低利用インスタンスを出す例です。実務ではビュー化してダッシュボードへ組み込み、日次で差分通知すると運用しやすくなります(本番適用前に集計期間やしきい値を環境に合わせて調整してください)。

-- Athena: 直近14日で平均CPUが5%未満のEC2を抽出
WITH usage AS (
  SELECT resource_id, AVG(cast(metric_value as double)) AS avg_cpu
  FROM cw_metrics_ec2
  WHERE metric_name = 'CPUUtilization' AND dt >= date_add('day', -14, current_date)
  GROUP BY resource_id
), cost AS (
  SELECT resourceid AS resource_id, SUM(unblendedcost) AS cost_14d
  FROM aws_cur
  WHERE line_item_usage_start_date >= date_add('day', -14, current_date)
    AND product_product_name = 'Amazon Elastic Compute Cloud'
  GROUP BY resourceid
)
SELECT u.resource_id, u.avg_cpu, c.cost_14d
FROM usage u JOIN cost c ON u.resource_id = c.resource_id
WHERE u.avg_cpu < 5
ORDER BY c.cost_14d DESC;

同様に、外向きデータ転送料(egress)は見落としやすい費目です。GCPではBigQueryで、どのリージョン/サービスからの外向きが多いかを即座に確認できます。結果はCDNキャッシュ戦略やエグレスの集約(出口の統一)に直結します。以下は上位のエグレス費用を把握するクエリです。

-- BigQuery: egressコストの上位サービス/リージョン
SELECT service.description AS service, location.location AS region,
       SUM(cost) AS egress_cost
FROM billing.gcp_billing_export_v1
WHERE usage_start_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  AND sku.description LIKE '%egress%'
GROUP BY service, region
ORDER BY egress_cost DESC
LIMIT 50;

単位経済の導入も鍵です。総額だけでなく、1検索、1API呼び出し、1バッチの原価を可視化し、意思決定のガードレール(例: 「1検索あたり1.2円を上限」)を設けます。キャッシュ戦略やインデックス設計などのアーキテクチャ議論が、費用対効果の言語で揃って進みます。ここまでで「削減ポテンシャルの高い順」に対象を列挙でき、後段の実装に繋がります。

即効性のある削減: コミットと稼働率の最適化

短期インパクトはコミットメント(Savings Plans/RI)と稼働率の最適化に集約されます。長期稼働の汎用CPUワークロードはSavings Plansで**最大66%**のレート低減が現実的で、ファミリー/AZに縛られにくいCompute Savings Plansは運用の自由度と削減率のバランスが良い選択肢です²⁵。購買は勘ではなく推奨APIで裏取りします。以下はAWS Cost Explorerの推奨を取得する例(期間・支払オプションは環境とキャッシュフローに合わせて調整)。

aws ce get-savings-plans-purchase-recommendation \
  --savings-plans-type COMPUTE_SP \
  --term-in-years ONE_YEAR \
  --payment-option NO_UPFRONT \
  --lookback-period-in-days THIRTY_DAYS \
  --region us-east-1

稼働率の最適化は「止める」「小さくする」「安いクラスへ移す」に還元されます。Compute Optimizerの推奨を取り込み、無停止でサイズ変更できる枠を機械的に処理すると、可視化の結果と合わせて二段で効きます。以下はboto3でアイドルなEBSとEC2のリサイズ候補を検出し、レポートするスニペットです(まずはドライラン/除外タグを徹底し、段階適用してください)。

import boto3
from botocore.exceptions import ClientError

ec2 = boto3.client('ec2')
co = boto3.client('compute-optimizer')

def list_unattached_ebs():
    try:
        vols = ec2.describe_volumes(Filters=[{'Name': 'status', 'Values': ['available']}])['Volumes']
        return [v['VolumeId'] for v in vols]
    except ClientError as e:
        print(f"Error listing volumes: {e}")
        return []

def rightsizing_recommendations():
    try:
        recs = co.get_ec2_instance_recommendations(maxResults=100)
        return [(r['instanceArn'], r['recommendationOptions'][0]['performanceRisk']) for r in recs['instanceRecommendations']]
    except ClientError as e:
        print(f"Error getting recommendations: {e}")
        return []

if __name__ == '__main__':
    unattached = list_unattached_ebs()
    print(f"Unattached EBS: {len(unattached)} candidates")
    rightsizes = rightsizing_recommendations()
    risky = [r for r in rightsizes if r[1] <= 3.0]
    print(f"Rightsize-safe instances: {len(risky)}")

Kubernetes環境では、ノードとPodのバースト差が主因になりがちです。HPA/VPA(Horizontal/Vertical Pod Autoscaler)の境界を現実的に設定し、スケーラの反応性に合わせてインスタンスのファミリー/サイズを寄せる。DaemonSetやサイドカーの常駐を見直す。オンデマンドからスポットへの置換比率はSLO(サービスレベル目標)と耐障害性設計に依存しますが、ステートレスなバッチやワーカーは50〜80%をスポット化しても現実的なことが多く、混在設計で短期に二桁%の削減を作りやすい領域です。

ストレージとネットワークを締める: 恒常費の下げ止まりを崩す

コンピュートの最適化に目処が立ったら、恒常的に積み上がるストレージとネットワークに手を入れます。S3はアクセス頻度に応じたストレージクラスへ移行(標準→Intelligent-Tiering/IA/Glacier)するだけでも長期で明確に効きます。以下はTerraformでのライフサイクル設定例で、90日非アクセスでIA、180日でGlacier Deep Archiveへ移行します。用途(分析/再処理/監査)ごとにバケットを分け、クラスを使い分けると運用しやすくなります。

resource "aws_s3_bucket_lifecycle_configuration" "log" {
  bucket = aws_s3_bucket.log.id
  rule {
    id     = "transition-ia-glacier"
    status = "Enabled"
    filter { prefix = "" }
    transition {
      days          = 90
      storage_class = "STANDARD_IA"
    }
    transition {
      days          = 180
      storage_class = "DEEP_ARCHIVE"
    }
    expiration {
      days = 1095
    }
  }
}

NAT Gatewayは小規模でも月額が膨らむ代表格で、処理量に比例する従量分も効きます。S3やDynamoDBなどリージョンサービスへのアクセスはGateway VPC Endpointでインターネット経由を回避するのが定石です。以下はS3のGateway EndpointをTerraformで追加する例。ルートテーブルの関連付けと、対象サブネットの経路検証を忘れないでください。

resource "aws_vpc_endpoint" "s3" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.us-east-1.s3"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = [aws_route_table.public.id, aws_route_table.private.id]
}

外向きトラフィックの最適化はアーキテクチャの話に繋がります。CDNのキャッシュヒット率をKPI化し、オブジェクトのTTL/キャッシュキー設計を調整する。APIは地域ごとの終端を見直し、Edge/Regionalのどちらが全体原価(クラウド利用料+転送料)を下げるかを実測で決める。データ転送の集約は「遠回りに見えて総量が下がる」非線形性がよく起きます。短期ディストリビューションで1週間ABを回し、ヒット率とエグレス総量から定量評価しましょう。

仕組み化して持続させる: ポリシーとガードレール

短期の削減は出ますが、費用は運用の慣性で再び膨らみます。恒常運用へ落とすには、発生源であるIaC(Infrastructure as Code)とCI/CD、さらにガバナンス層に埋め込み、逸脱を自動で検知・抑止するのが現実解です。まず、タグポリシーの強制で分析の前提を守ります。Open Policy Agent(OPA、ポリシーエンジン)で必須タグをRegoとして表現し、CIでテンプレートを検査します。

package tags

required = {"owner", "env", "cost-center"}

deny[msg] {
  input.resource.tags[t] == ""
  required[t]
  msg := sprintf("missing tag: %s", [t])
}

次に、営業時間外の停止や無負荷リソースの自動是正です。Cloud Custodianのようなポリシーエンジンは、タグとメトリクスに基づいて停止・通知・スナップショットを自動化できます。以下はオフアワーにRDSを停止する簡素な例。実導入では除外タグ、メンテナンス窓、通知チャネルを合わせます。

policies:
  - name: stop-rds-offhours
    resource: rds
    filters:
      - type: offhour
        tag: schedule
        default_tz: Asia/Tokyo
        offhour: 20
        weekends: true
    actions:
      - stop

コストの目標管理はBudgets/AlertsとKPIの二階建てにします。月次総額だけでなく、サービス別・プロダクト別・単位経済のしきい値を併記し、逸脱をSlackへ流す。意思決定のラグを減らすため、ダッシュボードは「今日の見込み着地」「コミットカバレッジ(コミットでカバーされる使用率)」「権利化の未充足」「アイドル上位」の3〜4枚に集約し、毎週のレビューで例外処理を決めると回ります。コミット購買やサイズ変更はGitのPRとして扱い、レビューと監査を通すと属人性を下げられます。

最後に、削減効果を事業言語へ翻訳し、投資判断を速めます。式は単純で、「削減額 − 運用コスト」すなわちネット削減が月次キャッシュフローにどう効くかを見せるだけです。たとえば、Savings Plansのカバレッジを50%→85%に引き上げ、平均レートが30%低下、月1,000万円のEC2/Compute支出なら仮に月300万円の粗削減、追加運用コストが月60万円なら正味240万円の改善、といった具合に積み上げます。加えて、リサイズとオフアワー停止で日中平均vCPUを20%削減、S3ライフサイクルで月120万円、NAT/エグレスで月80万円を抑制、といった具体値を積み上げると、半年で**30〜40%**の道筋を定量で説明できます(数値は一例)。

補助的な実装断片: 監視と自動化の接着剤

観測と自動化を繋ぐ小さな断片は、運用の摩擦を減らします。たとえばCloudWatchのアラームをタグベースで生成するスクリプトは、例外的な増加や新規ワークロードの暴れを即座に捕捉します。以下はPythonで特定タグのEC2にCPUアラームを一括適用する例です(冪等性と失敗時のログを確保し、アラームポリシーは環境に合わせてしきい値を調整)。

import boto3
from botocore.exceptions import ClientError

cw = boto3.client('cloudwatch')
ec2 = boto3.client('ec2')

def targets(tag_key, tag_value):
    res = ec2.describe_instances(Filters=[{"Name": f"tag:{tag_key}", "Values":[tag_value]}])
    for r in res['Reservations']:
        for i in r['Instances']:
            yield i['InstanceId']

def ensure_alarm(instance_id):
    name = f"CPU-High-{instance_id}"
    try:
        cw.put_metric_alarm(
            AlarmName=name,
            ComparisonOperator='GreaterThanThreshold',
            EvaluationPeriods=3,
            MetricName='CPUUtilization',
            Namespace='AWS/EC2',
            Period=60,
            Statistic='Average',
            Threshold=70.0,
            ActionsEnabled=False,
            Dimensions=[{'Name': 'InstanceId', 'Value': instance_id}],
            TreatMissingData='notBreaching')
    except ClientError as e:
        print(f"Failed to create alarm for {instance_id}: {e}")

if __name__ == '__main__':
    for iid in targets('env', 'prod'):
        ensure_alarm(iid)

また、コミット率の可視化は毎日の習慣に落とします。Cost ExplorerのカバレッジAPIと、Athena/BigQueryの実使用量を合わせ、ダッシュボードに「当月カバレッジ」「未コミット見込み」「閾値超のサービス」を並べると意思決定が遅れません。クラウド横断の集計は、為替と税込/税抜のルールを先に固定し、期間比較でブレない土台を作るのが要点です。

失敗しがちなポイントと回避策

よくある落とし穴を挙げます。コミットを急ぎすぎると需要のピーク/ボトムとズレて逆効果になり得ますが、直近90日のトレンド、季節性、プロダクトのロードマップを加味したシナリオ分析で回避できます。スポットは可用性要件と運用設計が先で、SLOに基づく混在比率を決め、プリエンプション耐性をテストしてから拡大するのが定石です。ガバナンスは「禁止」ではなく「逸脱の可視化」と「例外申請の迅速化」に重心を置くと、開発速度とコスト最適化を両立できます。どれも難しく見えますが、測定→即効→仕組み化の順で積めば、費用曲線は想定より早く下向きます。

まとめ: 3カ月で手応え、半年で40%へ

本稿の順序は単純です。まずは明細を掘って無負荷と外向きを数値化し、次にコミットとリサイズで短期の削減を取り、最後にライフサイクルとポリシーで再膨張を抑える仕組みに落とす。この三段を回すだけで、3カ月で10〜20%、半年で**30〜40%**の削減は十分に射程に入ります(一般的な目安)。あなたの環境では、どの費目が最も感応度が高いでしょうか。まずは今週中に「上位コストの可視化ビュー」「Savings Plans推奨の取得」「S3ライフサイクル適用範囲の洗い出し」の三点を小さく実施し、翌週の定例で意思決定にかけてください。クラウドコスト削減は一度のイベントではなく、回る仕組みが生む副産物です。今日から回し始めることが、最短の成功法です。

参考文献

  1. TechMonitor. Cloud waste hits billions as 78% of firms report significant expenditure losses. Citing Flexera 2024 State of the Cloud Report. https://www.techmonitor.ai/cloud/cloud-waste-hits-billions-as-78-of-firms-report-significant-expenditure-losses/
  2. AWS Savings Plans: Compute pricing and discounts. https://aws.amazon.com/savingsplans/compute-pricing/
  3. AWS EC2 Reserved Instances pricing. https://aws.amazon.com/ec2/pricing/reserved-instances/pricing/
  4. AWS EC2 Spot Instances overview (up to 90% savings). https://aws.amazon.com/ec2/spot/
  5. AWS News Blog. New – Savings Plans for AWS Compute Services. https://aws.amazon.com/blogs/aws/new-savings-plans-for-aws-compute-services/