380 lines
25 KiB
Markdown
380 lines
25 KiB
Markdown
# Ansible role: Wikideck
|
||
|
||
Deploy the Wikideck production container to an existing Kubernetes cluster using
|
||
`kubernetes.core.k8s`. The role creates a single-replica Deployment, a persistent
|
||
volume claim, a dedicated ServiceAccount, a ClusterIP Service, and a NetworkPolicy.
|
||
An HTTPS Ingress is optional and disabled by default.
|
||
|
||
**Wikideck is mainnet-first in code but remains an experimental, launch-gated
|
||
candidate; the current production decision is NO-GO.** No public network,
|
||
bootnodes, independent audit, or production readiness is established. The
|
||
application includes validating nodes, fork choice, native NFTs, and encrypted
|
||
local-wallet backup/recovery. Use test wallets and no valuable assets. This role
|
||
deploys a **validator**, never a miner: mining is an explicitly started native CLI
|
||
process outside the browser. Private keys, backups and passwords must stay off
|
||
validator pods and out of Ansible variables. See the upstream
|
||
[mainnet launch gates](https://github.com/ericomeehan/wikideck/blob/main/docs/mainnet-launch.md)
|
||
and [operations/recovery guidance](https://github.com/ericomeehan/wikideck/blob/main/docs/operations-recovery.md).
|
||
|
||
## Requirements
|
||
|
||
- A Linux/macOS/WSL controller with Python 3.10+ and Ansible Core 2.16–2.19
|
||
(the selected Ansible release may require a newer Python).
|
||
- Install controller packages from [requirements.txt](requirements.txt) and the
|
||
collection from [requirements.yml](requirements.yml).
|
||
- A supported Kubernetes cluster with `apps/v1` and `networking.k8s.io/v1` APIs,
|
||
a storage provisioner or an existing PVC, and a NetworkPolicy-capable CNI.
|
||
- Kubeconfig access to create/update/read the resources in the target namespace,
|
||
delete the role's Ingress/NetworkPolicy when disabled, and optionally create a
|
||
Namespace. No cluster-admin access or in-cluster workload RBAC is needed.
|
||
- **A published, immutable image built from Wikideck's production Dockerfile.** There is no
|
||
assumed official registry image. Set `wikideck_image` to your actual tagged or
|
||
preferably digest-pinned image. The role does not build/push images or install a cluster.
|
||
Rebuild from the current source: the image must include Node 24, libstdc++, and
|
||
the native RandomX executable, with `RANDOMX_BINARY` set by the image. An old
|
||
browser-mining image is incompatible. Build and verify for your worker node
|
||
architecture; do not assume a locally built image is multi-architecture. The
|
||
production Dockerfile defaults to mainnet and pins its profile/genesis into the
|
||
image manifest; runtime settings cannot change that identity. Testnet is an
|
||
explicit development fixture, not a public deployment profile.
|
||
- For ingress: an ingress controller, DNS, and a trusted TLS Secret in the app
|
||
namespace. Alternatively, configure cert-manager annotations and an existing
|
||
issuer. The role does not install cert-manager or create an issuer.
|
||
|
||
Install dependencies on the controller with `pip install -r requirements.txt`
|
||
and `ansible-galaxy collection install -r requirements.yml`. Use an isolated Python
|
||
environment. Windows controllers must run Ansible through WSL or Linux containers.
|
||
|
||
## Usage
|
||
|
||
Install this checkout into your playbook's role search path as `roles/wikideck`,
|
||
or install it using an Ansible Galaxy Git role requirement named `wikideck`.
|
||
[examples/playbook.yml](examples/playbook.yml) is the gated HTTPS deployment
|
||
example with ingress-nginx and cert-manager. It requires an approved image
|
||
digest, the image's verified manifest/genesis, launch gates, and real peers before
|
||
it will change the cluster. There is intentionally no ungated, copy-and-run
|
||
mainnet snippet: use a pre-task gate like the example. Empty gates cause the
|
||
application to exit before listening, but do not by themselves prevent Kubernetes
|
||
resources from being created.
|
||
|
||
Run the playbook on the controller, using its normal kubeconfig discovery or
|
||
`wikideck_kubeconfig` / `wikideck_kube_context` overrides. Do not target every
|
||
Kubernetes node: the role operates on the Kubernetes API, not over node SSH.
|
||
|
||
For an explicitly built testnet development image, forward the Service with
|
||
`kubectl -n wikideck port-forward service/wikideck 3001:80` and open
|
||
<http://127.0.0.1:3001>. Keep the forwarding bind address at its loopback default.
|
||
The app allows this local origin. Different hosts, ports, schemes, and browser
|
||
profiles use different browser wallets. This does not bypass mainnet startup gates.
|
||
|
||
For remote browsers, enable ingress and set `wikideck_public_origin` to exactly
|
||
`https://` followed by `wikideck_ingress_host` (no slash or path). HTTPS is needed
|
||
for browser wallet cryptography. Configure HTTP-to-HTTPS redirect at your ingress
|
||
controller; the example includes the ingress-nginx annotation. Ingress creation
|
||
does not wait for DNS, certificate issuance, or an externally reachable endpoint.
|
||
|
||
### Connect validators
|
||
|
||
Set `wikideck_peers` to a list of up to 16 compatible peer HTTPS origins, such as
|
||
`https://peer-a.example.org`. The role joins this list into `WIKIDECK_PEERS`.
|
||
An empty list deliberately starts an **isolated validator**. There is no automatic
|
||
discovery, bootnode list, or automatic reciprocal configuration: configure the
|
||
other operators' nodes too. All nodes must run the same network/genesis/consensus.
|
||
For mainnet, application startup additionally requires at least two distinct
|
||
peer origins (public HTTPS by default), an arrived image-pinned genesis time, the exact chain-ID
|
||
approval, and explicit unaudited-risk acceptance. These switches are not launch
|
||
approval from this role; the project currently records a NO-GO decision. The role
|
||
does not discover or verify peer independence.
|
||
|
||
Peer RPC uses `/p2p/*` on the **same port 3001** as the UI/API; no separate TCP/UDP
|
||
P2P Service or host networking is required. The existing `/` ingress path forwards
|
||
those routes. Keep peer JSON responses uncompressed and do not redirect HTTPS
|
||
peer requests: the client rejects redirects, non-JSON and compressed responses.
|
||
An interactive login gateway on `/p2p/*` will break the current unauthenticated
|
||
peer protocol; use deliberate source restrictions/abuse controls instead.
|
||
|
||
Public peers must use HTTPS and public DNS/IP addresses. Wikideck validates every
|
||
connection's DNS answers and pins the connection to that validated result. Never
|
||
disable TLS verification to work around a certificate or split-horizon DNS error.
|
||
The default policy allows public TCP 443 only when peers are configured. For
|
||
HTTPS peer origins on another port, add that port to
|
||
`wikideck_network_policy_https_ports`, or supply narrowly scoped explicit egress
|
||
rules. Browser Wikimedia image fetches are client-side; validators no longer
|
||
fetch random Wikipedia articles.
|
||
|
||
For an explicitly private testnet or operator-controlled mainnet candidate cluster,
|
||
set `wikideck_allow_private_peers: true`
|
||
and provide `wikideck_network_policy_peer_egress` rules with destination selectors
|
||
and numeric TCP ports. This opt-in permits **both private addresses and HTTP** in
|
||
the application; it does not automatically open network policy. For example:
|
||
|
||
```yaml
|
||
wikideck_peers:
|
||
- http://other-node.games.svc.cluster.local:80
|
||
wikideck_allow_private_peers: true
|
||
wikideck_network_policy_https_to: []
|
||
wikideck_network_policy_peer_egress:
|
||
- to:
|
||
- namespaceSelector:
|
||
matchLabels:
|
||
kubernetes.io/metadata.name: games
|
||
podSelector:
|
||
matchLabels:
|
||
app.kubernetes.io/instance: other-node
|
||
ports:
|
||
- protocol: TCP
|
||
port: 3001
|
||
```
|
||
|
||
The receiving node must separately allow the sender through its ingress policy.
|
||
Service DNAT handling depends on the CNI; the example selects the destination pod
|
||
and its target port 3001 rather than opening all destinations on Service port 80.
|
||
Do not enable private-peer exceptions for public peer configuration. Updated
|
||
mainnet candidate images advertise `privatePeersSupported: true` in their manifest;
|
||
older images reject the private opt-in. Browser HTTPS, chain approval, risk
|
||
acknowledgment and arrived genesis remain mandatory. Private HTTP RPC is not
|
||
authenticated or encrypted; keep it within a trusted cluster boundary or add
|
||
independently configured mesh transport protection.
|
||
|
||
Deploy multiple validators as **separate role instances with different names and
|
||
PVCs** (and separate hostnames if using ingress), not by scaling one Deployment.
|
||
Sharing a machine/cluster/storage failure domain does not provide independent
|
||
operator security. Empty local chains can synchronize from configured peers;
|
||
never seed a second running node by sharing its writable PVC.
|
||
|
||
### Three-node latest candidate playbook
|
||
|
||
[playbooks/wikideck.yaml](playbooks/wikideck.yaml) configures the public `wikideck`
|
||
node plus `wikideck-peer-a` and `wikideck-peer-b` within the same namespace. Each
|
||
uses its own Service and 2 TiB PVC (6 TiB requested in total), reciprocal internal
|
||
DNS peer URLs, scoped validator-pod ingress/egress, and public TCP 443 egress for
|
||
Wikipedia article and Wikimedia statistics requests used by mining templates.
|
||
Standard NetworkPolicy cannot select FQDNs; private address ranges remain excluded
|
||
from that public HTTPS rule. Only the public node gets
|
||
the `wikideck.eom.dev` TLS ingress. All three are created before readiness waits.
|
||
This deploys validators, not miners, and does not establish independent operators.
|
||
|
||
The playbook uses this role checkout directly, not a separately installed older
|
||
Galaxy role. It defaults to `ericomeehan/wikideck:latest` with pull policy `Always`
|
||
and `wikideck_candidate_risk_ack: operator-accepts-unaudited-risk`. This explicit
|
||
candidate workflow is not the digest-pinned public-launch example. Before creating
|
||
ledger resources, a short-lived hardened Kubernetes Job runs the image's
|
||
`--network-manifest` command. The playbook generates `wikideck_candidate_chain_id`
|
||
from its output and rejects older images without private-peer support, non-mainnet
|
||
images, or a future image-baked genesis. The Job is removed even on failure; it
|
||
mounts no ledger, wallet secrets, or service-account token.
|
||
|
||
Rebuild and publish `latest` from the updated application before running this
|
||
playbook. The default Dockerfile genesis is November 1, 2026, 00:00 UTC
|
||
(`1793491200`), so a normal rebuild can start now without custom genesis arguments.
|
||
Older images retain their old genesis; publishing updated source is required.
|
||
Never change the chain identity of an existing ledger without a deliberate backup
|
||
and migration plan. Do not move `latest` while inspection/deployment is in progress:
|
||
all nodes must pull the same image. For reproducible public releases use the
|
||
digest-pinned [examples/playbook.yml](examples/playbook.yml) instead. A mutable tag
|
||
with `Always` is pulled when pods start. The playbook records the inspected
|
||
container image ID in a pod-template annotation, so rerunning after publishing a
|
||
new `latest` triggers a rollout; unchanged image IDs do not force a restart.
|
||
Preserve existing data and keep the same genesis for updates to an operating chain.
|
||
|
||
The controller needs Job creation/deletion and Pod/log reads in addition to the
|
||
role's permissions. Manifest inspection needs a live cluster, so this playbook
|
||
rejects check mode; the role's offline render tests require no cluster credentials.
|
||
|
||
## Variables
|
||
|
||
All defaults are in [defaults/main.yml](defaults/main.yml).
|
||
|
||
| Variable | Default | Description |
|
||
| --- | --- | --- |
|
||
| `wikideck_image` | empty, required | Published image with explicit tag or SHA-256 digest; prefer a verified digest. |
|
||
| `wikideck_name` | `wikideck` | Resource name and instance label; at most 50 characters. |
|
||
| `wikideck_namespace` | `wikideck` | Namespace for all namespaced resources. |
|
||
| `wikideck_create_namespace` | `true` | Create the namespace; disable for a pre-provisioned namespace. |
|
||
| `wikideck_kubeconfig` / `wikideck_kube_context` | `null` | Override controller authentication/context. API TLS verification remains enabled. |
|
||
| `wikideck_wait` / `wikideck_wait_timeout` | `true` / `900` | Wait for Deployment readiness, timeout in seconds. |
|
||
| `wikideck_startup_probe_failure_threshold` | `180` | Failed probes at 5-second intervals before startup restart; default budget 900 seconds. |
|
||
| `wikideck_image_pull_policy` | `IfNotPresent` | `Always`, `IfNotPresent`, or `Never`. |
|
||
| `wikideck_image_pull_secrets` | `[]` | Names of existing registry Secrets in this namespace. |
|
||
| `wikideck_peers` | `[]` | Up to 16 static peer origins; empty means isolated. |
|
||
| `wikideck_allow_private_peers` | `false` | Explicit test-only private/HTTP peer permission. |
|
||
| `wikideck_mainnet_launch` | empty | Exact 64-character chain-ID startup approval; leave empty unless a launch is formally approved. |
|
||
| `wikideck_mainnet_risk_ack` | empty | Must equal `operator-accepts-unaudited-risk` to acknowledge residual risk; not a certification. |
|
||
| `wikideck_public_origin` | empty | Additional allowed HTTPS browser origin; required with ingress. |
|
||
| `wikideck_ingress_enabled` | `false` | Create TLS ingress; disabling removes the role's named ingress. |
|
||
| `wikideck_ingress_host` | empty | DNS hostname, without scheme, port, or path. |
|
||
| `wikideck_ingress_class_name` | empty | Omit to use the cluster default IngressClass. |
|
||
| `wikideck_ingress_annotations` | `{}` | Controller/cert-manager-specific configuration. |
|
||
| `wikideck_tls_secret_name` | `{{ wikideck_name }}-tls` | Existing or externally provisioned TLS Secret. |
|
||
| `wikideck_existing_claim` | empty | Use an existing PVC instead of creating one. |
|
||
| `wikideck_storage_size` | `1Gi` | Requested PVC capacity; resizing requires StorageClass support. |
|
||
| `wikideck_storage_class` | `null` | `null`: cluster default; empty string: no class; otherwise a class name. |
|
||
| `wikideck_storage_access_modes` | `[ReadWriteOnce]` | `ReadWriteOnce` or `ReadWriteOncePod`; never `ReadWriteMany`. |
|
||
| `wikideck_resources` | see defaults | CPU/memory requests `250m`/`512Mi`, limits `1`/`1Gi`; small-validator starting point, not a capacity guarantee. |
|
||
| `wikideck_node_selector` / `wikideck_tolerations` / `wikideck_affinity` | `{}` / `[]` / `{}` | Pod placement settings. |
|
||
| `wikideck_trusted_proxies` | `[]` | Up to 16 literal proxy IPs/CIDRs; only trust actual edge source addresses after the edge overwrites forwarded headers. |
|
||
| `wikideck_ops_port` | empty | Optional port for a diagnostics listener bound only to container loopback; never add it to the Service, Ingress, or NetworkPolicy. |
|
||
| `wikideck_network_policy_enabled` | `true` | Manage network isolation; disabling deletes this role's policy. |
|
||
| `wikideck_network_policy_ingress_from` | same-namespace pods | List of NetworkPolicy peers allowed to reach TCP 3001; empty list denies all ingress. |
|
||
| `wikideck_network_policy_dns_to` | `kube-system` namespace | DNS peers allowed on UDP/TCP 53; adapt for custom/NodeLocal DNS. |
|
||
| `wikideck_network_policy_https_to` | public IPv4/IPv6 ranges, private/link-local excluded | Public peer destinations; omitted when there are no configured peers. |
|
||
| `wikideck_network_policy_https_ports` | `[443]` | Public peer TCP ports; extend for custom HTTPS origins. |
|
||
| `wikideck_network_policy_peer_egress` | `[]` | Additional explicit `to` + numeric TCP `ports` rules, emitted only with configured peers. |
|
||
|
||
`wikideck_offline` / `WIKIDECK_OFFLINE` have been removed. The current catalog is
|
||
fixed and genesis-bound, not a live Wikipedia feed. Remove the old role variable;
|
||
it no longer controls networking. The image's packaged `RANDOMX_BINARY` and default
|
||
entrypoint are deliberately preserved; no production fake-PoW fallback is added.
|
||
|
||
## Storage and safe updates
|
||
|
||
- Exactly **one replica** and **Recreate** updates are deliberate and cannot be
|
||
changed through role variables. Updates briefly interrupt service. Do not add
|
||
an HPA, manually scale, or attach the same chain PVC to another writer.
|
||
- `ReadWriteOnce` alone does not enforce a single pod on the same node. Prefer
|
||
`ReadWriteOncePod` if supported by your CSI driver. Do not force-delete an old
|
||
pod on a partitioned node until it has been fenced; Recreate is not a
|
||
distributed storage lock.
|
||
- The active ledger is SQLite at `/app/data/<profile>/ledger.sqlite` (with WAL
|
||
sidecars); `/app/data/<profile>-node.lock` exclusively locks that profile's data.
|
||
A matching legacy `ledger.json` may be imported once and is retained as a
|
||
recovery copy. The import path accepts at most 128 MiB and 10,000 blocks; these
|
||
are legacy-import limits, not live SQLite disk bounds. Different profiles and
|
||
chain identities must not share a writable claim. Preserve and back up existing
|
||
data before changing image profile or genesis; incompatible chain data fails
|
||
closed rather than resetting automatically.
|
||
The process runs
|
||
as UID/GID 1000 with `fsGroup: 1000`. Your storage driver must honor ownership
|
||
settings, or the existing volume must already be writable by this identity.
|
||
No privileged/root ownership-fixing init container is used.
|
||
- The PVC is created before the Deployment without waiting, supporting
|
||
`WaitForFirstConsumer` storage classes. Existing claims are not modified.
|
||
- The role never deletes PVCs or Namespaces, and does not assign ownerReferences
|
||
that would garbage-collect storage with the Deployment. Renaming resources or
|
||
switching claims does not migrate data or remove previous resources.
|
||
- Back up the chain before upgrades. Stop the Deployment for a consistent file
|
||
backup or use your CSI provider's documented snapshot procedure. Encrypt disks
|
||
and backups, define retention, and test restores. Deleting a namespace or PVC
|
||
can still destroy data depending on the underlying reclaim policy.
|
||
- The current `node:backup` utility creates/verifies/restores ledger-only packages
|
||
while the node is stopped. It does not contain browser wallets, secrets, or
|
||
configuration, and it does not encrypt the package; store it in restricted,
|
||
encrypted off-host storage and verify a restore before relying on it.
|
||
- Full native RandomX revalidation runs before the server listens. Increase
|
||
`wikideck_startup_probe_failure_threshold` and `wikideck_wait_timeout` together
|
||
for your measured replay time, leaving scheduling/image-pull margin. A healthy
|
||
empty node does not exercise the native cache or prove peer synchronization.
|
||
- SQLite avoids whole-ledger JSON rewrites, but the node retains DAG records in
|
||
memory, rebuilds state roots over the full NFT set, and revalidates proofs at
|
||
startup. Long-chain capacity and archival-scale operation remain unresolved;
|
||
a larger PVC does not fix memory, replay, or consensus-capacity limits.
|
||
|
||
### Crash recovery and resource sizing
|
||
|
||
The application removes its lock on graceful shutdown but deliberately does
|
||
**not** automatically recover a stale lock after an OOM kill, forced termination,
|
||
node loss, or interruption during startup replay. Kubernetes restarts can remain
|
||
in CrashLoopBackOff until an operator intervenes. This role never deletes the lock
|
||
in an init container or as an automatic "repair".
|
||
|
||
To recover, first stop the Deployment and verify every former owner is gone;
|
||
fence an unreachable old node before mounting the claim elsewhere. Take a backup,
|
||
then remove only the confirmed stale lock using an approved maintenance pod or
|
||
storage procedure. Preserve the ledger, restore the Deployment to one replica,
|
||
and inspect replay and peer status. Do not automatically remove locks based on
|
||
their PID: PIDs are reused and isolated between containers.
|
||
|
||
Each validator uses native **light-mode RandomX**, requiring a 256 MiB cache plus
|
||
scratchpad, Node heap, ledger states, and process overhead. The new 1 GiB limit
|
||
matches the updated upstream Compose starting budget, but must be measured against
|
||
your ledger, peer load and replay. Watch OOM events, CPU throttling, replay time,
|
||
and block propagation. Fast miners need **over 2.3 GiB per process** and separate
|
||
capacity/security planning; this role never launches one or mounts its wallet.
|
||
|
||
## Security and networking
|
||
|
||
The workload uses a read-only root filesystem, drops all Linux capabilities,
|
||
disallows privilege escalation, uses runtime-default seccomp, and has no mounted
|
||
service account token or RBAC grants. Only persistent data and a 32 MiB memory
|
||
temporary directory are writable. All three HTTP probes target `/healthz` on port
|
||
3001; Kubernetes does not use the image's Docker HEALTHCHECK. A 30-second grace
|
||
period accommodates the application's 25-second shutdown deadline.
|
||
|
||
NetworkPolicy defaults allow same-namespace clients, cluster DNS in `kube-system`,
|
||
and public HTTPS only when peer origins are configured. With ingress, allow the ingress
|
||
controller's namespace/pods as shown in the example. Peer entries are additive
|
||
OR alternatives: put a namespaceSelector and podSelector in the **same entry** to
|
||
restrict pods within that namespace. Empty peer lists deny that traffic; empty
|
||
peer objects are rejected to avoid accidentally allowing every source/destination.
|
||
|
||
Standard NetworkPolicy cannot allow peer origins by hostname; public
|
||
TCP 443 egress is broader than the app's fixed peer allowlist. Narrow CIDRs or use CNI FQDN policies or an
|
||
egress gateway if required. Policies are additive with any other policies in the
|
||
namespace and have no effect without an enforcing CNI. NodeLocal DNS, host-network
|
||
ingress controllers, service meshes, and private proxies may need peer changes.
|
||
|
||
TLS terminates at ingress; backend HTTP is private but **not encrypted by this
|
||
role**. Use a properly configured service mesh if in-cluster encryption is
|
||
required. TLS keys and registry credentials must be provisioned separately, not
|
||
committed to playbooks. Use trusted, rotated certificates and retain Kubernetes
|
||
API certificate verification. The role does not embed secrets or implement its
|
||
own cryptography; image signature verification and encrypted storage are cluster
|
||
operator responsibilities. Scan and rebuild the application image regularly.
|
||
|
||
Native RandomX uses ordinary memory allocations and secure W^X JIT; the current
|
||
app does not request huge pages, host devices, executable files in `/tmp`, or
|
||
privileged capabilities. Keep the existing hardening. Verify actual hashing on
|
||
your worker architecture and runtime security profile; HTTP health alone cannot
|
||
detect every native engine failure. Do not grant privileged mode or disable
|
||
seccomp as an untested performance workaround.
|
||
|
||
`WIKIDECK_TRUSTED_PROXIES` is empty/untrusted by default. Populate
|
||
`wikideck_trusted_proxies` only with the literal source addresses/CIDRs actually
|
||
used by the trusted edge; the app validates them at startup. The edge must
|
||
overwrite forwarded headers, and network controls must prevent direct backend
|
||
access. Do not copy a generic proxy range without verifying the cluster path.
|
||
The optional `WIKIDECK_OPS_PORT` listener is loopback-only inside the pod and is
|
||
not exposed by role resources. It is intended for local/container-exec checks,
|
||
not an ingress endpoint. The role adds no authentication, WAF, or abuse
|
||
protection. Eclipse,
|
||
majority-hashpower, spam/DoS and reorganization risks remain application/protocol
|
||
issues; deployment hardening does not make a public mainnet safe.
|
||
|
||
## Validation
|
||
|
||
[tests/render.yml](tests/render.yml) runs entirely offline: it validates inputs,
|
||
renders/parses every template across default, ingress, existing-claim, storage
|
||
class, isolated/public/private peers, custom HTTPS ports, deny-all, longer startup,
|
||
digest-image, launch-gate, proxy-trust and diagnostics variants, and checks
|
||
wiring/security invariants. It also checks that unsafe/invalid settings are rejected. Run it with
|
||
`ansible-playbook -i tests/inventory tests/render.yml`.
|
||
|
||
[tests/test.yml](tests/test.yml) is a real-cluster smoke test using the local
|
||
checkout. Syntax-check it with `ansible-playbook -i tests/inventory tests/test.yml --syntax-check`.
|
||
To deploy to a disposable test namespace, run it with
|
||
`ansible-playbook -i tests/inventory tests/test.yml -e wikideck_image=YOUR_IMAGE -e wikideck_namespace=wikideck-test`.
|
||
Run it a second time to verify idempotence. Check Pod readiness, `/healthz`, PVC
|
||
retention across updates, DNS/peer egress, TLS, and wallet/transfer flows on your
|
||
chosen cluster. `/healthz` is only process health, not sync readiness. Inspect
|
||
`/api/peers` for connected peers and `/p2p/status` for matching network, chainId and
|
||
tip across independently deployed nodes. `/api/peers` exposes configuration;
|
||
apply your access policy deliberately. Offline tests do not prove CSI/CNI/controller
|
||
behavior or consensus safety. Mining a real block is a separate explicit-consent
|
||
test; it must not be part of routine deployment or health probes.
|
||
|
||
[tests/runtime-smoke.mjs](tests/runtime-smoke.mjs) is a disposable image-level
|
||
check: it runs the native known-vector self-test (hashing, **not mining**), checks
|
||
node API health, and verifies graceful lock cleanup and restart durability. Mount
|
||
it read-only and invoke Node inside the current image with disposable writable
|
||
data and no network. It does not use or modify a real chain or wallet.
|
||
|
||
Ansible check mode (`--check --diff`) is supported by the Kubernetes module, but
|
||
still needs API access; creating a new namespace in check mode may require a
|
||
separate namespace provisioning pass. No uninstall or automatic data deletion is
|
||
provided.
|
||
|
||
## License
|
||
|
||
MIT-0. See [LICENSE](LICENSE). The application and Wikipedia/Wikimedia content
|
||
retain their own upstream licenses and attribution requirements.
|