Run the leader on Kubernetes
This deployment runs the leader as one persistent replica. Smeltr does not provide a multi-replica or active/standby leader in this release. To run workers in the cluster, see Enroll workers on Kubernetes; to upgrade, see Upgrade Smeltr.
Requirements and image
Before deploying, provide:
- A Kubernetes cluster with a default or explicitly selected StorageClass that supports ReadWriteOnce persistent volumes.
- An ingress controller, DNS name and a TLS certificate that browsers and workers trust.
- Nodes that can pull from
ghcr.io, or a registry your organization mirrors the image into.
Pull the release's image, verify its signature, and name it by that digest in the manifests: a tag can move to a newer image, a digest cannot. Keep the digest and the release notes with the deployment. If you mirror the image, replace the whole image reference, registry and digest, in every manifest, the workers' included.
Deploy the leader
Save the following as smeltr-leader.yaml. Replace the public hostname, image digest
and storage requests for your environment. TLS terminates at the ingress, so Smeltr serves HTTP
only inside the cluster.
The port default is 443, which is privileged, and the pod runs as user 1000 -- so leader.http.port names an unprivileged port instead. Set it in the file rather than
the environment: the file only backfills variables that are unset, so an environment variable
wins over it. fsGroup matches the image's group, without which the process cannot write
a freshly provisioned volume.
The container's own securityContext meets the Kubernetes "restricted" Pod Security Standard:
no privilege escalation, no capabilities, the runtime's default seccomp profile, and a read-only root
filesystem. Smeltr writes only to its volumes, so nothing else needs to be writable.
The leader makes its data directory and the sealing key's directory private to itself, and only
a directory's owner can do that. A volume's root belongs to root whatever fsGroup says, so data_dir and key name directories inside their volumes, which the
leader creates on first start.
apiVersion: v1
kind: ConfigMap
metadata:
name: smeltr-leader
data:
smeltr.toml: |
[leader]
enabled = true
[leader.http]
bind = "0.0.0.0"
port = 4000
public_origin = "https://smeltr.example.com"
[leader.tls]
enabled = false
[leader.storage]
data_dir = "/var/lib/smeltr/data"
[leader.secrets]
key = "/var/lib/smeltr-secrets/key/sealing.key"
---
apiVersion: v1
kind: Service
metadata:
name: smeltr-leader
spec:
type: ClusterIP
selector:
app: smeltr-leader
ports:
- name: http
port: 4000
targetPort: http
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: smeltr-leader
spec:
serviceName: smeltr-leader
replicas: 1
selector:
matchLabels:
app: smeltr-leader
template:
metadata:
labels:
app: smeltr-leader
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: smeltr
image: ghcr.io/smeltr-sh/smeltr@sha256:REPLACE_WITH_DIGEST
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: [ALL]
seccompProfile:
type: RuntimeDefault
env:
- name: SMELTR_CONFIG_FILE
value: /config/smeltr.toml
ports:
- name: http
containerPort: 4000
volumeMounts:
- name: config
mountPath: /config
readOnly: true
- name: leader-data
mountPath: /var/lib/smeltr
- name: leader-secrets
mountPath: /var/lib/smeltr-secrets
volumes:
- name: config
configMap:
name: smeltr-leader
volumeClaimTemplates:
- metadata:
name: leader-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
- metadata:
name: leader-secrets
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi Apply it in the intended namespace, wait for smeltr-leader-0, and inspect its
console for startup errors:
kubectl apply -f smeltr-leader.yaml
kubectl rollout status statefulset/smeltr-leader
kubectl logs smeltr-leader-0 A new leader prints the initial administrator username and one-time password to stderr. Treat the pod log as sensitive until you change that password. The data and sealing-key claims are deliberately separate; back them up as one matched recovery set.
Expose the leader
Create an Ingress using the same hostname as leader.http.public_origin. Controller
annotations and certificate provisioning are cluster-specific:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: smeltr
spec:
tls:
- hosts:
- smeltr.example.com
secretName: smeltr-ingress-tls
rules:
- host: smeltr.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: smeltr-leader
port:
name: http Keep the Service as ClusterIP; only the ingress should be externally reachable. Configure the
ingress to preserve the browser Origin header. Open the configured public origin URL,
change the initial password, and create named administrator accounts. Because TLS terminates before
Smeltr, workers use platform trust for the ingress certificate.