Beskriv din deployment med suble.yml
En fil pr. projektmappe beskriver en hel instans — en bygget container, et publiceret image, en managed database eller et rent OS — og `suble deploy` / `suble update` reconciler den idempotent. Sådan virker det.
The Suble team
Engineering ·
suble deploy er fin til at få noget op at køre interaktivt. Men når det først findes, vil du have det i version control, reproducerbart og klar til at deploye fra CI uden et eneste spørgsmål. Det er præcis, hvad suble.yml er: en lille, deklarativ beskrivelse af en instans, som CLI'en reconciler — opret den hvis den mangler, bring den ajour hvis den findes, hver gang, på samme måde.
Hvor den kommer fra
Du behøver ikke skrive den i hånden. Den første interaktive suble deploy skriver filen for dig ud fra dine svar. suble init laver en kommenteret skabelon. Derefter reconciler suble update (i CI) filen helt uden prompts.
Filens form
En suble.yml beskriver en instans. Der er intet kind:-felt — den kildenøgle du sætter, vælger typen, så filen læser som det, du mener:
build:— en Docker-container bygget fra din lokale Dockerfile og pushet til dit private registry, derefter hentet på instansenimage:— et publiceret Docker-image (Docker Hub, GHCR, …)app:— en managed 1-klik-app eller database (postgresql,mysql,coolify, …)os:— et rent OS-image (Ubuntu, Debian, …)template:— en ny instans fra en af dine gemte templates
Alt andet — name, plan og valgfrie blokke som ports, env, volumes, expose, firewall, networks, backup, databases og users — lægges ovenpå. Både blok- og inline-flow-stil parses, så ports: ["80:80"] og firewall: { mode: strict, allow: ["10.0.0.0/8"] } virker også.
En bygget container, eksponeret med automatisk SSL
Det typiske tilfælde: byg imaget fra dit repo, kør det, og server det på et hostname med et Let's Encrypt-certifikat, som platformen styrer for dig.
name: web-01
plan: BXS.s1
build:
dockerfile: Dockerfile
tag: web:latest
container: web
ports:
- "80:8080"
env: # container-env — brug ${VAR} til secrets, aldrig literaler
NODE_ENV: production
volumes: # navngivne volumes overlever genskabelse af containeren
- "data:/var/lib/app"
expose:
domain: app.example.com
port: 80 # Caddy står foran og henter TLS-certifikatet automatisk
firewall: smart # off | smart | strict
backup: basic # none | basic | extendedsuble deploy bygger imaget lokalt, pusher det til dit private registry, instansen henter det (autentificeret automatisk — ingen docker login på serveren), (gen)skaber containeren, peger ingress mod den og giver dig den offentlige URL tilbage. Kører du den igen, bygges og redeployes den nyeste kode — navngivne volumes består på tværs af genskabelsen.
En managed database på et privat netværk
Sæt app: til en managed database, og du får motoren, root-legitimation (genereret server-side) og valgfrie databaser/brugere oprettet ved første deploy. Lås den til et privat netværk og en strict firewall, så kun din app kan nå den.
name: db-main
plan: CRA.m1
app: postgresql
password: ${ROOT_PASSWORD} # OS-root-login — env-interpoleret, aldrig en literal
databases:
- app_production # oprettes ved første deploy
users:
- name: app_user
password: ${APP_DB_PASSWORD}
database: app_production
networks:
- my-private-net # tilknyt via navn eller uid (tilknyt-hvis-mangler)
firewall:
mode: strict
allow: # kilde-CIDR'er (krævet ved strict)
- 10.20.0.0/16Hent genereret legitimation
En databases root-legitimation genereres på serveren — gemmes aldrig i din fil. Hent den når som helst med suble app info <navn> (tilføj --show-credentials i en ikke-interaktiv terminal). Secret-værdier er maskeret som standard.
Et publiceret image
Intet build-trin? Peg image: mod et hvilket som helst publiceret tag og publicer porte direkte.
name: edge
plan: BXS.s1
image: nginx:1.27
ports: ["80:80", "443:443"]Secrets bliver uden for filen
Enhver ${VAR} udvides fra miljøet, når filen læses, så du committer din deployments form — ikke dens adgangskoder. CLI'en advarer, hvis den ser en literal secret. I CI giver du værdierne som miljøvariabler / secrets ved siden af din SUBLE_API_KEY.
Firewall: off, smart eller strict
off— default-allow; du kan tilføje eksplicitterules:for at blokere bestemt trafiksmart— fornuftige standarder, der holder management-porte tilgængeligestrict— default-deny; du skal angive enallow:-liste af kilde-CIDR'er, så et headless-kørsel ikke kan låse dig ude
firewall:
mode: off
rules:
- direction: in
action: ACCEPT
proto: tcp
dport: "443"
- direction: in
action: ACCEPT
proto: tcp
dport: "22"
source: 203.0.113.0/24
comment: ssh fra kontoretstrict låser dig ikke ude
Under strict tjekker suble instance ssh din nuværende IP og tilbyder at tillade SSH fra den, før der forbindes — og en guard-IP holdes altid åben som sikkerhedsnet. Så du kan køre en låst firewall uden at miste adgang til din egen boks.
Sådan virker reconcile
deploy (interaktiv, første kørsel skriver filen) og update (CI, ingen prompts) deler en reconciler, så resultatet er ens uanset hvad:
- Find eller opret instansen ud fra
name— den genskabes aldrig, når den først findes. - Containere bygges / pulls igen og rulles ud — genskabes som standard, eller uden nedetid med
deploy.strategy: blue-green; navngivne volumes består (hold stateful data i en managedapp-database). - Firewall, expose (ingress + SSL) og private netværk asserteres på ny hver kørsel — netværk er tilknyt-hvis-mangler og frakobles aldrig automatisk.
- Databaser og brugere oprettes ved første create.
- Plan-ændringer advares der om, de auto-resizes ikke — brug
suble resizebevidst.
Forhåndsvis før du anvender
Kør suble plan (eller suble update --dry-run) for at se præcis, hvad der ville ændre sig — den markerer, om en container ville blive genskabt eller rullet ud blue/green, før det sker.
Deployment-strategier: rolling, canary, blue-green & immediate
Som standard laver en redeploy nu en rolling opdatering — de nye container(e) starter ved siden af de gamle, health-checkes, og overtager først trafik, når de er sunde. Bag expose: er det uden nedetid; fejler et health-check, bliver den gamle version ved med at servere, og deployet afslutter med fejlkode (så CI fanger det). deploy:-blokken lader dig vælge en anden strategi eller justere udrulningen.
name: web
plan: BXS.s1
image: ghcr.io/me/app:1.4.2
expose:
domain: app.example.com
port: 8080
deploy:
strategy: rolling # rolling (standard) | canary | blue-green | immediate
replicas: 3 # load-balancerede kopier (kræver expose:)
max_unavailable: 1 # replicas pr. batch (rolling/canary) — 1 eller "25%"
healthcheck:
type: http # docker (standard) | http | tcp
path: /healthz
port: 8080 # udledes fra expose:/ports: hvis udeladt
status: 200
timeout: 60 # sekunder til at blive sund, før der afbrydes- `rolling` (standard) — udskift replicas i batches af
max_unavailable; den nye startes og health-checkes, før en gammel fjernes. Begge versioner serverer kortvarigt; uden nedetid. - `canary` — verificer EN ny container først (den får en andel af live-trafikken via load-balanceren); er den sund, rulles resten. Mindste blast radius for en dårlig release.
- `blue-green` — start hele det nye sæt, health-check dem alle, og skift så al trafik på en gang. Ingen blandede versioner og øjeblikkelig rollback, men 2× replicas undervejs.
- `immediate` — udskift alt på en gang uden health checks (kort nedetid). Den hurtige mulighed uden sikkerhedsnet.
- `healthcheck.type` —
docker(container kører + stabil, respekterer imagetsHEALTHCHECK),http(GETpath→ forventstatus) ellertcp(porten accepterer en forbindelse). http/tcp-probes rammer containerens netværks-IP, så ingen publiceret port er nødvendig — de virker også for eksponerede containere. Juster timingen medinitial_delay(vent før første probe, ved langsom opstart),interval,retries(fejlede probes der tolereres) ogtimeout. - `replicas: N` — kør flere load-balancerede kopier bag ingress (kræver
expose:, stateless). Caddy round-robiner mellem dem, og den valgte strategi ruller hele sættet ud.
Et dårligt build erstatter aldrig et godt
Fejler den nye container sit health-check, afbrydes deployet med den gamle version stadig kørende — aldrig et halvt-ødelagt skift. Kombiner med expose: for ægte nul nedetid, og kør suble plan for at se rollout-strategien før du anvender.
Du kan også begrænse hver container med resources: (cpus/memory), så en replica ikke udsulter de andre, og deploy.drain styrer hvor mange sekunder en gammel container får til at afslutte igangværende requests, før den stoppes ved omskift (standard 10). deploy.keep beholder de seneste image-versioner på instansen, så suble rollback kan rulle tilbage til den forrige med det samme — uden ny build eller pull. Alle felter er dokumenteret i suble.yml-referencen.
I CI: push for at deploye, luk PR for at rive ned
suble update er ikke-interaktiv og idempotent — den behøver kun en projekt-API-nøgle. Et typisk workflow bygger og redeployer ved push og river miljøet ned, når en PR lukkes:
# ved push: byg + redeploy
- run: npx @suble/cli update
env: { SUBLE_API_KEY: ${{ secrets.SUBLE_API_KEY }} }
# ved PR-luk: riv det ned
- run: npx @suble/cli destroy --yes
env: { SUBLE_API_KEY: ${{ secrets.SUBLE_API_KEY }} }Samme API nedenunder
suble.yml er bare en bekvem front-end til v3-API'et — det samme som dashboardet og MCP-serveren bruger, med de samme rettigheder. Alt filen gør, kunne du gøre i hånden; den gør det blot deklarativt og gentageligt.
Start med suble init (eller lad din første suble deploy skrive den), commit filen, og fra da af er hver deploy en idempotent kommando. Ny til CLI'en? Se Kom i gang med Suble CLI'en.
Skrevet af
The Suble team
Engineering