Skip to content

Instantly share code, notes, and snippets.

@shubhamsre
Created January 14, 2025 20:32
Show Gist options
  • Save shubhamsre/b17f6bc52c0f0b94dd8381696db1b7a0 to your computer and use it in GitHub Desktop.
Save shubhamsre/b17f6bc52c0f0b94dd8381696db1b7a0 to your computer and use it in GitHub Desktop.
Optimising cost by scaling down deployments in off peak hours using cronJob
##########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