Git Product home page Git Product logo

rekuberate-io / sleepcycles Goto Github PK

View Code? Open in Web Editor NEW
116.0 2.0 2.0 10.73 MB

Define sleep & wake up cycles for your Kubernetes resources. Automatically schedule to shutdown Deployments, CronJobs, StatefulSets and HorizontalPodAutoscalers that occupy resources in your cluster and wake them up only when you need them, reducing that way the overall power consumption.

Home Page: https://medium.com/@akyriako/rekuberate-io-sleepcycles-reclaim-your-unused-kubernetes-resources-d144bb276aa4

License: GNU General Public License v3.0

Dockerfile 1.08% Makefile 8.31% Go 85.63% Smarty 4.98%
auto-shutdown energy-consumption green-it kubernetes kubernetes-operator auto-wakeup sleepcycle

sleepcycles's Introduction

rekuberate-sleepcycle-banner.png

Define sleep & wake up cycles for your Kubernetes resources. Automatically schedule to shutdown Deployments, CronJobs, StatefulSets and HorizontalPodAutoscalers that occupy resources in your cluster and wake them up only when you need them; in that way you can:

  • schedule resource-hungry workloads (migrations, synchronizations, replications) in hours that do not impact your daily business
  • depressurize your cluster
  • decrease your costs
  • reduce your power consumption
  • lower you carbon footprint

Getting Started

Youโ€™ll need a Kubernetes cluster to run against. You can use KIND or K3D to get a local cluster for testing, or run against a remote cluster.

Samples

Under config/samples you will find a set manifests that you can use to test this sleepcycles on your cluster:

SleepCycles

  • core_v1alpha1_sleepcycle_app_x.yaml, manifests to deploy 2 SleepCycle resources in namespaces app-1 and app-2
apiVersion: core.rekuberate.io/v1alpha1
kind: SleepCycle
metadata:
  name: sleepcycle-app-1
  namespace: app-1
spec:
  shutdown: "1/2 * * * *"
  shutdownTimeZone: "Europe/Athens"
  wakeup: "*/2 * * * *"
  wakeupTimeZone: "Europe/Dublin"
  enabled: true

Note

The cron expressions of the samples are tailored so you perform a quick demo. The shutdown expression schedules the deployment to scale down on odd minutes and the wakeup schedule to scale up on even minutes.

Every SleepCycle has the following mandatory properties:

  • shutdown: cron expression for your shutdown schedule
  • enabled: whether this sleepcycle policy is enabled

and the following non-mandatory properties:

  • shutdownTimeZone: the timezone for your shutdown schedule, defaults to UTC
  • wakeup: cron expression for your wake-up schedule
  • wakeupTimeZone: the timezone for your wake-up schedule, defaults to UTC
  • successfulJobsHistoryLimit: how many completed CronJob Runner Pods to retain for debugging reasons, defaults to 1
  • failedJobsHistoryLimit: how many failed CronJob Runner Pods to retain for debugging reasons, defaults to 1
  • runnerImage: the image to use when spawn CronJob Runner pods, defaults to akyriako78/rekuberate-io-sleepcycles-runners

Important

DO NOT ADD seconds or timezone information to you cron expressions.

Demo workloads

  • whoami-app-1_x-deployment.yaml, manifests to deploy 2 Deployment that provisions traefik/whoami in namespace app-1
  • whoami-app-2_x-deployment.yaml, manifests to deploy a Deploymentthat provisions traefik/whoami in namespace app-2
  • apache-hpa.yaml, manifest to deploy an HorizontalPodAutoscaler for a PHP application in namespace app-2
  • nginx-statefulset.yaml, manifest to deploy a Statefulsetin namespace app-2
  • busybox-cronjob.yaml, manifest to deploy a Statefulsetin namespace app-1

SleepCycle is a namespace-scoped custom resource; the controller will monitor all the resources in that namespace that are marked with a Label that has as key rekuberate.io/sleepcycle: and as value the name of the manifest you created:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-2
  namespace: app-2
  labels:
    app: app-2
    rekuberate.io/sleepcycle: sleepcycle-app-2
spec:
  replicas: 9
  selector:
    matchLabels:
      app: app-2
  template:
    metadata:
      name: app-2
      labels:
        app: app-2
    spec:
      containers:
        - name: app-2
          image: traefik/whoami
          imagePullPolicy: IfNotPresent

Important

