Add autoscaler for applications (#525)

- Transition to min/max instances instead of total instances
This commit is contained in:
Erèbe - Romain Gerard
2021-12-14 16:39:06 +01:00
committed by GitHub
parent 52b8fd5549
commit 739e3d12e9
33 changed files with 224 additions and 73 deletions

View File

@@ -118,7 +118,8 @@ let app = Application {
total_cpus: "1".to_string(),
cpu_burst: "1.5".to_string(),
total_ram_in_mib: 256,
total_instances: 1,
min_instances: 1,
max_instances: 4,
storage: vec![], // you can add persistent storage here
environment_variables: vec![], // you can include env var here
};

View File

@@ -13,10 +13,10 @@ metadata:
annotations:
releaseTime: {% raw %}{{ dateInZone "2006-01-02 15:04:05Z" (now) "UTC"| quote }}{% endraw %}
spec:
replicas: {{ total_instances }}
replicas: {{ min_instances }}
strategy:
type: RollingUpdate
{% if total_instances == 1 %}
{% if max_instances == 1 %}
rollingUpdate:
maxSurge: 1
{% endif %}

View File

@@ -0,0 +1,19 @@
{%- if not is_storage and min_instances != max_instances %}
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: {{ sanitized_name }}
namespace: {{ namespace }}
labels:
envId: {{ environment_id }}
appId: {{ id }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ sanitized_name }}
minReplicas: {{ min_instances }}
maxReplicas: {{ max_instances }}
targetCPUUtilizationPercentage: 60
{%- endif %}

View File

@@ -13,7 +13,7 @@ metadata:
annotations:
releaseTime: {% raw %}{{ dateInZone "2006-01-02 15:04:05Z" (now) "UTC"| quote }}{% endraw %}
spec:
replicas: {{ total_instances }}
replicas: {{ min_instances }}
serviceName: {{ sanitized_name }}
selector:
matchLabels:

View File

@@ -13,10 +13,10 @@ metadata:
annotations:
releaseTime: {% raw %}{{ dateInZone "2006-01-02 15:04:05Z" (now) "UTC"| quote }}{% endraw %}
spec:
replicas: {{ total_instances }}
replicas: {{ min_instances }}
strategy:
type: RollingUpdate
{% if total_instances == 1 %}
{% if max_instances == 1 %}
rollingUpdate:
maxSurge: 1
{% endif %}

View File

@@ -0,0 +1,19 @@
{%- if not is_storage and min_instances != max_instances %}
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: {{ sanitized_name }}
namespace: {{ namespace }}
labels:
envId: {{ environment_id }}
appId: {{ id }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ sanitized_name }}
minReplicas: {{ min_instances }}
maxReplicas: {{ max_instances }}
targetCPUUtilizationPercentage: 60
{%- endif %}

View File

@@ -13,7 +13,7 @@ metadata:
annotations:
releaseTime: {% raw %}{{ dateInZone "2006-01-02 15:04:05Z" (now) "UTC"| quote }}{% endraw %}
spec:
replicas: {{ total_instances }}
replicas: {{ min_instances }}
serviceName: {{ sanitized_name }}
selector:
matchLabels:

View File

@@ -13,10 +13,10 @@ metadata:
annotations:
releaseTime: {% raw %}{{ dateInZone "2006-01-02 15:04:05Z" (now) "UTC"| quote }}{% endraw %}
spec:
replicas: {{ total_instances }}
replicas: {{ min_instances }}
strategy:
type: RollingUpdate
{% if total_instances == 1 %}
{% if max_instances == 1 %}
rollingUpdate:
maxSurge: 1
{% endif %}

View File

@@ -0,0 +1,19 @@
{%- if not is_storage and min_instances != max_instances %}
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: {{ sanitized_name }}
namespace: {{ namespace }}
labels:
envId: {{ environment_id }}
appId: {{ id }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ sanitized_name }}
minReplicas: {{ min_instances }}
maxReplicas: {{ max_instances }}
targetCPUUtilizationPercentage: 60
{%- endif %}

View File

@@ -13,7 +13,7 @@ metadata:
annotations:
releaseTime: {% raw %}{{ dateInZone "2006-01-02 15:04:05Z" (now) "UTC"| quote }}{% endraw %}
spec:
replicas: {{ total_instances }}
replicas: {{ min_instances }}
serviceName: {{ sanitized_name }}
selector:
matchLabels:

View File

