fuse up
Compile a Fusefile and create an environment from it
fuse up [path] [flags]
Reads a Fusefile, compiles it into a resource
spec, manifest, and startup script, then creates an environment from the
result. Streams provisioning events until the environment settles, unless
--no-wait is set.
up returns as soon as the environment reaches running, so it is safe to
use in scripts and CI. Reaching running is the only success: up exits
non-zero if the environment reaches failed, is destroyed before it comes up,
or if the event stream ends before the environment settles at all (a dropped
connection or an orchestrator restart mid-provision). To keep watching an
environment after it is up, use
fuse environment watch,
which streams until the environment is destroyed or fails.
Flags
| Flag | Purpose |
|---|---|
-f, --file |
Path to the Fusefile. Default: the first of the discovered names below, or a positional path argument. |
--secret |
Secret as key=value. Repeatable. Overrides --secrets-file on key collision. |
--secrets-file |
Path to a file of KEY=VALUE secret lines. #-prefixed lines and blanks are ignored. |
--allow-empty-secrets |
Treat an empty value as satisfying a required secret. |
--task-id |
Environment task ID. Default: the Fusefile’s parent directory name. |
--gateway-url |
Gateway URL, matching fuse environment create. |
--gateway-token |
Gateway token. |
--dry-run |
Print the create request this Fusefile would post and exit without connecting to the orchestrator. |
--no-wait |
Create the environment without streaming provisioning events. |
--from-build |
Boot from a fuse build artifact instead of a base image. Skips the setup: phase. |
--plan |
Print the derived setup layer cache plan and exit without creating anything. |
--no-cache |
Ignore the Fusefile’s cache block and run every setup step. |
--wait-healthy |
After the environment is running, keep waiting until its healthcheck reports passing. |
--health-timeout |
How long --wait-healthy waits for a passing verdict before giving up. Default 2m. |
--show-copy |
Print what the copy: block ships, and what .fuseignore dropped, before creating anything. |
--from-build is mutually exclusive with both --plan and --no-cache: a
--from-build boot runs no setup steps, so there is no layer plan for it to
print and nothing for it to re-run. Use those flags on
fuse build, which is where the setup phase runs.
--dry-run and --plan are mutually exclusive for a different reason: both
print and exit, and they print different things.
The gateway carries a credential, so it is a flag rather than a Fusefile
field. Setting it here is the only difference that remained between the
Fusefile path and fuse environment create.
Waiting for healthy
Reaching running means the VM booted and the startup script returned. It does
not mean your app is serving: nothing has dialled it. --wait-healthy closes
that gap by keeping up waiting until the environment-level
healthcheck you declared reports
passing.
fuse up --wait-healthy --health-timeout 5m
It needs a healthcheck: block in the Fusefile; without one there is no verdict
to wait for and up says so instead of hanging until the timeout. It is also
mutually exclusive with --no-wait, which returns before the environment is even
running.
A failing verdict along the way is not a failure. A probe can legitimately fail
while the app is still coming up, which is what start_period exists for, so only
the timeout ends the wait unhappily, and the error carries the last verdict and
its reason:
environment fuse-api did not report healthy within 2m0s (failing: GET http://127.0.0.1:8080/healthz returned 502)
The verdict is produced in the guest and read back by the orchestrator on its
reconcile tick (30s by default), so expect up to a tick of lag between the probe
passing and up returning.
The layer cache
up consumes the layer cache but never
produces it. Populating it would mean snapshotting mid-boot, which means pausing
an environment somebody asked to have running;
fuse build is the command that makes layers.
With cache: {enabled: true} in the Fusefile, up resolves the chain deepest
first and, on a hit, boots from that artifact and runs only the setup: steps it
did not already cover, followed by run:. On a miss it boots the base image and
runs the setup phase in full, exactly as it always has.
A hit never costs you a working up. If the artifact lives on a host that cannot
take the workload, the orchestrator places the environment elsewhere and moves
the artifact to it; if the cache cannot be consulted at all, the boot goes cold.
The files: and copy: blocks are re-sent either way, since those are authoring
inputs that may have changed since the artifact was baked.
Copying local files in
A Fusefile’s copy: block is expanded here, on
your machine, before anything is posted: up resolves each from relative to
the Fusefile rather than to your working directory, walks a directory source
into one entry per regular file, and sends the result alongside the manifest so
the files exist in the guest before setup: and run: execute.
Everything that can go wrong with a source therefore fails locally, naming the
entry: a path that does not exist, a symlink (never followed), or a block over
the 512 KiB total. --dry-run runs the same walk, so it catches all three
without contacting the orchestrator.
The walk is filtered through the
.fuseignore next to the Fusefile, which
applies whether or not you wrote one: .git/, node_modules/, .env and a
handful of others are dropped by default. An ignored directory is pruned rather
than walked, so what it holds counts against neither the 512 KiB cap nor the
time the walk takes.
Seeing what copy: ships
--show-copy prints the result of that walk before anything is created:
$ fuse up --show-copy
copy ./src -> /workspace/src
412 files, 311.4 KB (4 skipped by .fuseignore, 2 by the defaults)
copy ./start.sh -> /workspace/start.sh
1 file, 842 B
total: 413 files, 312.2 KB (limit 512.0 KB)
It is a report, not a mode: up goes on to create the environment. Pair it
with --dry-run to stop before the orchestrator is contacted at all.
The skip counts are per path, not per file, because an ignored directory is
never walked: pruning node_modules/ counts as one skip whatever is inside it.
A missing file with a count next to .fuseignore means a pattern you wrote; one
counted against the defaults means a ! line will bring it back.
Path resolution
-f/--file wins if set, then a positional argument. With neither, up looks
in the working directory for these names, in order, and uses the first that
exists:
Fusefile Fusefile.yaml Fusefile.yml fusefile.yaml fusefile.yml
If none of them is there, the error names all five rather than reporting a
failed open of one. Discovery does not walk up to a parent directory: one
level too deep, pass -f.
Both -f and the positional argument name the file itself, neither
appends a Fusefile name to a directory, so pointing either at a directory
fails with read ./services/api: read ./services/api: is a directory (the
operation and path appear twice because the CLI prefixes an error that already
names them).
fuse up # ./Fusefile, ./Fusefile.yaml, ...
fuse up ./services/api/Fusefile
fuse up -f custom.fusefile.yaml
Secrets
fuse up --secret pg_password=hunter2
fuse up --secrets-file .env.secrets
fuse up --secrets-file .env.secrets --secret pg_password=override # override wins on collision
If any secret named in the Fusefile’s secrets list is missing from the
resolved set (flags plus file), up fails fast with the list of missing names
rather than creating a broken environment.
An empty value does not count as supplied: --secret pg_password= is a typo
far more often than a deliberate empty credential, and an environment that
boots with one fails later and further from the cause. Pass
--allow-empty-secrets when the empty value is intentional.
Task ID
The Fusefile has no task ID field, so with no --task-id the CLI derives one
from the Fusefile’s parent directory name and says so before it creates
anything:
fuse up
# no --task-id: using "my-service", derived from the Fusefile's directory
Two checkouts of the same repository derive the same ID, so pass --task-id
explicitly when that matters.
Dry run
--dry-run prints the create request up would post and exits before it
connects to anything, so it needs no context and no
configured host. Everything up to the network still runs, which means a dry
run still applies the secret gate and still reports a derived task ID.
The output is the same rendering fuse compile
produces, and honours -o json for a body you can diff or post by hand.
Secret values are never printed, only the names the create would require.
fuse up --dry-run
fuse up --dry-run -o json | jq .spec
Examples
fuse up
# creating environment fuse-abc123 (task my-service)
# provisioning
# running
# environment fuse-abc123 running
# task my-service
# host build-3
# agent 10.0.0.4:19551
# endpoint http 10.0.0.4:41337 -> guest :8080
# shell fuse environment shell fuse-abc123
The summary is printed once the environment settles at running. The
endpoint rows are the ports the Fusefile’s expose:
block published, paired with the guest port each one forwards to. The agent
row is the guest agent’s own address, not an exposed port. In -o json mode
the summary is the environment object instead, so stdout stays pipeable.
fuse up --no-wait
# creates immediately, does not stream events; watch separately with
# `fuse environment watch <id>`
fuse up --gateway-url https://gw.internal --gateway-token "$GW_TOKEN"
Startup script timeouts
The Fusefile’s setup: and run: compile into one startup script that the
orchestrator runs synchronously inside the create request, so its ceiling
is bounded by the control plane’s HTTP write timeout. A setup phase that
exceeds it fails the create:
startup script did not complete in time after 30s: ...
the startup script runs synchronously inside create, so its ceiling is bounded by the
control plane's http write timeout. raise it a little with `startup_timeout` in the
Fusefile, or move the slow work out of `setup:` and bake it once with `fuse build`,
then boot it with `fuse up --from-build <id>`
startup_timeout buys a little headroom but cannot exceed the fleet’s ceiling.
For anything genuinely long, such as an apt-get install, run it once with
fuse build and boot the artifact with --from-build:
that path runs the setup phase through exec under a much larger ceiling, and
later boots skip it entirely.
See Fusefile for the full field reference,
fuse init to scaffold one, and
fuse compile to print what one compiles into without
creating anything.