-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: add initial struct for HPA * chore: add default min replica * chore: add hpa to main nimble Object * chore: remove replicas field from manifest reason behind is that when using with HPA it is ideal that we don't define replicas * docs: add example for hpa usecase * feat: add controller for hpa * chore: add requests field for hpa usecase * chore: update mods * feat: add hpa controller to main * chore: update crd
- Loading branch information
Showing
13 changed files
with
310 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
apiVersion: ivaltryek.github.com/v1 | ||
kind: Nimble | ||
metadata: | ||
name: demo-deployment-service-hpa | ||
namespace: test | ||
spec: | ||
deployment: | ||
containers: | ||
- image: nginx:stable | ||
name: nginx-stable | ||
requests: | ||
cpu: 50m | ||
labels: | ||
test: hpa | ||
service: | ||
ports: | ||
- name: http | ||
port: 80 | ||
targetPort: 80 | ||
hpa: | ||
min: 2 | ||
max: 4 | ||
resourcePolicy: | ||
name: cpu | ||
type: Utilization | ||
avgUtil: 30 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
use std::sync::{ | ||
atomic::{AtomicBool, Ordering}, | ||
Arc, | ||
}; | ||
|
||
use k8s_openapi::api::autoscaling::v2::{ | ||
CrossVersionObjectReference, HorizontalPodAutoscaler, HorizontalPodAutoscalerSpec, | ||
}; | ||
use kube::{ | ||
api::{ObjectMeta, Patch, PatchParams}, | ||
runtime::{controller::Action, watcher::Config, Controller}, | ||
Api, Resource, | ||
}; | ||
use tracing::{error, info}; | ||
|
||
use crate::{ | ||
common::client::{error_policy, ContextData, Error}, | ||
crds::nimble::Nimble, | ||
transformers::hpa::transform_metrics, | ||
}; | ||
|
||
use futures::StreamExt; | ||
use tokio::time::Duration; | ||
|
||
static DOES_HPA_EXIST: AtomicBool = AtomicBool::new(false); | ||
|
||
/** | ||
* Reconciles the HPA of a Nimble instance. | ||
* | ||
* This function orchestrates the deployment of a Nimble instance based on the provided context data. | ||
* It creates or updates a Kubernetes Deployment object with the specified configuration. | ||
* | ||
* # Arguments | ||
* - `nimble`: An Arc reference to the Nimble instance to reconcile. | ||
* - `ctx`: An Arc reference to the context data needed for reconciliation. | ||
* | ||
* # Returns | ||
* An Ok(Action) containing the requeue action with a specified duration on successful reconciliation, | ||
* or an Err(Error) if the reconciliation process encounters any errors. | ||
* | ||
* # Errors | ||
* - Returns an Error::MissingObjectKey if required object keys are missing. | ||
* - Returns an Error::NimbleObjectCreationFailed if the creation or update of the Nimble object fails. | ||
*/ | ||
pub async fn reconcile(nimble: Arc<Nimble>, ctx: Arc<ContextData>) -> Result<Action, Error> { | ||
match nimble.spec.hpa.clone() { | ||
Some(hpa_spec) => { | ||
let client = &ctx.client; | ||
|
||
let oref = nimble.controller_owner_ref(&()).unwrap(); | ||
|
||
let hpa: HorizontalPodAutoscaler = HorizontalPodAutoscaler { | ||
metadata: ObjectMeta { | ||
annotations: hpa_spec.annotations.clone(), | ||
owner_references: Some(vec![oref]), | ||
name: nimble.metadata.name.clone(), | ||
..ObjectMeta::default() | ||
}, | ||
spec: Some(HorizontalPodAutoscalerSpec { | ||
max_replicas: hpa_spec.max, | ||
min_replicas: hpa_spec.min, | ||
scale_target_ref: CrossVersionObjectReference { | ||
api_version: Some("apps/v1".to_owned()), | ||
kind: "Deployment".to_owned(), | ||
name: nimble.metadata.name.clone().unwrap(), | ||
}, | ||
metrics: transform_metrics(nimble.spec.hpa.clone()), | ||
..HorizontalPodAutoscalerSpec::default() | ||
}), | ||
..HorizontalPodAutoscaler::default() | ||
}; | ||
|
||
let hpa_api = Api::<HorizontalPodAutoscaler>::namespaced( | ||
client.clone(), | ||
nimble | ||
.metadata | ||
.namespace | ||
.as_ref() | ||
.ok_or_else(|| Error::MissingObjectKey(".metadata.namespace"))?, | ||
); | ||
|
||
hpa_api | ||
.patch( | ||
hpa.metadata | ||
.name | ||
.as_ref() | ||
.ok_or_else(|| Error::MissingObjectKey(".metadata.name"))?, | ||
&PatchParams::apply("nimble.ivaltryek.github.com"), | ||
&Patch::Apply(&hpa), | ||
) | ||
.await | ||
.map_err(Error::NimbleObjectCreationFailed)?; | ||
|
||
DOES_HPA_EXIST.store(true, Ordering::Relaxed); | ||
|
||
Ok(Action::requeue(Duration::from_secs(30))) | ||
} | ||
_ => { | ||
DOES_HPA_EXIST.store(false, Ordering::Relaxed); | ||
Ok(Action::await_change()) | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Starts the main loop for the Nimble HPA controller. | ||
* | ||
* This function initiates the main event loop for the Nimble controller, responsible for monitoring and reconciling Nimble resources in the Kubernetes cluster. | ||
* | ||
* Args: | ||
* - crd_api (Api<Nimble>): Reference to the Kubernetes API client for Nimble resources. | ||
* - context (Arc<ContextData>): Reference-counted handle to the controller context data. | ||
* | ||
* Returns: | ||
* - Future: Represents the completion of the controller loop. | ||
* | ||
* Process: | ||
* 1. Creates a new controller instance using the provided API client and default configuration. | ||
* 2. Configures the controller to shut down gracefully on receiving specific signals. | ||
* 3. Starts the controller loop, running the `reconcile` function for each Nimble resource change it detects. | ||
* 4. Within the loop, handles reconciliation results: | ||
* - On success: logs a message with resource information. | ||
* - On error: logs an error message with details. | ||
* 5. Waits for the loop to complete. | ||
*/ | ||
pub async fn run_hpa_controller(crd_api: Api<Nimble>, context: Arc<ContextData>) { | ||
Controller::new(crd_api.clone(), Config::default()) | ||
.shutdown_on_signal() | ||
.run(reconcile, error_policy, context) | ||
.for_each(|reconcilation_result| async move { | ||
match reconcilation_result { | ||
Ok((nimble_resource, _)) => { | ||
// Log the reconciliation message only if service field exist in object manifest. | ||
if DOES_HPA_EXIST.load(Ordering::Relaxed) { | ||
info!(msg = "HPA reconciliation successful.", | ||
resource_name = ?nimble_resource.name, | ||
namespace = ?nimble_resource.namespace.unwrap(), | ||
); | ||
} | ||
} | ||
Err(reconciliation_err) => { | ||
error!("Service reconciliation error: {:?}", reconciliation_err) | ||
} | ||
} | ||
}) | ||
.await; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
pub mod dpcontroller; | ||
pub mod hpacontroller; | ||
pub mod servicecontroller; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use std::collections::BTreeMap; | ||
|
||
use schemars::JsonSchema; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use super::deploymentspec::default_annotations; | ||
|
||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, JsonSchema)] | ||
pub struct HPASpec { | ||
#[doc = "Annotations to be applied to the HPA object"] | ||
#[serde(default = "default_hpa_annotations")] | ||
pub annotations: Option<BTreeMap<String, String>>, | ||
#[doc = "maxReplicas is the upper limit for the number of replicas to which the autoscaler can scale up. | ||
It cannot be less that minReplicas."] | ||
pub max: i32, | ||
#[doc = "minReplicas is the lower limit for the number of replicas to which the autoscaler can scale down. | ||
It defaults to 1 pod. | ||
minReplicas is allowed to be 0 if the alpha feature gate HPAScaleToZero is enabled and at least one Object or External metric is configured. | ||
Scaling is active as long as at least one metric value is available."] | ||
#[serde(default = "default_min_replicas")] | ||
pub min: Option<i32>, | ||
#[doc = "resource refers to a resource metric (such as those specified in requests and limits) | ||
known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory)."] | ||
#[serde(rename = "resourcePolicy")] | ||
pub resource_policy: Option<ResourceMetricSpec>, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, JsonSchema)] | ||
pub struct ResourceMetricSpec { | ||
#[doc = "name is the name of the resource in question."] | ||
pub name: String, | ||
#[doc = "type represents whether the metric type is Utilization, Value, or AverageValue"] | ||
#[serde(rename = "type")] | ||
pub type_: String, | ||
#[doc = "avgUtil is the target value of the average of the resource metric across all relevant pods, | ||
represented as a percentage of the requested value of the resource for the pods. | ||
Currently only valid for Resource metric source type"] | ||
#[serde(rename = "avgUtil")] | ||
pub average_utilization: Option<i32>, | ||
} | ||
|
||
// Return default annotations to applied to an object. | ||
fn default_hpa_annotations() -> Option<BTreeMap<String, String>> { | ||
default_annotations() | ||
} | ||
|
||
// Return default min replica value. | ||
fn default_min_replicas() -> Option<i32> { | ||
Some(1) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
pub mod deploymentspec; | ||
pub mod hpaspec; | ||
pub mod nimble; | ||
pub mod servicespec; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.