cronicle-docker/README.md
Emil Lerch e75cc7468a
Some checks failed
Build Cronicle image / build (push) Failing after 29s
initial commit: ai generated all the things
2026-08-11 17:36:02 -07:00

116 lines
4.4 KiB
Markdown

# cronicle-docker
Container image for [vanilla upstream Cronicle](https://github.com/jhuckaby/Cronicle),
built from the GitHub release tarball.
Produces `git.lerch.org/lobo/cronicle`.
## Why this repo exists
The `cronicle/cronicle` image on Docker Hub is effectively abandoned: `:latest`
is `:0.9.74`, last pushed 2025-02-24, while upstream Cronicle releases roughly
monthly. It is published by the [cronicle-edge](https://github.com/cronicle-edge/cronicle-edge)
project, whose own fork (`cronicle/edge`) ships regularly -- the "classic"
variant just stopped getting rebuilt.
The surveyed alternatives were all worse for this purpose:
| Image | Cronicle version | Last built | Notes |
| --- | --- | --- | --- |
| `cronicle/cronicle` | 0.9.74 | 2025-02-24 | vanilla, abandoned tag |
| `soulteary/cronicle` | 0.9.80 | 2025-06-02 | vanilla, stale |
| `cronicle/edge` | fork v1.14.x | current | actively maintained, but a fork |
| `intelliops`, `bluet`, `nicholasamorim` | 0.8.x | 2019-2021 | ancient |
Staying on vanilla keeps the MIT license, the existing on-disk data format, and
local-time log annotation. This repo is the minimum needed to do that: the
Dockerfile mirrors `cronicle/cronicle:0.9.74`'s layout (recovered from
`docker history`), with deviations documented inline.
## Concrete problem it solved
Cronicle v0.9.74's `package-lock.json` pins `pixl-json-stream` **1.0.9**, which
drops the trailing newline from the last complete line of every read chunk.
Because `bin/shell-plugin.js` appends the line verbatim and relies on the
library for the terminator, job logs silently concatenate:
```
[2026/08/11 14:00:02] EDGAR company ticker map okinfo(...): provider data lag ...
```
Upstream fixed the library in 1.0.10, and Cronicle v0.9.126's lockfile pins it.
Building current releases therefore fixes the bug -- but since a *lockfile*
delivered it in the first place, `test/newline-regression.js` runs during
`docker build` and fails the build if it ever comes back. See that file for the
full write-up.
## Build
`CRONICLE_VERSION` is required and takes no leading `v`:
```sh
docker build --build-arg CRONICLE_VERSION=0.9.126 -t cronicle:local .
```
## Tags
CI publishes three tags per build:
| Tag | Mutability | Use |
| --- | --- | --- |
| `0.9.126-a1b2c3d` | immutable | **pin this in deployments** |
| `0.9.126` | moves | latest build of that Cronicle release |
| `latest` | moves | latest build of anything |
The immutable tag is `<cronicle-version>-<short-sha-of-this-repo>`.
## CI
`.forgejo/workflows/build.yaml` runs on push to `master`, on manual dispatch,
and nightly at 13:00 UTC.
It resolves upstream's latest release, then checks whether the immutable tag
already exists in the registry and skips the build if so. Because that tag
encodes both the upstream version and this repo's commit, a rebuild is triggered
by either a new Cronicle release or a change here -- with no state file to keep
in sync.
Note: the nightly does **not** rebuild for base-image security patches alone,
since nothing about the tag would change. Force one with a manual dispatch or an
empty commit if a relevant Alpine CVE lands.
## Running
No `CMD` is set, matching upstream. Start it with `control.sh start`:
```sh
docker run -d --name cronicle \
-h cronicle-master \
-e TZ="America/Los_Angeles" \
-v /data/cronicle/data:/opt/cronicle/data \
-v /data/cronicle/conf:/opt/cronicle/conf \
git.lerch.org/lobo/cronicle:0.9.126-a1b2c3d control.sh start
```
The image defaults to **UTC**, unlike `cronicle/cronicle` which hardcoded
`America/New_York`. Set `TZ` explicitly.
`CRONICLE_foreground=1` and `CRONICLE_echo=1` are baked in, so the process stays
in the foreground and streams its log to `docker logs`.
### Behind a reverse proxy
If the proxy sets `X-Forwarded-Proto: https`, Cronicle reports its `https_port`
in `/api/app/config`, and the live log watcher will try to reach a worker
directly on that port -- which fails when the address is a container-internal IP.
Set `custom_live_log_socket_url` at the **top level** of `config.json` (not
inside `client`, where it is silently overwritten by the server-side default):
```json
"custom_live_log_socket_url": "https://cronicle.example.org"
```
Cronicle polls `config.json` every 10 seconds and hot-reloads it, so this
particular key takes effect without a restart. That is inherited
`pixl-server` behaviour and applies only to values read per-request; anything
consumed at startup (bound ports, storage engine) still needs a restart.