GreenOps: Kubernetes を使用したカーボン認識インフラストラクチャ
現在、世界のデータセンターは次のようなものを消費しています。世界の電力の1%と2%、と CO₂ 換算排出量は年間 1 億トンから 2 億トンと推定され、これは全体を上回る 航空産業。生成 AI の急速な普及により、GPT-4 のようなモデルのトレーニングはエネルギーを消費します 1 回の運航で数百回の大西洋横断フライトに相当します。それでもほとんどのインフラストラクチャは クラウドは、これらの排出が存在しないかのように動作し続けます。Kubernetes クラスターはサイクルで実行されます。 CI/CD パイプラインは、電力網の炭素強度に関係なく継続的に実行されます。 彼らは電気がいつクリーンになるかを考慮せずにすぐにトリガーし、チームは DevOps はコストとレイテンシーを監視しますが、ポッドごとの排出量はほとんどありません。
グリーンオプス このパラダイムを変えるのは運用規律です。借入方法 FinOps から — クラウド支出を最適化する実践 — GreenOps は持続可能性をもたらします インフラストラクチャの決定の中心となる環境: ワークロードをどのように割り当てるか、いつバッチ ジョブを実行するか、 どのリージョンにデプロイするか、ノードのサイズをどのように設定するか。その結果は環境に与える影響だけではありません。 GreenOps を採用している組織は、平均して 排出量を 30 ~ 60% 削減 クラウド関連 エネルギー効率と効率性により、コストが 15 ~ 30% 削減されます。 経済状況はしばしば一致します。
この記事では、真にカーボンを意識した Kubernetes インフラストラクチャをゼロから構築します。 クラスターをインスツルメントします ケプラー ポッドごとの消費電力を測定するには、 を設定します 炭素を意識したKEDAオペレーター 強度に基づいてワークロードをスケーリングする リアルタイムでカーボンを実装します。 マルチリージョンカーボンルーティング カルマダと、 最も環境に優しい時間枠を自動的に選択する CI/CD パイプラインを構築します。 ビルドを実行します。各セクションには、本番環境で使用可能な YAML コードと Python コードが含まれています。
何を学ぶか
- GreenOps と FinOps の違い、およびクラウドの持続可能性のために両者がどのように相互補完するか
- KEDA および Azure の Carbon Aware KEDA Operator を使用したカーボン認識自動スケーリング
- Kepler (Kubernetes ベースの Efficient Power Level Exporter) をインストールして構成する方法
- Kepler Prometheus メトリクス: コンテナー、ポッド、ノードごとのエネルギー消費量
- 二酸化炭素強度ベースの CronJob と PriorityClass による二酸化炭素を意識したスケジューリング
- Karmada によるマルチリージョン カーボン ルーティング: ワークロードをより環境に優しいリージョンに移動
- クラウドプロバイダーの二酸化炭素排出量 API: AWS、Google Cloud、Azure の比較
- Kubernetes クラスターの排出量を監視するための Grafana ダッシュボード
- グリーン CI/CD: インテリジェントなビルド スケジューリングを備えたカーボン対応 GitHub アクション
- ケーススタディ: 50 ノードのクラスターで 3 か月で排出量が 35% 削減
グリーン ソフトウェア エンジニアリング シリーズ — すべての記事
| # | タイトル | 主題 |
|---|---|---|
| 1 | グリーン ソフトウェア エンジニアリングの原則 | 8 GSF 原則、SCI 仕様 ISO/IEC 21031 |
| 2 | CodeCarbon による排出量の測定 | Python、MLflow、ダッシュボードでの CO₂ 追跡 |
| 3 | Climatiq API: クラウド システムの炭素強度 | REST API、クラウド排出量計算およびサプライチェーン |
| 4 | Carbon Aware SDK: 時間と場所の変化 | GSF SDK、WattTime、ElectricityMaps、Kubernetes、CI/CD |
| 5 | スコープ3とESGパイプライン | 上流/下流排出量、CSRD データ パイプライン |
| 6 | GreenOps: Kubernetes を使用したカーボン認識インフラストラクチャ (この記事) | KEDA カーボン スケーラー、Kepler、マルチリージョン ルーティング、グリーン CI/CD |
| 7 | スコープ1、2、3のモデリング | GHG プロトコル会計フレームワーク、SBTi |
| 8 | AI の二酸化炭素排出量 | LLM トレーニング、推論、エネルギー最適化 |
| 9 | 持続可能なソフトウェア パターン | 環境に優しいパターン設計、効率的なアーキテクチャ |
| 10 | ソフトウェアのESGとCSRD | 規制遵守、EU報告義務 |
GreenOps と FinOps: 代替ではなく補完
FinOps は、クラウド支出の制御不能な増大への対応として誕生しました。 コストを考慮していないリソース、数か月間アクティブになっている忘れられた EC2 インスタンス、最適化されていないストレージ 価値を生み出すことなく請求書が蓄積されていました。 FinOps は、実行するための文化、プロセス、ツールをもたらします 支出を可視化し、体系的に最適化します。 GreenOps は明らかにこのモデルからインスピレーションを受けています 二酸化炭素排出量に適用: ワークロードごとに排出量を可視化し、プロセスを導入 最適化を実現し、チームに説明責任をもたらします。
良いニュースは、2 つの分野が非常に重複していることです。同じポッドです。 サイズが大きすぎると、お金とエネルギーの両方が無駄になります。アイドル状態のクラスターが一晩で両方の予算を消費してしまう そのCO₂。最適化とは、多くの場合、両方を最適化することを意味します。しかし、重要な相違点もあります 理解すること。
GreenOps と FinOps: 比較表
| サイズ | フィンオプス | グリーンオプス | 統合 |
|---|---|---|---|
| 主な目的 | クラウド支出を削減し、ROI を最適化 | CO₂ 排出量を削減し、エネルギー効率を向上 | 多くの場合、効率 = 節約 = 排出削減と一致します。 |
| コアメトリクス | ビジネスユニットあたりのコスト (リクエストあたりのドル、ユーザーあたりのドル) | ビジネスユニットあたりの gCO₂eq (炭素強度) | 統合的な意思決定のための共同コスト + カーボン ダッシュボード |
| メインレバー | 適切なサイジング、リザーブドインスタンス、スポット価格 | タイムシフト、ロケーションシフト、デマンドシェーピング | タイムシフトにより、コストのピークと排出量の両方が削減されます |
| 粒度 | タグクラウド、チーム、サービス、アカウント | ポッド、コンテナ、サーバーレス機能 | Kepler は、GreenOps の細分性を FinOps のようなポッド レベルにもたらします |
| 一時性 | 月次/四半期の最適化 (請求書) | 時間ごとの最適化 (炭素強度の変動) | GreenOps にはリアルタイムの自動化が必要です。より静的な FinOps |
| 競合の可能性 | スポット インスタンスは安価ですが、リージョンの二酸化炭素集約型です | リージョンはグリーンだが高価で遅延が長い | コストと炭素スコアを組み合わせた明示的なトレードオフ |
| 楽器 | AWS Cost Explorer、CloudHealth、Kubecost | Kepler、Carbon Aware SDK、クラウド カーボン API | Kubecost + Kepler: 同じダッシュボード内のポッドあたりのコストと炭素 |
| 標準 | FinOps Foundation FOCUS の仕様 | GSF SCI 仕様、GHG プロトコル | 統一された指標による収束は 2026 年に予想される |
FinOps と GreenOps を統合する最も戦略的なポイントは、 適切なサイズ: ポッドの過剰な CPU/メモリ要求を削減すると、クラウドの料金が下がるだけでなく、直接的にも削減されます。 ノードのエネルギー消費量。負荷に比例して増加します。買収後のCloudBoltデータによると StormForge による (2025 年 3 月)、AI 主導の適切なサイジングで最適化されたクラスターでは平均削減が見られました コストと排出量の両方で 40% 削減されます。これは、トレードオフがないまれなケースです。
炭素強度の低い雲領域が地理的に存在する場合、代わりに紛争が発生します。 遠く離れているためデータ転送にコストがかかる場合、または安価なスポット インスタンスが使用できない場合 主に石炭を燃料とする地域に位置する。このようなシナリオでは、GreenOps チームがさらに強化されます 成熟した大人が養子となる 複合スコアリング関数 コスト、排出量、遅延のバランスをとる さまざまな種類のワークロードに合わせて重みを構成できます。
Carbon-Aware Kubernetes: KEDA と Carbon Aware Operator
KEDA (Kubernetes Event-Driven Autoscaler) は、以下を可能にするオープンソースの Kubernetes コンポーネントです。 イベントと外部メトリクス (メッセージ キュー、Prometheus メトリクス、 HTTP エンドポイント。の カーボンを意識した KEDA オペレーター、Microsoft Azureによって開発され、公開されました GitHub では、電力網の炭素強度という根本的に新しい次元で KEDA を拡張します。 地元の。結果として、スケーリング可能なクラスターが得られます。 下向き 電気があるとき 化石資源から生産される、e 上向き 再生可能エネルギーが豊富にあるとき。
メカニズムはシンプルながらもエレガントです。オペレーターは現在の炭素強度を読み取ります — WattTime、ElectricityMaps、またはその他のソースから取得し、クラスター内の ConfigMap に 値は 1 時間ごとに更新されます。 KEDA ScaledObject はその ConfigMap を読み取り、その値を入力として使用します。 許容されるレプリケーションの最大数を決定します: 強度が高い場合 (ネットワーク 炭素集約的)、天井は下がります。強度が低い場合(クリーン エネルギー)、 上限が上昇し、クラスターはより積極的に拡張できるようになります。
カーボンを意識した KEDA オペレーター アーキテクチャ
# carbon-aware-keda-operator/config/samples/carbonawarekedascaler.yaml
# Installa l'operator: kubectl apply -f https://github.com/Azure/carbon-aware-keda-operator/releases/latest/download/operator.yaml
apiVersion: carbon.azure.com/v1alpha1
kind: CarbonAwareKedaScaler
metadata:
name: batch-processor-carbon-scaler
namespace: default
spec:
# Riferimento al KEDA ScaledObject da modificare
kedaTarget:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
name: batch-processor-scaler
# Definisce come il ceiling di repliche cambia con la carbon intensity
carbonIntensityForecastDataSource:
mockCarbonForecast: false
localConfigMap:
name: carbon-intensity-forecast
namespace: kube-system
key: data
# Soglie carbon intensity (gCO2/kWh) -> max replicas
maxReplicasByCarbonIntensity:
- carbonIntensityThreshold: 50 # Energia molto pulita
maxReplicas: 20 # Scala aggressivamente
- carbonIntensityThreshold: 100 # Energia mediamente pulita
maxReplicas: 15
- carbonIntensityThreshold: 200 # Mix energetico moderato
maxReplicas: 10
- carbonIntensityThreshold: 350 # Carbon-intensive
maxReplicas: 5 # Scala al minimo
- carbonIntensityThreshold: 500 # Molto carbon-intensive
maxReplicas: 2 # Solo carichi critici
デプロイメントの実際の自動スケーリングを処理する、対応する KEDA ScaledObject:
# keda-scaled-object.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: batch-processor-scaler
namespace: default
spec:
scaleTargetRef:
name: batch-processor
minReplicaCount: 2
maxReplicaCount: 20 # Viene sovrascritto dal CarbonAwareKedaScaler
cooldownPeriod: 300
pollingInterval: 60
triggers:
- type: rabbitmq
metadata:
protocol: amqp
queueName: batch-jobs
mode: QueueLength
value: "10"
authenticationRef:
name: rabbitmq-trigger-auth
---
# Deployment del batch processor
apiVersion: apps/v1
kind: Deployment
metadata:
name: batch-processor
namespace: default
labels:
app: batch-processor
green-software: "true"
spec:
replicas: 2
selector:
matchLabels:
app: batch-processor
template:
metadata:
labels:
app: batch-processor
annotations:
# Annotazione per tracking GreenOps
greenops.io/workload-type: "deferrable-batch"
greenops.io/carbon-policy: "carbon-aware-scaling"
spec:
containers:
- name: batch-processor
image: myregistry/batch-processor:v1.2.0
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2000m"
memory: "2Gi"
炭素強度 ConfigMap エクスポーター
炭素強度データを含む ConfigMap は、外部 API をクエリするジョブによって設定される必要があります。
プロジェクト kubernetes-carbon-intensity-exporter Azure は次のコンポーネントを提供します。
# carbon-intensity-exporter.yaml
# Installa: kubectl apply -f https://github.com/Azure/kubernetes-carbon-intensity-exporter/releases/latest/download/deploy.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: carbon-intensity-exporter-config
namespace: kube-system
data:
# Provider dati: WattTime o ElectricityMaps
CARBON_INTENSITY_PROVIDER: "WattTime"
# Region/location in formato standard (ISO3166-1)
LOCATION: "eastus"
# Aggiornamento ogni 12 ore con forecast 24h
FETCH_INTERVAL_SECONDS: "43200"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: carbon-intensity-exporter
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: carbon-intensity-exporter
template:
metadata:
labels:
app: carbon-intensity-exporter
spec:
serviceAccountName: carbon-intensity-exporter
containers:
- name: exporter
image: ghcr.io/azure/kubernetes-carbon-intensity-exporter:latest
envFrom:
- configMapRef:
name: carbon-intensity-exporter-config
env:
- name: WATTTIME_USERNAME
valueFrom:
secretKeyRef:
name: carbon-intensity-secrets
key: watttime-username
- name: WATTTIME_PASSWORD
valueFrom:
secretKeyRef:
name: carbon-intensity-secrets
key: watttime-password
カーボンアウェアなスケーリングに適したワークロード
カーボン対応スケーリングはワークロードに対してのみ機能します 延期可能な o 弾性のある:
バッチ ジョブ、ML トレーニング、ETL パイプライン、レポート処理、メディアのトランスコーディング。サービスには適用しないでください
遅延が重要なリアルタイムのユーザー対応 (API ゲートウェイ、フロントエンド)。パラメータ
minReplicaCount 炭素濃度が高い条件でもポッドが最小限に抑えられることを保証します
サービスの可用性を維持するためにローテーションを続けます。
カーボン認識スケジューリング: CronJob および PriorityClass Verdi
リアクティブな自動スケーリングに加えて、GreenOps はスケジューリングを導入します 積極的: 代わりに 現在の炭素濃度に反応すると、最も環境に優しい時間帯が予想されます。 次の 24 時間の時刻にジョブを実行するようにスケジュールします。 WattTime と ElectricalMaps が提供する 最大 72 時間まで予測できるため、この最適化が可能になります。
カーボン対応 CronJob 用の Python コントローラー
Carbon Aware SDK にクエリを実行し、スケジュールを動的に書き換える軽量の Python コントローラー Kubernetes CronJob を緑のウィンドウを指すように設定します。
#!/usr/bin/env python3
# carbon_aware_scheduler.py
# Richiede: pip install kubernetes requests python-crontab
import os
import json
import logging
from datetime import datetime, timedelta
from typing import Optional
import requests
from kubernetes import client, config
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("carbon-aware-scheduler")
CARBON_AWARE_SDK_URL = os.getenv("CARBON_AWARE_SDK_URL", "http://carbon-aware-sdk:8080")
CARBON_THRESHOLD = float(os.getenv("CARBON_THRESHOLD_G_CO2_KWH", "150"))
def get_best_window(location: str, duration_minutes: int = 60) -> Optional[datetime]:
"""Interroga il Carbon Aware SDK per la finestra ottimale nelle prossime 24h."""
window_start = datetime.utcnow()
window_end = window_start + timedelta(hours=24)
url = f"{CARBON_AWARE_SDK_URL}/emissions/forecasts/best"
params = {
"location": location,
"dataStartAt": window_start.isoformat() + "Z",
"dataEndAt": window_end.isoformat() + "Z",
"windowSize": duration_minutes,
}
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
# Il Carbon Aware SDK restituisce la finestra ottimale
if data and len(data) > 0:
best = data[0]
optimal_time_str = best.get("optimalDataPoints", [{}])[0].get("timestamp")
if optimal_time_str:
return datetime.fromisoformat(optimal_time_str.replace("Z", "+00:00"))
except requests.RequestException as e:
logger.error(f"Errore Carbon Aware SDK: {e}")
return None
def update_cronjob_schedule(namespace: str, cronjob_name: str, target_time: datetime) -> bool:
"""Aggiorna la schedule del CronJob Kubernetes."""
config.load_incluster_config()
batch_v1 = client.BatchV1Api()
# Converti in espressione cron (minuto e ora UTC)
cron_expression = f"{target_time.minute} {target_time.hour} * * *"
try:
cronjob = batch_v1.read_namespaced_cron_job(cronjob_name, namespace)
cronjob.spec.schedule = cron_expression
# Annotazione per audit trail GreenOps
if cronjob.metadata.annotations is None:
cronjob.metadata.annotations = {}
cronjob.metadata.annotations["greenops.io/last-schedule-update"] = datetime.utcnow().isoformat()
cronjob.metadata.annotations["greenops.io/scheduled-carbon-window"] = target_time.isoformat()
batch_v1.patch_namespaced_cron_job(cronjob_name, namespace, cronjob)
logger.info(f"CronJob {cronjob_name} aggiornato: schedule={cron_expression}")
return True
except client.ApiException as e:
logger.error(f"Errore aggiornamento CronJob: {e}")
return False
if __name__ == "__main__":
location = os.getenv("GRID_LOCATION", "IT")
namespace = os.getenv("TARGET_NAMESPACE", "default")
cronjob_name = os.getenv("TARGET_CRONJOB", "ml-training-job")
job_duration = int(os.getenv("JOB_DURATION_MINUTES", "90"))
best_window = get_best_window(location, job_duration)
if best_window:
logger.info(f"Finestra ottimale trovata: {best_window}")
update_cronjob_schedule(namespace, cronjob_name, best_window)
else:
logger.warning("Nessuna finestra ottimale trovata, mantengo schedule corrente")
PriorityClass カーボンアウェア
Kubernetes を使用すると、ポッドに優先順位を付けることができます。 PriorityClass。文脈の中で
GreenOps では、延期の許容範囲を反映する優先クラスを定義します: ワークロード
重要なものは高い優先度を維持し、延期できないものは低い優先度でスケジュールされます。
リソースを複数のジョブに集中させる必要がある場合、それらは排除されたり遅延されたりする可能性があります。
低炭素強度期間中に緊急を要する。
# priority-classes-greenops.yaml
# Gerarchia di priorità GreenOps
# Workload critici: sempre in esecuzione, non deferrabili
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: greenops-critical
annotations:
greenops.io/deferrable: "false"
greenops.io/carbon-policy: "always-run"
value: 1000000
globalDefault: false
description: "Workload critici: API user-facing, servizi core business"
---
# Workload standard: possono aspettare finestre verdi brevi (1-2h)
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: greenops-standard
annotations:
greenops.io/deferrable: "true"
greenops.io/max-defer-hours: "2"
greenops.io/carbon-threshold: "200"
value: 500000
globalDefault: true
description: "Workload standard: servizi interni, analytics real-time"
---
# Workload batch: ottimizzati per finestre verdi lunghe (fino a 12h)
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: greenops-batch
annotations:
greenops.io/deferrable: "true"
greenops.io/max-defer-hours: "12"
greenops.io/carbon-threshold: "100"
value: 100000
globalDefault: false
description: "Workload batch: ETL, training ML, report, backup"
---
# Workload opportunistici: solo durante energia molto pulita
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: greenops-opportunistic
annotations:
greenops.io/deferrable: "true"
greenops.io/max-defer-hours: "48"
greenops.io/carbon-threshold: "80"
value: 10000
globalDefault: false
description: "Workload opportunistici: pre-training, batch mensili, archivio"
Karmada を使用したマルチリージョン カーボン ルーティング
タイムシフトによりワークロードが次の時間に移動されます。 時間 同じ地域にあります。の 場所の移動 さらに言えば、ワークロードを次の場所に移動します。 空間、カーボンを使用してクラウド リージョンでジョブを実行します。 その時点で最低強度。地理的な変動は非常に大きいです。 特定の瞬間、eu-north-1 (ストックホルム、ほぼ完全に水力発電) us-east-1 (バージニア州、石炭/ガス/原子力混合) の強度は 15 gCO₂/kWh です。 それは 300 ~ 400 gCO₂/kWh になる可能性があります。 ML トレーニングの仕事を代わりにスウェーデンに持ち込む バージニア州は排出量を削減 同じ計算で90%以上.
カルマダ (Kubernetes Armada) はクラスター管理のための CNCF プロジェクトです 複数の Kubernetes。これにより、複数のリージョンの複数のクラスターにワークロードを分散できます。 洗練された政策。リアルタイムの炭素強度データと組み合わせることで、 マルチリージョンのカーボンルーティング。
マルチリージョン GreenOps アーキテクチャ
# Struttura del setup Karmada multi-cluster
#
# karmada-control-plane (hub)
# ├── cluster-eu-north-1 (Stoccolma - 15-40 gCO2/kWh)
# ├── cluster-eu-west-1 (Irlanda - 100-250 gCO2/kWh)
# ├── cluster-us-west-2 (Oregon - 50-150 gCO2/kWh, molto rinnovabili)
# └── cluster-us-east-1 (Virginia - 300-400 gCO2/kWh)
#
# PropagationPolicy determina dove gira il workload in base a carbon intensity
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: ml-training-carbon-routing
namespace: ml-workloads
annotations:
greenops.io/routing-strategy: "carbon-optimized"
spec:
resourceSelectors:
- apiVersion: batch/v1
kind: Job
labelSelector:
matchLabels:
workload-type: "ml-training"
greenops/deferrable: "true"
placement:
clusterAffinity:
# Preferenza ordinata per carbon intensity (aggiornata dal carbon-router)
clusterNames:
- cluster-eu-north-1 # Prima scelta: Svezia (sempre verde)
- cluster-us-west-2 # Seconda: Oregon (molto rinnovabili)
- cluster-eu-west-1 # Terza: Irlanda (mediamente verde)
- cluster-us-east-1 # Ultima: Virginia (carbon-intensive)
replicaScheduling:
replicaSchedulingType: Duplicated
# Non divisibile: il job va su UN cluster, quello più verde
Carbon Router: Karmada ポリシーの動的更新
#!/usr/bin/env python3
# carbon_router.py - Aggiorna la PropagationPolicy Karmada in base alla carbon intensity
# Eseguito ogni ora da un CronJob nel control plane
import os
import json
import requests
import logging
from typing import Dict, List, Tuple
from kubernetes import client, config
from kubernetes.client.rest import ApiException
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("carbon-router")
CARBON_SDK_URL = os.getenv("CARBON_SDK_URL", "http://carbon-aware-sdk:8080")
# Mapping cluster -> location ElectricityMaps/WattTime
CLUSTER_LOCATIONS: Dict[str, str] = {
"cluster-eu-north-1": "SE", # Svezia
"cluster-eu-west-1": "IE", # Irlanda
"cluster-us-west-2": "US-NW", # Pacific Northwest
"cluster-us-east-1": "US-MIDA", # Mid-Atlantic
}
def fetch_carbon_intensity(location: str) -> float:
"""Recupera carbon intensity corrente per una location."""
url = f"{CARBON_SDK_URL}/emissions/bylocation"
params = {"location": location}
try:
r = requests.get(url, params=params, timeout=8)
r.raise_for_status()
data = r.json()
if data:
return float(data[0].get("rating", 999.0))
except Exception as e:
logger.error(f"Impossibile recuperare carbon intensity per {location}: {e}")
return 999.0 # Valore di fallback: considera come molto carbon-intensive
def rank_clusters_by_carbon() -> List[Tuple[str, float]]:
"""Ordina i cluster dalla carbon intensity più bassa alla più alta."""
intensities: List[Tuple[str, float]] = []
for cluster, location in CLUSTER_LOCATIONS.items():
intensity = fetch_carbon_intensity(location)
intensities.append((cluster, intensity))
logger.info(f"{cluster} ({location}): {intensity:.1f} gCO2/kWh")
intensities.sort(key=lambda x: x[1])
return intensities
def update_propagation_policy(ranked_clusters: List[Tuple[str, float]]) -> None:
"""Aggiorna la clusterNames nella PropagationPolicy Karmada."""
# Karmada usa CRD custom - accesso via dynamic client
config.load_incluster_config()
dynamic_client = client.ApiClient()
# Lista ordinata per il patch
cluster_names = [c[0] for c in ranked_clusters]
patch_body = {
"spec": {
"placement": {
"clusterAffinity": {
"clusterNames": cluster_names
}
}
}
}
# Annota la policy con i dati correnti per audit
timestamp = __import__("datetime").datetime.utcnow().isoformat()
patch_body["metadata"] = {
"annotations": {
"greenops.io/last-routing-update": timestamp,
"greenops.io/carbon-ranking": json.dumps(
[{"cluster": c, "gco2_kwh": round(i, 1)} for c, i in ranked_clusters]
)
}
}
logger.info(f"Aggiornamento routing: ordine cluster = {cluster_names}")
# In produzione: usare kubernetes.client.CustomObjectsApi per patch Karmada CRD
if __name__ == "__main__":
ranked = rank_clusters_by_carbon()
logger.info("Classifica cluster per carbon intensity:")
for cluster, intensity in ranked:
logger.info(f" {cluster}: {intensity:.1f} gCO2/kWh")
update_propagation_policy(ranked)
クラウドプロバイダー Carbon API: AWS、Google Cloud、Azure
オープンソース ツールと並行して、大手クラウド プロバイダー 3 社がリリースまたは改良したツールをリリースしました。 重要なのは、ネイティブの二酸化炭素排出量ツールです。 2025年の状況は非常に厳しい 成熟度と使いやすさの点で多様化しています。
二酸化炭素排出量のクラウド プロバイダー API の比較 (2025 年)
| プロバイダー | 楽器 | 粒度 | API? | ほうき | アップデート |
|---|---|---|---|---|---|
| AWS | 顧客二酸化炭素排出量ツール | アカウント、地域、サービス | CSVエクスポートのみ | スコープ1、2、3(2024年~) | 毎月(3か月遅れ) |
| グーグルクラウド | クラウドの二酸化炭素排出量 | プロジェクト、サービス、地域 | BigQuery エクスポート + API | スコープ1、2、3 | 毎月(4週間遅れ) |
| アズール | Microsoft 排出量影響ダッシュボード / 炭素最適化 | サブスクリプション、リソース グループ、サービス | 完全な REST API (2025) | スコープ1、2、3 | 毎月(2か月遅れ) |
| マルチクラウド | クラウド二酸化炭素排出量 (オープンソース) | アカウント、サービス、地域 | セルフホスト型 REST API | スコープ 2 (独自の方法論) | 毎日 |
Azure Carbon Optimization REST API
Microsoft は 2025 年に最も重要な一歩を踏み出し、 カーボン 最適化 Azure portal 内で、完全な REST API によってサポートされ、 内部システム。統合例:
#!/usr/bin/env python3
# azure_carbon_api.py
# Richiede: pip install azure-identity requests
import os
from azure.identity import DefaultAzureCredential
import requests
SUBSCRIPTION_ID = os.environ["AZURE_SUBSCRIPTION_ID"]
CREDENTIAL = DefaultAzureCredential()
def get_azure_carbon_emissions(
resource_group: str,
start_date: str,
end_date: str
) -> dict:
"""
Recupera emissioni CO2 per resource group tramite Azure Carbon Optimization API.
API endpoint (2025): https://management.azure.com/providers/Microsoft.Carbon/carbonEmissionReports
"""
token = CREDENTIAL.get_token("https://management.azure.com/.default").token
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
# Azure Carbon Optimization API (GA 2025)
url = (
f"https://management.azure.com/subscriptions/{SUBSCRIPTION_ID}"
f"/resourceGroups/{resource_group}"
f"/providers/Microsoft.Carbon/carbonEmissionReports"
f"?api-version=2023-04-01-preview"
)
payload = {
"reportType": "OverallSummaryReport",
"subscriptionList": [SUBSCRIPTION_ID],
"carbonScopeList": ["Scope1", "Scope2", "Scope3"],
"dateRange": {
"start": start_date, # "2025-01-01"
"end": end_date # "2025-03-01"
}
}
response = requests.post(url, json=payload, headers=headers, timeout=30)
response.raise_for_status()
return response.json()
def get_google_carbon_data(project_id: str, dataset: str = "carbon_footprint") -> None:
"""
Google Cloud esporta i dati carbon footprint in BigQuery automaticamente.
Abilita: Cloud Billing Export -> BigQuery -> Carbon Footprint
Query esempio BigQuery:
"""
bq_query = """
SELECT
usage_month,
service.description AS service,
location.region AS region,
SUM(carbon_footprint_kgCO2e.market_based) AS kg_co2e_market_based,
SUM(carbon_footprint_kgCO2e.location_based) AS kg_co2e_location_based
FROM
`{project_id}.{dataset}.carbon_footprint`
WHERE
usage_month BETWEEN '2025-01-01' AND '2025-03-31'
GROUP BY
usage_month, service, region
ORDER BY
kg_co2e_market_based DESC
"""
print(f"Esegui in BigQuery:\n{bq_query.format(project_id=project_id, dataset=dataset)}")
if __name__ == "__main__":
# Azure example
data = get_azure_carbon_emissions(
resource_group="production-rg",
start_date="2025-01-01",
end_date="2025-03-01"
)
print(f"Azure Carbon Emissions: {data}")
# Google BigQuery example
get_google_carbon_data("my-gcp-project")
炭素データに関する推奨戦略
- リアルタイムのスケジューリング: 意思決定には Carbon Aware SDK + WattTime/ElectricityMap を使用します カーボンを意識したスケジューリングでリアルタイムに
- 月次報告: クラウド プロバイダーのネイティブ ツールを会計に使用する CSRD/ESG レポートには公式 CO₂ (スコープ 1/2/3) が必要
- マルチクラウド: オープンソースのクラウドカーボンフットプリントを使用して、複数のデータを集約します。 プロバイダーを一貫して
- 運用上のアラート: Kepler + Prometheus を使用して、消費量の急増に関するリアルタイムのアラートを作成します ポッドあたりのエネルギー
Kepler: ポッドあたりのエネルギー消費量の測定
ケプラー (Kubernetes ベースの Efficient Power Level Exporter) は CNCF プロジェクトです Kubernetes クラスター内のコンテナー、ポッド、ノード レベルでエネルギー消費を測定し、エクスポートします。 Prometheus へのメトリクス。排出量を可視化するための基本的なコンポーネントです 運用レベル: Kepler がなければ、DevOps チームはワークロードごとの排出量を把握できず、 GreenOps を効果的に実行します。
Kepler は拡張 Berkeley Packet Filter (eBPF) アプローチを使用してリソース消費を追跡します カーネルレベルのハードウェア、からのデータを組み合わせる ラップル (実行平均電力制限、インターフェース CPU 消費量については Intel/AMD)、 ACPI システム消費およびセンサー用 NVIDIA NVML GPU用。物理ハードウェア センサーが存在しないクラウド プロバイダー上 アクセス可能な場合、Kepler は利用可能な CPU メトリクスに基づいた予測モデルを使用します。
バージョン 0.10.0 (2025) の時点で、Kepler はアーキテクチャを完全に書き直されました。 内部。クラウド VM での予測の精度が向上し、DaemonSet のオーバーヘッドが約 1 から削減されます。 CPU 5% ~ 2% 未満。
Helm を使用した Kepler のインストール
# Installazione Kepler con Helm (metodo raccomandato)
# 1. Prerequisiti: Prometheus Operator (o stack kube-prometheus)
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set grafana.enabled=true \
--set alertmanager.enabled=true
# 2. Installa Kepler dal registry OCI (stable)
helm install kepler oci://quay.io/sustainable_computing_io/charts/kepler \
--namespace kepler \
--create-namespace \
--set serviceMonitor.enabled=true \
--set serviceMonitor.namespace=monitoring \
--set serviceMonitor.jobLabel=kepler \
--version 0.5.9 # verifica ultima versione su quay.io
# 3. Verifica che il DaemonSet sia running su tutti i nodi
kubectl get daemonset -n kepler
# Expected: kepler-kepler con DESIRED=N, READY=N
# 4. Verifica raccolta metriche
kubectl port-forward -n kepler svc/kepler-internal 8888:8888 &
curl http://localhost:8888/metrics | grep kepler_container_
# Output atteso:
# kepler_container_joules_total{container_name="...",namespace="...",pod_name="..."}
# kepler_container_cpu_joules_total{...}
# kepler_container_dram_joules_total{...}
# kepler_container_gpu_joules_total{...}
主要な Kepler メトリクス
GreenOps に不可欠な Kepler メトリクス
| メトリック | 説明 | ユニット | 使用事例 |
|---|---|---|---|
kepler_container_joules_total |
起動以降にコンテナが消費した合計エネルギー | ジュール(カウンター) | 一定期間にわたるポッドあたりのエネルギー |
kepler_container_cpu_joules_total |
コンテナのCPUによって消費されるエネルギー | ジュール(カウンター) | 高電力の CPU に依存するワークロードを特定する |
kepler_container_dram_joules_total |
コンテナのRAMによって消費されるエネルギー | ジュール(カウンター) | メモリバウンドのワークロード分析 |
kepler_container_gpu_joules_total |
GPU 消費電力 (NVIDIA が必要) | ジュール(カウンター) | ML トレーニング消費量の追跡 |
kepler_node_core_joules_total |
CPU コアあたりのノードの合計エネルギー | ジュール(カウンター) | ノード効率、消費ベースライン |
kepler_node_package_joules_total |
CPU パッケージの合計エネルギー (すべてのコア) | ジュール(カウンター) | PUE 計算、ノード総消費量 |
kepler_container_watts |
インスタントコンテナパワー | ワット (ゲージ) | エネルギーの急増に関するリアルタイムのアラート |
GreenOps の PromQL クエリ
# Query Prometheus per analisi GreenOps con Kepler
# 1. Energia totale per namespace (kWh nell'ultima ora)
sum by (namespace) (
increase(kepler_container_joules_total[1h])
) / 3600000
# 2. Top 10 pod per consumo energetico (Watt medi ultima ora)
topk(10,
avg by (pod_name, namespace) (
rate(kepler_container_joules_total[1h]) * 1000
)
)
# 3. CO2e per namespace (assumendo carbon intensity 200 gCO2/kWh)
# Sostituisci 200 con il valore real-time da Carbon Aware SDK
sum by (namespace) (
increase(kepler_container_joules_total[24h])
) / 3600000 * 200 / 1000 # risultato in kgCO2e
# 4. Efficienza energetica: Joule per richiesta HTTP (se hai metriche app)
sum(rate(kepler_container_joules_total[5m])) by (pod_name)
/
sum(rate(http_requests_total[5m])) by (pod_name)
# 5. Alert: pod con consumo energetico anomalo (>50W per 15min)
avg_over_time(
sum by (pod_name, namespace) (
kepler_container_watts
)[15m:1m]
) > 50
# 6. Trend consumo cluster (kWh/giorno ultimi 7 giorni)
sum(increase(kepler_node_package_joules_total[1d])) / 3600000
GreenOps 用 Grafana ダッシュボード
Kepler プロジェクトは、直接インポートできる事前構築済みの Grafana ダッシュボードを提供します。構成 Kepler メトリクスと炭素強度データを組み合わせて統合ビューを作成することをお勧めします。
# grafana-dashboard-greenops.yaml
# ConfigMap con dashboard Grafana per GreenOps
apiVersion: v1
kind: ConfigMap
metadata:
name: greenops-dashboard
namespace: monitoring
labels:
grafana_dashboard: "1" # Label per auto-discovery Grafana
data:
greenops-cluster.json: |
{
"title": "GreenOps Cluster Dashboard",
"panels": [
{
"title": "Carbon Intensity Corrente (gCO2/kWh)",
"type": "stat",
"targets": [
{
"expr": "carbon_intensity_g_co2_kwh",
"legendFormat": "Carbon Intensity"
}
],
"thresholds": {
"steps": [
{"color": "green", "value": 0},
{"color": "yellow", "value": 150},
{"color": "orange", "value": 300},
{"color": "red", "value": 450}
]
}
},
{
"title": "kWh Cluster (ultima ora)",
"type": "stat",
"targets": [
{
"expr": "sum(increase(kepler_node_package_joules_total[1h])) / 3600000",
"legendFormat": "kWh"
}
]
},
{
"title": "kgCO2e Cluster (ultima ora)",
"type": "stat",
"targets": [
{
"expr": "sum(increase(kepler_node_package_joules_total[1h])) / 3600000 * carbon_intensity_g_co2_kwh / 1000",
"legendFormat": "kgCO2e"
}
]
},
{
"title": "Top Namespace per Consumo (kWh/h)",
"type": "bargauge",
"targets": [
{
"expr": "topk(10, sum by (namespace) (rate(kepler_container_joules_total[1h])) / 3600)",
"legendFormat": "{{namespace}}"
}
]
}
]
}
グリーン CI/CD: カーボンを意識した GitHub アクション
CI/CD パイプラインは、カーボンを考慮したスケジューリングの理想的な候補です。つまり、次の条件でトリガーされるビルドです。 各プッシュは必ずしも実行する必要はありません すぐに。機能ブランチのビルド、i 包括的な回帰テスト、アーティファクトの生成、ステージング環境へのデプロイメント、そのすべて 遅延許容範囲は測定可能であり、多くの場合は数時間です。これらのパイプラインを Windows に移動します 低炭素強度はほとんど労力を必要とせず、CI/CD 排出量を削減できます。 20~40%。
カーボンアウェアなスケジューリングを使用した GitHub アクション
# .github/workflows/carbon-aware-build.yml
# Build carbon-aware: verifica carbon intensity prima di eseguire
name: Carbon-Aware Build Pipeline
on:
push:
branches: [main, develop, 'feature/**']
workflow_dispatch:
inputs:
force_run:
description: 'Forza esecuzione ignorando carbon intensity'
type: boolean
default: false
jobs:
# Job 1: Verifica carbon intensity e decide se eseguire ora o schedulare
carbon-check:
runs-on: ubuntu-latest
outputs:
should_run_now: ${{ steps.check.outputs.should_run_now }}
carbon_intensity: ${{ steps.check.outputs.carbon_intensity }}
next_green_window: ${{ steps.check.outputs.next_green_window }}
steps:
- name: Check Carbon Intensity
id: check
run: |
# Forza esecuzione su main o se force_run=true
if [[ "${{ github.ref }}" == "refs/heads/main" ]] || \
[[ "${{ inputs.force_run }}" == "true" ]]; then
echo "should_run_now=true" >> $GITHUB_OUTPUT
echo "carbon_intensity=forced" >> $GITHUB_OUTPUT
exit 0
fi
# Interroga Carbon Aware SDK (self-hosted o public endpoint)
CARBON_SDK_URL="${{ secrets.CARBON_AWARE_SDK_URL }}"
LOCATION="${{ vars.GRID_LOCATION }:-DE}" # Germania di default
THRESHOLD=150 # gCO2/kWh soglia accettabile
INTENSITY=$(curl -sf \
"${CARBON_SDK_URL}/emissions/bylocation?location=${LOCATION}" \
| jq '.[0].rating // 999' 2>/dev/null || echo "999")
echo "carbon_intensity=${INTENSITY}" >> $GITHUB_OUTPUT
if (( $(echo "${INTENSITY} < ${THRESHOLD}" | bc -l) )); then
echo "Carbon intensity ${INTENSITY} gCO2/kWh - sotto soglia ${THRESHOLD}, eseguo ora"
echo "should_run_now=true" >> $GITHUB_OUTPUT
else
echo "Carbon intensity ${INTENSITY} gCO2/kWh - sopra soglia, cerco finestra verde"
NEXT_WINDOW=$(curl -sf \
"${CARBON_SDK_URL}/emissions/forecasts/best?location=${LOCATION}&windowSize=60" \
| jq -r '.[0].optimalDataPoints[0].timestamp // empty' 2>/dev/null)
echo "should_run_now=false" >> $GITHUB_OUTPUT
echo "next_green_window=${NEXT_WINDOW}" >> $GITHUB_OUTPUT
fi
- name: Annotate with Carbon Data
if: always()
run: |
echo "::notice::Carbon Intensity: ${{ steps.check.outputs.carbon_intensity }} gCO2/kWh"
echo "::notice::Prossima finestra verde: ${{ steps.check.outputs.next_green_window }}"
# Job 2: Build (eseguita solo se carbon intensity e bassa)
build:
needs: carbon-check
if: needs.carbon-check.outputs.should_run_now == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
env:
NODE_ENV: production
- name: Test
run: npm test -- --coverage
- name: Carbon annotation
run: |
echo "::notice::Build eseguita con carbon intensity: ${{ needs.carbon-check.outputs.carbon_intensity }} gCO2/kWh"
CI/CD 排出量の推定
ビルドをグリーン ウィンドウに移動することに加えて、実際の排出量を測定することも役立ちます。 CI/CD パイプライン。 GitHub でホストされているランナーは、ビルド時間あたり約 0.05 ~ 0.2 kWh を消費します。 ランナーのタイプ。排出量を推定して記録するためのアクション ステップは次のとおりです。
# Step da aggiungere alla fine di ogni workflow
- name: Estimate CI Carbon Footprint
run: |
# Stima durata job in minuti (GitHub fornisce start time)
START_TIME="${{ steps.start-time.outputs.time }}"
END_TIME=$(date -u +%s)
DURATION_MINUTES=$(( (END_TIME - START_TIME) / 60 ))
# Runner ubuntu-latest: ~0.15 kWh/ora (stima conservativa)
RUNNER_POWER_KWH_PER_HOUR=0.15
ENERGY_KWH=$(echo "scale=6; $DURATION_MINUTES / 60 * $RUNNER_POWER_KWH_PER_HOUR" | bc)
# Carbon intensity: usa il valore del carbon-check job
CARBON_INTENSITY="${{ needs.carbon-check.outputs.carbon_intensity }}"
CO2_G=$(echo "scale=2; $ENERGY_KWH * $CARBON_INTENSITY" | bc 2>/dev/null || echo "N/A")
echo "=== GreenOps CI Report ==="
echo "Durata build: ${DURATION_MINUTES} min"
echo "Energia stimata: ${ENERGY_KWH} kWh"
echo "Carbon intensity: ${CARBON_INTENSITY} gCO2/kWh"
echo "Emissioni stimate: ${CO2_G} gCO2e"
echo "========================="
# Scrivi su GitHub Step Summary per visibilità nel report
echo "## GreenOps CI Report" >> $GITHUB_STEP_SUMMARY
echo "| Metrica | Valore |" >> $GITHUB_STEP_SUMMARY
echo "|---------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Durata | ${DURATION_MINUTES} min |" >> $GITHUB_STEP_SUMMARY
echo "| Energia | ${ENERGY_KWH} kWh |" >> $GITHUB_STEP_SUMMARY
echo "| Carbon Intensity | ${CARBON_INTENSITY} gCO2/kWh |" >> $GITHUB_STEP_SUMMARY
echo "| Emissioni | ${CO2_G} gCO2e |" >> $GITHUB_STEP_SUMMARY
FinOps + GreenOps ダッシュボード: コストと炭素の統合
組織の GreenOps の成熟度は、相互に関連付ける能力によっても測定されます。 コストと排出量の指標を単一のビューで表示します。これらのディメンションを個別に管理するチーム 彼らは最適とは言えない決定を下します。コストを 20% 削減する適切なサイジングは効果がない可能性があります。 節約された分が炭素集約地域のインスタンスに再投資される場合、排出量が削減されます。逆に、 より緑豊かな地域に移転すると移転コストが増加する可能性がある データは経済的利益を打ち消します。
理想的な統合の組み合わせ クベコスト (ポッド/名前空間あたりのコスト) ケプラー (ポッド/名前空間ごとのエネルギー) を単一の Grafana ダッシュボードに表示し、炭素強度データを強化 リアルタイムで各ワークロードの実際の炭素コストを計算します。
# Esempio query PromQL per dashboard costo+carbonio unificato
# Assume Kubecost + Kepler + carbon_intensity_g_co2_kwh (da ConfigMap exporter)
# Costo + CO2e per namespace (ultimi 30 giorni)
# Kubecost espone: kubecost_cluster_hourly_cost_by_namespace
# Kepler espone: kepler_container_joules_total
# Costo giornaliero per namespace (USD)
sum by (namespace) (
kubecost_cluster_hourly_cost_by_namespace * 24
)
# CO2e giornaliero per namespace (kgCO2e)
sum by (namespace) (
increase(kepler_container_joules_total[24h])
) / 3600000 # Joule -> kWh
* on() group_left() (carbon_intensity_g_co2_kwh / 1000) # -> kgCO2e
# "Green Efficiency Score" per namespace
# Combina efficienza costo e efficienza carbonica (più alto e meglio)
(
sum by (namespace) (rate(http_requests_total[1h])) # throughput
)
/
(
sum by (namespace) (kubecost_cluster_hourly_cost_by_namespace) # costo
*
(sum by (namespace) (rate(kepler_container_joules_total[1h])) / 3600) # energia kW
* on() group_left() carbon_intensity_g_co2_kwh
)
監視すべき必須の GreenOps KPI
- 現在の炭素強度 (gCO₂/kWh): 電力網からのリアルタイム データ
- kgCO₂e/時間クラスター: クラスターの総排出量
- kWh/需要: 単位仕事当たりのエネルギー効率
- gCO₂e/需要: ビジネスユニット別の二酸化炭素排出量
- グリーン ウィンドウのワークロードの割合: CI < しきい値で実行されたバッチ ジョブの割合
- kgあたりのコストCO₂を削減: GreenOps 取り組みの ROI
- 推定PUE: クラスターの電力使用効率 (目標 < 1.2)
- アイドルエネルギーの無駄遣い: 十分に活用されていないポッド/ノードによって消費されるエネルギー
ケーススタディ: 50 ノードクラスタで排出量を 35% 削減
次のケーススタディは、クラスタを備えたヨーロッパの SaaS 企業からの実際の結果を要約しています。 50 ノードで構成される本番 Kubernetes (AWS us-east-1 上の c5.4xlarge と m5.2xlarge の混合)、 データ分析パイプライン、ML モデルのトレーニング、バックエンド API を管理します。
初期クラスタープロファイル (ベースライン)
| メトリック | ベースライン値 | GreenOps 後の価値 (3 か月) | 削減 |
|---|---|---|---|
| CO₂e 排出量/月 | 12.4tCO₂e | 8.1tCO₂e | -35% |
| クラウド費用/月 | 47,200ドル | 38,900ドル | -17.6% |
| 平均CPU使用率 | 23% | 41% | +78% (効率) |
| アイドルノード (夜間) | 50 ノット中 35 ノット | 50 ノード中 8 ノード (最小クラスター) | -78% アイドル状態のノード |
| 緑色のウィンドウのバッチ ジョブの割合 | 0%(未測定) | 68% | +68pp |
| kgCO₂e/1000 API リクエスト | 0.84 | 0.55 | -35% |
時系列順に実施されるアクション
GreenOps プログラムは、12 週間にわたる 3 つのフェーズで実装されました。
# FASE 1 - Settimane 1-4: Visibility
# Obiettivo: rendere visibili le emissioni, nessuna modifica ai workload
# 1.1 Deploy Kepler DaemonSet
helm install kepler oci://quay.io/sustainable_computing_io/charts/kepler \
--namespace kepler --create-namespace
# 1.2 Configura ServiceMonitor per Prometheus
kubectl apply -f kepler-service-monitor.yaml
# 1.3 Import dashboard Grafana ufficiale Kepler
# Dashboard ID: 16117 (Kepler Exporter Grafana Dashboard)
# 1.4 Deploy carbon intensity exporter
kubectl apply -f carbon-intensity-exporter.yaml
# Risultato dopo 2 settimane di osservazione:
# - 12 namespace identificati, 3 consumano 78% dell'energia
# - Pipeline ETL notturna: 8.2 kW per 4 ore ogni notte
# - 35 nodi idle dalle 22:00 alle 07:00 (weekdays), tutto il weekend
# ============================================================
# FASE 2 - Settimane 5-8: Quick Wins
# Obiettivo: implementare ottimizzazioni immediate
# 2.1 Cluster Autoscaler + Karpenter per nodi dinamici
helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter \
--namespace kube-system \
--set settings.aws.clusterName=production-cluster
# NodePool ottimizzato GreenOps
cat <<EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: greenops-batch
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot"] # Spot instances: 70% risparmio
- key: kubernetes.io/arch
operator: In
values: ["arm64"] # Graviton3: 40% più efficiente di x86
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: graviton-nodes
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 30s # Rimuovi nodi idle rapidamente
EOF
# 2.2 Namespace sleep per ambienti non-prod (kube-green)
helm install kube-green kube-green/kube-green --namespace kube-green --create-namespace
cat <<EOF | kubectl apply -f -
apiVersion: kube-green.com/v1alpha1
kind: SleepInfo
metadata:
name: staging-nighttime-sleep
namespace: staging
spec:
weekdays: "1-5" # Lunedi-Venerdi
sleepAt: "20:00"
wakeUpAt: "08:00"
timeZone: "Europe/Rome"
suspendCronJobs: true
EOF
# Risparmio stimato: 12 ore/giorno x 5 giorni x 8 nodi staging = 480 nodo-ore/settimana
# ============================================================
# FASE 3 - Settimane 9-12: Carbon-Aware Scheduling
# Obiettivo: spostare batch jobs nelle finestre verdi
# 3.1 Deploy Carbon Aware KEDA Operator
kubectl apply -f https://github.com/Azure/carbon-aware-keda-operator/releases/latest/download/operator.yaml
# 3.2 Configura CarbonAwareKedaScaler per pipeline ETL
kubectl apply -f carbon-aware-etl-scaler.yaml
# 3.3 Carbon-aware scheduler per training jobs
# (Python controller dal Paragrafo 3 - eseguito come CronJob ogni ora)
kubectl apply -f carbon-aware-scheduler-cronjob.yaml
結果の分析
排出量の 35% 削減は、さまざまな取り組みに次のように配分されました。
- 適切なサイジングとノードの統合 (Karpenter + Graviton3): -18% の排出量。 Graviton3 arm64 インスタンスに移行すると、コンピューティング ユニットあたりの消費電力が削減されました 40%増加しました。 Karpenter の統合ポリシーにより、十分に活用されていない 27 個のノードが削除されました。
- ステージング/開発環境用の kube-green: -9%の排出量。非生産的な環境 彼らは年中無休で活動し、クラスターの総エネルギーの 22% を消費しました。 誰も使っていない時間帯に。
- カーボンを意識したバッチ ジョブのスケジューリング: -8% の排出量。バッチ ジョブの 68% は 現在、us-east-1 ネットワークの炭素強度が 150 gCO₂/kWh 未満のウィンドウでスケジュールされています。
運用上の観点から最も重要なデータ: 月額 8,300 ドルのコスト削減 (-17.6%) GreenOps プログラムの導入コストの大部分を賄いました (約 3 週間) 工学部)4週間以内。 GreenOps のビジネス ケースでは、もはや 純粋に環境の観点から正当化されます。
注意: 最適化する前に測定してください
最初の可視化フェーズを行わずに GreenOps を導入したチームの 40% が物事を最適化しています 間違っています。このケーススタディでは、ML トレーニングが主な消費者であると想定されています エネルギー — 代わりに、夜間の ETL パイプラインと常時稼働のステージング環境がありました。ケプラー 2週間で真実が明らかになった。 他の作業を行う前に Kepler をデプロイする.
GreenOps アンチパターン: 避けるべきこと
現場での経験により、GreenOps プログラムの利点を無効にする繰り返し発生するエラーが特定されました あるいはさらに悪いことに、排出量を実際に削減することなく、持続可能であるという誤った感覚を生み出します。
最も一般的な GreenOps アンチパターン
| アンチパターン | 説明 | インパクト | 解決 |
|---|---|---|---|
| 削減を伴わないカーボン・オフセット | 運用上の排出量を削減する代わりに炭素クレジットを購入する | 実質排出量は変わらず、影響は最小限 | 常に回避 > 削減 > オフセットを優先します (GSF フレームワーク) |
| 平均強度と限界強度 | 意思決定には限界値ではなく平均炭素強度を使用する | 不適切な最適化: マージナルソースが追加/削除される | WattTime の限界炭素強度データを使用します (サブスクリプションが必要です) |
| 測定せずに最適化する | Kepler ベースラインを使用せずにカーボンを意識したスケーリングを実装する | 実際の影響を検証することは不可能 | 最適化する前に、少なくとも 2 週間のベースラインで Kepler を導入します |
| リバウンド効果を無視する | あるワークロードでは排出量を節約し、別のワークロードでは排出量を増やす | 純利益がゼロまたはマイナス | 単一のワークロードではなく、クラスターレベルの監視 |
| 遅延不可能なワークロードでカーボンを意識する | ユーザー向け API にもカーボンシーリングを適用する | パフォーマンスの低下、SLA 違反 | 遅延可能なワークロードとリアルタイムのワークロードを厳密に分類します |
| スコープ2のみ | 動作時の消費電力のみを測定し、スコープ 3 を無視します。 | 実際の設置面積の大幅な過小評価 | ハードウェアとデータ転送の具体化されたカーボンを含む |
| アクションのないダッシュボード | Kepler と Grafana をインストールしますが、カーボン SLO を定義しません | 美しい指標、ゼロの改善 | 違反アラートを使用して名前空間ごとに Carbon SLO を定義する |
Carbon SLO: 排出量のサービスレベル目標
GreenOps を制度化する最も効果的なパターンは、次のことを定義することです。 カーボン SLO 名前空間/チームの場合、レイテンシと可用性の SLO が定義されているとおりに。カーボン SLO サステナビリティを漠然とした願望から、明確な責任を伴う測定可能な目標に変えます。
# carbon-slo.yaml
# Carbon SLO implementato come PrometheusRule
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: carbon-slo-rules
namespace: monitoring
spec:
groups:
- name: carbon.slo
interval: 5m
rules:
# SLO: namespace "ml-training" deve stare sotto 50 kgCO2e/giorno
- alert: CarbonSLOViolation_MLTraining
expr: |
sum(
increase(kepler_container_joules_total[24h])
) by (namespace) / 3600000
* on() group_left() (carbon_intensity_g_co2_kwh / 1000)
> 50
for: 1h
labels:
severity: warning
greenops: "true"
annotations:
summary: "Carbon SLO violato: namespace ml-training"
description: |
Il namespace ml-training ha emesso {{ $value | printf "%.1f" }} kgCO2e oggi,
sopra il SLO di 50 kgCO2e/giorno.
Carbon intensity corrente: {{ with query "carbon_intensity_g_co2_kwh" }}{{ . | first | value }}{{ end }} gCO2/kWh
# Trend: emissioni cluster in crescita per 3 giorni consecutivi
- alert: CarbonTrendIncrease
expr: |
(
sum(rate(kepler_node_package_joules_total[24h]))
-
sum(rate(kepler_node_package_joules_total[24h] offset 72h))
)
/ sum(rate(kepler_node_package_joules_total[24h] offset 72h)) > 0.15
for: 6h
labels:
severity: info
greenops: "true"
annotations:
summary: "Trend emissioni cluster in aumento"
description: "Emissioni cluster aumentate del {{ $value | humanizePercentage }} nelle ultime 72 ore"
GreenOps ロードマップ: 初心者からデータドリブンへ
GreenOps を導入するには、すべてを一度に実装する必要はありません。パスは段階的に発展します 進歩的であり、それぞれがさらなる投資を必要とする前に測定可能な価値をもたらします。
GreenOps の成熟度: 4 レベル
| レベル | 名前 | 特徴 | 一般的なタイムライン | 期待されるCO₂削減量 |
|---|---|---|---|---|
| 1 | 可視性 | Kepler がインストールされ、Grafana で最初のメトリクスが設定され、Carbon SLO が定義されました (まだ施行されていません) | 2~4週間 | 0%(測定のみ) |
| 2 | 即効性 | 適切なサイジング、非本番環境用の kube-green、最適化されたオートスケーラー クラスター、Graviton/ARM64 | 1~2ヶ月 | 15-25% |
| 3 | カーボンを意識したスケジューリング | KEDA カーボン スケーラー、カーボン対応 CronJob スケジューラー、グリーン CI/CD、カーボン SLO の強制 | 2~3ヶ月 | 25~40% |
| 4 | マルチリージョンの最適化 | Karmada ロケーションシフト、炭素最適化データ転送ルーティング、完全なスコープ 3 アカウンティング | 4~6ヶ月 | 35-60% |
レベル 1 (可視性) は最も重要なステップですが、最も見落とされがちなステップです。 測定しないものを最適化することはできません: 2 週間の Kepler データが明らかに 常に予期せぬチャンス - 忘れ去られた環境、ループで実行されるジョブ、 実際の使用量と一致しない、CPU 要求が膨らんだ名前空間。これらの発見は、 これだけでも、Kepler のインストールへの投資が正当化されます。
結論
GreenOps は、環境に優しいと思われたい企業にとって贅沢ではありません。規律です。 直接的かつ測定可能な経済的利益をもたらす成熟したエンジニアリング。 欧州連合の CSRD 指令の対象となる企業には必須です。スコープ2排出量 クラウド コンピューティング — データ センターで消費される電力からの排出 — は、 すでに今日、数千の欧州企業にとって必須のステートメント項目となっており、その粒度は ESRS フレームワークで要求される課題は、ますます個々のワークロードのレベルにまで落ち込んでいます。
Kubernetes 用の GreenOps ツールキットは現在、驚くほど成熟しています。 ケプラー のために ポッドごとのエネルギー測定、 カーボンを意識した KEDA オペレーター スケーリング用 カーボンを意識した、 カーボンアウェア SDK Green Software Foundation からのデータについては、 リアルタイムの炭素強度、 カルマダ 場所移動用に マルチクラスター。これらのツールはすべてオープンソースでアクティブであり、大規模な企業が運用環境で使用しています。 組織。
出発点は常に同じです。Kepler をインストールし、2 週間のデータを確認し、 現実に優先順位を導きましょう。経験上、70% は迅速であることがわかっています。 GreenOps の勝利は最初の 14 日間の観察で特定されます。そして、このケーススタディのように 記事によると、経済的な ROI により、プログラム全体が 1 ~ 2 か月以内に自己資金で賄えるようになります。
グリーン ソフトウェア エンジニアリング シリーズは継続します
- 前回の記事(5): スコープ 3 と ESG パイプライン — 上流排出量 CSRD 準拠のための下流のデータ パイプライン
- 次の記事(7): スコープ 1、2、3 のモデリング — 会計フレームワーク GHG プロトコル、SBTi Net-Zero Standard、モデリング ツール
- MLOps シリーズの関連: ML トレーニングを最適化して炭素を削減する フットプリント — 量子化、枝刈り、ハードウェアの選択
- データ&AIビジネスシリーズ関連: データセンターと持続可能性 — PUE、WUE、中小企業向け再生可能エネルギー調達
リソースと参考資料
- GitHub の Kepler — Kubernetes ベースの効率的な電力レベル エクスポーター
- Carbon Aware KEDA オペレーター — Azure/Microsoft
- Carbon Aware SDK — Green Software Foundation (MIT ライセンス)
- Kepler プロジェクト — CNCF サンドボックス
- クラウド二酸化炭素排出量 — オープンソースのマルチクラウド ツール
- GreenOps と FinOps: 持続可能な AI のための二重戦略 — 新しいスタック
- Green Software Foundation — SCI 仕様とリソース







