Docker - ZornTaov/ZornCoMix GitHub Wiki
Running the updater in a container, its environment variables, and running edited scripts without rebuilding.
The image, ghcr.io/zorntaov/zcm-updater, is built from the repository and published to the GitHub
container registry for amd64 and arm64. It pins Chromium and a matching ChromeDriver together and carries
the scripts, so it needs only your library and a settings folder mounted - nothing to clone or build. It runs
the same on any Docker host - a NAS, a Linux server, Docker Desktop - and the compose file,
docker-compose.yml, works
with docker compose or with any GUI that takes a compose file (Container Station, Portainer, Unraid's
compose plugin and the like).
Download docker-compose.yml,
edit it as below, and beside it:
docker compose up -d
docker compose logs -fdocker compose pull
docker compose up -d| Tag | What it is |
|---|---|
:latest |
The newest release. What the compose file uses. |
:1.2.0, :1.2, :1
|
A release, or the newest within that minor or major version: pin one to stay put, should a newer one misbehave. |
:nightly |
main as of last night, rebuilt only on a night it changed: what is coming in the next release, before it is released. |
:sha-<commit> |
One particular nightly. |
:pr-<number> |
The latest successful build of an open PR from a branch in this repository, for testing before merge. Moves after each new commit and is removed when the PR closes or merges. |
The updater and the Reader are released together and share a version number.
Before the project was ZornCoMix, the image was ghcr.io/zorntaov/comics-updater and the container
comics-updater. Releases are still published under the old name for now, so an untouched compose file keeps
updating, but that name will be dropped in a later release. To move over, change two lines in your compose
file:
image: ghcr.io/zorntaov/zcm-updater:latest
container_name: zcm-updaterthen docker compose pull && docker compose up -d. Compose replaces the old container with one of the new
name; everything it keeps is in the folders mounted into it, so nothing is lost. Anything of your own that
names the container - a script running docker exec comics-updater ... - needs the new name too. The
Reader moves the same way, from comic-reader to zcm-reader.
Each PR from a branch in this repository builds both images for amd64 and arm64, when opened, updated or reopened. Its number is its tag; for PR #1:
ghcr.io/zorntaov/zcm-updater:pr-1
ghcr.io/zorntaov/zcm-reader:pr-1
Set the service's image: to the matching image and PR tag, then pull and recreate the container:
docker compose pull
docker compose up -dThe tag moves. Pull again after the PR's PR images workflow succeeds to try its newest commit;
a running container is not updated merely by a push or a finished build. An older build cannot replace a
newer PR commit's image, and a failed build leaves the last published tag alone. These builds never move
:latest, release version tags, :nightly or nightly :sha-<commit> tags. Fork PRs do not publish images,
so code from a fork never receives registry write access.
Closing or merging the PR cancels unfinished builds and automatically removes its pr-<number> tags
from both images. The cleanup does not delete release/nightly images, another PR's tags, or images
already downloaded to your host. After testing, switch back to :latest or :nightly and pull/recreate
again; a closed PR's tag cannot be pulled. Reopening it builds and publishes the PR tag again.
The PR workflow and registry helper are read from the base branch. Workflow changes must reach main
before they can govern PR builds; editing them only in the PR does not change how it is published.
No updater/reader restart or rebuild is needed to enable the CI itself. For the updater, a scripts folder
mounted over /app still overrides the scripts baked into any test image, just as for a release.
PR images are published under the zcm- names only, never the old ones.
To run your own changes in an image, rather than mounting them,
build from a clone of the repository and put your tag in the compose file's image::
docker build -t zcm-updater:local .The compose file has no build: key on purpose: some compose GUIs try to build from a context they do not
have and leave a useless second image.
Every line to change is marked CHANGE ME in
the file.
| Setting | What to set |
|---|---|
volumes |
Your library as /library, and a settings folder as /app/config (holds ComicScraper.json, element paths, index/; without it they are lost when the container is recreated). The left-hand paths are wherever those folders are on your host. |
TZ |
Required, or the schedule runs on UTC. |
user |
The library folder's owner (ls -n on the host), so pages are not owned by root. The library and every folder mounted into the container must be writable by this user on the host: a folder docker made for a missing path belongs to root, so chown it to match. |
ports |
The web page's port; change the left number to serve it on another. |
command |
Schedule and jobs; see Running Unattended. Keep restart: unless-stopped for restart files. |
A memory limit is optional; one headless Chromium is a few hundred MB per job, so 4 GB is headroom rather than
a target. Pulling or building over an existing tag leaves <none> images; docker image prune clears them.
Not flags on purpose, so they never get baked into a comic's saved command.
| Variable | Effect |
|---|---|
MIRROR_BROWSER_BINARY, MIRROR_DRIVER_BINARY, MIRROR_BROWSER_ARGS
|
Browser, driver and arguments; how the container points Selenium at its Chromium. |
MIRROR_PAGE_TIMEOUT |
Seconds a page may load; default 60. Selenium has no limit, so without it one page can stall the queue. |
MIRROR_BROWSER_IMAGES |
1 lets the browser load images. Off, since images are fetched with requests; for debugging only. |
MIRROR_WEB_PASSWORD |
Password for The Web Page. |
MIRROR_ALLOW_PLUGIN_INSTALLS |
yes lets the web page install, update and remove Scraper Plugins without a password. With a password set, it is not needed. |
MIRROR_CONFIG, MIRROR_ELEMENTS
|
The settings folder and element-path file; see Settings and Metadata. |
MIRROR_LOGS |
Where each comic's output from an update is kept; default logs/ beside the settings folder, /app/logs in the container. Without the scripts mounted, uncomment the compose file's /app/logs volume to keep the logs across a recreate. |
Uncomment the compose file's last volume to run the scripts from a folder on the host instead of the image:
- /path/to/ComicScraper:/appThe mount replaces /app, so the folder must hold the six .py scripts (mirror_base, chapters,
update_comics, adopt_comic, web_ui, run_plugin), web_page/, comiclib/ and a writable config/
(drop the separate settings volume). An empty or missing folder mounts an empty /app and nothing
starts; check before switching. To go back, comment it out and restore the settings volume.
| Changed | Needs |
|---|---|
mirror_base.py, chapters.py, adopt_comic.py, run_plugin.py
|
Nothing; each run starts them afresh, so even a run in progress picks up the change for comics not reached yet. |
web_page/, settings, element paths, a newly adopted comic |
Nothing; read on each page load or each run. |
update_comics.py, web_ui.py, comiclib/
|
A container restart (docker compose restart, your GUI's restart button, or a restart.txt in the library root). |
The image then only carries Python, Chromium and ChromeDriver, and needs pulling again only when those or
requirements.txt change.
QNAP Container Station. Create the container under Applications from the compose file, or run
docker compose up -d over ssh. Library paths are under /share/... (for example /share/Media/Comics).
Container Station rejects mem_limit in the compose file; set memory in the container's Advanced Settings
instead. Building there yourself and failing on a home-directory permission error over ssh:
HOME=/tmp DOCKER_CONFIG=/tmp/.docker docker build ....
Docker Desktop (Windows, macOS). Mount host folders by their full path (C:/Comics:/library or
/Users/you/Comics:/library). user can be left out, since files written to a Windows or macOS folder
take the host user's ownership regardless.