The k8s-cj-scheduler project introduces a custom Kubernetes controller that simplifies the management of scheduled tasks within your cluster. Instead of directly interacting with Kubernetes CronJob resources, this operator allows you to define your schedules in a more declarative and streamlined way through a custom resource called Scheduler.
It's designed to abstract away the underlying CronJob complexities, enabling users to easily define multiple scheduled commands, specify container images, arguments, and even environment variables for each scheduled run, all within a single Scheduler object.
- Declarative Scheduling: Define recurring tasks using a custom
Schedulerresource, making your scheduled workloads a first-class citizen in Kubernetes. - Multiple Schedules per Resource: Consolidate multiple scheduled commands into a single
Schedulercustom resource, simplifying management. - Customizable Container Images: Specify any container image to run your scheduled commands.
- Command-Line Arguments: Pass custom arguments to your container commands via the
paramsfield. - Environment Variables: Inject necessary environment variables into your scheduled jobs using the
envfield, supporting both literal values and dynamic values from the Downward API. - Automated CronJob Management: The controller automatically creates, updates, and deletes Kubernetes
CronJobresources based on yourSchedulerdefinitions. - Cleanup: Automatically removes
CronJobs that are no longer defined in yourSchedulerresource.
To deploy and use the k8s-cj-scheduler operator in your Kubernetes cluster, follow these steps.
Before you begin, ensure you have the following installed:
- Go:
v1.24.0+ - Docker:
v17.03+ - kubectl:
v1.11.3+(compatible with your cluster) - Kubernetes Cluster: Access to a
v1.11.3+Kubernetes cluster.
To install the controller and its custom resources:
kubectl apply -f https://raw.githubusercontent.com/LorenzoRottigni/k8s-cj-scheduler/main/config/crd/bases/lr.labs_schedulers.yaml
kubectl apply -k https://github.com/LorenzoRottigni/k8s-cj-scheduler/config/defaultTo install the controller and its custom resources:
helm repo add lr-labs https://lorenzorottigni.github.io/k8s-scheduler
helm repo update
helm install cj-scheduler lr-labs/k8s-cj-scheduler --namespace kube-system --create-namespace --skip-crds-
Build and Push Your Operator Image: First, build your controller image and push it to a container registry you have access to. Replace
<your-registry>with your registry's URL andtagwith your preferred image tag (e.g.,v0.1.0).make docker-build docker-push IMG=<your-registry>/k8s-cj-scheduler:tag
Note: Ensure the image is published to a registry that your Kubernetes cluster can pull from. If you encounter permission issues, check your registry credentials.
-
Install the Custom Resource Definitions (CRDs): This step registers the
Schedulercustom resource with your Kubernetes API server.make install
-
Deploy the Operator (Manager): Deploy the
k8s-cj-schedulercontroller to your cluster. This will create the necessary deployments, service accounts, and RBAC roles.make deploy IMG=<your-registry>/k8s-cj-scheduler:tag
Note: If you face RBAC errors during deployment, you might need cluster-admin privileges or ensure your current
kubectlcontext has sufficient permissions.
Once the controller is running, you can create instances of your Scheduler custom resource to define your jobs.
You can apply the provided sample configuration:
kubectl apply -k config/samples/Example Scheduler Resource (config/samples/v1_scheduler.yaml or test.yml):
apiVersion: lr.labs/v1 # Your API Group
kind: Scheduler
metadata:
name: my-first-scheduler
namespace: default
spec:
schedules:
- name: minutely-ping
image: alpine/curl
cronExpression: "*/1 * * * *" # Runs every minute
params:
- curl
- "[https://www.google.com](https://www.google.com)"
- name: env-variable-test
image: busybox:latest
cronExpression: "*/2 * * * *" # Runs every 2 minutes
params:
- sh
- -c
- "echo 'Hello from ENVIRONMENT!'; echo 'MY_CUSTOM_VAR is: $MY_CUSTOM_VAR'; echo 'ANOTHER_SECRET_VAR is: $ANOTHER_SECRET_VAR'; sleep 5"
env:
- name: MY_CUSTOM_VAR
value: "This is a custom value!"
- name: ANOTHER_SECRET_VAR
value: "Shhh, this is a secret!"
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespaceNote: After applying, the
k8s-cj-schedulercontroller will create correspondingCronJobresources in thedefaultnamespace. You can verify them withkubectl get cronjobs.
Let's assume you've deployed the k8s-cj-scheduler operator to your cluster. Here's a quick example of how you can define and manage a scheduled task.
-
Define Your
SchedulerResource: Create a file namedmy-daily-report-scheduler.yamlwith the following content:apiVersion: lr.labs/v1 kind: Scheduler metadata: name: daily-report-generator namespace: default # Or your desired namespace spec: schedules: - name: generate-report image: myorg/report-generator:latest # Replace with your actual image cronExpression: "0 0 * * *" # Runs every day at midnight UTC params: - "/app/generate-report.sh" - "--date=$(date +%Y-%m-%d)" env: - name: REPORT_TYPE value: "daily-summary" - name: API_KEY_SECRET_NAME valueFrom: secretKeyRef: name: my-api-key-secret # Name of your secret key: api_key
This
Schedulerresource will create aCronJobthat runs daily at midnight, executing a report generation script with specific parameters and environment variables (including one fetched from a Kubernetes Secret). -
Apply the
SchedulerResource:kubectl apply -f my-daily-report-scheduler.yaml
-
Verify the Created CronJob: You can see the
CronJobcreated by your operator:kubectl get cronjobs -n default # Expected output similar to: # NAME SCHEDULE SUSPEND FORBIDDEN AGE # daily-report-generator-generate-report 0 0 * * * False False 10s
-
Inspect Job Runs (Optional): As time passes,
CronJobs will createJobresources. You can check them with:kubectl get jobs -n default -l scheduler=daily-report-generatorAnd view logs of a specific job run:
kubectl logs -f <job-name-from-above-command> -n default
To remove the k8s-cj-scheduler and all its components from your cluster:
-
Delete Your
SchedulerInstances: This will trigger the controller to clean up all associatedCronJobs.kubectl delete -f my-daily-report-scheduler.yaml # Delete your specific example kubectl delete -k config/samples/ # If you used the sample kustomize base
-
Delete the CRDs: This removes the
SchedulerAPI from your cluster.make uninstall
-
Undeploy the Controller Manager: This removes the operator's deployment and related resources.
make undeploy
If you wish to package and distribute your k8s-cj-scheduler solution to others:
You can generate a single YAML file containing all necessary Kubernetes resources for installation:
-
Build the Installer Bundle:
make build-installer IMG=<your-registry>/k8s-cj-scheduler:tag
This command generates an
install.yamlfile in thedistdirectory. This file bundles all resources required to install the project. -
Distribute and Use: Users can then install the project by simply applying this bundle:
kubectl apply -f [https://raw.githubusercontent.com/](https://raw.githubusercontent.com/)<your-org>/k8s-cj-scheduler/<tag-or-branch>/dist/install.yaml
(Replace
<your-org>and<tag-or-branch>with your actual GitHub organization and desired release tag/branch).
You can leverage the optional Helm plugin to generate a Helm Chart for easier deployment via Helm.
-
Generate/Update the Helm Chart:
kubebuilder edit --plugins=helm/v1-alpha
This command generates (or updates) a Helm chart under
dist/chart. -
Distribute the Chart: Users can obtain and install your solution using standard Helm commands.
Note: If you modify your project (e.g., add webhooks), you'll need to re-run the above
kubebuilder editcommand to sync changes to the Helm Chart. Use the--forceflag if necessary, and manually re-apply any custom configurations indist/chart/values.yamlordist/chart/manager/manager.yaml.
- Fork the repository.
- Clone your forked repository:
git clone https://github.com/<your-username>/k8s-cj-scheduler.git - Create a new feature branch:
git checkout -b feature/your-feature-name - Make your changes and commit them:
git commit -m "feat: Add new feature" - Push to your branch:
git push origin feature/your-feature-name - Open a Pull Request to the
mainbranch of the upstream repository.
Please ensure your code adheres to the existing style and conventions. Run make test and make fmt before submitting.
Additional Information: Run make help for more information on all potential make targets.
More information can be found via the Kubebuilder Documentation.
Copyright 2025.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
