Warning
We're in the process of refining a complete rewrite of the project. main should be considered unstable until this is complete.
See the legacy branch for the original bash-based version of this project, which will only receive critical bug fixes.
- Project Status
- What's new? / Current Features
- Reworked conf repo structure
- Smarter reconciliation
- Secrets Management
- Stricter container isolation
- Better packaging / update story
- Simplified SSL Certificate management
- More flexible ingress declaration, and proxy management
- Dependency aware start/stop ordering
- Flexible network layout
- Shell completions
- Additional Docs
- Development
- LLM Policy
The following commands are already implemented:
up- starts the clusterdown- stops the clusterreconcile- reconciles the cluster with conf repo statereload-proxy- regenerates proxy config and signals haproxy containerssecrets- decrypts secrets using sops/ageself-update- updates the CLI to the latest version
initcommand / pre-defined application librarylint- static analysis of the configuration repo, checking volumes and secrets references all resolve, etc- HAProxy conf template could be further cleaned up / abstracted
docker/docker-composecompatibility testing- backup orchestration / tooling
updatecliintegration- More complete documentation / runbooks. Sorry this will come soon.
- Flat applications structure, as some applications may be available on both internal and public networks
- Top-level separation of
confanddata- Enables auto-classification of
confvsdatavolume mounts for reconciliation purposes - Simplifies
.gitignoremaintenance
- Enables auto-classification of
cluster.yaml- new configuration filesecrets.encrypted.yaml- new sops secrets filemise.toml- mise is recommended to manage thenodejs,age,sopsruntime dependencies.
Example:
├── applications
| ├── example.yaml
| ├── haproxy-internal.yaml
| └── haproxy-public.yaml
├── conf
| ├── example
| | └── whatever.yaml
| ├── haproxy
| ├── internal
| | ├── directory.html
| | ├── haproxy.cfg
| | └── haproxy.cfg.template
| └── public
| ├── haproxy.cfg
| └── haproxy.cfg.template
├── data
| ├── example
| └── whatever.sqlite
├── mise.lock
├── mise.toml
├── cluster.yaml
├── secrets.encrypted.yamlHashes container configuration volumes and injects as labels, such that compose reconciliation will detect changes. This means that we only restart containers that have changed, instead of all of them as in the legacy version.
Formalizes secrets management using sops and age, to inject compose secrets
Includes a command to help decrypt specific secrets. Example usage: run-updatecli.sh
#!/usr/bin/env bash
eval "$(mise exec -- shoe-string secrets --filter 'DOCKER_HUB_USERNAME|DOCKER_HUB_TOKEN')"
docker run --rm -v "$PWD":/home/updatecli \
-e DOCKERHUB_USERNAME="${DOCKER_HUB_USERNAME}" \
-e DOCKERHUB_TOKEN="${DOCKER_HUB_TOKEN}" \
ghcr.io/updatecli/updatecli:latest@sha256:63d08532b91df649fbc585b8aa9434309531e25ac92069dd2a3be76db9cf399d pipeline applyLeverages userns and :Z SELinux relabelling,
to isolate containers from the host, and each-other.
Explicit SELinux labels are preferred, eg:
security_opt:
- label:level:s0:c100,c209,c211To give each container a stable labeling, such that we don't have to relabel its volumes on every recreation.
New self update command is able to track main, or check npm for updates.
We now use lego exclusively and use a lego.yml conf file. Individual certificates are mounted directly
to the proxy containers that require it, with no intermediate processing required. By ditching HTTP-01 challenges, we can issue certs before
starting the cluster for the first time.
The CLI no longer directly controls any container definitions - this is completely delegated to your conf repository, meaning you have full
control of the HAProxy versioning and updates.
Additionally, the compose extensions now support more complex ingress configurations (multiple ports, raw tcp, wss, forward-auth). See docker-compose-extensions.ts
Applications can declare dependencies on other applications with the x-requires compose extension:
x-requires:
- database.yamlshoe-string up starts applications in dependency order, and down stops them in reverse. Entries are resolved relative to the Compose file that declares them, so sibling stacks are referenced by bare file name. Dependencies outside the current selection are left untouched (up warns when such a dependency isn't already running), and circular dependencies abort with an error.
Similar to the proxy definitions moving into your conf repository, so do all network definitions. This means there are no longer
hardcoded assumptions about the network layout, and you can define your own networks as required.
Generate completions for Zsh, Bash, Fish, or PowerShell with shoe-string complete <shell>.
For a one-time Zsh setup in the current shell:
source <(shoe-string complete zsh)To load Zsh completions automatically in future shells:
shoe-string complete zsh > ~/.shoe-string-completion.zsh
echo 'source ~/.shoe-string-completion.zsh' >> ~/.zshrc- Contributing: setup, test selection, formatting, and review checklist.
- Agent guidance: repository map, implementation constraints, and verification instructions.
- License.
We have used LLM's in the development of this project and are doing our best to find ways to work effectively with them. That said, we still expect human judgment and care to be exercised and will not entertain slop.
Please see the Jellyfin LLM Policy for the general vibe of our expectations.