99 lines
6.0 KiB
Markdown
99 lines
6.0 KiB
Markdown
# Build networking, cache and CI
|
|
|
|
### Build networking and cache
|
|
|
|
The runtime uses an official Python 3.14 Alpine 3.24 image pinned by digest,
|
|
locked Python dependencies, and `font-noto-cjk` for Chinese rendering. APK
|
|
repository signatures and offline wheel SHA256 checks remain enabled.
|
|
Production uses `scripts/build-verify.sh`; CI uses `scripts/ci-compose-verify.py`.
|
|
Both build the same Dockerfile with BuildKit and `docker compose build --pull`.
|
|
|
|
`ALPINE_MIRROR` accepts a mirror host (without scheme or path), defaulting to
|
|
`dl-cdn.alpinelinux.org`. For mainland-China builds:
|
|
|
|
```sh
|
|
. ./deploy/build-cn.env
|
|
./scripts/build-verify.sh
|
|
```
|
|
|
|
CI uses this profile; the Gitea `ALPINE_MIRROR` repository variable can override
|
|
it. APK upgrades available packages during a fresh dependency-layer build.
|
|
Use `docker compose build --pull --no-cache` to refresh OS packages explicitly.
|
|
|
|
Layer order is pinned base → APK/fonts → requirements → Python dependencies
|
|
→ application source → metadata. BuildKit caches pip downloads separately for
|
|
musl and architecture. Optional `build-cache/wheels/` must contain compatible
|
|
musllinux wheels and their SHA256 manifest; empty-cache builds work normally.
|
|
Do not reuse Debian/manylinux wheels on Alpine. Caches are disposable builder
|
|
resources and are not runtime mounts or dependencies.
|
|
|
|
### CI with a host Docker socket
|
|
|
|
The managed CI runner runs on Ubuntu Server; the NAS no longer executes jobs.
|
|
It retains `ubuntu-latest` compatibility and fixed runner/job image digests,
|
|
accepts one job at a time, and limits each task container to 4 CPUs and 8 GiB.
|
|
The runner's private state resides on the guarded business disk. Its systemd
|
|
service checks the mount identity before starting. Registration credentials are
|
|
supplied through a temporary file and removed after registration; the daemon
|
|
container does not retain the reusable registration token in its environment.
|
|
Keep the current runner and job images even when no task is executing: they are
|
|
active CI dependencies. Only trusted repository events may reach this runner's
|
|
Docker socket; CI does not automatically deploy production or write to frames.
|
|
|
|
Run `python scripts/ci-compose-verify.py` after loading the build mirror profile.
|
|
The script derives a temporary Compose document from production settings, with
|
|
an absolute client-side build context, a UUID project name, a unique CI image
|
|
tag, and project-scoped `data` / `config` named volumes. It removes production
|
|
bind mounts, the fixed container name, host ports, and the production `.env`
|
|
reference. A fresh test token, mock driver, and disabled device writes are
|
|
explicitly configured. Docker initializes empty named volumes from the image's
|
|
owned `/data` and `/config` directories; the service remains UID/GID 10333.
|
|
|
|
Build contexts are sent by the Docker client, so the job workspace can remain
|
|
inside the job container. Runtime storage is managed by the daemon; no matching
|
|
Docker host `/workspace` directory is needed. HTTP readiness and the unmodified
|
|
nine-endpoint smoke script run inside the service with `compose exec -T`.
|
|
Restart is followed by another readiness check and the same smoke test.
|
|
|
|
A `finally` block removes the test containers, network, volumes, and unique
|
|
image tag on success or failure. The workflow records the private temporary
|
|
Compose path in `GITHUB_ENV` and repeats cleanup in an `always()` step, covering
|
|
normal cancellation/interruption. Failed cleanup retains the manifest so the
|
|
fallback can retry. Abrupt host/daemon loss or a forcibly terminated entire job
|
|
can prevent both cleanup paths; no CI script can guarantee cleanup in that case.
|
|
No global prune or production resource removal is performed. Keep builder
|
|
caches: only the run-specific image tag is removed.
|
|
|
|
### CI Job pip indexes versus Docker build indexes
|
|
|
|
The Job bootstrap runs `python scripts/ci-install.py` before Ruff/mypy/tests.
|
|
It needs only the Python standard library, so it runs before PyYAML or tooling
|
|
is installed. `CI_PIP_INDEX_URL` and `CI_PIP_FALLBACK_INDEX_URL` are optional
|
|
Gitea repository variables. Defaults are the TUNA HTTPS PyPI simple endpoint
|
|
and official `https://pypi.org/simple`. Each is attempted separately; the
|
|
fallback repeats the unchanged editable `.[test]` installation, including
|
|
PEP 517 build isolation and `setuptools>=75`. No simultaneous extra index is
|
|
used, no build dependency is removed, and both failures fail CI.
|
|
|
|
Logs show inherited index/config/proxy hosts and the selected index host for
|
|
each attempt, with URL credentials and query strings removed. Bootstrap
|
|
disables inherited pip config files via `PIP_CONFIG_FILE=/dev/null`, explicitly
|
|
sets the selected index, and clears no-index/extra-index/find-links, insecure
|
|
trusted-host, and no-build-isolation environment settings. Constraints, TLS
|
|
certificate environment settings, and proxy settings remain in effect.
|
|
|
|
These `CI_PIP_*` settings apply only to the Job's pip install. They are not
|
|
passed into Docker build arguments or persisted into the production image.
|
|
The Dockerfile keeps its own cached/offline dependency installation and logs
|
|
the Docker pip index host for online installs. The Alpine mirror variable affects
|
|
APK only and are loaded later in the Docker verification step.
|
|
|
|
If dependency installation fails, the always() cleanup step still executes.
|
|
It skips the Python/PyYAML cleanup script when no CI Compose manifest exists,
|
|
as no Docker verification resources have been created at that point.
|
|
|
|
|
|
### Verified prebuilt production image
|
|
|
|
When the production host cannot reach the registry, build the complete Dockerfile in a trusted build environment and transfer it with `docker image save` / `docker image load`. Supply the immutable `sha256:` image ID privately as `FRAME_FLOW_PREBUILT_IMAGE_ID` to `scripts/server-release.py`. The expected version/commit tag must already exist. The script checks the ID, version and revision labels, then verifies runtime source and license hashes in an isolated container without production mounts before switching the service. Existing storage checks, backups, post-deployment verification and rollback remain in effect.
|