@@ -27,7 +27,8 @@ pub struct Application {
total_cpus: String,
cpu_burst: String,
total_ram_in_mib: u32,
total_instances: u16,
min_instances: u32,
max_instances: u32,
start_timeout_in_seconds: u32,
image: Image,
storage: Vec<Storage<StorageType>>,
@@ -45,7 +46,8 @@ impl Application {
total_cpus: String,
cpu_burst: String,
total_ram_in_mib: u32,
total_instances: u16,
min_instances: u32,
max_instances: u32,
start_timeout_in_seconds: u32,
image: Image,
storage: Vec<Storage<StorageType>>,
@@ -61,7 +63,8 @@ impl Application {
total_cpus,
cpu_burst,
total_ram_in_mib,
total_instances,
min_instances,
max_instances,
start_timeout_in_seconds,
image,
storage,
@@ -165,8 +168,12 @@ impl Service for Application {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
self.total_instances
fn min_instances(&self) -> u32 {
self.min_instances
}
fn max_instances(&self) -> u32 {
self.max_instances
}
fn publicly_accessible(&self) -> bool {

View File

@@ -141,7 +141,11 @@ impl Service for MongoDB {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -137,7 +137,11 @@ impl Service for MySQL {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -137,7 +137,11 @@ impl Service for PostgreSQL {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -140,7 +140,11 @@ impl Service for Redis {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -104,7 +104,11 @@ impl Service for Router {
1
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -29,7 +29,8 @@ pub struct Application {
total_cpus: String,
cpu_burst: String,
total_ram_in_mib: u32,
total_instances: u16,
min_instances: u32,
max_instances: u32,
start_timeout_in_seconds: u32,
image: Image,
storage: Vec<Storage<StorageType>>,
@@ -47,7 +48,8 @@ impl Application {
total_cpus: String,
cpu_burst: String,
total_ram_in_mib: u32,
total_instances: u16,
min_instances: u32,
max_instances: u32,
start_timeout_in_seconds: u32,
image: Image,
storage: Vec<Storage<StorageType>>,
@@ -63,7 +65,8 @@ impl Application {
total_cpus,
cpu_burst,
total_ram_in_mib,
total_instances,
min_instances,
max_instances,
start_timeout_in_seconds,
image,
storage,
@@ -167,8 +170,12 @@ impl Service for Application {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
self.total_instances
fn min_instances(&self) -> u32 {
self.min_instances
}
fn max_instances(&self) -> u32 {
self.max_instances
}
fn publicly_accessible(&self) -> bool {

View File

@@ -128,7 +128,11 @@ impl Service for MongoDB {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -128,7 +128,11 @@ impl Service for MySQL {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -128,7 +128,11 @@ impl Service for PostgreSQL {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -128,7 +128,11 @@ impl Service for Redis {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -104,7 +104,11 @@ impl Service for Router {
1
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -58,14 +58,14 @@ impl Environment {
pub fn required_resources(&self) -> EnvironmentResources {
let mut total_cpu_for_stateless_services: f32 = 0.0;
let mut total_ram_in_mib_for_stateless_services: u32 = 0;
let mut required_pods = self.stateless_services.len() as u16;
let mut required_pods = self.stateless_services.len() as u32;
for service in &self.stateless_services {
match *service.action() {
Action::Create | Action::Nothing => {
total_cpu_for_stateless_services += cpu_string_to_float(&service.total_cpus());
total_ram_in_mib_for_stateless_services += &service.total_ram_in_mib();
required_pods += service.total_instances();
required_pods += service.max_instances()
}
Action::Delete | Action::Pause => {}
}
@@ -83,7 +83,7 @@ impl Environment {
Action::Pause | Action::Delete => {
total_cpu_for_stateful_services += cpu_string_to_float(service.total_cpus());
total_ram_in_mib_for_stateful_services += service.total_ram_in_mib();
required_pods += service.total_instances();
required_pods += service.max_instances()
}
Action::Create | Action::Nothing => {}
}
@@ -98,7 +98,7 @@ impl Environment {
}
pub struct EnvironmentResources {
pub pods: u16,
pub pods: u32,
pub cpu: f32,
pub ram_in_mib: u32,
}

View File

@@ -106,14 +106,8 @@ pub trait Kubernetes: Listen {
resources.max_cpu += cpu_string_to_float(node.status.capacity.cpu);
resources.free_ram_in_mib += any_to_mi(node.status.allocatable.memory);
resources.max_ram_in_mib += any_to_mi(node.status.capacity.memory);
resources.free_pods = match node.status.allocatable.pods.parse::<u16>() {
Ok(v) => v,
_ => 0,
};
resources.max_pods = match node.status.capacity.pods.parse::<u16>() {
Ok(v) => v,
_ => 0,
};
resources.free_pods = node.status.allocatable.pods.parse::<u32>().unwrap_or(0);
resources.max_pods = node.status.capacity.pods.parse::<u32>().unwrap_or(0);
resources.running_nodes += 1;
}
@@ -224,9 +218,9 @@ pub struct Resources {
pub max_cpu: f32,
pub free_ram_in_mib: u32,
pub max_ram_in_mib: u32,
pub free_pods: u16,
pub max_pods: u16,
pub running_nodes: u16,
pub free_pods: u32,
pub max_pods: u32,
pub running_nodes: u32,
}
/// common function to deploy a complete environment through Kubernetes and the different

View File

@@ -30,7 +30,8 @@ pub struct Application {
total_cpus: String,
cpu_burst: String,
total_ram_in_mib: u32,
total_instances: u16,
min_instances: u32,
max_instances: u32,
start_timeout_in_seconds: u32,
image: Image,
storage: Vec<Storage<StorageType>>,
@@ -48,7 +49,8 @@ impl Application {
total_cpus: String,
cpu_burst: String,
total_ram_in_mib: u32,
total_instances: u16,
min_instances: u32,
max_instances: u32,
start_timeout_in_seconds: u32,
image: Image,
storage: Vec<Storage<StorageType>>,
@@ -64,7 +66,8 @@ impl Application {
total_cpus,
cpu_burst,
total_ram_in_mib,
total_instances,
min_instances,
max_instances,
start_timeout_in_seconds,
image,
storage,
@@ -168,8 +171,12 @@ impl Service for Application {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
self.total_instances
fn min_instances(&self) -> u32 {
self.min_instances
}
fn max_instances(&self) -> u32 {
self.max_instances
}
fn publicly_accessible(&self) -> bool {

View File

@@ -128,7 +128,11 @@ impl Service for MongoDB {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -159,7 +159,11 @@ impl Service for MySQL {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -168,7 +168,11 @@ impl Service for PostgreSQL {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -128,7 +128,11 @@ impl Service for Redis {
self.total_ram_in_mib
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -104,7 +104,11 @@ impl Service for Router {
1
}
fn total_instances(&self) -> u16 {
fn min_instances(&self) -> u32 {
1
}
fn max_instances(&self) -> u32 {
1
}

View File

@@ -52,7 +52,8 @@ pub trait Service {
fn total_cpus(&self) -> String;
fn cpu_burst(&self) -> String;
fn total_ram_in_mib(&self) -> u32;
fn total_instances(&self) -> u16;
fn min_instances(&self) -> u32;
fn max_instances(&self) -> u32;
fn publicly_accessible(&self) -> bool;
fn fqdn<'a>(&self, target: &DeploymentTarget, fqdn: &'a String, is_managed: bool) -> String {
match &self.publicly_accessible() {
@@ -301,7 +302,8 @@ pub fn default_tera_context(
context.insert("cluster_name", kubernetes.name());
context.insert("total_cpus", &service.total_cpus());
context.insert("total_ram_in_mib", &service.total_ram_in_mib());
context.insert("total_instances", &service.total_instances());
context.insert("min_instances", &service.min_instances());
context.insert("max_instances", &service.max_instances());
context.insert("is_private_port", &service.private_port().is_some());
if service.private_port().is_some() {

View File

@@ -201,7 +201,8 @@ pub struct Application {
pub total_cpus: String,
pub cpu_burst: String,
pub total_ram_in_mib: u32,
pub total_instances: u16,
pub min_instances: u32,
pub max_instances: u32,
pub start_timeout_in_seconds: u32,
pub storage: Vec<Storage>,
// Key is a String, Value is a base64 encoded String
@@ -229,7 +230,8 @@ impl Application {
self.total_cpus.clone(),
self.cpu_burst.clone(),
self.total_ram_in_mib,
self.total_instances,
self.min_instances,
self.max_instances,
self.start_timeout_in_seconds,
image.clone(),
self.storage.iter().map(|s| s.to_aws_storage()).collect::<Vec<_>>(),
@@ -246,7 +248,8 @@ impl Application {
self.total_cpus.clone(),
self.cpu_burst.clone(),
self.total_ram_in_mib,
self.total_instances,
self.min_instances,
self.max_instances,
self.start_timeout_in_seconds,
image.clone(),
self.storage.iter().map(|s| s.to_do_storage()).collect::<Vec<_>>(),
@@ -264,7 +267,8 @@ impl Application {
self.total_cpus.clone(),
self.cpu_burst.clone(),
self.total_ram_in_mib,
self.total_instances,
self.min_instances,
self.max_instances,
self.start_timeout_in_seconds,
image.clone(),
self.storage.iter().map(|s| s.to_scw_storage()).collect::<Vec<_>>(),
@@ -294,7 +298,8 @@ impl Application {
self.total_cpus.clone(),
self.cpu_burst.clone(),
self.total_ram_in_mib,
self.total_instances,
self.min_instances,
self.max_instances,
self.start_timeout_in_seconds,
image,
self.storage.iter().map(|s| s.to_aws_storage()).collect::<Vec<_>>(),
@@ -311,7 +316,8 @@ impl Application {
self.total_cpus.clone(),
self.cpu_burst.clone(),
self.total_ram_in_mib,
self.total_instances,
self.min_instances,
self.max_instances,
self.start_timeout_in_seconds,
image,
self.storage.iter().map(|s| s.to_do_storage()).collect::<Vec<_>>(),
@@ -329,7 +335,8 @@ impl Application {
self.total_cpus.clone(),
self.cpu_burst.clone(),
self.total_ram_in_mib,
self.total_instances,
self.min_instances,
self.max_instances,
self.start_timeout_in_seconds,
image,
self.storage.iter().map(|s| s.to_scw_storage()).collect::<Vec<_>>(),

View File

@@ -274,7 +274,8 @@ pub fn environment_3_apps_3_routers_3_databases(
}],
total_cpus: "100m".to_string(),
total_ram_in_mib: 256,
total_instances: 2,
min_instances: 2,
max_instances: 2,
cpu_burst: "100m".to_string(),
start_timeout_in_seconds: 60,
},
@@ -319,7 +320,8 @@ pub fn environment_3_apps_3_routers_3_databases(
}],
total_cpus: "100m".to_string(),
total_ram_in_mib: 256,
total_instances: 2,
min_instances: 2,
max_instances: 2,
cpu_burst: "100m".to_string(),
start_timeout_in_seconds: 60,
},
@@ -366,7 +368,8 @@ pub fn environment_3_apps_3_routers_3_databases(
}],
total_cpus: "100m".to_string(),
total_ram_in_mib: 256,
total_instances: 2,
min_instances: 2,
max_instances: 2,
cpu_burst: "100m".to_string(),
start_timeout_in_seconds: 60,
},
@@ -520,7 +523,8 @@ pub fn working_minimal_environment(context: &Context, organization_id: &str, tes
}],
total_cpus: "100m".to_string(),
total_ram_in_mib: 256,
total_instances: 2,
min_instances: 2,
max_instances: 2,
cpu_burst: "100m".to_string(),
start_timeout_in_seconds: 60,
}],
@@ -631,7 +635,8 @@ pub fn environnement_2_app_2_routers_1_psql(
}],
total_cpus: "100m".to_string(),
total_ram_in_mib: 256,
total_instances: 2,
min_instances: 2,
max_instances: 2,
cpu_burst: "100m".to_string(),
start_timeout_in_seconds: 60,
},
@@ -676,7 +681,8 @@ pub fn environnement_2_app_2_routers_1_psql(
}],
total_cpus: "100m".to_string(),
total_ram_in_mib: 256,
total_instances: 2,
min_instances: 2,
max_instances: 2,
cpu_burst: "100m".to_string(),
start_timeout_in_seconds: 60,
},
@@ -770,7 +776,8 @@ pub fn echo_app_environment(context: &Context, organization_id: &str, test_domai
}],
total_cpus: "100m".to_string(),
total_ram_in_mib: 256,
total_instances: 2,
min_instances: 2,
max_instances: 2,
cpu_burst: "100m".to_string(),
start_timeout_in_seconds: 60,
}],
@@ -829,7 +836,8 @@ pub fn environment_only_http_server(context: &Context, organization_id: &str) ->
}],
total_cpus: "100m".to_string(),
total_ram_in_mib: 256,
total_instances: 2,
min_instances: 2,
max_instances: 2,
cpu_burst: "100m".to_string(),
start_timeout_in_seconds: 60,
}],
@@ -877,7 +885,8 @@ pub fn environment_only_http_server_router(context: &Context, organization_id: &
}],
total_cpus: "100m".to_string(),
total_ram_in_mib: 256,
total_instances: 2,
min_instances: 2,
max_instances: 2,
cpu_burst: "100m".to_string(),
start_timeout_in_seconds: 60,
}],