Any workload in namespace kube-system marked with rekuberate.io/sleepcycle will be ignored by the controller by design.

How it works

The diagram below describes how rekuberate.io/sleepcycles are dealing with scheduling a Deployment:

  1. The sleepcycle-controller watches periodically, every 1min, all the SleepCycle custom resources for changes (in all namespaces).
  2. The controller, for every SleepCycle resource within the namespace app-1, collects all the resources that have been marked with the label rekuberate.io/sleepcycle: sleepcycle-app1.
  3. It provisions, for every workload - in this case deployment deployment-app1 a CronJob for the shutdown schedule and optionally a second CronJob if a wake-up schedule is provided.
  4. It provisions a ServiceAccount, a Role and a RoleBinding per namespace, in order to make possible for runner-pods to update resources' specs.
  5. The Runner pods will be created automatically by the cron jobs and are responsible for scaling the resources up or down.

SCR-20240527-q9y.png

Note

In the diagram it was depicted how rekuberate.io/sleepcycles scales Deployment. The same steps count for a StatefulSet and a HorizontalPodAutoscaler. There are two exception though:

  • a HorizontalPodAutoscaler will scale down to 1 replica and not to 0 as for a Deployment or a Statefulset.
  • a CronJob has no replicas to scale up or down, it is going to be enabled or suspended respectively.

Using it together with ArgoCD

You can combine rekuberate.io/sleepcycles with applications provisioned with ArgoCD, as long as you disable self-healing when an automatic sync policy is enabled, otherwise ArgoCD's sync mechanism will operate antagonistically towards the shutdown and wakeup cronjobs. In this case ArgoCD will always automatically revert to the state described in the git manifests and practically will cancel the effect of the sleepcycle schedule. An ArgoCD application with Manual or Automatic sync policy without self-healing will work as expected.

Screenshot from 2024-06-01 14-00-23.png

Tip

There is a git repository in place, with all the necessary artifacts to deploy via ArgoCD an nginx application and a preconfigured sleepcycle. You can find the git repo here.

Deploy

From sources

  1. Build and push your image to the location specified by IMG in Makefile:
# Image URL to use all building/pushing image targets
IMG_TAG ?= $(shell git rev-parse --short HEAD)
IMG_NAME ?= rekuberate-io-sleepcycles
DOCKER_HUB_NAME ?= $(shell docker info | sed '/Username:/!d;s/.* //')
IMG ?= $(DOCKER_HUB_NAME)/$(IMG_NAME):$(IMG_TAG)
RUNNERS_IMG_NAME ?= rekuberate-io-sleepcycles-runners
KO_DOCKER_REPO ?= $(DOCKER_HUB_NAME)/$(RUNNERS_IMG_NAME)
make docker-build docker-push
  1. Deploy the controller to the cluster using the image defined in IMG:
make deploy

and then deploy the samples:

kubectl create namespace app-1
kubectl create namespace app-2
kubectl apply -f config/samples

Uninstall

make undeploy

Using Helm (from sources)

If you are on a development environment, you can quickly test & deploy the controller to the cluster using a Helm chart directly from config/helm:

helm install rekuberate-io-sleepcycles config/helm/ -n <namespace> --create-namespace

and then deploy the samples:

kubectl create namespace app-1
kubectl create namespace app-2
kubectl apply -f config/samples

Uninstall

helm uninstall rekuberate-io-sleepcycles -n <namespace>

Using Helm (from repo)

On the other hand if you are deploying on a production environment, it is highly recommended to deploy the controller to the cluster using a Helm chart from its repo:

helm repo add sleepcycles https://rekuberate-io.github.io/sleepcycles/
helm repo update

helm upgrade --install sleepcycles sleepcycles/sleepcycles -n rekuberate-system --create-namespace

and then deploy the samples:

kubectl create namespace app-1
kubectl create namespace app-2
kubectl apply -f config/samples

Uninstall

helm uninstall rekuberate-io-sleepcycles -n <namespace>

Develop

This project aims to follow the Kubernetes Operator pattern. It uses Controllers which provides a reconcile function responsible for synchronizing resources until the desired state is reached on the cluster.

Controller

Modifying the API definitions

If you are editing the API definitions, generate the manifests such as CRs or CRDs using:

make generate
make manifests

then install the CRDs in the cluster with:

make install

Tip

You can debug the controller in the IDE of your choice by hooking to the main.go or you can start the controller without debugging with:

