Skip to content

Cronicle

Multi-server task scheduler and cron replacement with a web-based UI. Cronicle lets you create and manage scheduled jobs from a browser — set cron expressions, set concurrency limits, view live logs, receive email alerts, and review job history. Job data and state are stored in flat JSON files on a persistent volume.

Key Features

  • Web UI — browser-based job management with live log streaming
  • Cron replacement — cron-compatible scheduling with visual editor
  • Email notifications — SMTP alerts for job success, failure, and warnings
  • Session encryption — auto-generated secret_key stored in a Kubernetes Secret
  • Job memory limits — configurable per-job memory cap
  • Concurrency control — configurable maximum concurrent jobs per server
  • Persistent storage — PVC for job data, history, and state JSON files

Installation

HTTPS repository:

helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install cronicle helmforge/cronicle

OCI registry:

helm install cronicle oci://ghcr.io/helmforgedev/helm/cronicle

Deployment Examples

# values.yaml — Cronicle with public URL and persistence
cronicle:
  baseUrl: 'https://cronicle.example.com'

persistence:
  enabled: true
  size: 5Gi

ingress:
  enabled: true
  ingressClassName: traefik
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: cronicle.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: cronicle-tls
      hosts:
        - cronicle.example.com
# values.yaml — Cronicle with SMTP notifications
cronicle:
  baseUrl: 'https://cronicle.example.com'
  emailFrom: 'cronicle@example.com'
  smtpHostname: 'smtp.example.com'
  extraEnv:
    # SMTP port (default is 25; use 587 for STARTTLS)
    - name: CRONICLE_smtp_port
      value: '587'
    # SMTP authentication (if required)
    - name: CRONICLE_smtp_secure
      value: 'true'

persistence:
  enabled: true
  size: 5Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: cronicle.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Production setup with job limits and existing secret
cronicle:
  baseUrl: 'https://cronicle.example.com'
  emailFrom: 'cronicle@example.com'
  smtpHostname: 'smtp.example.com'
  maxJobs: 10
  jobMemoryMax: 2147483648 # 2 GB per job

secret:
  create: false
  existingSecret: cronicle-secret # must contain key: secret_key

resources:
  requests:
    memory: 256Mi
    cpu: 100m
  limits:
    memory: 1Gi
    cpu: 1000m

persistence:
  enabled: true
  size: 10Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: cronicle.example.com
      paths:
        - path: /
          pathType: Prefix

Configuration Reference

Core

ParameterTypeDefaultDescription
nameOverridestring""Override the chart name.
fullnameOverridestring""Override the full release name.
commonLabelsobject{}Extra labels added to all resources.

Image

ParameterTypeDefaultDescription
image.repositorystringdocker.io/soulteary/cronicleCronicle container image.
image.tagstring"0.9.80"Image tag.
image.pullPolicystringIfNotPresentImage pull policy.
imagePullSecretsarray[]Pull secrets for private registries.

Cronicle Configuration

ParameterTypeDefaultDescription
cronicle.portinteger3012Internal HTTP port for the Cronicle web UI.
cronicle.discoveryPortinteger3014UDP auto-discovery port for multi-server setups.
cronicle.discoveryEnabledbooleanfalseEnable UDP auto-discovery Service port.
cronicle.baseUrlstringhttp://localhost:3012Public base URL. Must be updated for notifications and UI links to work.
cronicle.emailFromstringcronicle@localhostEmail sender address for job notifications.
cronicle.smtpHostnamestringlocalhostSMTP server hostname for notifications.
cronicle.jobMemoryMaxinteger1073741824Maximum memory per job in bytes (default 1 GB = 1073741824).
cronicle.maxJobsinteger0Maximum concurrent jobs. 0 means unlimited.
cronicle.extraEnvarray[]Extra environment variables for SMTP auth and advanced configuration.
baseUrl defaults to localhost — update before deploying

The default cronicle.baseUrl is http://localhost:3012. If not changed, email notification links and some internal UI references will point to localhost instead of your actual instance. Set this to your public URL (e.g. https://cronicle.example.com) before first deployment.

Limit maxJobs in production to avoid node overload

With maxJobs: 0 (unlimited), Cronicle will run as many concurrent jobs as are scheduled, which can saturate the node’s CPU and memory. For production use, set maxJobs to a value that matches your available resources — typically 5–10 for a standard pod with 1–2 CPU cores.

