#Stacks
A stack is a group of apps and services deployed together from one
compose.yml onto a Bay estate. Lore stores the file and its revisions, holds
the variables, and tells the machine what to run. This page covers Lore's side:
the console, revisions, deploys and the rights they need. The file's format, and
what Bay does with it, are in Stacks in the Bay
documentation.
#Turning it on
Stacks are the Stacks option of the Apps capability, off by default, in
Settings ▸ General ▸ Capabilities. It adds Stacks to the sidebar, at
/<project-slug>/stacks.
Reading needs app:read, which the default Member rank holds. Everything that
changes something needs deploy:manage and the option on, and so does reading a
service's logs, because logs can hold what an app printed. Turn the option off
and your stacks stay, readable, for when it comes back.
⚠️ Two things need the Deploy apps option as well, which is off by default: deploying one app service, and storing a registry credential.
Only a Bay runs stacks. A stack needs an estate lent to the project, and that estate must have Allow deploys on.
#Stacks, environments and revisions
| Word | What it is |
|---|---|
| Stack | A name, unique in the project, and a default estate. Lowercase letters, digits and hyphens, up to 64. |
| Environment | One running copy of the stack, such as production, addressed as <stack>/<env>. |
| Revision | One numbered upload of the Compose file, with the files it references. A stack has many. |
| Member | An app instance that belongs to an environment. |
An environment deploys to its own estate if it names one, and otherwise to the stack's default. A deploy never asks: as with an app, where it goes is a property of the environment.
#Creating a stack
Open Stacks ▸ New stack, or from a project directory:
lore stack create --estate my-vps --file compose.yml
The name defaults to the project slug. On the page, the next steps are Add environment, then uploading the Compose file on the Revisions tab.
#Uploading a revision
A revision is a compose.yml, or a gzip or zstd tar bundle holding one with the
files it mounts.
Lore parses it and checks it before storing anything, against every estate the stack deploys to, in Bay's own words, so a file the machine would refuse is refused at upload. Every reason is listed at once:
- no
container_name, nobuild, noprivileged, no host network, PID, IPC or user namespace; - no
container:undernetwork_mode,pid,ipcorvolumes_from, which would reach another environment's containers:service:<name>, or a plain service name undervolumes_from, names one of the stack's own; - every plain service needs an
image; - no Docker socket;
- no bind mount,
env_file, orfile:undersecretsorconfigsoutside the bundle, and no variable in anenv_filepath; - no
include, and noextendsfrom another file: a stack is one compose file; - no named volume with
driver_opts, which could bind any host path; - no named volume or network marked
external, or with anameof its own; - a plain service cannot depend on an app service.
The Revisions tab lists them newest first and shows the difference between two.
#Deploying
Deploy on an environment sends the newest revision, or the one you name. From
a terminal, lore stack deploy uploads the Compose file beside the command as a
new revision first, and creates the environment on its first deploy:
lore stack deploy -e staging
lore stack deploy -e staging --file deploy/compose.yml
lore stack deploy -e staging --revision 4 # a revision already uploaded
lore stack deploy -e staging --dry-run # say what would happen
-e defaults to production.
Lore checks everything before anything reaches the machine, and refuses:
- an environment with no estate, or one no longer lent to the project;
- an estate that is not a Bay, or that does not accept deploys;
- a revision that cannot run there;
- a Compose file that interpolates a required variable this environment has not set, naming every one.
Then it queues the deploy for the machine. The Deploys tab follows it, with the plan and the outcome of each service.
#Rolling back
A rollback deploys an earlier revision again, and it is the same operation as a deploy.
⚠️ The Compose file goes back. Volumes and their data do not.
lore stack rollback -e production --to 2
#One app at a time
An app service can be deployed alone. When a copy is a member of an environment, a deploy of that copy sends its stored build into its own service, blue/green, against the revision the environment already runs. No other service is touched and nothing of the Compose file is applied.
An app names its stack in alepha.config.ts:
1lore({ stack: "mcs" });
alepha deploy staging then puts the app into mcs/staging, creating the copy if
needed and making it a member. The stack and the environment must already exist,
so deploy the stack there once first.
A copy joins the environment of its own environment name: mcs-api/staging can
join mcs/staging, never mcs/production. It belongs to one environment at a
time, and it takes its estate from that environment rather than from its own
Settings tab.
#The environment page
Each environment has seven tabs:
| Tab | What it shows |
|---|---|
| Services | What the revision declares, beside what the machine last reported, with restart, stop, start. |
| Deploys | Its deploys, newest first, with their plan and outcome. |
| Revisions | The stack's revisions and their differences, with upload. |
| Routes | The full domains it serves. |
| Variables | Its variables, never their values. |
| Volumes | The named volumes of the running revision, and whether a backup hook covers each. |
| Settings | The stack's default estate, this environment's override, and its base domain. |
⚠️ A stopped service stays stopped. The way back is Start, or a deploy.
#Logs
Opening a service's logs asks the machine for the last 200 lines, and shows them once it has answered. They are kept for 24 hours. The CLI and the tool take a different count, up to 2,000:
lore stack logs web -e production --lines 1000
#Variables
Variables are per environment and write-only. Lore seals them, opens them only for the deploy, and answers with names and at most a four-character prefix of a long value. A generated value shows no prefix.
lore stack secrets set DATABASE_URL=postgres://... -e production
lore stack secrets set APP_SECRET --generate -e production
lore stack secrets list -e production
--generate makes a random hex value on the server, 64 characters unless
--length says otherwise (16 to 256), so it never passes through a terminal.
-e is required on these commands: a variable set on the wrong environment is a
production secret in staging. An environment holds up to 200 variables, each
up to 5,000 characters. Bay refuses a deploy with a variable named COMPOSE_*,
which would configure Compose itself.
#Routes
An environment's base domain and routes labels are Bay's, see
Routes and domains. The Routes
tab adds a full domain on top, served by one service:
lore stack route add web --domain app.example.com -e production
#Private registries
An image from a private registry needs a credential, stored per project and pulled by the machine for the deploy:
lore registry add ghcr.io --username bot --password-stdin
See The lore CLI.
#Removing
Delete environment, on its Settings tab, forgets an environment in Lore,
with its routes and variables. Its member apps stay, as ordinary copies, and ⚠️
nothing on the estate is touched: what runs keeps running. Neither the page nor
the CLI deletes a whole stack. lore stack destroy forgets an environment too, and prints the command
that removes it from the machine, which --purge extends to its volumes.
#For agents
| Tool | What it does |
|---|---|
stack_list |
Every stack, with its environments, routes, member apps and the revision each runs. |
stack_get |
One stack: each environment's services and newest deploys. Never a variable's value. |
stack_deploy |
Deploy a revision to an environment, the newest by default. With app, deploy one app service alone from a stored build. |
stack_rollback |
Deploy an earlier revision again. |
stack_logs |
Two calls: with service it asks for the tail and answers a request; with that request it answers the lines when ready. |
No stack_* tool takes an estate. Creating a stack, uploading a revision and
setting variables and routes have no tool: those are for the CLI and the page.