make run

Tip

Run make --help for more information on all potential make targets More information can be found via the Kubebuilder Documentation

Build

You always need to build a new docker container and push it to your repository:

make docker-build docker-push

Important

In this case you will need to adjust your Helm chart values to use your repository and container image.

Runner

Build

make ko-build-runner

Important

In this case you will need to adjust the runnerImage of your SleepCycle manifest to use your own Runner image.

Uninstall CRDs

To delete the CRDs from the cluster:

make uninstall

sleepcycles's People

Contributors

akyriako avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

sleepcycles's Issues

Crashed w/ runtime error [Observed a panic in reconciler: runtime error: invalid memory address or nil pointer dereference]

Hey there ๐Ÿ‘‹๐Ÿป

I'm running on AWS EKS cluster v1.25.

The sleepcycles were installed on the cluster and the label were configured on one of the deployments.

Here are some logs from sleepcycles pod:

1.70249953358739e+09	INFO	controller-runtime.metrics	Metrics server is starting to listen	{"addr": "127.0.0.1:8080"}
1.7024995335878196e+09	INFO	setup	starting manager
1.7024995335883129e+09	INFO	Starting server	{"kind": "health probe", "addr": "[::]:8081"}
1.7024995335883129e+09	INFO	Starting server	{"path": "/metrics", "kind": "metrics", "addr": "127.0.0.1:8080"}
I1213 20:32:13.588770       1 leaderelection.go:248] attempting to acquire leader lease sleepcycles-system/04cbe4c0.rekuberate.io...
I1213 20:32:30.242666       1 leaderelection.go:258] successfully acquired lease sleepcycles-system/04cbe4c0.rekuberate.io
1.702499550243052e+09	DEBUG	events	Normal	{"object": {"kind":"Lease","namespace":"sleepcycles-system","name":"04cbe4c0.rekuberate.io","uid":"294d077b-9dfd-4795-8120-99bddec3cd2b","apiVersion":"coordination.k8s.io/v1","resourceVersion":"852177480"}, "reason": "LeaderElection", "message": "sleepcycles-controller-manager-bf6c64857-j5k8d_808b4e88-ba76-4555-b558-8d7b48640b11 became leader"}
1.7024995502432828e+09	INFO	Starting EventSource	{"controller": "sleepcycle", "controllerGroup": "core.rekuberate.io", "controllerKind": "SleepCycle", "source": "kind source: *v1alpha1.SleepCycle"}
1.7024995502433164e+09	INFO	Starting Controller	{"controller": "sleepcycle", "controllerGroup": "core.rekuberate.io", "controllerKind": "SleepCycle"}
1.7024995503444824e+09	INFO	Starting workers	{"controller": "sleepcycle", "controllerGroup": "core.rekuberate.io", "controllerKind": "SleepCycle", "worker count": 1}
1.7024995505854793e+09	INFO	๐Ÿ“š Processing Deployments	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown"}
1.7024995508859751e+09	INFO	๐Ÿ•‘ Processing CronJobs	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown"}
1.7024995509862914e+09	INFO	๐Ÿ“ฆ Processing StatefulSets	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown"}
1.7024995510869236e+09	INFO	๐Ÿ“ˆ Processing HorizontalPodAutoscalers	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown"}
1.7024995510988872e+09	INFO	๐Ÿ” Requeue	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown", "next-op": "Shutdown", "after": "28.901116474s"}
1.7024995511085997e+09	INFO	๐Ÿ” Requeue	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown", "next-op": "Shutdown", "after": "28.891404078s"}
1.7024995800032704e+09	INFO	๐Ÿ“š Processing Deployments	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown"}
1.7024995800034337e+09	INFO	๐Ÿ•‘ Processing CronJobs	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown"}
1.7024995800034702e+09	INFO	๐Ÿ“ฆ Processing StatefulSets	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown"}
1.702499580003513e+09	INFO	๐Ÿ“ˆ Processing HorizontalPodAutoscalers	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown"}
1.7024995800151165e+09	INFO	๐Ÿ” Requeue	{"namespace": "es-digital-journeys", "sleepcycle": "sleepcycle-sample1", "op": "Shutdown", "next-op": "Shutdown", "after": "59.984887885s"}
1.7024995800156264e+09	INFO	Observed a panic in reconciler: runtime error: invalid memory address or nil pointer dereference	{"controller": "sleepcycle", "controllerGroup": "core.rekuberate.io", "controllerKind": "SleepCycle", "sleepCycle": {"name":"sleepcycle-sample1","namespace":"es-digital-journeys"}, "namespace": "es-digital-journeys", "name": "sleepcycle-sample1", "reconcileID": "f199f8db-368c-43e0-ad11-9c304278acdf"}
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x13881bb]

