The Vertical Pod Autoscaler (VPA) is a Kubernetes component that automatically adjusts the CPU and memory requests and limits for pods based on historical usage data. For memory-intensive Java applications, VPA provides crucial optimization to prevent resource waste and OutOfMemory errors.
Understanding Vertical Pod Autoscaler
VPA automatically rightsizes pod resources by:
- Recommending optimal CPU and memory requests/limits
- Automatically updating pod specifications (in auto mode)
- Preventing OOMKills by ensuring sufficient memory allocation
- Reducing resource waste by eliminating overallocation
VPA Components and Modes
- Recommender: Analyzes historical usage and suggests resources
- Updater: Evicts pods that need resource changes
- Admission Controller: Modifies pod resources during creation
- Modes:
Auto: Automatically apply recommendationsInitial: Only apply at pod creationRecreate: Similar to Auto but only for recreate controllersOff: Only provide recommendations
Implementing VPA Management in Java
1. Project Dependencies
Maven Dependencies:
<dependencies> <dependency> <groupId>io.fabric8</groupId> <artifactId>kubernetes-client</artifactId> <version>6.8.1</version> </dependency> <dependency> <groupId>io.fabric8</groupId> <artifactId>kubernetes-model</artifactId> <version>6.8.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>io.github.cdimascio</groupId> <artifactId>java-dotenv</artifactId> <version>5.2.2</version> </dependency> </dependencies>
2. VPA CRD Model Classes
// VerticalPodAutoscaler.java
public class VerticalPodAutoscaler {
private String metadata;
private VpaSpec spec;
private VpaStatus status;
// Constructors, getters, setters
public VerticalPodAutoscaler() {}
public VerticalPodAutoscaler(String name, String namespace, VpaSpec spec) {
this.metadata = String.format("""
{
"name": "%s",
"namespace": "%s"
}
""", name, namespace);
this.spec = spec;
}
// Getters and setters
public String getMetadata() { return metadata; }
public void setMetadata(String metadata) { this.metadata = metadata; }
public VpaSpec getSpec() { return spec; }
public void setSpec(VpaSpec spec) { this.spec = spec; }
public VpaStatus getStatus() { return status; }
public void setStatus(VpaStatus status) { this.status = status; }
}
// VpaSpec.java
public class VpaSpec {
private VpaTargetRef targetRef;
private VpaUpdatePolicy updatePolicy;
private VpaResourcePolicy resourcePolicy;
private List<VpaRecommender> recommenders;
public VpaSpec() {}
public VpaSpec(VpaTargetRef targetRef, VpaUpdatePolicy updatePolicy) {
this.targetRef = targetRef;
this.updatePolicy = updatePolicy;
}
// Getters and setters
public VpaTargetRef getTargetRef() { return targetRef; }
public void setTargetRef(VpaTargetRef targetRef) { this.targetRef = targetRef; }
public VpaUpdatePolicy getUpdatePolicy() { return updatePolicy; }
public void setUpdatePolicy(VpaUpdatePolicy updatePolicy) { this.updatePolicy = updatePolicy; }
public VpaResourcePolicy getResourcePolicy() { return resourcePolicy; }
public void setResourcePolicy(VpaResourcePolicy resourcePolicy) { this.resourcePolicy = resourcePolicy; }
public List<VpaRecommender> getRecommenders() { return recommenders; }
public void setRecommenders(List<VpaRecommender> recommenders) { this.recommenders = recommenders; }
}
// VpaTargetRef.java
public class VpaTargetRef {
private String apiVersion;
private String kind;
private String name;
public VpaTargetRef() {}
public VpaTargetRef(String kind, String name) {
this.apiVersion = "apps/v1";
this.kind = kind;
this.name = name;
}
// Getters and setters
public String getApiVersion() { return apiVersion; }
public void setApiVersion(String apiVersion) { this.apiVersion = apiVersion; }
public String getKind() { return kind; }
public void setKind(String kind) { this.kind = kind; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
// VpaUpdatePolicy.java
public class VpaUpdatePolicy {
private String updateMode;
public VpaUpdatePolicy() {}
public VpaUpdatePolicy(String updateMode) {
this.updateMode = updateMode;
}
// Getters and setters
public String getUpdateMode() { return updateMode; }
public void setUpdateMode(String updateMode) { this.updateMode = updateMode; }
}
// VpaStatus.java
public class VpaStatus {
private List<VpaRecommendation> recommendations;
private List<VpaCondition> conditions;
// Getters and setters
public List<VpaRecommendation> getRecommendations() { return recommendations; }
public void setRecommendations(List<VpaRecommendation> recommendations) { this.recommendations = recommendations; }
public List<VpaCondition> getConditions() { return conditions; }
public void setConditions(List<VpaCondition> conditions) { this.conditions = conditions; }
}
// VpaRecommendation.java
public class VpaRecommendation {
private Map<String, String> containerRecommendations;
// Getters and setters
public Map<String, String> getContainerRecommendations() { return containerRecommendations; }
public void setContainerRecommendations(Map<String, String> containerRecommendations) { this.containerRecommendations = containerRecommendations; }
}
3. VPA Manager Service
// VpaManagerService.java
@Service
@Slf4j
public class VpaManagerService {
private final KubernetesClient kubernetesClient;
public VpaManagerService(KubernetesClient kubernetesClient) {
this.kubernetesClient = kubernetesClient;
}
public void createVPA(String namespace, String vpaName, String targetDeployment,
String updateMode, VpaResourcePolicy resourcePolicy) {
try {
String vpaManifest = buildVPAManifest(namespace, vpaName, targetDeployment, updateMode, resourcePolicy);
kubernetesClient.genericKubernetesResources(
"autoscaling.k8s.io/v1",
"VerticalPodAutoscaler"
).inNamespace(namespace).createOrReplace(
kubernetesClient.getKubernetesSerialization().unmarshal(vpaManifest)
);
log.info("Created VPA '{}' for deployment '{}' in namespace '{}' with mode '{}'",
vpaName, targetDeployment, namespace, updateMode);
} catch (Exception e) {
log.error("Failed to create VPA: {}", e.getMessage(), e);
throw new VpaOperationException("VPA creation failed", e);
}
}
private String buildVPAManifest(String namespace, String vpaName, String targetDeployment,
String updateMode, VpaResourcePolicy resourcePolicy) {
return String.format("""
{
"apiVersion": "autoscaling.k8s.io/v1",
"kind": "VerticalPodAutoscaler",
"metadata": {
"name": "%s",
"namespace": "%s"
},
"spec": {
"targetRef": {
"apiVersion": "apps/v1",
"kind": "Deployment",
"name": "%s"
},
"updatePolicy": {
"updateMode": "%s"
},
"resourcePolicy": {
"containerPolicies": [
{
"containerName": "*",
"minAllowed": {
"cpu": "%s",
"memory": "%s"
},
"maxAllowed": {
"cpu": "%s",
"memory": "%s"
},
"controlledResources": ["cpu", "memory"]
}
]
}
}
}
""", vpaName, namespace, targetDeployment, updateMode,
resourcePolicy.getMinCpu(), resourcePolicy.getMinMemory(),
resourcePolicy.getMaxCpu(), resourcePolicy.getMaxMemory());
}
public VpaStatus getVPAStatus(String namespace, String vpaName) {
try {
var vpa = kubernetesClient.genericKubernetesResources(
"autoscaling.k8s.io/v1",
"VerticalPodAutoscaler"
).inNamespace(namespace).withName(vpaName).get();
if (vpa == null) {
throw new VpaNotFoundException("VPA not found: " + vpaName);
}
return extractVpaStatus(vpa);
} catch (Exception e) {
log.error("Failed to get VPA status: {}", e.getMessage(), e);
throw new VpaOperationException("Failed to retrieve VPA status", e);
}
}
public void updateVPAMode(String namespace, String vpaName, String newUpdateMode) {
try {
var vpa = kubernetesClient.genericKubernetesResources(
"autoscaling.k8s.io/v1",
"VerticalPodAutoscaler"
).inNamespace(namespace).withName(vpaName).get();
if (vpa != null) {
var updatedVpa = kubernetesClient.resource(vpa).edit(v -> {
v.get("spec").get("updatePolicy").put("updateMode", newUpdateMode);
return v;
});
log.info("Updated VPA '{}' to mode '{}'", vpaName, newUpdateMode);
}
} catch (Exception e) {
log.error("Failed to update VPA mode: {}", e.getMessage(), e);
throw new VpaOperationException("VPA mode update failed", e);
}
}
public void deleteVPA(String namespace, String vpaName) {
try {
boolean deleted = kubernetesClient.genericKubernetesResources(
"autoscaling.k8s.io/v1",
"VerticalPodAutoscaler"
).inNamespace(namespace).withName(vpaName).delete();
if (deleted) {
log.info("Deleted VPA '{}' from namespace '{}'", vpaName, namespace);
}
} catch (Exception e) {
log.error("Failed to delete VPA: {}", e.getMessage(), e);
throw new VpaOperationException("VPA deletion failed", e);
}
}
public List<VpaRecommendation> getVPARecommendations(String namespace, String vpaName) {
VpaStatus status = getVPAStatus(namespace, vpaName);
return status.getRecommendations() != null ? status.getRecommendations() : List.of();
}
private VpaStatus extractVpaStatus(GenericKubernetesResource vpa) {
VpaStatus status = new VpaStatus();
// Extract recommendations from VPA status
if (vpa.get("status") != null) {
var recommendations = new ArrayList<VpaRecommendation>();
// Parse recommendation data from VPA status
// This is a simplified implementation
status.setRecommendations(recommendations);
}
return status;
}
}
4. Java Application Resource Analyzer
// JavaResourceAnalyzer.java
@Service
@Slf4j
public class JavaResourceAnalyzer {
private final KubernetesClient kubernetesClient;
private final VpaManagerService vpaManager;
public JavaResourceAnalyzer(KubernetesClient kubernetesClient, VpaManagerService vpaManager) {
this.kubernetesClient = kubernetesClient;
this.vpaManager = vpaManager;
}
public JavaAppResourceAnalysis analyzeJavaApplication(String namespace, String deploymentName) {
try {
Deployment deployment = kubernetesClient.apps().deployments()
.inNamespace(namespace)
.withName(deploymentName)
.get();
if (deployment == null) {
throw new DeploymentNotFoundException("Deployment not found: " + deploymentName);
}
return analyzeDeploymentResources(deployment);
} catch (Exception e) {
log.error("Failed to analyze Java application: {}", e.getMessage(), e);
throw new ResourceAnalysisException("Resource analysis failed", e);
}
}
private JavaAppResourceAnalysis analyzeDeploymentResources(Deployment deployment) {
JavaAppResourceAnalysis analysis = new JavaAppResourceAnalysis();
analysis.setDeploymentName(deployment.getMetadata().getName());
analysis.setNamespace(deployment.getMetadata().getNamespace());
List<Container> containers = deployment.getSpec().getTemplate().getSpec().getContainers();
List<ContainerAnalysis> containerAnalyses = new ArrayList<>();
for (Container container : containers) {
ContainerAnalysis containerAnalysis = analyzeContainer(container);
containerAnalyses.add(containerAnalysis);
}
analysis.setContainers(containerAnalyses);
analysis.setRecommendations(generateRecommendations(containerAnalyses));
return analysis;
}
private ContainerAnalysis analyzeContainer(Container container) {
ContainerAnalysis analysis = new ContainerAnalysis();
analysis.setContainerName(container.getName());
// Analyze resource requests
if (container.getResources() != null && container.getResources().getRequests() != null) {
analysis.setCurrentCpuRequest(container.getResources().getRequests().get("cpu"));
analysis.setCurrentMemoryRequest(container.getResources().getRequests().get("memory"));
}
// Analyze resource limits
if (container.getResources() != null && container.getResources().getLimits() != null) {
analysis.setCurrentCpuLimit(container.getResources().getLimits().get("cpu"));
analysis.setCurrentMemoryLimit(container.getResources().getLimits().get("memory"));
}
// Check for common Java issues
analysis.setIssues(identifyResourceIssues(container));
return analysis;
}
private List<String> identifyResourceIssues(Container container) {
List<String> issues = new ArrayList<>();
// Check for missing memory limits (critical for Java apps)
if (container.getResources() == null ||
container.getResources().getLimits() == null ||
container.getResources().getLimits().get("memory") == null) {
issues.add("Missing memory limits - risk of OOMKill");
}
// Check for unreasonable memory ratios
if (container.getResources() != null &&
container.getResources().getRequests() != null &&
container.getResources().getLimits() != null) {
String memoryRequest = container.getResources().getRequests().get("memory");
String memoryLimit = container.getResources().getLimits().get("memory");
if (memoryRequest != null && memoryLimit != null) {
double requestMB = parseMemoryToMB(memoryRequest);
double limitMB = parseMemoryToMB(memoryLimit);
if (limitMB / requestMB > 4) {
issues.add("Memory limit is more than 4x request - may cause resource contention");
}
}
}
// Check JVM heap settings vs container memory
List<String> envVars = container.getEnv().stream()
.map(env -> env.getName() + "=" + env.getValue())
.collect(Collectors.toList());
if (envVars.stream().anyMatch(env -> env.contains("Xmx"))) {
issues.add("Explicit Xmx setting detected - ensure alignment with container memory limits");
}
return issues;
}
private List<String> generateRecommendations(List<ContainerAnalysis> containers) {
List<String> recommendations = new ArrayList<>();
for (ContainerAnalysis container : containers) {
if (container.getIssues().contains("Missing memory limits")) {
recommendations.add(String.format(
"Set memory limits for container '%s' to prevent OOMKills",
container.getContainerName()));
}
if (container.getCurrentMemoryRequest() == null) {
recommendations.add(String.format(
"Set memory requests for container '%s' for better scheduling",
container.getContainerName()));
}
}
recommendations.add("Consider enabling VPA for automatic resource optimization");
recommendations.add("Monitor application for 24-48 hours before enabling VPA Auto mode");
return recommendations;
}
private double parseMemoryToMB(String memory) {
if (memory.endsWith("Gi")) {
return Double.parseDouble(memory.replace("Gi", "")) * 1024;
} else if (memory.endsWith("Mi")) {
return Double.parseDouble(memory.replace("Mi", ""));
} else if (memory.endsWith("G")) {
return Double.parseDouble(memory.replace("G", "")) * 1000; // Approximation
} else if (memory.endsWith("M")) {
return Double.parseDouble(memory.replace("M", ""));
}
return 0;
}
}
5. VPA Recommendation Engine
// VpaRecommendationEngine.java
@Service
@Slf4j
public class VpaRecommendationEngine {
private final KubernetesClient kubernetesClient;
private final MetricsService metricsService;
public VpaRecommendationEngine(KubernetesClient kubernetesClient, MetricsService metricsService) {
this.kubernetesClient = kubernetesClient;
this.metricsService = metricsService;
}
public VpaRecommendationResult generateCustomRecommendations(String namespace, String deploymentName) {
try {
// Get historical metrics
Map<String, Double> cpuUsage = metricsService.getCpuUsage(deploymentName, namespace, "7d");
Map<String, Double> memoryUsage = metricsService.getMemoryUsage(deploymentName, namespace, "7d");
// Analyze usage patterns
ResourceProfile cpuProfile = analyzeResourceUsage(cpuUsage, "cpu");
ResourceProfile memoryProfile = analyzeResourceUsage(memoryUsage, "memory");
// Generate recommendations
return buildRecommendationResult(deploymentName, cpuProfile, memoryProfile);
} catch (Exception e) {
log.error("Failed to generate VPA recommendations: {}", e.getMessage(), e);
throw new RecommendationException("Recommendation generation failed", e);
}
}
private ResourceProfile analyzeResourceUsage(Map<String, Double> usageData, String resourceType) {
if (usageData.isEmpty()) {
return new ResourceProfile(0, 0, 0, 0);
}
List<Double> values = new ArrayList<>(usageData.values());
Collections.sort(values);
double p50 = values.get((int) (values.size() * 0.5));
double p95 = values.get((int) (values.size() * 0.95));
double p99 = values.get((int) (values.size() * 0.99));
double max = values.get(values.size() - 1);
// Add safety buffer based on resource type
double safetyBuffer = resourceType.equals("memory") ? 1.3 : 1.2; // Higher buffer for memory
return new ResourceProfile(p50, p95 * safetyBuffer, p99 * safetyBuffer, max * safetyBuffer);
}
private VpaRecommendationResult buildRecommendationResult(String deploymentName,
ResourceProfile cpuProfile,
ResourceProfile memoryProfile) {
VpaRecommendationResult result = new VpaRecommendationResult();
result.setDeploymentName(deploymentName);
result.setGeneratedAt(Instant.now());
// CPU recommendations (in millicores)
String cpuRequest = String.format("%dm", (int) (cpuProfile.getP95() * 1000));
String cpuLimit = String.format("%dm", (int) (cpuProfile.getMax() * 1000));
// Memory recommendations (in MiB)
String memoryRequest = String.format("%dMi", (int) memoryProfile.getP95());
String memoryLimit = String.format("%dMi", (int) memoryProfile.getMax());
result.setRecommendedCpuRequest(cpuRequest);
result.setRecommendedCpuLimit(cpuLimit);
result.setRecommendedMemoryRequest(memoryRequest);
result.setRecommendedMemoryLimit(memoryLimit);
result.setConfidenceScore(calculateConfidence(cpuProfile, memoryProfile));
result.setRecommendationReason(buildRecommendationReason(cpuProfile, memoryProfile));
return result;
}
private double calculateConfidence(ResourceProfile cpu, ResourceProfile memory) {
// Simple confidence calculation based on data spread
double cpuConfidence = 1.0 - (cpu.getMax() - cpu.getP50()) / Math.max(cpu.getMax(), 1.0);
double memoryConfidence = 1.0 - (memory.getMax() - memory.getP50()) / Math.max(memory.getMax(), 1.0);
return (cpuConfidence + memoryConfidence) / 2.0;
}
private String buildRecommendationReason(ResourceProfile cpu, ResourceProfile memory) {
return String.format(
"Based on historical usage: CPU P95=%.2f cores, Max=%.2f cores; Memory P95=%.1f MiB, Max=%.1f MiB",
cpu.getP95(), cpu.getMax(), memory.getP95(), memory.getMax()
);
}
}
6. REST API for VPA Management
// VpaController.java
@RestController
@RequestMapping("/api/v1/vpa")
@Slf4j
public class VpaController {
private final VpaManagerService vpaManager;
private final JavaResourceAnalyzer resourceAnalyzer;
private final VpaRecommendationEngine recommendationEngine;
public VpaController(VpaManagerService vpaManager,
JavaResourceAnalyzer resourceAnalyzer,
VpaRecommendationEngine recommendationEngine) {
this.vpaManager = vpaManager;
this.resourceAnalyzer = resourceAnalyzer;
this.recommendationEngine = recommendationEngine;
}
@PostMapping("/create")
public ResponseEntity<VpaCreationResponse> createVPA(@RequestBody VpaCreationRequest request) {
try {
vpaManager.createVPA(
request.getNamespace(),
request.getVpaName(),
request.getTargetDeployment(),
request.getUpdateMode(),
request.getResourcePolicy()
);
VpaCreationResponse response = new VpaCreationResponse(
true,
"VPA created successfully",
request.getVpaName(),
request.getNamespace()
);
return ResponseEntity.ok(response);
} catch (Exception e) {
log.error("VPA creation failed: {}", e.getMessage());
return ResponseEntity.badRequest().body(
new VpaCreationResponse(false, e.getMessage(), null, null)
);
}
}
@GetMapping("/status/{namespace}/{vpaName}")
public ResponseEntity<VpaStatusResponse> getVPAStatus(
@PathVariable String namespace,
@PathVariable String vpaName) {
try {
VpaStatus status = vpaManager.getVPAStatus(namespace, vpaName);
List<VpaRecommendation> recommendations = vpaManager.getVPARecommendations(namespace, vpaName);
VpaStatusResponse response = new VpaStatusResponse(
vpaName,
namespace,
status,
recommendations
);
return ResponseEntity.ok(response);
} catch (VpaNotFoundException e) {
return ResponseEntity.notFound().build();
} catch (Exception e) {
return ResponseEntity.internalServerError().build();
}
}
@PostMapping("/analyze/{namespace}/{deployment}")
public ResponseEntity<JavaAppResourceAnalysis> analyzeApplication(
@PathVariable String namespace,
@PathVariable String deployment) {
try {
JavaAppResourceAnalysis analysis = resourceAnalyzer.analyzeJavaApplication(namespace, deployment);
return ResponseEntity.ok(analysis);
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
@GetMapping("/recommendations/{namespace}/{deployment}")
public ResponseEntity<VpaRecommendationResult> getCustomRecommendations(
@PathVariable String namespace,
@PathVariable String deployment) {
try {
VpaRecommendationResult recommendations =
recommendationEngine.generateCustomRecommendations(namespace, deployment);
return ResponseEntity.ok(recommendations);
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
@PatchMapping("/mode/{namespace}/{vpaName}")
public ResponseEntity<String> updateVPAMode(
@PathVariable String namespace,
@PathVariable String vpaName,
@RequestParam String mode) {
try {
vpaManager.updateVPAMode(namespace, vpaName, mode);
return ResponseEntity.ok("VPA mode updated successfully");
} catch (Exception e) {
return ResponseEntity.badRequest().body("Failed to update VPA mode: " + e.getMessage());
}
}
@DeleteMapping("/{namespace}/{vpaName}")
public ResponseEntity<String> deleteVPA(
@PathVariable String namespace,
@PathVariable String vpaName) {
try {
vpaManager.deleteVPA(namespace, vpaName);
return ResponseEntity.ok("VPA deleted successfully");
} catch (Exception e) {
return ResponseEntity.badRequest().body("Failed to delete VPA: " + e.getMessage());
}
}
}
// DTO Classes
class VpaCreationRequest {
private String namespace;
private String vpaName;
private String targetDeployment;
private String updateMode; // "Auto", "Initial", "Recreate", "Off"
private VpaResourcePolicy resourcePolicy;
// Constructors, getters, setters
}
class VpaResourcePolicy {
private String minCpu = "100m";
private String minMemory = "128Mi";
private String maxCpu = "2";
private String maxMemory = "8Gi";
// Constructors, getters, setters
}
class VpaCreationResponse {
private boolean success;
private String message;
private String vpaName;
private String namespace;
// Constructors, getters, setters
}
class VpaStatusResponse {
private String vpaName;
private String namespace;
private VpaStatus status;
private List<VpaRecommendation> recommendations;
// Constructors, getters, setters
}
class JavaAppResourceAnalysis {
private String deploymentName;
private String namespace;
private List<ContainerAnalysis> containers;
private List<String> recommendations;
private List<String> issues;
// Constructors, getters, setters
}
class ContainerAnalysis {
private String containerName;
private String currentCpuRequest;
private String currentMemoryRequest;
private String currentCpuLimit;
private String currentMemoryLimit;
private List<String> issues;
// Constructors, getters, setters
}
class VpaRecommendationResult {
private String deploymentName;
private String recommendedCpuRequest;
private String recommendedCpuLimit;
private String recommendedMemoryRequest;
private String recommendedMemoryLimit;
private double confidenceScore;
private String recommendationReason;
private Instant generatedAt;
// Constructors, getters, setters
}
class ResourceProfile {
private double p50;
private double p95;
private double p99;
private double max;
// Constructors, getters, setters
}
Best Practices for VPA with Java Applications
- Start with Initial Mode: Begin with
updateMode: Initialto test recommendations - Set Resource Boundaries: Always define minAllowed and maxAllowed to prevent extreme recommendations
- Monitor JVM Metrics: Combine VPA with JVM metrics for optimal memory settings
- Gradual Transition: Use Recreate mode for applications that can tolerate restarts
- Avoid HPA+VPA Conflict: Don't use VPA and HPA on CPU simultaneously
# Example VPA configuration for Java application apiVersion: autoscaling.k8s.io/v1 kind: VerticalPodAutoscaler metadata: name: java-app-vpa spec: targetRef: apiVersion: "apps/v1" kind: Deployment name: java-application updatePolicy: updateMode: "Recreate" # Use "Initial" for testing resourcePolicy: containerPolicies: - containerName: "*" minAllowed: cpu: "100m" memory: "256Mi" maxAllowed: cpu: "2" memory: "8Gi" controlledResources: ["cpu", "memory"]
Vertical Pod Autoscaling is particularly valuable for Java applications where memory usage patterns can be complex and JVM heap settings need careful tuning. By implementing VPA management in Java, you can create intelligent systems that automatically optimize resource allocation, reduce costs, and improve application stability in Kubernetes environments.