Session Secret

ParameterTypeDefaultDescription
secret.createbooleantrueAuto-generate a secret_key for Cronicle session encryption.
secret.existingSecretstring""Use an existing Kubernetes Secret (must contain key secret_key).
Preserve the secret_key across reinstalls

Cronicle uses secret_key to sign user sessions. If the Helm release is deleted and reinstalled with secret.create: true, a new key is generated and all existing sessions are invalidated. For stable deployments, create the Secret manually and reference it with secret.existingSecret.

Persistence

Cronicle stores all job definitions, schedules, history, and state in flat JSON files under /opt/cronicle/data. No external database is required.

ParameterTypeDefaultDescription
persistence.enabledbooleantrueEnable a PVC for /opt/cronicle/data.
persistence.sizestring5GiPVC size.
persistence.storageClassstring""StorageClass for the PVC.
persistence.accessModesarray["ReadWriteOnce"]PVC access modes.
persistence.existingClaimstring""Use an existing PVC instead of creating one.

Service

ParameterTypeDefaultDescription
service.typestringClusterIPKubernetes service type.
service.portinteger80Service port exposed to the cluster.
service.annotationsobject{}Annotations for the Service.

Ingress

ParameterTypeDefaultDescription
ingress.enabledbooleanfalseEnable an Ingress resource.
ingress.ingressClassNamestringtraefikIngress class name.
ingress.annotationsobject{}Annotations for the Ingress (e.g. cert-manager).
ingress.hostsarray[]Ingress host and path rules.
ingress.tlsarray[]TLS configuration (secret name and hosts).

Probes

ParameterTypeDefaultDescription
probes.startup.enabledbooleantrueEnable startup probe.
probes.startup.initialDelaySecondsinteger5Startup probe initial delay.
probes.startup.periodSecondsinteger5Startup probe period.
probes.startup.timeoutSecondsinteger3Startup probe timeout.
probes.startup.failureThresholdinteger30Startup probe failure threshold.
probes.liveness.enabledbooleantrueEnable liveness probe.
probes.liveness.initialDelaySecondsinteger0Liveness probe initial delay.
probes.liveness.periodSecondsinteger15Liveness probe period.
probes.liveness.timeoutSecondsinteger5Liveness probe timeout.
probes.liveness.failureThresholdinteger3Liveness probe failure threshold.
probes.readiness.enabledbooleantrueEnable readiness probe.
probes.readiness.initialDelaySecondsinteger0Readiness probe initial delay.
probes.readiness.periodSecondsinteger10Readiness probe period.
probes.readiness.timeoutSecondsinteger5Readiness probe timeout.
probes.readiness.failureThresholdinteger3Readiness probe failure threshold.

Resources and Security

ParameterTypeDefaultDescription
resourcesobject{}CPU and memory requests and limits.
podSecurityContextobject{}Pod-level security context.
securityContextobject{}Container-level security context.

Service Account

ParameterTypeDefaultDescription
serviceAccount.createbooleanfalseCreate a dedicated ServiceAccount.
serviceAccount.namestring""Override the ServiceAccount name.
serviceAccount.annotationsobject{}Annotations for the ServiceAccount.

Scheduling

ParameterTypeDefaultDescription
nodeSelectorobject{}Node selector for scheduling.
tolerationsarray[]Tolerations for scheduling.
affinityobject{}Affinity rules.
topologySpreadConstraintsarray[]Topology spread constraints.
priorityClassNamestring""PriorityClass for the pod.
terminationGracePeriodSecondsinteger30Termination grace period.
podLabelsobject{}Extra labels for the pod.
podAnnotationsobject{}Extra annotations for the pod.

Extra

ParameterTypeDefaultDescription
extraVolumesarray[]Extra volumes to attach to the pod.
extraVolumeMountsarray[]Extra volume mounts for the container.
extraManifestsarray[]Extra Kubernetes manifests deployed alongside the chart.

Common Issues

Jobs not running after pod restart

If scheduled jobs stop running after a pod restart, verify that persistence.enabled: true and that the PVC is correctly mounted. Cronicle stores all job definitions in the PVC — if it is not mounted, the scheduler starts with no configured jobs.

Viewing job output and history

Cronicle stores job run logs in the web UI under Activity Log. For debugging, live output is visible in real time during job execution. Historical log files are also stored in the PVC under /opt/cronicle/data/logs/.

More Information