goroutine 201 [running]:
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Reconcile.func1()
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:118 +0x1f4
panic({0x14c2c80, 0x2328090})
	/usr/local/go/src/runtime/panic.go:838 +0x207
github.com/rekuberate-io/sleepcycles/controllers.(*SleepCycleReconciler).getCurrentScheduledOperation(_, {{{0x13b128d, 0xa}, {0xc001af5780, 0x1b}}, {{0xc001af9b00, 0x12}, {0x0, 0x0}, {0xc001af9b30, ...}, ...}, ...})
	/workspace/controllers/sleepcycle_controller.go:455 +0x17b
github.com/rekuberate-io/sleepcycles/controllers.(*SleepCycleReconciler).Reconcile(0xc000490ab0, {0x18b67c0, 0xc001ba44e0}, {{{0xc0006803a8?, 0x10?}, {0xc000680390?, 0x40d787?}}})
	/workspace/controllers/sleepcycle_controller.go:84 +0x3a5
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Reconcile(0x18b6718?, {0x18b67c0?, 0xc001ba44e0?}, {{{0xc0006803a8?, 0x15c5740?}, {0xc000680390?, 0x4041f4?}}})
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:121 +0xc8
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler(0xc0001a6b40, {0x18b6718, 0xc00057f4c0}, {0x1512b20?, 0xc0029332c0?})
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:320 +0x33c
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem(0xc0001a6b40, {0x18b6718, 0xc00057f4c0})
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:273 +0x1d9
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func2.2()
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:234 +0x85
created by sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).Start.func2
	/go/pkg/mod/sigs.k8s.io/[email protected]/pkg/internal/controller/controller.go:230 +0x325

Here is the output from **k get sleepcycles.core.rekuberate.io -w**:

NAME                 SHUTDOWN      WAKEUP   ENABLED   NEXT SHUTDOWN          NEXT WAKE UP   LAST RUN               LAST RUN SUCCESS
sleepcycle-sample1   */1 * * * *            true      2023-12-13T20:28:00Z                  2023-12-13T20:27:00Z   true
sleepcycle-sample1   */1 * * * *            true      2023-12-13T20:33:00Z                  2023-12-13T20:32:31Z   true
sleepcycle-sample1   */1 * * * *            true      2023-12-13T20:34:00Z                  2023-12-13T20:33:00Z   true
sleepcycle-sample1   */1 * * * *            true      2023-12-13T20:39:00Z                  2023-12-13T20:38:30Z   true
sleepcycle-sample1   */1 * * * *            true      2023-12-13T20:40:00Z                  2023-12-13T20:39:00Z   true

๐Ÿ™๐Ÿป Thanks you in advance, Let me know in case there is some issue template.

Sleepcycle ignores wakeup schedule

Hello @akyriako

First of all, thank you for this tool, it helps us to decrease costs.
But I implemented it in different namespaces, and time to time wakeup schedule is ignored, and last action is Watch.
For example, logs from one env:

NAME                 SHUTDOWN SCHEDULE   SHUTDOWN TIMEZONE   WAKEUP SCHEDULE   WAKEUP TIMEZONE   ENABLED   SUCCESS   LAST OP
sleepcycle   0 23 * * 1-5        Europe/Warsaw       0 7 * * 1-5       Europe/Warsaw     true      true      Watch

Could you please help me? Maybe, you can help how I can debug this problem.

Best regards,
Hanna

Move Sleepcycles ops to Runners (CronJobs)

  • Offload all ops from controller to dedicated cronjobs per schedule
  • Controller would monitor only the lifecycle of the cronjobs
  • Cronjobs will execute schedules and update status of Sleepcycle
  • One cronjob per op per sleepcycle per workload e.g: sleepcycle-1-app-1-shutdown, sleepcycle-1-app-1-wakeup

Add timezones to schedules

Following the paradigm of CronJobs specifications in Kubernetes, shutdown and wakeup schedules need to support other timezones apart from the default UTC

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.