Deployment
monolock is a single process with no state on disk, so deploying it is mostly
about three things: file descriptors (capacity),
signal delivery (SIGHUP reloads, graceful shutdown), and keeping exactly
one instance reachable at a stable address.
flowchart LR
subgraph clients [workers]
W1[worker]
W2[worker]
W3[worker]
end
W1 & W2 & W3 -->|TCP :7070, TLS| M
subgraph host [one instance]
M[monolock]
end
P[Prometheus] -->|scrape :9090 /metrics| M
O[operator] -.->|ssh -L / port-forward :7071| M
M -->|stdout / file| A[(audit log)]
One instance is the model, not a limitation to engineer around. monolock
is a single point of coordination by design — do not run two instances behind
one load balancer, because locks live in one server’s memory and two servers
are two independent lock spaces. Run one, restart it fast, and let clients
reconnect: on shutdown they are told to (error 0x01),
and a restart loses only queue positions, while the guarded resources stay
protected by fencing tokens.
Docker
Section titled “Docker”docker run -d --name monolock \ -p 7070:7070 -p 9090:9090 \ --ulimit nofile=1048576:1048576 \ -v /etc/monolock:/etc/monolock:ro \ -e MONOLOCK_OPS_LISTEN_ADDRESS=0.0.0.0:9090 \ -e MONOLOCK_TLS_CERT=/etc/monolock/server.crt \ -e MONOLOCK_TLS_KEY=/etc/monolock/server.key \ -e MONOLOCK_AUDIT_LOG=- \ ghcr.io/monolock-dev/monolock--ulimit nofile= is the connection capacity. MONOLOCK_AUDIT_LOG=- sends
the audit stream to stdout for the container log pipeline, while diagnostics
stay on stderr — the two-log model
keeps them separable.
Reload certificates or the ACL file with:
docker kill --signal=HUP monolocksystemd
Section titled “systemd”[Unit]Description=monolock — named lock serverAfter=network-online.targetWants=network-online.target
[Service]ExecStart=/usr/local/bin/monolock \ -ops-listen 0.0.0.0:9090 \ -admin-listen 127.0.0.1:7071 \ -tls-cert /etc/monolock/server.crt \ -tls-key /etc/monolock/server.key \ -audit-log /var/log/monolock/audit.jsonl \ -log-format jsonExecReload=/bin/kill -HUP $MAINPIDRestart=alwaysRestartSec=1LimitNOFILE=1048576User=monolockDynamicUser=yesLogsDirectory=monolockNoNewPrivileges=yesProtectSystem=strictReadWritePaths=/var/log/monolock
[Install]WantedBy=multi-user.targetsystemctl reload monolock maps to SIGHUP — certificate rotation, ACL
reload and audit reopen. LimitNOFILE= sets the capacity. The hardening
options are safe because the server needs nothing from the filesystem beyond
its config files (read) and the audit log (write).
Kubernetes
Section titled “Kubernetes”One replica, Recreate strategy — two pods during a rolling update would be
two independent lock spaces, so trade a few seconds of coordination gap for
correctness:
apiVersion: apps/v1kind: Deploymentmetadata: name: monolockspec: replicas: 1 strategy: type: Recreate selector: matchLabels: { app: monolock } template: metadata: labels: { app: monolock } spec: containers: - name: monolock image: ghcr.io/monolock-dev/monolock ports: - { name: protocol, containerPort: 7070 } - { name: ops, containerPort: 9090 } - { name: admin, containerPort: 7071 } env: - { name: MONOLOCK_OPS_LISTEN_ADDRESS, value: "0.0.0.0:9090" } - { name: MONOLOCK_ADMIN_LISTEN_ADDRESS, value: "127.0.0.1:7071" } - { name: MONOLOCK_AUDIT_LOG, value: "-" } - { name: MONOLOCK_LOG_FORMAT, value: "json" } readinessProbe: httpGet: { path: /readyz, port: ops } livenessProbe: httpGet: { path: /healthz, port: ops }---apiVersion: v1kind: Servicemetadata: name: monolockspec: selector: { app: monolock } ports: - { name: protocol, port: 7070 }Clients connect to monolock:7070. The probes hit the
ops server, which keeps answering through the
shutdown window, so the endpoint is pulled out of the Service before
connections are cut. The admin API stays on 127.0.0.1 — reach it with
kubectl port-forward deploy/monolock 7071:7071.
For TLS, mount the certificate Secret and point the MONOLOCK_TLS_*
variables at it; on rotation send the reload signal instead of restarting:
kubectl exec deploy/monolock -- kill -HUP 1Choosing leases around restarts
Section titled “Choosing leases around restarts”A server restart drops all sessions; clients that classify errors correctly reconnect immediately (shutdown is a server-condition code) and re-queue. The visible cost of a restart is therefore roughly your image pull + process start, and it is worth measuring: clients whose lease is far below that window will report acquisition failures during the restart rather than riding it out, which is correct behavior — just be sure their retry policy expects it.

