• Stars
    star
    1,887
  • Rank 24,583 (Top 0.5 %)
  • Language
    Go
  • License
    MIT License
  • Created over 7 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Cron for containers

Supercronic

Supercronic has an announcement blog post over here!

Supercronic is a crontab-compatible job runner, designed specifically to run in containers.

Why Supercronic?

Crontabs are the lingua franca of job scheduling, but typical server cron implementations are ill-suited for container environments:

  • They purge their environment before starting jobs. This is an important security feature in multi-user systems, but it breaks a fundamental configuration mechanism for containers.
  • They capture the output from the jobs they run, and often either want to email this output or simply discard it. In a containerized environment, logging task output and errors to stdout / stderr is often easier to work with.
  • They often don't respond gracefully to SIGINT / SIGTERM, and may leave running jobs orphaned when signaled. Again, this makes sense in a server environment where init will handle the orphan jobs and Cron isn't restarted often anyway, but it's inappropriate in a container environment as it'll result in jobs being forcefully terminated (i.e. SIGKILL'ed) when the container exits.
  • They often try to send their logs to syslog. This conveniently provides centralized logging when a syslog server is running, but with containers, simply logging to stdout or stderr is preferred.

Finally, they are often quiet, making these issues difficult to understand and debug!

Supercronic's goal is to behave exactly how you would expect cron running in a container to behave:

  • Your environment variables are available in jobs
  • Job output is logged to stdout / stderr
  • SIGTERM triggers a graceful shutdown (and so does SIGINT, which you can deliver via CTRL+C when used interactively)
  • Job return codes and schedules are logged to stdout / stderr
  • SIGUSR2 triggers a graceful shutdown and reloads the crontab configuration

How does it work?

  • Install Supercronic (see below)
  • Point it at a crontab: supercronic CRONTAB
  • You're done!

Who is it for?

We (Aptible) originally created Supercronic to make it easy for customers of our Enclave container orchestration platform to incorporate periodic jobs in their apps, but it's more broadly applicable to anyone running cron jobs in containers.

Installation

Download

The easiest way to install Supercronic is to download a pre-built binary.

Navigate to the releases page, and grab the build that suits your system. The releases include example Dockerfile stanzas to install Supercronic that you can easily include in your own Dockerfile or adjust as needed.

Note: If you are unsure which binary is right for you, try supercronic-linux-amd64.

Build

You can also build Supercronic from source.

Run the following to fetch Supercronic, install its dependencies, and install it:

go get -d github.com/aptible/supercronic
cd "${GOPATH}/src/github.com/aptible/supercronic"
go mod vendor
go install

Crontab format

Broadly speaking, Supercronic tries to process crontabs just like Vixie cron does. In most cases, it should be compatible with your existing crontab.

There are, however, a few exceptions:

  • First, Supercronic supports second-resolution schedules: Under the hood, Supercronic uses the cronexpr package, so refer to its documentation to know exactly what you can do.
  • Second, Supercronic does not support changing users when running tasks. Setting USER in your crontab will have no effect. Changing users is usually best accomplished in container environments via other means, e.g., by adding a USER directive to your Dockerfile.

Here's an example crontab:

# Run every minute
*/1 * * * * echo "hello"

# Run every 2 seconds
*/2 * * * * * * ls 2>/dev/null

# Run once every hour
@hourly echo "$SOME_HOURLY_JOB"

Environment variables

Just like regular cron, Supercronic lets you specify environment variables in your crontab using a KEY=VALUE syntax.

However, this is only here for compatibility with existing crontabs, and using this feature is generally not recommended when using Supercronic.

Indeed, Supercronic does not wipe your environment before running jobs, so if you need environment variables to be available when your jobs run, just set them before starting Supercronic itself, and your jobs will inherit them.

For example, if you're using Docker, jobs started by Supercronic will inherit the environment variables defined using ENV directives in your Dockerfile, and variables passed when you run the container (e.g. via docker run -e SOME_VARIABLE=SOME_VALUE).

Unless you've used cron before, this is exactly how you expect environment variables to work!

Timezone

Supercronic uses your current timezone from /etc/localtime to schedule jobs. You can also override the timezone by setting the environment variable TZ (e.g. TZ=Europe/Berlin) when running Supercronic. You may need to install tzdata in order for Supercronic to find the supplied timezone.

You can override TZ to use a different timezone, but if you need your cron jobs to be scheduled in a timezone A and have them run in a timezone B, you can run with /etc/localtime or TZ set to B and add a CRON_TZ=A line to your crontab.

If you're unsure what timezone Supercronic is using, you can run it with the -debug flag to confirm.

Logging

Supercronic provides rich logging, and will let you know exactly what command triggered a given message. Here's an example:

$ cat ./my-crontab
*/5 * * * * * * echo "hello from Supercronic"

$ ./supercronic ./my-crontab
INFO[2017-07-10T19:40:44+02:00] read crontab: ./my-crontab
INFO[2017-07-10T19:40:50+02:00] starting                                      iteration=0 job.command="echo "hello from Supercronic"" job.position=0 job.schedule="*/5 * * * * * *"
INFO[2017-07-10T19:40:50+02:00] hello from Supercronic                        channel=stdout iteration=0 job.command="echo "hello from Supercronic"" job.position=0 job.schedule="*/5 * * * * * *"
INFO[2017-07-10T19:40:50+02:00] job succeeded                                 iteration=0 job.command="echo "hello from Supercronic"" job.position=0 job.schedule="*/5 * * * * * *"
INFO[2017-07-10T19:40:55+02:00] starting                                      iteration=1 job.command="echo "hello from Supercronic"" job.position=0 job.schedule="*/5 * * * * * *"
INFO[2017-07-10T19:40:55+02:00] hello from Supercronic                        channel=stdout iteration=1 job.command="echo "hello from Supercronic"" job.position=0 job.schedule="*/5 * * * * * *"
INFO[2017-07-10T19:40:55+02:00] job succeeded                                 iteration=1 job.command="echo "hello from Supercronic"" job.position=0 job.schedule="*/5 * * * * * *"

Debugging

If your jobs aren't running, or you'd simply like to double-check your crontab syntax, pass the -debug flag for more verbose logging:

$ ./supercronic -debug ./my-crontab
INFO[2017-07-10T19:43:51+02:00] read crontab: ./my-crontab
DEBU[2017-07-10T19:43:51+02:00] try parse(7): */5 * * * * * * echo "hello from Supercronic"[0:15] = */5 * * * * * *
DEBU[2017-07-10T19:43:51+02:00] job will run next at 2017-07-10 19:44:00 +0200 CEST  job.command="echo "hello from Supercronic"" job.position=0 job.schedule="*/5 * * * * * *"

Duplicate Jobs

Supercronic will wait for a given job to finish before that job is scheduled again (some cron implementations do this, others don't). If a job is falling behind schedule (i.e. it's taking too long to finish), Supercronic will warn you.

Here is an example:

$ cat ./my-crontab
# Sleep for 2 seconds every second. This will take too long.
* * * * * * * sleep 2

$ ./supercronic ./my-crontab
INFO[2017-07-11T12:24:25+02:00] read crontab: ./my-crontab
INFO[2017-07-11T12:24:27+02:00] starting                                      iteration=0 job.command="sleep 2" job.position=0 job.schedule="* * * * * * *"
INFO[2017-07-11T12:24:29+02:00] job succeeded                                 iteration=0 job.command="sleep 2" job.position=0 job.schedule="* * * * * * *"
WARN[2017-07-11T12:24:29+02:00] job took too long to run: it should have started 1.009438854s ago  job.command="sleep 2" job.position=0 job.schedule="* * * * * * *"
INFO[2017-07-11T12:24:30+02:00] starting                                      iteration=1 job.command="sleep 2" job.position=0 job.schedule="* * * * * * *"
INFO[2017-07-11T12:24:32+02:00] job succeeded                                 iteration=1 job.command="sleep 2" job.position=0 job.schedule="* * * * * * *"
WARN[2017-07-11T12:24:32+02:00] job took too long to run: it should have started 1.014474099s ago  job.command="sleep 2" job.position=0 job.schedule="* * * * * * *"

You can optionally disable this behavior and allow overlapping instances of your jobs by passing the -overlapping flag to Supercronic. Supercronic will still warn about jobs falling behind, but will run duplicate instances of them.

Reload crontab

Send SIGUSR2 to Supercronic to reload the crontab:

# docker environment (Supercronic needs to be PID 1 in the container)
docker kill --signal=USR2 <container id>

# shell
kill -USR2 <pid>

Testing your crontab

Use the -test flag to prompt Supercronic to verify your crontab, but not execute it. This is useful as part of e.g. a build process to verify the syntax of your crontab.

Level-based logging

By default, Supersonic routes all logs to stderr. If you wish to change this behaviour to level-based logging, pass the -split-logs flag to route debug and info level logs to stdout:

$ ./supercronic -split-logs ./my-crontab 1>./stdout.log
$ cat ./stdout.log
time="2019-01-12T19:34:57+09:00" level=info msg="read crontab: ./my-crontab"
time="2019-01-12T19:35:00+09:00" level=info msg=starting iteration=0 job.command="echo \"hello from Supercronic\"" job.position=0 job.schedule="*/5 * * * * * *"
time="2019-01-12T19:35:00+09:00" level=info msg="hello from Supercronic" channel=stdout iteration=0 job.command="echo \"hello from Supercronic\"" job.position=0 job.schedule="*/5 * * * * * *"
time="2019-01-12T19:35:00+09:00" level=info msg="job succeeded" iteration=0 job.command="echo \"hello from Supercronic\"" job.position=0 job.schedule="*/5 * * * * * *"

Integrations

Sentry

Report errors to Sentry by passing a Sentry DSN:

$ ./supercronic -sentry-dsn DSN

You can also specify the DSN via the SENTRY_DSN environment variable. When a DSN is specified via both the environment variable and the command line parameter the parameter's DSN has priority.

Questions and Support

Please feel free to open an issue in this repository if you have any question about Supercronic!

Note that if you're trying to use Supercronic on Aptible Enclave, we have a dedicated support article.

Contributing

PRs are always welcome! Before undertaking a major change, consider opening an issue for some discussion.

License

See LICENSE.md.

Copyright

Copyright (c) 2019 Aptible. All rights reserved.

More Repositories

1

docker-cron-example

DEPRECATED - Please see https://github.com/aptible/supercronic instead
Makefile
88
star
2

dashboard.aptible.com

DEPRECATED - Ember.js dashboard for the Aptible PaaS
JavaScript
81
star
3

aptible-cli

Command line interface to Aptible
Ruby
28
star
4

docker-registry-proxy

NGiNX proxy for Docker registries with SSL/Basic Auth
Shell
27
star
5

docker-nginx

NGiNX HTTP server
Shell
26
star
6

docker-sftp

OpenSSH-based SFTP on Docker
Shell
26
star
7

elasticsearch-logstash-s3-backup

Scripts to backup and restore Logstash indexes from Elasticsearch. Can be run as a cron on Aptible.
Shell
18
star
8

www.aptible.com

Deprecated - see `www` repository.
HTML
17
star
9

aptible-deploy-action

Github action to deploy
Shell
11
star
10

docker-mirthconnect

Docker Image for Mirth Connect
Shell
11
star
11

terraform-provider-aptible

The official Terraform provider for Aptible Deploy
Go
10
star
12

omnivault

Multi-platform keychain functionality
Ruby
9
star
13

docker-ruby

The Ruby programming language, on Docker
Makefile
9
star
14

docker-postgresql

PostgreSQL on Docker
Shell
9
star
15

opsworks-cli

An alternative CLI for Amazon OpsWorks
Ruby
9
star
16

ember-json-schema-document

Build and validate JSON Schema documents
JavaScript
8
star
17

app-ui

TypeScript
8
star
18

docker-ubuntu

Ubuntu base image with custom Aptible patches and Dockerfile building tools
Makefile
8
star
19

docker-kibana

Kibana on top of Docker
HTML
8
star
20

docker-elasticsearch-legacy

Elasticsearch on Docker
Shell
7
star
21

ember-json-schema-views

A collection of Ember.js form components for aptible/ember-json-schema-document
JavaScript
6
star
22

fridge

Token validation for distributed resource servers
Ruby
6
star
23

handbook

Aptible Employee Handbook
6
star
24

ember-cli-aptible-shared

DEPRECATED - An Ember CLI addon for sharing components between Aptible Ember apps
JavaScript
5
star
25

gentlemanjerry

A wrapper around Logstash intended for forwarding Docker container logs
Shell
5
star
26

docker-sentry

DEPRECATED - Sentry Docker image, deployable as an Aptible app
Python
5
star
27

go-deploy

Go Client Library for the Deploy API
Go
5
star
28

omnibus-aptible-toolbelt

An omnibus package for the Aptible CLI
Ruby
5
star
29

docker-rabbitmq

RabbitMQ on Docker
Python
4
star
30

aptible-api-ruby

Ruby client for api.aptible.com
Ruby
4
star
31

docker-mysql

MySQL on Docker
Shell
4
star
32

www

staging: https://app-28098.on-aptible.com/
JavaScript
3
star
33

docker-redis

Redis on Docker
Shell
3
star
34

docker-alpine

Alpine base image, borrowed from gliderlabs/docker-alpine
Makefile
3
star
35

deploy-demo-app

Demo application used to highlight features of the Aptible Deploy platform
Python
3
star
36

pg_activity

Useful for debugging live PostgreSQL performance.
Shell
3
star
37

mini_ca

A Gem to generate custom X509 certificates in specs
Ruby
3
star
38

docker-hog

A simple configurable memory hog, packaged in a container
C
3
star
39

sidekiq-field-encryptor

Field encryption middleware for Sidekiq
Ruby
3
star
40

aptible-resource

Foundation classes for Aptible resource server gems
Ruby
2
star
41

docker-logstash

Makefile
2
star
42

aptible-auth-ruby

Ruby client for auth.aptible.com
Ruby
2
star
43

straptible

DEPRECATED - A tool for bootstrapping new Aptible projects
Ruby
2
star
44

terraform-provider-aptible-iaas

Go
2
star
45

lessonly-ruby

DEPRECATED - A Ruby client for the Lessonly API
Ruby
2
star
46

joecool

An agent that forwards Docker container logs to a Logstash instance
Shell
2
star
47

docker-nodejs

DEPRECATED - Node.js on Docker
Makefile
2
star
48

docker-php

DEPRECATED - Aptible PHP Base Image
Shell
2
star
49

docker-nginx-tcp

Shell
2
star
50

autoscale-example

Python
2
star
51

docker-registry-all-in-one

An all-in-one Docker Registry image (v1 and v2 tags available to configure the default), including Nginx for TLS / auth and Redis for caching
Shell
2
star
52

ember-error-display

JavaScript
2
star
53

aptible-sass

Bower package for Aptible's common SASS assets.
2
star
54

support

DEPRECATED - Aptible's Support and Documentation Site
HTML
2
star
55

template-django

Django template for Aptible.com
Python
1
star
56

terrapyst

Python
1
star
57

terraform-provider-aptible-v2

Pre-alpha experimental repository for new Aptible functionality
Go
1
star
58

docker-debian

Debian base image with custom Aptible patches and Dockerfile building tools
Shell
1
star
59

aptstract

Python
1
star
60

aptible-deploy-action-demo

Demo app deploying to github actions
HTML
1
star
61

training

1
star
62

aptible-rails

DEPRECATED - Rails helpers for Aptible service applications
Ruby
1
star
63

action-python-lockfile-update

A Github Action that uses pip-tools to update a project's lockfiles via a Pull Request.
Shell
1
star
64

docker-mongodb

MongoDB on Docker
Shell
1
star
65

cloud-cli

Go
1
star
66

teamspace

Teamspace is a social media clone, meant for demonstrating security vulnerabilities in Django.
Python
1
star
67

terraform-aptible-metrics

Easily provision and managed all of the resources necessary to monitor your Aptible Environments. All hosted in your Aptible account!
HCL
1
star
68

octotron

DEPRECATED -
CoffeeScript
1
star
69

ember-json-schema-builder

A simple EmberJS-based JSON Schema editor built on JSONEditor, ember-json-schema-views, and ember-json-schema-document
JavaScript
1
star