Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
653dcb4
chore: update alpine image.
SimplicityGuy Jul 16, 2022
9701554
fix: SC2086 shellcheck fixes.
SimplicityGuy Jul 16, 2022
82875ab
fix: SC2004 shellcheck fixes.
SimplicityGuy Jul 16, 2022
8c8e19c
fix: SC2006 shellcheck fixes.
SimplicityGuy Jul 16, 2022
4d94552
fix: SC2236 shellcheck fixes.
SimplicityGuy Jul 16, 2022
96e699c
fix: SC2162 shellcheck fixes.
SimplicityGuy Jul 16, 2022
dcd3e42
fix: SC2166 shellcheck fixes.
SimplicityGuy Jul 16, 2022
6d92c31
fix: SC2005 and SC2046 shellcheck fixes.
SimplicityGuy Jul 16, 2022
882fb13
fix: SC1001, SC2018, SC2019 shellcheck fixes.
SimplicityGuy Jul 16, 2022
f18275e
fix: simplifying logic.
SimplicityGuy Jul 16, 2022
99aa59d
chore: whitespace and dead code cleanup.
SimplicityGuy Jul 16, 2022
dc18a51
chore: reorganization.
SimplicityGuy Jul 16, 2022
c685687
chore: rename function to better describe what it does.
SimplicityGuy Jul 16, 2022
8426541
chore: adding error handling.
SimplicityGuy Jul 16, 2022
f0c3063
chore: standardize on {}.
SimplicityGuy Jul 16, 2022
7f29f06
chore: standardizing on env vars.
SimplicityGuy Jul 16, 2022
1d844f8
chore: missed one spot using previously set env var.
SimplicityGuy Jul 16, 2022
2b1c209
Merge pull request #1 from SimplicityGuy/fixes
SimplicityGuy Jul 16, 2022
8f1d920
chore: tabs to spaces.
SimplicityGuy Jul 16, 2022
c4da20c
fix: addressing issue with parsing json.
SimplicityGuy Jul 16, 2022
36ef24f
chore: omit additional items.
SimplicityGuy Jul 16, 2022
a523ad7
fix: reset COMMENT.
SimplicityGuy Jul 16, 2022
9316c9f
fix: address jq parsing errors when some properties are not set.
SimplicityGuy Jul 16, 2022
0643e9c
chore: moving line to be consistent.
SimplicityGuy Jul 16, 2022
08bbcef
fix: cleaning script creation.
SimplicityGuy Jul 16, 2022
e69b276
chore: nicer formatting.
SimplicityGuy Jul 16, 2022
31d0b73
chore: cleaning up echos.
SimplicityGuy Jul 16, 2022
9da4249
fix: moving the top level key name to the "name" property.
SimplicityGuy Jul 16, 2022
c530324
Merge pull request #2 from SimplicityGuy/additional-fixes
SimplicityGuy Jul 16, 2022
76b524f
chore: merge from private git repo.
SimplicityGuy Aug 7, 2022
035cd4a
feat: Major Updates
SimplicityGuy Feb 19, 2023
022399e
feat: adding TEST_MODE.
SimplicityGuy Mar 5, 2023
2b364b9
fix: fixing @random since it was broken and removing @every since it …
SimplicityGuy Mar 5, 2023
899ec9c
fix: allow multiple networks.
SimplicityGuy May 21, 2023
2b46bb2
chore: remove FUNDING.yml
SimplicityGuy May 21, 2023
ccaf605
chore: remove forked build.yml.
SimplicityGuy Jun 24, 2023
e3bfdeb
chore: move build to the repo rather than the dockerfiles repo.
SimplicityGuy Jun 24, 2023
4cfb302
fix: typo.
SimplicityGuy Jun 24, 2023
ac49cae
chore: remove arm64.
SimplicityGuy Jun 24, 2023
c7a8352
chore: update and upgrade require the cache.
SimplicityGuy Jun 24, 2023
c3a1963
feat: cleanup old images on the 15th of the month.
SimplicityGuy Jun 26, 2023
9c8b32c
chore: add discord notification to cleanup.
SimplicityGuy Jun 26, 2023
5aeeb19
fix: missed id.
SimplicityGuy Jun 26, 2023
a72e847
chore: update pre-commit.
SimplicityGuy Dec 31, 2024
5172ed0
fix: use docker user.
SimplicityGuy Dec 31, 2024
a87292b
chore: casing.
SimplicityGuy Dec 31, 2024
1a540df
fix: make /var/log/crontab writeable for everyone.
SimplicityGuy Jan 5, 2025
18880be
fix: LOG_DIR is not used anywhere, remove it.
SimplicityGuy Jan 5, 2025
799ccc8
fix: permissions for /opt/crontab.
SimplicityGuy Jan 5, 2025
176cb2e
fix: move back to root user to debug permissions more completely.
SimplicityGuy Jan 5, 2025
7725e2f
fix: handle users at Dockerfile instead of in entrypoint script.
SimplicityGuy Jan 11, 2025
165ea6a
chore: update pre-commit.
SimplicityGuy Jan 11, 2025
495c98f
fix: use rootless.
SimplicityGuy Jan 11, 2025
8cd6616
fix: using docker user and back to dind.
SimplicityGuy Jan 11, 2025
903fb60
fix: trying out gosu.
SimplicityGuy Jan 11, 2025
7b24975
fix: change group.
SimplicityGuy Jan 11, 2025
0338bed
fix: Dockerfile to reduce vulnerabilities
snyk-bot Jan 17, 2025
a2c6492
chore: update pre-commit.
SimplicityGuy Jun 19, 2025
3a01924
fix: attempt to fix startup issues.
SimplicityGuy Jun 19, 2025
e333194
Merge pull request #7 from SimplicityGuy/snyk-fix-0d72670c2bce0340446…
SimplicityGuy Jun 19, 2025
23e4961
fix: Dockerfile to reduce vulnerabilities
snyk-bot Jun 19, 2025
243d4a3
fix: fix docker build.
SimplicityGuy Jun 19, 2025
738857a
Merge branch 'main' of github.com:SimplicityGuy/docker-crontab into s…
SimplicityGuy Jun 19, 2025
a2a7754
Merge pull request #8 from SimplicityGuy/snyk-fix-8994dbf363bbd972bbd…
SimplicityGuy Jun 19, 2025
fc27569
fix: Dockerfile to reduce vulnerabilities
snyk-bot Jun 19, 2025
c12805e
Merge pull request #9 from SimplicityGuy/snyk-fix-ff09303c15dc246c2ac…
SimplicityGuy Jun 19, 2025
9052ef7
fix: add su-exec.
SimplicityGuy Jun 19, 2025
8fb0222
chore: update claude docs.
SimplicityGuy Jun 29, 2025
48f67b1
chore: update pre-commit.
SimplicityGuy Jun 29, 2025
60bc7f4
fix: permission error.
SimplicityGuy Jun 29, 2025
598be37
fix: fix the error 'can't set groups: Operation not permitted'.
SimplicityGuy Jun 30, 2025
05710ab
fix: use crond -s flag to prevent user switching errors
SimplicityGuy Jul 6, 2025
c5a802c
fix: correct scripts and update dependencies
SimplicityGuy Jul 19, 2025
c637f74
fix: filter out unsupported -s flag for BusyBox crond
SimplicityGuy Jul 26, 2025
26f5591
fix: moving the CRONTAB_FILE.
SimplicityGuy Aug 3, 2025
6d8f92f
fix: Issue was that the environment variable wasn't being expanded i…
SimplicityGuy Aug 16, 2025
26afa4f
chore: update pre-commit.
SimplicityGuy Aug 16, 2025
1d28255
fix: BusyBox crond crontab directory configuration
SimplicityGuy Aug 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
# These are supported funding model platforms

