Skip to content

Patching

Omniglass compiles Zabbix from source using the zabbix-docker build system, injecting source patches at build time. If a patch fails to apply, the build fails. If Zabbix ships the feature upstream, the patch is removed.

RepoPurpose
zabbix/zabbixUpstream source (read-only)
hyperscaleav/zabbixFork for patch development
zabbix/zabbix-dockerBuild system (cloned at build time, not forked)
hyperscaleav/omniglassProduct repo; carries .patch files as build artifacts

The build-zabbix.sh script:

  1. Clones zabbix-docker at the tag matching ZABBIX_VERSION
  2. Copies patches/*.patch into the build-pgsql patches directory
  3. Runs docker buildx bake which clones Zabbix source, applies patches with patch -p1, and compiles everything

One build produces all patched component images: server, web, proxy. Schema changes in schema.tmpl are compiled into create.sql.gz and schema.inc.php automatically.

Omniglass Dockerfiles then layer branding, modules, and configuration on top of the patched base images.

patches/ # Zabbix source modifications
0000-security-deps.patch # Composer/dependency CVE fixes
0001-sla-severity.patch # Feature patches (future)
components/core/db/migrations/ # Omniglass-owned schema (dbmate)
20260211052804_create_omniglass_schema.sql # Sequential, tracked, run once
...

Ownership boundary:

  • patches/*.patch = modifications to Zabbix (applied at build time, removed when upstream ships the feature)
  • components/core/db/migrations/ = tables Omniglass owns (applied at runtime by dbmate)
Terminal window
cd /path/to/zabbix-fork
git fetch origin --tags
git checkout 7.4.8
git checkout -b omniglass/my-feature
Terminal window
git diff 7.4.8 > /path/to/omniglass/patches/NNNN-my-feature.patch

Patches are applied in alphabetical order by numeric prefix (0000-, 0001-, etc.).

Terminal window
rm -rf /tmp/zabbix-docker-* # clear cache if patches changed
make build # full build: zabbix base + omniglass layers
make test-e2e
Terminal window
cd /path/to/zabbix-fork
git push omniglass omniglass/my-feature
git tag omniglass/7.4.8/my-feature
git push omniglass omniglass/7.4.8/my-feature
  1. git fetch origin --tags in the Zabbix fork
  2. Rebase each omniglass/* branch onto the new tag
  3. Regenerate patches with git diff <new-tag>
  4. make set-zabbix-version VERSION=<new-version>
  5. rm -rf /tmp/zabbix-docker-* (clear build cache)
  6. make build && make test-e2e
  • og_ prefix for all columns added to Zabbix tables (avoids namespace collisions)
  • 0000-security-deps.patch for dependency CVE fixes (always first alphabetically)
  • NNNN-feature-name.patch for feature patches (numeric prefix controls apply order)
  • Patch branches in the fork: omniglass/<feature>
  • Tags after generating patches: omniglass/<version>/<feature>

All Alpine-based images build on Docker Hardened Images (DHI). DHI images ship with near-zero CVEs, continuous patching, and SLSA Build Level 3 provenance. The free tier is Apache 2.0 licensed with no usage restrictions.

dhi.io/alpine-base:3.23-dev # DHI hardened Alpine (FROM in zabbix-base-alpine Dockerfile)
-> omniglass-zabbix-base-alpine:latest # Compatibility shim (restores missing system groups)
-> zabbix-build-base # Toolchain (compilers, headers, Go)
-> zabbix-build-pgsql # Patched Zabbix source compilation
-> zabbix-build-sqlite3 # Patched Zabbix source compilation (proxy)
-> zabbix-server-pgsql # Server runtime
-> zabbix-web-nginx-pgsql # Web frontend runtime
-> zabbix-proxy-sqlite3 # Proxy runtime

The omniglass-zabbix-base-alpine shim exists because DHI strips system groups and users that stock Alpine includes (e.g. dialout). Upstream zabbix-docker Dockerfiles expect these to exist. The shim restores only what is actually needed, keeping the zabbix-docker clone unmodified.

  1. build-zabbix.sh builds scripts/zabbix-base-alpine.Dockerfile, which layers compatibility fixes on top of the DHI image and tags it as omniglass-zabbix-base-alpine:latest
  2. The tag is passed as OS_BASE_IMAGE to all three docker buildx bake phases
  3. zabbix-docker Dockerfiles consume it as their FROM without modification

The patching strategy is designed so that the zabbix-docker clone requires zero modifications beyond injecting .patch files into the patches directory:

  • Base image override: Handled via --set "*.args.OS_BASE_IMAGE" at bake time, not by editing Dockerfiles
  • Missing system groups: Handled by the zabbix-base-alpine shim layer, not by sed-patching Dockerfiles
  • Source patches: Copied into the existing patches directory that zabbix-docker already reads from

This means rm -rf /tmp/zabbix-docker-* and a fresh clone always produces a working build.

  1. Update the FROM line in scripts/zabbix-base-alpine.Dockerfile
  2. Update DHI image tags in components/core/Dockerfile, components/gateway/Dockerfile, and components/zabbix-proxy-sqlite3/Dockerfile
  3. rm -rf /tmp/zabbix-docker-* (clear build cache)
  4. make build && make test-e2e
  5. If the build fails on a missing group or user, add it to zabbix-base-alpine/Dockerfile

Other Omniglass components use DHI images directly in their own Dockerfiles:

ComponentBase image
coredhi.io/golang (build) + dhi.io/alpine-base (runtime)
gatewaydhi.io/nginx
zabbix-proxy-sqlite3dhi.io/golang (Go builder stage only)
noderednodered/node-red (vendor image, not swappable)

These do not go through the zabbix-base-alpine shim since they don’t consume zabbix-docker Dockerfiles.

  • Patches are generated artifacts. Never hand-edit a .patch file.
  • Patches are applied alphabetically by filename. Use numeric prefixes to control order.
  • Schema changes to Zabbix tables go through source patches on schema.tmpl, not runtime migrations.
  • Omniglass-owned tables go through dbmate migrations, not source patches.
  • Every patch branch in the fork must be tagged with the Zabbix version it was generated against.