Created
January 14, 2025 20:32
-
-
Save shubhamsre/b17f6bc52c0f0b94dd8381696db1b7a0 to your computer and use it in GitHub Desktop.
Optimising cost by scaling down deployments in off peak hours using cronJob
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
##########Dockerfile########### | |
# Start with a lightweight Alpine image | |
FROM alpine:3.18 | |
# Install curl, bash, and kubectl | |
RUN apk update && \ | |
apk add --no-cache \ | |
curl \ | |
bash \ | |
&& curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.25.7/bin/linux/amd64/kubectl \ | |
&& chmod +x kubectl \ | |
&& mv kubectl /usr/local/bin/ | |
# Set a working directory | |
WORKDIR /scripts | |
# Command to run if no other args are passed | |
CMD ["sh"] | |
##########CronJob.yaml########## | |
--- | |
apiVersion: batch/v1 | |
kind: CronJob | |
metadata: | |
name: {{ .Chart.Name }}-cost-optimizer | |
namespace: {{ .Release.Namespace }} | |
labels: | |
app: {{ .Chart.Name }} | |
spec: | |
schedule: "{{ .Values.costOptimization.frequency | default '*/10 * * * *' }}" | |
jobTemplate: | |
spec: | |
template: | |
spec: | |
serviceAccountName: deployment-scaler-sa | |
containers: | |
- name: deployment-scheduler | |
image: your-repository/your-image-name:latest # Replace with your Docker image name | |
command: ["/bin/sh", "-c"] | |
args: | |
- | | |
echo "Setting timezone to {{ .Values.costOptimization.timeZone }}" | |
export TZ="{{ .Values.costOptimization.timeZone }}" | |
current_time=$(date +"%H:%M") | |
current_day=$(date +"%u") # Get current weekday as a number (1=Monday, 7=Sunday) | |
echo "Current time: $current_time, Current day: $current_day" | |
weekdays="{{ .Values.costOptimization.weekdays }}" | |
echo "Allowed weekdays: $weekdays" | |
# Check if today is a valid weekday for scaling | |
if echo "$weekdays" | grep -qw "$current_day"; then | |
echo "Today is a valid weekday for scaling." | |
# Scale down at sleep time | |
if [ "$current_time" = "{{ .Values.costOptimization.sleepAt }}" ]; then | |
echo "Initiating sleep process for deployments..." | |
for deployment in {{ .Values.deployments | join " " }}; do | |
if ! echo "{{ .Values.costOptimization.exclusions | toJson }}" | grep -q "$deployment"; then | |
echo "Scaling down deployment: $deployment" | |
kubectl scale deployment $deployment --replicas=0 -n {{ .Release.Namespace }} | |
else | |
echo "Skipping excluded deployment: $deployment" | |
fi | |
done | |
# Scale up at wake time | |
elif [ "$current_time" = "{{ .Values.costOptimization.wakeUpAt }}" ]; then | |
echo "Initiating wake-up process for deployments..." | |
for deployment in {{ .Values.deployments | join " " }}; do | |
if ! echo "{{ .Values.costOptimization.exclusions | toJson }}" | grep -q "$deployment"; then | |
echo "Scaling up deployment: $deployment to minReplicas" | |
kubectl scale deployment $deployment --replicas={{ .Values.autoscaling.minReplicas | default 1 }} -n {{ .Release.Namespace }} | |
else | |
echo "Skipping excluded deployment: $deployment" | |
fi | |
done | |
else | |
echo "No scaling operation required at this time." | |
fi | |
else | |
# Fallback: Ensure deployments are scaled up on non-specified days | |
echo "Today is not a valid weekday for scaling. Checking deployment states for fallback." | |
for deployment in {{ .Values.deployments | join " " }}; do | |
replica_count=$(kubectl get deployment $deployment -n {{ .Release.Namespace }} -o=jsonpath='{.spec.replicas}') | |
if [ "$replica_count" = "0" ]; then | |
echo "Scaling up deployment: $deployment to minReplicas" | |
kubectl scale deployment $deployment --replicas={{ .Values.autoscaling.minReplicas | default 1 }} -n {{ .Release.Namespace }} | |
else | |
echo "Deployment $deployment is already scaled up with $replica_count replicas." | |
fi | |
done | |
fi | |
env: | |
- name: TZ | |
value: "{{ .Values.costOptimization.timeZone }}" | |
resources: | |
requests: | |
memory: "64Mi" | |
cpu: "250m" | |
limits: | |
memory: "128Mi" | |
cpu: "500m" | |
restartPolicy: OnFailure | |
###########serviceAccount.yaml########## | |
--- | |
apiVersion: v1 | |
kind: ServiceAccount | |
metadata: | |
name: deployment-scaler-sa | |
namespace: {{ .Release.Namespace }} | |
##########role.yaml########## | |
--- | |
apiVersion: rbac.authorization.k8s.io/v1 | |
kind: Role | |
metadata: | |
name: deployment-scaler-role | |
namespace: {{ .Release.Namespace }} | |
rules: | |
- apiGroups: ["apps"] | |
resources: ["deployments/scale"] | |
verbs: ["get", "patch", "update"] | |
##########roleBinding.yaml########## | |
--- | |
apiVersion: rbac.authorization.k8s.io/v1 | |
kind: RoleBinding | |
metadata: | |
name: deployment-scaler-rolebinding | |
namespace: {{ .Release.Namespace }} | |
roleRef: | |
apiGroup: rbac.authorization.k8s.io | |
kind: Role | |
name: deployment-scaler-role | |
subjects: | |
- kind: ServiceAccount | |
name: deployment-scaler-sa | |
namespace: {{ .Release.Namespace }} | |
##########values.yaml########## | |
costOptimization: | |
# Frequency for the cron job. Default: Run every 10 minutes. | |
frequency: "*/10 *" | |
# Weekdays for applying the scaling policy (e.g., Monday, Tuesday, Thursday, Friday). | |
weekdays: "1,2,4,5" | |
# Time to scale down deployments (off-peak hours). | |
sleepAt: "20:00" | |
# Time to scale up deployments (traffic hours). | |
wakeUpAt: "08:00" | |
# Timezone for the cron job schedule. | |
timeZone: "Europe/Rome" | |
# List of deployments to exclude from scaling operations. | |
exclusions: | |
- test-deployment1 | |
- test-deployment2 | |
autoscaling: | |
# Minimum replicas for deployments when scaling up. | |
minReplicas: 2 | |
# List of deployments to manage. | |
deployments: | |
- service-a | |
- service-b | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment