GreenOps: infrastruktura uwzględniająca emisję dwutlenku węgla z Kubernetesem
Dzisiejsze centra danych na świecie zużywają pomiędzy1 i 2% światowej energii elektrycznej, z Emisje równoważne CO₂ szacowane są na 100–200 milionów ton rocznie – czyli więcej niż cała emisja przemysł lotniczy. W obliczu pośpiechu w kierunku generatywnej sztucznej inteligencji modele szkoleniowe takie jak GPT-4 zużywają energię co odpowiada setkom lotów transatlantyckich w jednym rejsie. Jednak większość infrastruktury cloud nadal działa tak, jakby tych emisji nie było: klastry Kubernetes działają cyklicznie ciągłość niezależnie od intensywności emisji dwutlenku węgla przez sieć elektroenergetyczną, tak jest w przypadku rurociągów CI/CD uruchamiają się natychmiast, nie biorąc pod uwagę, kiedy prąd jest czystszy, i zespoły DevOps monitoruje koszty i opóźnienia, ale rzadko emisje na pod.
GreenOps to dyscyplina operacyjna zmienia ten paradygmat. Metody pożyczania z FinOps — praktyki optymalizacji wydatków na chmurę — GreenOps zapewnia zrównoważony rozwój środowisko w centrum decyzji dotyczących infrastruktury: jak alokować obciążenia, kiedy uruchamiać zadania wsadowe, w którym regionie wdrożyć, jak dopasować rozmiar węzłów. Rezultatem jest nie tylko środowisko: organizacje wdrażające raport GreenOps średnio a Redukcja emisji o 30–60%. związane z chmurą i oszczędność kosztów na poziomie 15-30%, ponieważ efektywność energetyczna i wydajność ekonomiczne często się pokrywają.
W tym artykule zbudujemy od zera prawdziwie świadomą emisji dwutlenku węgla infrastrukturę Kubernetes: będziemy instrumentować klaster Keplera do pomiaru zużycia energii na moduł, skonfigurujemy świadomy emisji dwutlenku węgla operator KEDA skalować obciążenia w oparciu o intensywność carbon w czasie rzeczywistym, wdrożymy wieloregionalne trasowanie emisji dwutlenku węgla z Karmadą i zbudujemy rurociąg CI/CD, który automatycznie wybierze najbardziej ekologiczne okno czasowe uruchom kompilacje. Każda sekcja zawiera gotowy do produkcji kod YAML i Python.
Czego się nauczysz
- Różnice między GreenOps i FinOps oraz sposób, w jaki się uzupełniają, aby zapewnić zrównoważony rozwój chmury
- Automatyczne skalowanie uwzględniające emisję dwutlenku węgla za pomocą operatora KEDA i operatora KEDA z uwzględnieniem emisji dwutlenku węgla na platformie Azure
- Jak zainstalować i skonfigurować Keplera (eksporter efektywnego poziomu mocy oparty na Kubernetes)
- Metryki Keplera Prometheusa: zużycie energii na kontener, kapsułę i węzeł
- Planowanie uwzględniające emisję dwutlenku węgla za pomocą CronJob i PriorityClass opartych na intensywności emisji dwutlenku węgla
- Wieloregionalne kierowanie emisją dwutlenku węgla za pomocą Karmady: przenieś obciążenia do bardziej ekologicznych regionów
- Porównanie interfejsów API śladu węglowego dostawców usług w chmurze: AWS, Google Cloud, Azure
- Dashboard Grafana do monitorowania emisji klastra Kubernetes
- Ekologiczne CI/CD: działania GitHub uwzględniające emisję gazów cieplarnianych z inteligentnym planowaniem kompilacji
- Studium przypadku: klaster 50 węzłów z redukcją emisji o 35% w ciągu 3 miesięcy
Seria o inżynierii oprogramowania ekologicznego — wszystkie artykuły
| # | Tytuł | Temat |
|---|---|---|
| 1 | Zasady zielonej inżynierii oprogramowania | 8 zasad GSF, specyfikacja SCI ISO/IEC 21031 |
| 2 | Pomiar emisji za pomocą CodeCarbon | Śledzenie CO₂ w Pythonie, MLflow, dashboard |
| 3 | Climatiq API: Intensywność emisji dwutlenku węgla w systemach chmurowych | REST API, kalkulacja emisji w chmurze i łańcuch dostaw |
| 4 | Carbon Aware SDK: zmiana czasu i lokalizacji | GSF SDK, WattTime, ElectricityMaps, Kubernetes, CI/CD |
| 5 | Zakres 3 i rurociąg ESG | Emisje typu upstream/downstream, rurociąg danych CSRD |
| 6 | GreenOps: Infrastruktura uwzględniająca emisję dwutlenku węgla z Kubernetesem (ten artykuł) | Skaler węgla KEDA, Kepler, routing wieloregionowy, Green CI/CD |
| 7 | Modelowanie zakresu 1, 2, 3 | Ramy rachunkowości protokołu GHG, SBTi |
| 8 | Ślad węglowy AI | Szkolenia LLM, wnioskowanie, optymalizacja energetyczna |
| 9 | Zrównoważone wzorce oprogramowania | Zielony wzór, wydajna architektura |
| 10 | ESG i CSRD dla oprogramowania | Zgodność z przepisami, obowiązkowe raportowanie UE |
GreenOps vs FinOps: uzupełnienie, a nie alternatywa
FinOps narodziło się w odpowiedzi na niekontrolowany wzrost wydatków na chmurę: zespoły, które alokowały zasoby bez uwzględnienia kosztów, zapomniane instancje EC2 aktywne od miesięcy, niezoptymalizowana pamięć masowa które gromadziły faktury, nie wytwarzając wartości. FinOps zapewnia kulturę, procesy i narzędzia do działania widoczne wydatki i systematycznie je optymalizować. GreenOps jest wyraźnie inspirowany tym modelem zastosowanie go do emisji dwutlenku węgla: uwidacznia emisję poprzez nakład pracy, wprowadza procesy optymalizację i tworzy odpowiedzialność w zespołach.
Dobra wiadomość jest taka, że te dwie dyscypliny w ogromnym stopniu się pokrywają: ten sam strąk zbyt duże marnują zarówno pieniądze, jak i energię. Bezczynny klaster z dnia na dzień zużywa oba budżety ten CO₂. Optymalizacja często oznacza optymalizację obu. Ale są też istotne rozbieżności zrozumieć.
GreenOps vs FinOps: tabela porównawcza
| Rozmiar | FinOps | GreenOps | Integracja |
|---|---|---|---|
| Główny cel | Zmniejsz wydatki na chmurę, zoptymalizuj zwrot z inwestycji | Zmniejsz emisję CO₂, zwiększ efektywność energetyczną | Często zgodne: wydajność = oszczędności = redukcja emisji |
| Metryka podstawowa | Koszt na jednostkę biznesową ($/żądanie, $/użytkownik) | gCO₂eq na jednostkę biznesową (intensywność emisji dwutlenku węgla) | Wspólne pulpity nawigacyjne dotyczące kosztów i emisji dwutlenku węgla umożliwiające zintegrowane podejmowanie decyzji |
| Główna dźwignia | Odpowiedni rozmiar, instancje zarezerwowane, wycena spot | Zmiana czasu, zmiana lokalizacji, kształtowanie popytu | Przesunięcie w czasie zmniejsza zarówno szczytowe koszty, jak i emisję |
| Szczegółowość | Chmura tagów, zespół, usługa, konto | Pod, kontener, funkcja bezserwerowa | Kepler przenosi szczegółowość GreenOps na poziom kapsuły, podobnie jak FinOps |
| Doczesność | Optymalizacja miesięczna/kwartalna (faktura) | Optymalizacja godzinowa (zmienność intensywności emisji dwutlenku węgla) | GreenOps wymaga automatyzacji w czasie rzeczywistym; Bardziej statyczne FinOps |
| Możliwe konflikty | Wykryj przypadki tańsze, ale w regionie charakteryzujące się dużą emisją dwutlenku węgla | Region zielony, ale droższy, większe opóźnienia | Wyraźne kompromisy w połączeniu z oceną kosztów i emisji dwutlenku węgla |
| Instrumenty | Eksplorator kosztów AWS, CloudHealth, Kubecost | Kepler, SDK Carbon Aware, API Cloud Carbon | Kubecost + Kepler: koszt i emisja dwutlenku węgla na kapsułę na tym samym pulpicie nawigacyjnym |
| Standard | Specyfikacja Fundacji FinOps FOCUS | Specyfikacja GSF SCI, protokół dotyczący GHG | Oczekiwana konwergencja w 2026 r. przy ujednoliconych wskaźnikach |
Najbardziej strategicznym punktem zbieżności pomiędzy FinOps i GreenOps jest odpowiedni rozmiar: zmniejszenie nadmiernego zapotrzebowania na procesor/pamięć podów nie tylko obniża rachunki za chmurę, ale bezpośrednio je zmniejsza zużycie energii przez węzły, które skaluje się proporcjonalnie do obciążenia. Według danych po przejęciu CloudBolt przez StormForge (marzec 2025 r.) klastry zoptymalizowane przy użyciu odpowiedniego rozmiaru opartego na sztucznej inteligencji przyniosły średnie redukcje o 40% zarówno pod względem kosztów, jak i emisji – rzadki przypadek, w którym nie ma kompromisu.
Zamiast tego konflikt pojawia się, gdy obszar chmur o niskiej intensywności emisji dwutlenku węgla jest położony geograficznie daleko i dlatego jest droższy w przypadku przesyłania danych lub gdy jest to tania instancja punktowa zlokalizowanych na obszarze opalanym głównie węglem. W takich scenariuszach GreenOps łączy więcej zespołów dojrzali dorośli adoptują jednego złożona funkcja punktacji co równoważy koszty, emisję i opóźnienia z konfigurowalnymi wagami dla różnych rodzajów obciążeń.
Kubernetes świadomy emisji dwutlenku węgla: KEDA i operator świadomy emisji dwutlenku węgla
KEDA (Kubernetes Event-Driven Autoscaler) to komponent Kubernetes typu open source, który umożliwia skaluj obciążenia w oparciu o zdarzenia i metryki zewnętrzne — kolejki komunikatów, metryki Prometheus, Punkty końcowe HTTP. The Operator KEDA świadomy emisji dwutlenku węgla, opracowany przez Microsoft Azure i opublikowany na GitHubie rozszerza KEDA o radykalnie nowy wymiar: intensywność emisji dwutlenku węgla przez sieć elektroenergetyczną lokalny. Rezultatem jest klaster, który można skalować ku dołowi kiedy jest prąd produkowane ze źródeł kopalnych, np w górę gdy energii odnawialnej jest pod dostatkiem.
Mechanizm jest elegancki w swojej prostocie. Operator odczytuje aktualną intensywność emisji dwutlenku węgla — z WattTime, ElectricityMaps lub dowolnego innego źródła — i zapełnia ConfigMap w klastrze wartość aktualizowana co godzinę. Obiekt KEDA ScaledObject odczytuje ConfigMap i wykorzystuje tę wartość jako dane wejściowe określ maksymalną dozwoloną liczbę replikacji: gdy intensywność jest wysoka (network wysokoemisyjne), sufit się obniża; gdy intensywność jest niska (czysta energia), sufit się podnosi, a klaster może skalować się bardziej agresywnie.
Architektura operatora KEDA uwzględniająca emisję dwutlenku węgla
# 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
Odpowiedni KEDA ScaledObject, który obsługuje faktyczne automatyczne skalowanie wdrożenia:
# 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"
Eksporter mapy konfiguracji intensywności emisji dwutlenku węgla
ConfigMap z danymi dotyczącymi intensywności emisji dwutlenku węgla musi zostać wypełniony zadaniem wysyłającym zapytania do zewnętrznych interfejsów API.
Projekt kubernetes-carbon-intensity-exporter Platforma Azure udostępnia ten komponent:
# 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
Obciążenia odpowiednie do skalowania uwzględniającego emisję dwutlenku węgla
Skalowanie uwzględniające emisję dwutlenku węgla działa tylko w przypadku obciążeń odroczone o elastyczny:
zadania wsadowe, szkolenia ML, potok ETL, przetwarzanie raportów, transkodowanie multimediów. Nie stosuj tego do usług
w czasie rzeczywistym, bezpośrednio do użytkownika (bramka API, frontend), gdzie opóźnienie jest krytyczne. Parametr
minReplicaCount gwarantuje, że nawet w warunkach dużej intensywności emisji dwutlenku węgla strąki są minimalne
kontynuować rotację, aby utrzymać dostępność usługi.
Planowanie uwzględniające emisję dwutlenku węgla: CronJob i PriorityClass Verdi
Oprócz reaktywnego autoskalowania, GreenOps wprowadza planowanie proaktywny: zamiast reagować na aktualną intensywność emisji dwutlenku węgla, oczekuje się, że najbardziej ekologiczne okno czasowe nastąpi w następne 24 godziny i planuje uruchomienie zadania o tej godzinie. WattTime i ElectricityMaps dostarczają prognozy do 72 godzin, dzięki czemu możliwa jest optymalizacja.
Kontroler Pythona dla CronJob uwzględniający emisję dwutlenku węgla
Lekki kontroler Pythona, który wysyła zapytania do zestawu SDK Carbon Aware i dynamicznie przepisuje harmonogram Kubernetes CronJob, aby wskazywał zielone okno:
#!/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 uwzględniający emisję dwutlenku węgla
Kubernetes umożliwia ustalanie priorytetów podów poprzez PriorityClass. W kontekście
GreenOps definiujemy klasy priorytetów odzwierciedlające tolerancję na odroczenie: obciążenia pracą
zadania krytyczne mają wysoki priorytet, te, których nie można odłożyć na później, mają niski priorytet
i mogą zostać eksmitowani lub opóźnieni, gdy zasoby muszą zostać skoncentrowane na wielu zadaniach
pilne w okresach niskiej intensywności emisji dwutlenku węgla.
# 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"
Wieloregionalne trasy węglowe z Karmada
Przesunięcie w czasie przenosi obciążenie pracą do czas w tym samym regionie. The zmiana lokalizacji idzie dalej: przenosi obciążenie pracą na przestrzeń, uruchamiając zadanie w regionie chmury z węglem najniższa intensywność w tym momencie. Zróżnicowanie geograficzne jest ogromne: w specyficzny moment, eu-north-1 (Sztokholm, zasilany prawie w całości hydroelektrownią). mają intensywność 15 gCO₂/kWh, podczas gdy us-east-1 (Wirginia, z mieszanką węgiel/gaz/jądr) może wynosić 300–400 gCO₂/kWh. Zamiast tego przeniesiemy pracę w ramach szkolenia ML do Szwecji Wirginia ogranicza emisję gazów cieplarnianych 90%+ przy tych samych obliczeniach.
Karmada (Kubernetes Armada) to projekt CNCF do zarządzania klastrami Wiele Kubernetesów. Umożliwia dystrybucję obciążeń pomiędzy wieloma klastrami w wielu regionach wyrafinowane polityki. W połączeniu z danymi dotyczącymi intensywności emisji dwutlenku węgla w czasie rzeczywistym staje się motorem wieloregionalne trasowanie emisji dwutlenku węgla.
Wieloregionalna architektura 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: dynamiczna aktualizacja zasad 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)
Interfejsy API dostawcy usług w chmurze: AWS, Google Cloud, Azure
Równolegle z narzędziami open source trzech głównych dostawców usług w chmurze udostępniło lub udoskonaliło narzędzia znacząco swoje rodzime narzędzia służące do śledzenia śladu węglowego. Sytuacja w 2025 roku jest bardzo trudna zróżnicowane pod względem dojrzałości i użyteczności.
Porównanie API dostawców usług w chmurze dotyczących śladu węglowego (2025 r.)
| Dostawcy | Instrument | Szczegółowość | API? | Miotły | Aktualizacja |
|---|---|---|---|---|---|
| AWS | Narzędzie do pomiaru śladu węglowego klienta | Konto, region, usługa | Tylko eksport CSV | Zakres 1, 2, 3 (od 2024 r.) | Miesięcznie (opóźnienie 3 miesiące) |
| Chmura Google | Ślad węglowy w chmurze | Projekt, usługa, region | Eksport BigQuery + API | Zakres 1, 2, 3 | Co miesiąc (opóźnienie 4 tygodnie) |
| Lazur | Panel kontrolny wpływu emisji firmy Microsoft / optymalizacja emisji dwutlenku węgla | Subskrypcja, grupa zasobów, usługa | Kompletne API REST (2025) | Zakres 1, 2, 3 | Miesięcznie (opóźnienie 2 miesiące) |
| Wiele chmur | Ślad węglowy chmury (open source) | Konto, usługa, region | Własny hostowany interfejs API REST | Zakres 2 (metodologia własna) | Codziennie |
Interfejs API REST optymalizacji emisji dwutlenku węgla na platformie Azure
Najbardziej znaczący krok Microsoft wykonał w 2025 roku wraz z wprowadzeniem na rynek Węgiel Optymalizacja w Azure Portal, obsługiwany przez kompletny interfejs API REST do integracji z systemy wewnętrzne. Przykład integracji:
#!/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")
Zalecana strategia dotycząca danych dotyczących emisji dwutlenku węgla
- Planowanie w czasie rzeczywistym: do podejmowania decyzji użyj pakietu SDK Carbon Aware + WattTime/ElectricityMaps w czasie rzeczywistym w oparciu o planowanie uwzględniające emisję dwutlenku węgla
- Raportowanie miesięczne: Użyj natywnych narzędzi dostawcy chmury do księgowości Oficjalny CO₂ (Zakres 1/2/3) wymagany do raportowania CSRD/ESG
- Wiele chmur: Użyj rozwiązania Cloud Carbon Footprint o otwartym kodzie źródłowym, aby agregować dane z wielu źródeł dostawcy konsekwentnie
- Alerty operacyjne: Użyj Keplera + Prometheusa, aby otrzymywać powiadomienia w czasie rzeczywistym o skokach zużycia energia na kapsułę
Kepler: Pomiar zużycia energii na kapsułę
Keplera (Efficient Power Level Exporter oparty na Kubernetes) to projekt CNCF który mierzy zużycie energii na poziomie kontenera, podu i węzła w klastrze Kubernetes, eksportuje metryki dla Prometeusza. Jest to podstawowy element uwidocznienia emisji poziom operacyjny: Bez Keplera zespół DevOps jest ślepy na emisję na obciążenie pracą i nie może skutecznie realizować GreenOps.
Kepler wykorzystuje rozszerzoną metodę filtrowania pakietów Berkeley (eBPF) do śledzenia zużycia zasobów sprzęt na poziomie jądra, łączący dane z RAPL (Bieżący limit średniej mocy, interfejs Intel/AMD dla zużycia procesora), ACPI za zużycie systemu i czujniki NVIDIA NVML dla procesorów graficznych. U dostawców usług w chmurze, u których nie ma fizycznych czujników sprzętowych dostępne, Kepler wykorzystuje modele predykcyjne oparte na dostępnych metrykach procesora.
Od wersji 0.10.0 (2025) Kepler przeszedł całkowitą przeróbkę architektury internal, co poprawia dokładność przewidywań na maszynach wirtualnych w chmurze i zmniejsza obciążenie DaemonSet z ok 5% do mniej niż 2% procesora.
Instalacja Keplera z Helmem
# 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{...}
Główne metryki Keplera
Metryki Keplera niezbędne dla GreenOps
| Metryczny | Opis | Jednostka | Użyj przypadku |
|---|---|---|---|
kepler_container_joules_total |
Całkowita energia zużyta przez kontener od momentu uruchomienia | Dżule (licznik) | Energia na kapsułę w określonym czasie |
kepler_container_cpu_joules_total |
Energia zużywana przez procesor dla kontenera | Dżule (licznik) | Identyfikuj obciążenia związane z procesorem o dużej mocy |
kepler_container_dram_joules_total |
Energia zużywana przez pamięć RAM dla kontenera | Dżule (licznik) | Analiza obciążenia związanego z pamięcią |
kepler_container_gpu_joules_total |
Pobór mocy procesora graficznego (wymaga NVIDIA) | Dżule (licznik) | Śledzenie zużycia szkoleń ML |
kepler_node_core_joules_total |
Całkowita energia węzła na rdzeń procesora | Dżule (licznik) | Wydajność węzła, poziom bazowy zużycia |
kepler_node_package_joules_total |
Całkowita energia pakietu procesora (wszystkie rdzenie) | Dżule (licznik) | Obliczenia PUE, całkowite zużycie węzła |
kepler_container_watts |
Natychmiastowa moc kontenera | Waty (miernik) | Alerty w czasie rzeczywistym o skokach energii |
Zapytania PromQL dla GreenOps
# 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
Panel Grafana dla GreenOps
Projekt Kepler udostępnia gotowe dashboardy Grafana, które można bezpośrednio zaimportować. Konfiguracja zalecane łączy metryki Keplera z danymi dotyczącymi intensywności emisji dwutlenku węgla, aby stworzyć zintegrowany widok:
# 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}}"
}
]
}
]
}
Zielony CI/CD: GitHub Actions świadomy emisji dwutlenku węgla
Rurociągi CI/CD są idealnymi kandydatami do planowania uwzględniającego emisję dwutlenku węgla: kompilacja, która uruchamia się każde naciśnięcie nie musi koniecznie zostać wykonane natychmiast. Kompilacje gałęzi funkcji, tj kompleksowe testy regresyjne, generowanie artefaktów, wdrożenia w środowiskach testowych — wszystko to mają mierzalną tolerancję opóźnienia, często godzinną. Przenieś te potoki do okien Niska intensywność emisji dwutlenku węgla wymaga bardzo niewielkiego wysiłku i może zmniejszyć emisję CI/CD 20-40%.
Działania GitHub z planowaniem uwzględniającym emisję dwutlenku węgla
# .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"
Oszacuj emisję CI/CD
Oprócz przenoszenia budynków do zielonych okien warto zmierzyć rzeczywistą emisję gazów cieplarnianych Rurociąg CI/CD. Moduły uruchamiające hostowane w GitHub zużywają około 0,05–0,2 kWh na godzinę kompilacji, w zależności od typ biegacza. Oto krok działania pozwalający oszacować i zarejestrować emisję:
# 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
Panel FinOps + GreenOps: koszty i emisja dwutlenku węgla razem
Dojrzałość GreenOps organizacji mierzy się także jej zdolnością do korelacji wskaźniki kosztów i emisji w jednym widoku. Zespoły zarządzające tymi wymiarami oddzielnie podejmują nieoptymalne decyzje: zmiana rozmiaru zmniejszająca koszty o 20% może nie mieć żadnego wpływu na emisję, jeśli oszczędności zostaną ponownie zainwestowane w regionach o dużej emisji dwutlenku węgla. I odwrotnie, przeniesienie lokalizacji do bardziej ekologicznego regionu może zwiększyć koszty przeniesienia dane anulujące korzyść ekonomiczną.
Idealna integracja łączy Kubecost (koszt na pod/przestrzeń nazw) z Keplera (energia na kapsułę/przestrzeń nazw) w jednym panelu Grafana, wzbogaconym o dane dotyczące intensywności emisji dwutlenku węgla w czasie rzeczywistym, aby obliczyć rzeczywisty koszt emisji dwutlenku węgla przy każdym obciążeniu pracą.
# 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
)
Niezbędne KPI GreenOps do monitorowania
- Aktualna intensywność emisji dwutlenku węgla (gCO₂/kWh): dane w czasie rzeczywistym z sieci elektroenergetycznej
- kgCO₂e/godzinę klastra: zagregowane emisje klastra
- kWh/zapotrzebowanie: efektywność energetyczna na jednostkę pracy
- gCO₂e/zapotrzebowanie: ślad węglowy według jednostki biznesowej
- % obciążenia pracą w zielonych oknach: procent zadań wsadowych wykonanych z progiem CI <
- Uniknięty koszt/kg CO₂: ROI inicjatyw GreenOps
- Szacowany PUE: Efektywność zużycia energii przez klaster (docelowo < 1,2)
- Bezczynne marnowanie energii: Energia zużywana przez niewykorzystane moduły/węzły
Studium przypadku: 35% redukcja emisji w klastrach 50 węzłów
Poniższe studium przypadku podsumowuje rzeczywiste wyniki europejskiej firmy SaaS z klastrem Produkcyjny Kubernetes składający się z 50 węzłów (połączenie c5.4xlarge i m5.2xlarge na AWS us-east-1), który zarządza potokami analizy danych, szkoleniem modeli ML i interfejsami API zaplecza.
Początkowy profil klastra (wartość bazowa)
| Metryczny | Wartość bazowa | Wartość po GreenOps (3 miesiące) | Zmniejszenie |
|---|---|---|---|
| Emisja CO₂/miesiąc | 12,4 tCO₂e | 8,1 tCO₂e | -35% |
| Koszt chmury/miesiąc | 47 200 dolarów | 38 900 dolarów | -17,6% |
| Średnie wykorzystanie procesora | 23% | 41% | +78% (wydajność) |
| Węzły bezczynne (noc) | 35 węzłów na 50 | 8 węzłów z 50 (min. klaster) | -78% bezczynnych węzłów |
| % zadań wsadowych w zielonych oknach | 0% (niezmierzone) | 68% | +68 pp |
| kgCO₂e/1000 żądań API | 0,84 | 0,55 | -35% |
Działania realizowane w porządku chronologicznym
Program GreenOps był realizowany w trzech fazach w ciągu 12 tygodni:
# 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
Analiza wyników
Redukcja emisji o 35% została rozdzielona pomiędzy różne inicjatywy w następujący sposób:
- Dopasowanie rozmiaru i konsolidacja węzłów (Karpenter + Graviton3): -18% emisji. Przejście na instancje Graviton3 arm64 zmniejszyło zużycie energii na jednostkę obliczeniową o 40%. Polityka konsolidacyjna Karpentera wyeliminowała 27 niewykorzystanych węzłów.
- kube-green dla środowisk testowych/dev: -9% emisji. Środowiska nieprodukcyjne były aktywne 24 godziny na dobę, 7 dni w tygodniu i zużywały przeważnie 22% całkowitej energii klastra w godzinach, kiedy nikt z nich nie korzystał.
- Zadania wsadowe planowania uwzględniające emisję gazów cieplarnianych: -8% emisji. 68% zadań wsadowych to zadania obecnie zaplanowane w oknach, w których sieć us-east-1 charakteryzuje się intensywnością emisji dwutlenku węgla niższą niż 150 gCO₂/kWh.
Najważniejsze dane z operacyjnego punktu widzenia: Oszczędności w wysokości 8300 USD miesięcznie (-17,6%) w dużej części pokrył koszty realizacji programu GreenOps (około 3 tygodnie inżynierii) w ciągu 4 tygodni. Uzasadnienie biznesowe dla GreenOps nie wymaga już bycia uzasadnione w kategoriach czysto środowiskowych.
Uwaga: zmierz przed optymalizacją
40% zespołów, które wdrażają GreenOps bez fazy początkowej widoczności, optymalizuje działania źle. W tym studium przypadku założono, że głównym konsumentem jest szkolenie ML energia — zamiast tego były to nocne rurociągi ETL i zawsze włączone środowiska testowe. Keplera ujawnił prawdę w ciągu 2 tygodni. Rozmieść Keplera, zanim zrobisz cokolwiek innego.
Antywzorzec GreenOps: czego unikać
Doświadczenie praktyczne wykazało powtarzające się błędy, które negują korzyści płynące z programów GreenOps lub, co gorsza, dają fałszywe poczucie zrównoważonego rozwoju bez rzeczywistej redukcji emisji.
Najczęstsze anty-wzorce GreenOps
| Antywzorzec | Opis | Uderzenie | Rozwiązanie |
|---|---|---|---|
| Kompensacja emisji dwutlenku węgla bez redukcji | Kupuj kredyty węglowe zamiast zmniejszać emisję operacyjną | Rzeczywiste emisje niezmienione, wpływ minimalny | Zawsze traktuj priorytetowo Unikaj > Ograniczaj > Przesunięcie (rama GSF) |
| Intensywność średnia vs marginalna | Przy podejmowaniu decyzji należy stosować średnią intensywność emisji dwutlenku węgla zamiast marginalnej | Złe optymalizacje: źródło marginalne to to, które zostało dodane/usunięte | Użyj danych o marginalnej intensywności emisji dwutlenku węgla z WattTime (wymaga subskrypcji) |
| Optymalizuj bez mierzenia | Wdrażaj skalowanie uwzględniające emisję dwutlenku węgla bez linii bazowych Keplera | Nie da się zweryfikować faktycznego wpływu | Przed optymalizacją wdroż Keplera na co najmniej 2 tygodnie w wersji bazowej |
| Ignoruj efekt odbicia | Oszczędzaj emisje przy jednym obciążeniu i zwiększaj je przy innym | Zerowa lub ujemna korzyść netto | Monitorowanie na poziomie klastra, a nie pojedynczego obciążenia |
| Świadomość emisji dwutlenku węgla w przypadku obciążeń, których nie można odroczyć | Zastosuj pułap emisji dwutlenku węgla także do interfejsów API dostępnych dla użytkownika | Spadek wydajności, naruszona umowa SLA | Rygorystycznie klasyfikuje obciążenia odroczone i obciążenia w czasie rzeczywistym |
| Tylko zakres 2 | Mierz tylko operacyjny pobór mocy, ignoruj Zakres 3 | Znaczące niedoszacowanie rzeczywistego śladu | Uwzględnij wbudowaną część sprzętu i transferu danych |
| Panel bez akcji | Zainstaluj Keplera i Grafanę, ale nie definiuj SLO węgla | Piękne wskaźniki, zero poprawy | Zdefiniuj SLO Carbon dla każdej przestrzeni nazw z alertem o naruszeniu |
Carbon SLO: Cele poziomu usług w zakresie emisji
Najskuteczniejszym sposobem instytucjonalizacji GreenOps jest zdefiniowanie Węgiel SLO dla przestrzeni nazw/zespołu dokładnie tak, jak zdefiniowano opóźnienia i dostępność SLO. Węglowe SLO przekształca zrównoważony rozwój z niejasnych aspiracji w mierzalny cel z jasną odpowiedzialnością:
# 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"
Plan działania GreenOps: od początkującego do opartego na danych
Wdrożenie GreenOps nie wymaga wdrożenia wszystkiego na raz. Ścieżka rozwija się etapami progresywny, z których każdy przynosi wymierną wartość, zanim będzie wymagał dalszych inwestycji.
Dojrzałość GreenOps: 4 poziomy
| Poziom | Nazwa | Charakterystyka | Typowa linia czasu | Oczekiwana redukcja CO₂ |
|---|---|---|---|---|
| 1 | Widoczność | Zainstalowano Keplera, pierwsze metryki w Grafanie, zdefiniowano SLO emisji dwutlenku węgla (jeszcze nie wdrożone) | 2-4 tygodnie | 0% (tylko pomiar) |
| 2 | Szybkie wygrane | Odpowiedni rozmiar, kube-green dla środowisk innych niż produkcyjne, zoptymalizowany klaster automatycznego skalowania, Graviton/ARM64 | 1-2 miesiące | 15-25% |
| 3 | Planowanie uwzględniające emisję dwutlenku węgla | Skaler węgla KEDA, harmonogram CronJob uwzględniający emisję dwutlenku węgla, Green CI/CD, wymuszanie Carbon SLO | 2-3 miesiące | 25-40% |
| 4 | Optymalizacja wielu regionów | Zmiana lokalizacji Karmada, routing przesyłu danych zoptymalizowany pod kątem emisji dwutlenku węgla, pełna księgowość w zakresie 3 | 4-6 miesięcy | 35-60% |
Poziom 1 (Widoczność) jest najważniejszym i często najczęściej pomijanym krokiem. Nie możesz zoptymalizować tego, czego nie mierzysz: ujawniają się dane Keplera z dwóch tygodni niezmiennie nieoczekiwane możliwości — zapomniane środowiska, zadania działające w pętli, przestrzenie nazw z zawyżonym zapotrzebowaniem na procesor, które nie odpowiada rzeczywistemu użyciu. Te odkrycia z samo w sobie uzasadnia inwestycję w instalację Keplera.
Wnioski
GreenOps nie jest luksusem dla firm, które chcą wyglądać ekologicznie: to dyscyplina dojrzała inżynieria, która przynosi bezpośrednie i wymierne korzyści ekonomiczne, i które wkrótce staną się obowiązkowe dla spółek podlegających dyrektywie Unii Europejskiej CSRD. Zakres 2 emisji przetwarzanie w chmurze – emisje z energii elektrycznej zużywanej przez centra danych – wynoszą już dziś obowiązkowa pozycja w oświadczeniu dla tysięcy europejskich firm oraz szczegółowość wymagane przez frameworki ESRS w coraz większym stopniu spada do poziomu indywidualnych obciążeń.
Zestaw narzędzi GreenOps dla Kubernetes jest dziś zaskakująco dojrzały: Keplera dla pomiar energii na kapsułę, Operator KEDA świadomy emisji dwutlenku węgla do skalowania świadomi emisji dwutlenku węgla, Pakiet SDK uwzględniający emisję dwutlenku węgla od Green Software Foundation za dane z intensywność emisji dwutlenku węgla w czasie rzeczywistym, Karmada do zmiany lokalizacji wieloklastrowy. Wszystkie te narzędzia są open source, są aktywne i powszechnie wykorzystywane w produkcji organizacje.
Punkt wyjścia jest zawsze ten sam: zainstaluj Keplera, spójrz na dane przez dwa tygodnie i niech rzeczywistość wyznacza priorytety. Doświadczenie pokazuje, że 70% szybkich wygrane GreenOps są identyfikowane w ciągu pierwszych 14 dni obserwacji. I tak jak w przypadku tego studium przypadku artykule ekonomiczny zwrot z inwestycji sprawia, że cały program samofinansuje się w ciągu 1-2 miesięcy.
Kontynuacja serii „Zielona Inżynieria Oprogramowania”.
- Poprzedni artykuł (5): Zakres 3 i rurociąg ESG – emisje z wydobycia np downstream, potok danych w celu zapewnienia zgodności z dyrektywą CSRD
- Następny artykuł (7): Modelowanie zakresu 1, 2, 3 – standardy rachunkowości Protokół GHG, standard SBTi Net-Zero, narzędzia do modelowania
- Powiązane w serii MLOps: Zoptymalizuj szkolenie ML, aby zmniejszyć emisję dwutlenku węgla ślad — kwantyzacja, przycinanie, wybór sprzętu
- Powiązane z serią Data & AI Business: Centrum danych i zrównoważony rozwój — PUE, WUE, zamówienia na energię odnawialną dla MŚP
Zasoby i referencje
- Kepler na GitHubie — oparty na Kubernetes eksporter efektywnego poziomu mocy
- Operator KEDA świadomy emisji dwutlenku węgla — Azure/Microsoft
- Carbon Aware SDK — Green Software Foundation (licencja MIT)
- Projekt Kepler — piaskownica CNCF
- Cloud Carbon Footprint — narzędzie typu open source obsługujące wiele chmur
- GreenOps i FinOps: podwójna strategia na rzecz zrównoważonej sztucznej inteligencji — nowy stos
- Green Software Foundation — specyfikacja i zasoby SCI