github: [willfarrell]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
github: [SimplicityGuy]
ko_fi: robertwlodarczyk
custom: [paypal.me/RWlodarczyk]
92 changes: 59 additions & 33 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,49 +1,75 @@
name: build
---
name: crontab

on:
workflow_dispatch:
push:
branches:
- main
tags:
- '*'
pull_request:
branches:
- main
schedule:
- cron: '0 0 * * *'
- cron: '0 1 * * 6'

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.actor }}/crontab

jobs:
multi:
build-crontab:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write

steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
-
name: Login to DockerHub
uses: docker/login-action@v1
- name: Checkout repository.
uses: actions/checkout@v4
with:
submodules: true

- name: Log in to the GitHub Container Registry.
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}

- if: github.ref == 'refs/heads/main'
name: Conditional(Set tag as `latest`)
run: echo "tag=willfarrell/crontab:latest" >> $GITHUB_ENV
- name: Extract metadata (tags, labels) for Docker.
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=branch
type=ref,event=pr
type=schedule,pattern={{date 'YYYYMMDD'}}

- if: startsWith(github.ref, 'refs/tags/')
name: Conditional(Set tag as `{version}`)
run: echo "tag=willfarrell/crontab:${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Set up QEMU.
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx.
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64

-
name: Build and push
uses: docker/build-push-action@v2
- name: Build and push Docker image to GitHub Container Registry.
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: |
${{ env.tag }}
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
provenance: true
sbom: true

