provisioning-catalog/components/zot/cluster/install-zot.sh

120 lines
6.3 KiB
Bash
Raw Permalink Normal View History

#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# shellcheck source=/dev/null
[ -f "${SCRIPT_DIR}/env-zot" ] && source "${SCRIPT_DIR}/env-zot"
[ -f "${SCRIPT_DIR}/_credentials.env" ] && source "${SCRIPT_DIR}/_credentials.env"
# env-zot rendered from zot.ncl by the orchestrator (run_taskserv).
[ -f "${SCRIPT_DIR}/env-zot" ] && source "${SCRIPT_DIR}/env-zot"
ZOT_NAMESPACE="${ZOT_NAMESPACE:-registry}"
ZOT_IMAGE="${ZOT_IMAGE:-ghcr.io/project-zot/zot-linux-arm64:v2.1.18}"
ZOT_PORT="${ZOT_PORT:-5000}"
ZOT_DATA_DIR="${ZOT_DATA_DIR:-/var/lib/data/zot}"
ZOT_STORAGE_CLASS="${ZOT_STORAGE_CLASS:-longhorn-retain}"
ZOT_STORAGE_SIZE="${ZOT_STORAGE_SIZE:-5Gi}"
ZOT_NODE_PORT="${ZOT_NODE_PORT:-30500}"
# No hardcoded bucket fallback: absent/empty ZOT_S3_BUCKET means storage_backend.kind
# = "local" (see zot.ncl) — a hardcoded default here would silently re-enable S3 for
# every deploy that declares local storage, since env-zot sets this var to "" (not
# unset) and `:-` treats empty the same as unset. That's exactly what happened
# 2026-07-06: zot.ncl had said kind=local for a while, but this fallback kept
# regenerating an S3 storageDriver config anyway, invisibly, until a routine
# redeploy restarted the pod and it tried (and failed) to auth against a bucket
# nothing had pointed at in months.
ZOT_S3_BUCKET="${ZOT_S3_BUCKET:-}"
ZOT_S3_REGION="${ZOT_S3_REGION:-eu-central-1}"
ZOT_S3_ENDPOINT="${ZOT_S3_ENDPOINT:-}"
ZOT_S3_PATH_STYLE="${ZOT_S3_PATH_STYLE:-true}"
ZOT_S3_ACCESS_KEY="${ZOT_S3_ACCESS_KEY:-}"
ZOT_S3_SECRET_KEY="${ZOT_S3_SECRET_KEY:-}"
# htpasswd content — when set, creates zot-auth secret and enables auth in config
ZOT_HTPASSWD="${ZOT_HTPASSWD:-}"
# TLS: name of an existing k8s secret with tls.crt + tls.key — when set, enables TLS in config
ZOT_TLS_SECRET="${ZOT_TLS_SECRET:-}"
# Gateway API — two modes:
# terminate (default) Gateway terminates TLS with ZOT_GATEWAY_CERT_SECRET in ZOT_TLS_NAMESPACE
# (workload ns by default; ReferenceGrant authorizes the cross-ns read when
# ZOT_TLS_NAMESPACE != ZOT_GATEWAY_NAMESPACE).
# Zot runs plain HTTP. HTTPRoute routes HTTPS traffic. Cert rotation does not restart Zot.
# Good when: you want path-level routing, WAF, rate limiting, or selective public exposure.
# passthrough Gateway routes raw TLS by SNI. Zot terminates TLS via ZOT_TLS_SECRET.
# Requires TLSRoute CRD (experimental channel):
# kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.1/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml
# Good when: e2e encryption is required or the gateway must remain opaque.
ZOT_GATEWAY_ENABLED="${ZOT_GATEWAY_ENABLED:-false}"
ZOT_GATEWAY_MODE="${ZOT_GATEWAY_MODE:-terminate}"
ZOT_GATEWAY_IP="${ZOT_GATEWAY_IP:-}"
# When set, the gateway shares the given IP with other gateways via Cilium LB IP sharing.
# A dedicated CiliumLoadBalancerIPPool is NOT created; the existing pool for that IP is reused.
# Use the infrastructure.annotations form (io.cilium/lb-ipam-ips + lbipam.cilium.io/sharing-key).
ZOT_GATEWAY_SHARING_KEY="${ZOT_GATEWAY_SHARING_KEY:-}"
ZOT_GATEWAY_CERT_SECRET="${ZOT_GATEWAY_CERT_SECRET:-}"
ZOT_GATEWAY_NAMESPACE="${ZOT_GATEWAY_NAMESPACE:-kube-system}"
# TLS resources (Certificate + Secret) live with the workload by default.
# When ZOT_TLS_NAMESPACE != ZOT_GATEWAY_NAMESPACE, a ReferenceGrant is emitted
# in ZOT_TLS_NAMESPACE granting Gateways in ZOT_GATEWAY_NAMESPACE permission to
# read the secret cross-namespace (Gateway API contract).
ZOT_TLS_NAMESPACE="${ZOT_TLS_NAMESPACE:-${ZOT_NAMESPACE}}"
# Cloudflare DNS-01 token — required when cert-manager is used. Created as Secret
# in cert-manager namespace, referenced by ClusterIssuer.spec.acme.solvers[0].dns01.
ZOT_CF_DNS_TOKEN="${ZOT_CF_DNS_TOKEN:-}"
ZOT_CF_DNS_SECRET_NAME="${ZOT_CF_DNS_SECRET_NAME:-dns-cloudflare}"
ZOT_GATEWAY_HOSTNAME_UI="${ZOT_GATEWAY_HOSTNAME_UI:-reg.librecloud.online}"
ZOT_GATEWAY_HOSTNAME_REG="${ZOT_GATEWAY_HOSTNAME_REG:-termas.librecloud.online}"
ZOT_COSIGN_PUBKEY_PATH="${ZOT_COSIGN_PUBKEY_PATH:-}"
# Path to a JSON file produced by the workspace's deploy recipe (nickel export of multi_tenant.policies).
# Schema: { "<namespace>/**": { read: [...], write: [...], anonymous_read: bool } }
# When set, install-zot reads per-namespace ACL from this file instead of relying on defaults.
ZOT_REPOSITORIES_FILE="${ZOT_REPOSITORIES_FILE:-}"
ZOT_ADMIN_USER="${ZOT_ADMIN_USER:-regadm}"
ZOT_ADMIN_PASS="${ZOT_ADMIN_PASS:-}"
# Public gateway to patch with the registry listener.
# When set, an HTTPS listener for ZOT_GATEWAY_HOSTNAME_REG is added to this shared gateway
# (following the lbipam sharing pattern used by odoo/jesusperez tenants) and a separate
# zot-public HTTPRoute is created so external clients reach Zot without VPN access.
# Leave empty when registry exposure is private-only.
ZOT_PUBLIC_GATEWAY_NAME="${ZOT_PUBLIC_GATEWAY_NAME:-}"
ZOT_PUBLIC_GATEWAY_NS="${ZOT_PUBLIC_GATEWAY_NS:-kube-system}"
# Upstream sync extension — optional.
# When ZOT_SYNC_UPSTREAM is set, a sync.extensions block is injected into config.json
# that mirrors the given prefixes from the upstream registry on first request.
# ZOT_SYNC_UPSTREAM_PREFIXES is a comma-separated list of namespace prefixes (no wildcards).
# Default prefixes: domains/**,modes/** — content-addressed OCI artifacts for ecosystem integration.
ZOT_SYNC_UPSTREAM="${ZOT_SYNC_UPSTREAM:-}"
ZOT_SYNC_UPSTREAM_TLS="${ZOT_SYNC_UPSTREAM_TLS:-true}"
ZOT_SYNC_UPSTREAM_PREFIXES="${ZOT_SYNC_UPSTREAM_PREFIXES:-domains/**,modes/**}"
ZOT_SYNC_ON_DEMAND="${ZOT_SYNC_ON_DEMAND:-true}"
# Credentials for authenticating to the upstream sync registry.
# Sourced from _credentials.env (SOPS-decrypted). Leave empty for anonymous upstreams.
ZOT_SYNC_USERNAME="${ZOT_SYNC_USERNAME:-}"
ZOT_SYNC_PASSWORD="${ZOT_SYNC_PASSWORD:-}"
KUBECONFIG="${KUBECONFIG:-/etc/kubernetes/admin.conf}"
export KUBECONFIG
CMD_TSK="${CMD_TSK:-${1:-install}}"
# shellcheck source=zot-lib.sh
source "${SCRIPT_DIR}/zot-lib.sh"
case "$CMD_TSK" in
install) _do_install ;;
update) _do_install ;;
reinstall) _do_delete; _do_install ;;
delete) _do_delete ;;
health) _do_health ;;
*)
echo "ERROR: unknown CMD_TSK='$CMD_TSK'. Valid: install|update|reinstall|delete|health" >&2
exit 1
;;
esac