You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -35,26 +35,27 @@ Your actual application code lives in separate repositories. The workflow checks
35
35
36
36
```
37
37
This repo (deployment orchestrator)
38
-
├── .github/workflows/deploy.yml ← the pipeline
38
+
├── .github/workflows/deploy.yml ← the pipeline
39
39
├── zerops/
40
40
│ ├── recipes/
41
-
│ │ ├── zerops-import-dev.yml ← lightweight config for dev environments
42
-
│ │ ├── zerops-import-stage.yml ← mid-tier config for staging
43
-
│ │ └── zerops-import-prod.yml ← full config for production (HA, dedicated CPU)
41
+
│ │ ├── zerops-import.yml.tpl ← single template for all environments
42
+
│ │ ├── env-dev.env ← variable values for dev (lightweight)
43
+
│ │ ├── env-stage.env ← variable values for staging (mid-tier)
44
+
│ │ └── env-prod.env ← variable values for production (HA, dedicated CPU)
44
45
│ └── scripts/
45
-
│ └── zerops-api.sh ← API helper functions (curl + jq, no CLI needed)
46
+
│ └── zerops-api.sh ← API helper functions (curl + jq, no CLI needed)
46
47
47
48
Your app repos (separate repositories)
48
-
├── your-org/your-app ← e.g. Bun/Node web app, has zerops.yml
49
-
└── your-org/your-worker ← e.g. Python worker, has zerops.yml
49
+
├── your-org/your-app ← e.g. Bun/Node web app, has zerops.yml
50
+
└── your-org/your-worker ← e.g. Python worker, has zerops.yml
50
51
```
51
52
52
53
### What Happens When You Push a Feature Branch
53
54
54
55
1. GitHub Actions detects the push
55
56
2. The workflow checks out this repo + your app repos
56
57
3. It calls the Zerops API to check if a project named `showcase-dev-{branch}` exists
57
-
4. If not, it creates one using the dev recipe (PostgreSQL, Valkey/Redis, NATS, object storage, plus your app and worker services)
58
+
4. If not, it renders the import template (`zerops-import.yml.tpl`) with dev values (`env-dev.env`) and creates the project (PostgreSQL, Valkey/Redis, NATS, object storage, plus your app and worker services)
58
59
5. It waits for all infrastructure services to be ready
59
60
6. It packages your app code into a tarball, uploads it to Zerops, and triggers a build + deploy
60
61
7. It does the same for your worker service
@@ -90,7 +91,7 @@ If you're new to Zerops, here are the key concepts this pipeline uses:
90
91
91
92
**Service (Service Stack)** — A single component within a project: a web app, a database, a cache, etc. Each service has a type (like `postgresql@17` or `bun@1.2`) and configuration for scaling, memory, and storage.
92
93
93
-
**Import YAML**— A file that describes a complete project: its name and all its services. Zerops can create an entire project from this file in one API call. The recipes in `zerops/recipes/` are import YAML files.
94
+
**Import YAML**-- A file that describes a complete project: its name and all its services. Zerops can create an entire project from this file in one API call. In this pipeline, the import YAML is generated from a template (`zerops-import.yml.tpl`) combined with per-environment variables (`env-dev.env`, `env-stage.env`, `env-prod.env`).
94
95
95
96
**zerops.yml** — A file in your app's repository that tells Zerops how to build and run your application. It defines build commands, runtime commands, and which files to deploy. This is analogous to a Dockerfile, but simpler.
96
97
@@ -150,90 +151,131 @@ env:
150
151
151
152
`ZEROPS_YAML_SETUP` must match the `setup` field in your app's `zerops.yml`. For example, if your `zerops.yml` starts with `zerops: - setup: prod`, set this to `prod`.
152
153
153
-
#### 2. Customize the import recipes
154
+
#### 2. Understand the template system
154
155
155
-
The three recipe files define what services each environment gets. Edit them to match your application's needs.
156
+
Instead of maintaining three separate recipe files (one per environment), this pipeline uses a single template with per-environment variable files. You edit services in one place and only vary the values that differ.
156
157
157
-
**`zerops/recipes/zerops-import-dev.yml`** — Lightweight, for development:
158
+
```
159
+
zerops/recipes/
160
+
zerops-import.yml.tpl <- the template (shared structure)
161
+
env-dev.env <- values for dev environments
162
+
env-stage.env <- values for staging
163
+
env-prod.env <- values for production
164
+
```
165
+
166
+
The template uses `${VARIABLE}` placeholders that get replaced by [`envsubst`](https://www.gnu.org/software/gettext/manual/html_node/envsubst-Invocation.html) at deploy time. Lines where the value is empty are removed automatically -- this is how optional fields like `corePackage`, `cpuMode`, or `minContainers` only appear in environments that set them.
167
+
168
+
#### 3. Customize the template
169
+
170
+
Open `zerops/recipes/zerops-import.yml.tpl`. This defines the structure of every environment:
158
171
159
172
```yaml
160
173
project:
161
-
name: <FILLED_BY_PIPELINE> # ← don't change this, the pipeline fills it in
174
+
name: ${PROJECT_NAME}
175
+
corePackage: ${CORE_PACKAGE}
162
176
163
177
services:
164
178
- hostname: app
165
-
type: bun@1.2 # ← change to your app's runtime
166
-
enableSubdomainAccess: true # ← gives it a public URL
167
-
168
-
- hostname: worker
169
-
type: python@3.12 # ← change to your worker's runtime
179
+
type: ${APP_TYPE}
180
+
enableSubdomainAccess: true
181
+
envSecrets:
182
+
CORE_MODE: ${APP_CORE_MODE}
183
+
minContainers: ${APP_MIN_CONTAINERS}
184
+
maxContainers: ${APP_MAX_CONTAINERS}
185
+
verticalAutoscaling:
186
+
cpuMode: ${APP_CPU_MODE}
187
+
minRam: ${APP_MIN_RAM}
188
+
minFreeRamGB: ${APP_MIN_FREE_RAM}
170
189
171
190
- hostname: db
172
-
type: postgresql@17
173
-
mode: NON_HA # ← single instance (cheaper for dev)
174
-
priority: 10 # ← infrastructure: created first, never redeployed
175
-
176
-
- hostname: redis
177
-
type: valkey@7.2
178
-
mode: NON_HA
191
+
type: ${DB_TYPE}
192
+
mode: ${DB_MODE}
179
193
priority: 10
194
+
# ... more services
195
+
```
180
196
181
-
- hostname: queue
182
-
type: nats@2.12
183
-
mode: NON_HA
184
-
priority: 10
197
+
Change the `hostname`, `type`, and structure to match your application. Add or remove services as needed. Use `${VARIABLE_NAME}` for any value that should differ between environments.
185
198
186
-
- hostname: storage
187
-
type: object-storage
188
-
objectStorageSize: 2 # ← 2 GB
189
-
objectStoragePolicy: public-read
190
-
priority: 10
199
+
**Important:**`${PROJECT_NAME}` is set automatically by the pipeline. Do not hardcode it.
200
+
201
+
**Important:** Services with `priority: 10` are infrastructure. They are created on first deploy and never touched again. Only services without a `priority` (app, worker) receive code deployments.
202
+
203
+
#### 4. Customize the env files
204
+
205
+
Each env file is a simple `KEY=VALUE` list. Here's what the dev file looks like:
206
+
207
+
```bash
208
+
# env-dev.env -- lightweight, single-instance, shared CPU
209
+
210
+
CORE_PACKAGE= # empty = field is omitted from the YAML
211
+
APP_TYPE=bun@1.2
212
+
APP_CORE_MODE= # empty = envSecrets block omitted
213
+
APP_MIN_CONTAINERS= # empty = no auto-scaling
214
+
APP_MAX_CONTAINERS=
215
+
APP_CPU_MODE= # empty = shared CPU (default)
216
+
APP_MIN_RAM=0.5
217
+
APP_MIN_FREE_RAM=0.25
218
+
DB_TYPE=postgresql@17
219
+
DB_MODE=NON_HA # single instance
220
+
# ... etc
191
221
```
192
222
193
-
**`zerops/recipes/zerops-import-prod.yml`** — Full production config:
223
+
And the prod file sets everything:
224
+
225
+
```bash
226
+
# env-prod.env -- full HA, dedicated CPU, auto-scaling
The rule is simple: **set a value and it appears in the YAML; leave it empty and the entire line is removed.** Section headers like `verticalAutoscaling:` or `envSecrets:` are also removed automatically if all their children are empty.
244
+
245
+
This means the generated YAML for dev is clean and minimal:
194
246
195
247
```yaml
248
+
# What the pipeline actually sends to Zerops for a dev environment:
196
249
project:
197
-
name: <FILLED_BY_PIPELINE>
198
-
corePackage: SERIOUS # ← higher resource tier
250
+
name: showcase-dev-feat-login
199
251
200
252
services:
201
253
- hostname: app
202
254
type: bun@1.2
203
255
enableSubdomainAccess: true
204
-
minContainers: 2 # ← auto-scaling: 2-6 containers
205
-
maxContainers: 6
206
256
verticalAutoscaling:
207
-
cpuMode: DEDICATED # ← dedicated CPU for production
- **Prod**: `HA` (high availability), `DEDICATED` CPU, more RAM, auto-scaling
227
-
228
-
**Important:** The `<FILLED_BY_PIPELINE>` placeholder in the project name is replaced automatically. Do not change it.
229
-
230
-
**Important:** Services with `priority: 10` are infrastructure services. They are created when the project is first set up and are never touched by subsequent deploys. Only services without a `priority` (app, worker) receive code deployments.
272
+
While prod gets the full config with HA, dedicated CPU, auto-scaling, and envSecrets -- all from the same template.
231
273
232
-
#### 3. Add or remove services
274
+
#### 5. Add or remove services
233
275
234
-
If your app doesn't use a message queue, remove the `queue` service from all three recipe files. If you need MySQL instead of PostgreSQL, change the `type` field. The available service types are listed in the [Zerops documentation](https://docs.zerops.io).
276
+
To add a service, add it to the template and define its variables in all three env files. To remove one (e.g., no message queue), delete it from the template.
235
277
236
-
If you have more than two app services (e.g., an API, a frontend, and a worker), add them to the recipes and duplicate the deploy steps in the workflow:
278
+
If you have more than two app services (e.g., an API, a frontend, and a worker), add them to the template and duplicate the deploy steps in the workflow:
237
279
238
280
```yaml
239
281
# In the workflow, after deploying app and worker:
The project names (`showcase-dev-*`, `showcase-stage`, `showcase-prod`, `showcase-mr-*`) are set in the workflow's deploy steps. Search for `showcase` and replace with your project's name, e.g., `myapp-dev-*`, `myapp-stage`, etc.
249
291
@@ -335,9 +377,10 @@ The file `zerops/scripts/zerops-api.sh` contains all the functions that talk to
335
377
336
378
| Function | What it does |
337
379
|---|---|
338
-
| `zerops_ensure_project` | Find a project by name; create it if it doesn't exist. This is the core function that keeps permanent environments safe. |
380
+
| `zerops_render_template` | Render the import template with an env file using `envsubst`. Strips empty values and orphaned section headers. Sets `RENDERED_YAML`. |
381
+
| `zerops_ensure_project` | Find a project by name; create it if it doesn't exist. Uses `RENDERED_YAML` if set, otherwise falls back to a static import file. This is the core function that keeps permanent environments safe. |
339
382
| `zerops_find_project` | Look up a project by name. Sets `PROJECT_FOUND_ID` if found. |
340
-
| `zerops_import_project` | Create a new project from an import YAML file. |
383
+
| `zerops_import_project` | Create a new project from rendered or file-based YAML. |
341
384
| `zerops_delete_project` | Delete a project by ID. |
342
385
| `zerops_find_service` | Look up a service within a project by hostname. |
343
386
| `zerops_deploy_service` | Full deploy cycle: create app version, package code, upload, build, deploy, poll until complete. |
@@ -355,9 +398,9 @@ The file `zerops/scripts/zerops-api.sh` contains all the functions that talk to
355
398
356
399
If your project has only one deployable service (no separate worker), remove the worker-related lines from:
357
400
358
-
1. The workflow — remove the worker checkout step and the `zerops_find_service`/`zerops_deploy_service` lines for the worker in each job
359
-
2. The recipes — remove the `worker` service definition
360
-
3. The workflow env — remove the `WORKER_REPO` and `WORKER_SERVICE_NAME` variables
401
+
1. The workflow -- remove the worker checkout step and the `zerops_find_service`/`zerops_deploy_service` lines for the worker in each job
402
+
2. The template -- remove the `worker` service block from `zerops-import.yml.tpl` and worker variables from the env files
403
+
3. The workflow env -- remove the `WORKER_REPO` and `WORKER_SERVICE_NAME` variables
0 commit comments