- name: Send notification to Discord.
uses: sarisia/[email protected]
if: always()
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
39 changes: 39 additions & 0 deletions .github/workflows/cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
name: cleanup

on:
schedule:
- cron: '0 0 15 * *'

env:
IMAGE_NAME: ${{ github.actor }}/docker-crontab

jobs:
cleanup-docker-crontab:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write

steps:
- name: Delete Docker images older than a month.
id: cleanup-images
uses: snok/container-retention-policy@v2
with:
account-type: personal
cut-off: One month ago UTC
keep-at-least: 4
skip-tags: latest
image-names: ${{ env.IMAGE_NAME }}
token: ${{ secrets.GHCR_TOKEN }}

- name: Send notification to Discord.
uses: sarisia/[email protected]
if: always()
with:
title: ${{ env.IMAGE_NAME }}
description: |
succeded cleanup : ${{ steps.cleanup-images.outputs.deleted }}
failed cleanup : ${{ steps.cleanup-images.outputs.failed }}
webhook: ${{ secrets.DISCORD_WEBHOOK }}
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
.idea
*.iml

config.json
.vscode
.DS_Store

config.json
config.working.json

jobs/
projects/
32 changes: 32 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks:
- id: check-added-large-files
- id: check-executables-have-shebangs
- id: check-merge-conflict
- id: check-shebang-scripts-are-executable
- id: check-yaml
- id: detect-aws-credentials
- id: detect-private-key
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace

- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 54da05914997e6b04e4db33ed6757d744984c68b # frozen: 0.33.2
hooks:
- id: check-github-workflows

- repo: https://github.com/executablebooks/mdformat
rev: ff29be1a1ba8029d9375882aa2c812b62112a593 # frozen: 0.7.22
hooks:
- id: mdformat
additional_dependencies:
- mdformat-gfm

- repo: https://github.com/hadolint/hadolint
rev: c3dc18df7a501f02a560a2cc7ba3c69a85ca01d3 # frozen: v2.13.1-beta
hooks:
- id: hadolint
151 changes: 151 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is `docker-crontab`, a Docker-based cron job scheduler that allows running complex cron jobs in other containers. It's a lightweight alternative to mcuadros/ofelia with enterprise features.

## Key Architecture

### Core Components

- **Dockerfile**: Multi-stage build using Alpine Linux base with Docker-in-Docker capability

- Builder stage: Downloads and compresses `rq` tool for config parsing
- Release stage: Based on `docker:dind-alpine` with cron and Docker client
- Uses `su-exec` for proper user privilege handling
- Configurable Docker group ID via `DOCKER_GID` build arg (default: 999)

- **entrypoint.sh**: Main orchestration script that:

- Normalizes config files (JSON/YAML/TOML) using `rq` and `jq`
- Processes shared settings via `~~shared-settings` key
- Generates crontab entries and executable scripts
- Supports both `image` (docker run) and `container` (docker exec) execution modes
- Handles trigger chains and onstart commands

### Configuration System

