Installing components
apply.sh installs and reconciles the components your config.yaml declares. It
is cluster-scoped: run it once, from one control-plane node, not once per
node.
# Reports what would change. Changes nothing.
curl -sL https://bke.maml.uk/apply.sh | sh -s -- --version 2.0.0
# Applies it.
curl -sL https://bke.maml.uk/apply.sh | sh -s -- --version 2.0.0 --commit
Nothing happens without --commit. The first command prints a report — which
versions move, whether any node drains, whether it can be rolled back, and what
changes in each of your values files — and touches neither the cluster nor a file
on this node. Read it, then run the same command again with --commit.
--version names where this run takes the cluster, not where it is. The
version you are on is recorded on the cluster and read from there; the report’s
first line shows both sides, as BKE <current> -> <requested>. Running with
the version you are already on applies your configuration at that version —
which is the ordinary way to roll out a config.yaml change. Naming a newer
version moves the components — read Upgrading first.
To see what you are on:
curl -sL https://bke.maml.uk/version.sh | sh
It needs no licence, calls no API and changes nothing. On a control-plane node it prints the cluster’s recorded BKE and Kubernetes versions and each component as last applied; on a worker it prints that node’s own record.
There is no confirmation prompt in between. This script is piped from curl, so
its standard input is the script itself and a prompt would consume the script
rather than your answer. Report, then commit, is also the more useful shape: the
report can be read by someone who is not at the keyboard.
There is no --role, because a role is a property of a node and this is not a
node script.
| Option | Effect |
|---|---|
--version X.Y.Z |
required — the version this run applies: what the cluster is on when it completes, never a statement of what it runs now |
--commit |
actually apply. Without it, nothing changes |
--show-unchanged |
also print the components that change nothing. Affects the report only, never what happens |
What it reads
| Path | Used for | Transmitted? |
|---|---|---|
/etc/bke/license |
the credential for everything below | as the Authorization header only |
/etc/bke/config.yaml |
checking your configuration and resolving what to install | yes |
/etc/bke/secrets.d/ |
creating Secrets in the cluster | never |
/etc/bke/values/ |
the Helm values each component runs with — yours | yes |
Credentials live in their own directory, and not in config.yaml, precisely so
that one can be sent and the other cannot.
/etc/bke/values/ is sent so that your file and the new default can be merged
where a YAML parser exists — see The values files are yours, below. Nothing
about it is stored. BKE’s own files name Secrets and never contain their values;
that file is yours to edit, so do not put a password in it — put it in
secrets.d/ and refer to the Secret by name.
It installs no package, writes nothing outside the cluster, and leaves no file behind — including when it fails.
What happens, in order
- The plan.
config.yamland--versionare sent toapi.maml.uk, which returns the exact versions to install, the components your licence covers, and the Secrets each one needs. - The endpoint is checked. The address on your licence is compared with the one this cluster reports for itself. A mismatch is refused — a licence covers one cluster, and this is how BKE knows it is still the same one.
- Secrets are resolved — all of them, before anything is applied. Every
Secret reference must resolve, either to a directory under
secrets.d/or to a Secret already in the cluster if its name is insecrets.unmanaged. Every unresolved reference is reported, not just the first. - Namespaces, then Secrets, then charts. The order is fixed, because Longhorn reads its backup credentials when it starts and netdata claims when it starts. A Secret that arrived after its component would mean restarting that component rather than simply configuring it.
- You are shown what would change, and asked. The report covers the
versions, whether nodes drain, the difference between the values files you
have and the ones BKE proposes, and which Kubernetes objects that difference
actually moves — including when the answer is none. Without
--commit, this is where it stops. - Each component is installed or upgraded via Helm, in a fixed order — not
the order your
config.yamllists them in. - What was installed is recorded in the
bke-stateConfigMap, with the versions, so a later run can tell what has changed.
Run it again
apply.sh is idempotent. Running it a second time with nothing changed makes no
changes and exits 0. This is the normal way to reconcile after editing
config.yaml.
It is also a step in an upgrade: run it after the control plane has moved, and again at the end.
What reconciliation does not touch
Anything BKE did not install. If you have your own Helm releases, your own namespaces, your own CRDs, they are not BKE’s to reconcile and it does not look at them.
Your workloads. Installing a component may roll that component’s own pods. It does not drain nodes and does not touch your applications.
Settings config.yaml does not expose
config.yaml covers the settings most clusters need. The charts underneath have
hundreds more, and you can set any of them — not through config.yaml, but
directly, in the values files.
The values files are yours
/etc/bke/values/longhorn.yaml the file in force. YOURS. Edit it.
/etc/bke/values/longhorn.dist.yaml what BKE rendered. OURS. Leave it alone.
apply.sh passes <component>.yaml to Helm. Anything the chart accepts, you can
put in it, and it survives every subsequent run.
<component>.dist.yaml is BKE’s record of what it last gave you. It exists so
that BKE can tell what you changed from what we changed — editing it
makes that comparison wrong, which is the only reason it is off limits.
Both files are written before Helm runs, so they are on disk whatever happens
next. The directory carries a README saying the same thing.
What happens to your edits on an upgrade
A new version of BKE ships new defaults. For each file, one of four things happens, and the report tells you which before anything is applied:
| Your file | What happens |
|---|---|
| you have not changed it | it takes the new default, quietly |
| you changed it; BKE did not | nothing. Your file is untouched |
| you changed one setting, BKE changed another | both apply. You see the diff |
| you and BKE changed the same setting | the run stops and shows you both values |
BKE never silently overwrites an edit of yours. The last row is the whole
point: a wrong automatic choice about a gateway’s configuration is worse than a
halted upgrade, so BKE will not make one. You resolve it by editing the file —
take the new default, keep your value, or write a third thing — and run
apply.sh again.
Your comments, your key order and your blank lines survive. Only the settings that actually change are touched.
Keep them in source control
If you run more than one cluster, keep /etc/bke/values/ in a repository the
way you keep everything else that decides what runs. Nothing in BKE needs to
know you are doing it — they are ordinary files, and a checkout populates the
directory.
Running Helm by hand
You can, and it will take effect. But the next apply.sh will notice: it
compares what the release is actually running with what your file says, and if
they disagree it stops rather than proceeding, because every other thing it
was about to tell you would have been computed against a file the cluster is not
using.
The fix is to put the change in <component>.yaml, where it belongs and where it
will last.
One consequence to accept
This is a directory you can edit, so a YAML syntax error in it is a failed run. The failure comes at the report, with the problem named, before anything is applied — not halfway through a Helm upgrade.
If a component needs a setting config.yaml does not expose and you would rather
not maintain it in a values file, tell us. The list is short because it started
from what clusters actually needed, not because it is finished.
Drift
bke-state records what BKE installed, and enough about how it was configured
to notice later if something changed underneath it.
On a later run, a component whose live state no longer matches what BKE recorded
is reported. That is how a hand-edited release surfaces, rather than being
silently overwritten without anyone noticing it had been changed.
When something refuses
Refusals are plain text, and each carries a cause. The three you are most likely to meet:
| Refusal | Means |
|---|---|
| not registered | the licence has no cluster yet — run register.sh |
| endpoint mismatch | this cluster’s endpoint is not the one on the licence |
| unresolved Secret reference | a name in config.yaml matches neither secrets.d/ nor secrets.unmanaged |
If we are unreachable, you get a 503 that says so — in those words, that
it is our fault and not a problem with your licence. You will never have to guess
whether you have been cut off or we are down. Retry shortly.