High Availability
artifacthub-shim can run multiple API replicas behind one Kubernetes Service.
Use this mode to improve read availability and spread resolver/UI traffic across
pods.
TOC
What HA meansBaseline HA valuesSizing and load modelRepository ConfigMaps in HAChoose a storage modeOperational checklistProbes and initial syncWhat HA means
Each replica is an independent read server:
- It watches the same repository configuration.
- It refreshes catalog sources into its own source work directory.
- It builds and publishes its own immutable read snapshot.
- It serves requests only after its first snapshot is ready.
This model provides read redundancy and read traffic distribution. It does not provide leader election, a shared runtime metadata index, or a single coordinated source refresher. Repository changes can become visible on different replicas at slightly different times while each pod completes its own refresh cycle.
Baseline HA values
Use this profile for normal offline catalog deployments and small to medium custom catalog sets:
The baseline keeps the HA deployment simple:
- Three replicas provide redundancy for in-cluster clients.
- A longer refresh interval reduces repeated Git and indexing load across pods.
maxConcurrentSources: 2limits each pod to two concurrent source loads.- UI RBAC cache and Kubernetes client limits reduce repeated TokenReview and SubjectAccessReview pressure from UI traffic.
- ContentStore stays disabled so no shared runtime storage is required.
- The resource baseline leaves room for refresh-time memory overlap in typical offline catalog deployments.
ClusterIPkeeps traffic internal for Tekton resolver and DevOps UI paths.
Sizing and load model
config.maxConcurrentSources is a per-pod limit. In HA mode, cluster-wide
source refresh concurrency is approximately:
For the baseline values, the cluster may load about 3 * 2 = 6 sources at the
same time during a refresh cycle. Increase this value only when refresh latency
is a real problem and the Git server, API server, CPU, memory, and disk I/O
budget can absorb the additional load.
For ConfigMap-backed Git sources, a source means one nested
gitRepositories[].repositories[] entry in repository.yaml, not one ConfigMap
object. A single ConfigMap can declare multiple externally visible repositories,
and each entry is loaded and indexed as an independent source during refresh.
When estimating HA load, count the total number of repository entries across all
labeled ConfigMaps.
Keep resource requests realistic. The baseline 512Mi memory request and 1Gi
memory limit are a starting point, not a capacity guarantee. Each replica builds
its own snapshot and, when ContentStore is disabled, keeps manifest and README
payloads in memory. Refreshes can temporarily hold the current serving snapshot
and the next snapshot at the same time.
For many ConfigMap-backed Git sources, large README payloads, or large catalog sets with ContentStore disabled, use a larger profile:
Repository ConfigMaps in HA
Use multi-repository ConfigMaps for entries that are operationally owned
together, such as task, pipeline, and stepaction paths from the same
Git repository and team.
Avoid putting unrelated teams or high-risk repositories into one ConfigMap. If
any gitRepositories[] item or nested repositories[] item in a ConfigMap is
invalid, artifacthub-shim rejects the whole ConfigMap payload. Splitting
independent repositories into separate ConfigMaps limits the blast radius of a
bad URL, invalid path, duplicate name, or credential reference.
Choose a storage mode
sourceWorkDir stores materialized source checkouts and provider caches. It can
be made persistent to reduce pod-recreation cost for large external repository
sources, but it does not store a ready-to-serve metadata index. Each pod still
fetches or validates the requested revision, scans source files, and rebuilds its
own snapshot before becoming ready. In HA mode, sourceWorkDir must stay
pod-local because Git checkouts are mutable runtime state.
ContentStore stores manifest and README payload bytes; it does not store the metadata index or coordinate replicas. Each pod still builds and keeps its own metadata index, package maps, search tokens, source status, and hot payload cache.
Enable ContentStore only when all of these are true:
- There are many configured repositories or very large manifest/README payloads.
- Pod memory pressure is visible and attributable to payload storage.
- The operational cost of additional storage configuration is acceptable.
If ContentStore must be enabled with multiple replicas, prefer pod-local
emptyDir:
Avoid PVC-backed runtime storage in HA mode. The chart rejects
replicaCount>1 when ContentStore uses pvc or existingPVC. Keep
replicaCount: 1 for those storage modes:
For existingPVC, set a soft limit because the chart cannot infer the claim
capacity:
Operational checklist
UI-compatible endpoints use the shared request authentication chain. In HA mode, the authorization cache is per pod, so repeated requests that land on different replicas may still perform separate platform, OIDC, or Kubernetes reviews.
Use this checklist when enabling or validating HA:
- Confirm every replica reaches
/readyzbefore treating the Service as ready for resolver or UI traffic. - Load test through the Kubernetes Service, not by connecting to a single pod.
- Watch Git server load, Kubernetes API throttling, CPU, memory, and disk I/O during initial sync and background refresh.
- Keep
config.uiRBACCacheTTLenabled for normal UI traffic. Increaseconfig.kubeClientQPSandconfig.kubeClientBurstonly when metrics or logs show client-side throttling during UI list/detail requests. - Add scheduling rules that spread replicas across nodes or zones according to the cluster policy.
For example, spread replicas across nodes with pod anti-affinity:
Probes and initial sync
The API server starts before the initial source refresh completes. /healthz
reports process liveness, while /readyz returns success only after the first
snapshot has been published. This lets Kubernetes keep the process alive during
large initial syncs while keeping the Service endpoint unready. Source-level
failures in the first refresh are published as source statuses in the snapshot
instead of keeping the pod unready indefinitely.
The chart also exposes configurable startupProbe, livenessProbe, and
readinessProbe values. The default startupProbe is disabled because the
server listens before the initial refresh. Enable it when your environment has
slow image startup, slow catalog init containers, or storage paths that can
delay the process before it starts listening: