Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Several instances

The instances of a deployment find and talk to each other on a port of their own, over TLS 1.3 in both directions, admitted by the certificate they share. The Kubernetes chart sets all of this up as soon as replicaCount exceeds 1.

[cluster]
listen = "0.0.0.0:8083"
peers = "dns:craft-file-gate-cluster:8083"
cert_file = "/var/lib/craft-file-gate/cluster/tls.crt"
key_file = "/var/lib/craft-file-gate/cluster/tls.key"

All keys: Reference [cluster].

The shared certificate

Its SHA-256 fingerprint is the identity of the cluster: neither name nor date is checked, expiry is reported by craftfilegate_cluster_cert_not_after_seconds. To change it, remove the pair and restart every instance; during the rollout, a peer with the old certificate is certificate_mismatch.

kubectl patch secret sftp-cluster --type=json \
  -p '[{"op":"remove","path":"/data/tls.crt"},{"op":"remove","path":"/data/tls.key"}]'
kubectl rollout restart deployment/sftp

Detectors and withdrawal from service

After each round, each instance evaluates three detectors: storage_alone (a backend down here that a reachable peer sees up: an outage that everyone sees does not count), isolated (fewer than min_peers reachable peers for isolated_after_secs) and isolated_and_storage_down (isolated, and every non-local backend down here; a local backend, the pod’s disk, does not count: without a non-local backend, it never fires). By default they only alert: WARN cluster detector active, craftfilegate_unready_detector{detector}, craftfilegate_cluster_isolated, checks.cluster of /admin/health.

Named in unready_when, they withdraw the instance from service: /readyz not ready after unready_after_secs of an active detector, ready again after ready_after_secs with none; /livez does not change. storage_alone only withdraws a pod if another pod, in service and with no backend down, sees each of its failed backends available, and only one pod at a time: if every pod has an outage somewhere, none leaves.

[cluster]
min_peers = 1                    # the chart: floor(replicaCount / 2)
unready_when = ["storage_alone", "isolated_and_storage_down"]  # the chart: auto

isolated alone can withdraw every pod: cut of the cluster port, loss of a majority of nodes, split into two equal halves, manual reduction of the replica count. Only name it knowingly, and never go below 2 × min_peers + 1 replicas without helm upgrade.

With the defaults, a storage outage is seen in 35 s at worst, the withdrawal follows 60 s later, and Kubernetes takes the pod out of the Service after 3 readiness probes at 10 s: about 2 min.

What you will see

At startup, INFO cluster channel listening (TLS 1.3, pinned on the shared certificate); for each peer that answers, INFO cluster peer reachable; per status: craftfilegate_cluster_peers{status}. The Instances, Sessions and Bans tabs of the console read each peer with your credential, which the peer judges itself (scope=cluster); a kick goes only to the peer that holds the session, a lift to every peer, except on a ConfigMap list; per call: craftfilegate_cluster_relay_total{route,result}.

A ban there is a guard against attempts, not a withdrawal of access: an address banned on a peer still reads it through another instance with a valid credential (a revoked session stays refused).