EKS Cost Optimization: Dynamic Scaling with EventBridge & Lambda
Amazon EKS enables cost optimization by automating scaling down of clusters during off-peak hours using AWS Lambda and EventBridge, reducing EC2 expenses
- Central hub for event-driven architecture.
- Integrates various AWS services and custom applications.
- Captures events from AWS services, SaaS apps, and custom sources.
- Serverless computing service.
- Executes code in response to triggers.
- Supports multiple programming languages.
- Executes custom logic in response to events received from EventBridge.
- Managed Kubernetes service on AWS.
- Simplifies deployment, management, and scaling of containerized applications.
- Eliminates the need to manage underlying infrastructure.
- Enables efficient resource utilization and scaling based on demand.Image not found
Architecture
Steps Need to follow :
Step 2 : Create an IAM role for the new policy for Lambda Function
Step 3 : Create Lambda Functions for ScaleUp and ScaleDown
Step 4 : Create EventBridge scheduler for Scale Down
Step 5 : Create EventBridge scheduler for Scale Up
On the JSON tab need to enter following policy code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"eks:ListNodegroups",
"eks:UpdateNodegroupConfig",
"eks:DescribeNodegroup"
],
"Resource": [
"arn:aws:eks:CLUSTER_REGION:ACCOUNT_ID:cluster/CLUSTER_NAME",
"arn:aws:eks:CLUSTER_REGION:ACCOUNT_ID:nodegroup/CLUSTER_NAME/*/*"
]
}
]
}
Select Trusted entity type as AWS Service and Use case as Lambda.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import boto3
def describe_nodegroup(client, cluster_name, nodegroup_name):
return client.describe_nodegroup(
clusterName=cluster_name,
nodegroupName=nodegroup_name
)['nodegroup']['scalingConfig']
def update_nodegroup_config(client, cluster_name, nodegroup_name, scaling_config):
client.update_nodegroup_config(
clusterName=cluster_name,
nodegroupName=nodegroup_name,
scalingConfig=scaling_config
)
def update_nodegroup_sizes(eks, cluster_name, nodegroup_sizes):
for nodegroup_name, size in nodegroup_sizes.items():
current_size = describe_nodegroup(eks, cluster_name, nodegroup_name)
if size != current_size['desiredSize']:
update_nodegroup_config(eks, cluster_name, nodegroup_name, {'desiredSize': size})
print(f"Updated desired size for node group {nodegroup_name} to {size}")
else:
print(f"Desired size is already {size} for node group {nodegroup_name}")
def update_nodegroup_limits(eks, cluster_name, nodegroup_limits, key):
for nodegroup_name, limit in nodegroup_limits.items():
current_limit = describe_nodegroup(eks, cluster_name, nodegroup_name)
if limit != current_limit[key]:
update_nodegroup_config(eks, cluster_name, nodegroup_name, {key: limit})
print(f"Updated {key} for node group {nodegroup_name} to {limit}")
else:
print(f"{key.capitalize()} is already {limit} for node group {nodegroup_name}")
def lambda_handler(event, context):
eks = boto3.client('eks')
cluster_name = "CLUSTER_NAME"
nodegroup_sizes = {
'NODE_GROUP_1': ACTUAL_SIZE,
'NODE_GROUP_2': ACTUAL_SIZE,
'NODE_GROUP_3': ACTUAL_SIZE
}
nodegroup_minsizes = {
'NODE_GROUP_1': MIN_SIZE,
'NODE_GROUP_2': MIN_SIZE,
'NODE_GROUP_3': MIN_SIZE
}
nodegroup_maxsizes = {
'NODE_GROUP_1': MAX_SIZE,
'NODE_GROUP_2': MAX_SIZE,
'NODE_GROUP_3': MAX_SIZE
}
update_nodegroup_limits(eks, cluster_name, nodegroup_maxsizes, 'maxSize')
update_nodegroup_sizes(eks, cluster_name, nodegroup_sizes)
update_nodegroup_limits(eks, cluster_name, nodegroup_minsizes, 'minSize')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import boto3
def lambda_handler(event, context):
eks = boto3.client("eks")
cluster_name = "CLUSTER_NAME"
nodegroup_names = ["NODE_GROUP_1", "NODE_GROUP_2", "NODE_GROUP_3"]
new_desiredSize = 0
new_minSize = 0
new_maxSize = 1
# Update scaling configuration for all node groups
for nodegroup_name in nodegroup_names:
response = eks.update_nodegroup_config(
clusterName=cluster_name,
nodegroupName=nodegroup_name,
scalingConfig={
"desiredSize": new_desiredSize,
"minSize": new_minSize,
"maxSize": new_maxSize
}
)
# Print response if needed for debugging
# print(response)