- Supports JSON, YAML, and TOML config formats
- Config can be array or mapping (top-level keys ignored for organization)
- Special `~~shared-settings` key for shared configuration
- Key fields: `schedule`, `command`, `image`/`container`, `dockerargs`, `trigger`, `onstart`
- Schedule supports standard crontab syntax plus shortcuts (@hourly, @daily, @every 2m, etc.)
- Additional fields: `comment`, `name`, `environment`, `expose`, `networks`, `ports`, `volumes`

### Job Execution Flow

1. Config normalization: All formats converted to working JSON
1. Script generation: Each job becomes executable shell script in `/opt/crontab/jobs/`
1. Crontab creation: Standard crontab file generated with proper scheduling
1. Trigger processing: Post-job triggers executed in sequence
1. Onstart handling: Jobs marked with `onstart: true` run immediately

## Development Commands

### Building

```bash
# Basic build
docker build -t crontab .

# Build with custom Docker group ID
docker build --build-arg DOCKER_GID=$(stat -c '%g' /var/run/docker.sock) -t crontab .
```

### Running

```bash
# Command line execution
docker run -d \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v ./config-samples/config.sample.json:/opt/crontab/config.json:ro \
-v ./logs:/var/log/crontab:rw \
crontab

# With host directory for persistent config/logs
# Container will create directories with proper permissions
docker run -d \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v $PWD/crontab-config:/opt/crontab:rw \
-v $PWD/crontab-logs:/var/log/crontab:rw \
crontab

# Docker Compose
docker-compose up
```

### Testing

```bash
# Test with sample configuration
docker run -d \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v ./config-samples/config.sample.json:/opt/crontab/config.json:ro \
crontab

# Debug mode - view generated crontab and scripts
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v ./config-samples/config.sample.json:/opt/crontab/config.json:ro \
-e TEST_MODE=1 \
crontab bash -c "cat /tmp/crontab-docker-testing/test && ls -la /tmp/crontab-docker-testing/jobs/"
```

The repository includes sample configurations in `config-samples/` for testing different scenarios.

## Important Configuration Notes

- **Docker Socket Access**: Container requires read-only access to `/var/run/docker.sock`
- **User Permissions**: Uses `docker` user with configurable GID to match host Docker group
- **Volume Mounts**: Config and log directories should be mounted as volumes
- **Network Access**: For docker-compose usage, containers need network connectivity via `--network` in `dockerargs`

## Troubleshooting

### Common Issues

- **"failed switching to 'docker': operation not permitted"**: Docker group GID mismatch

- Solution: Rebuild with correct GID using `--build-arg DOCKER_GID=$(stat -c '%g' /var/run/docker.sock)`

- **"Permission denied" creating directories**: Volume mount permissions issue

- Solution: Ensure host directories have correct ownership before mounting
- Quick fix: `sudo chown -R $(id -u):$(getent group docker | cut -d: -f3) /path/to/host/directory`
- Or let container create directories (it runs as root initially, then drops privileges)

- **Jobs not executing**: Check crontab generation and script permissions

- Debug: Use `TEST_MODE=1` environment variable to inspect generated files

- **Container networking issues**: Ensure proper network configuration in `dockerargs`

- For docker-compose: Add `--network <compose_network_name>` to dockerargs

### File Locations

- Generated scripts: `/opt/crontab/jobs/`
- Working config: `/opt/crontab/config.working.json`
- Crontab file: `/etc/crontabs/docker`
- Logs: Container stdout/stderr (configure external logging as needed)

## Security Considerations

- Container runs as non-root `docker` user for security
- Docker socket access is read-only to prevent container escape
- Uses `su-exec` for privilege dropping instead of `sudo`
- Multi-stage build minimizes attack surface
- SBOM and provenance generation enabled in CI/CD

## CI/CD

GitHub Actions workflow (`.github/workflows/build.yml`):

- Builds on push to main and PRs
- Multi-platform support (linux/amd64)
- Publishes to GitHub Container Registry (`ghcr.io`)
- Includes security scanning with SBOM and provenance
- Discord notifications for build status
- Weekly scheduled builds for base image security updates
Loading
Loading