zeabur-template
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseZeabur Template Knowledge Base
Zeabur模板知识库
This skill provides comprehensive knowledge for creating, debugging, and publishing Zeabur templates. It combines reference documentation with battle-tested patterns from real template development.
本技能提供了创建、调试和发布Zeabur模板的全面知识,结合了参考文档与实际模板开发中经过验证的实践模式。
External Documentation
外部文档
For the latest schema and detailed docs, fetch from :
https://raw.githubusercontent.com/zeabur/zeabur-template-doc/main/| User Need | Document to Fetch | Path |
|---|---|---|
| Create a template from scratch | Step-by-step guide | |
| Convert docker-compose.yml | Migration guide | |
| Look up YAML fields or built-in variables | Technical reference | |
| Naming, design patterns, best practices | Best practices | |
| Debug template errors | Troubleshooting | |
| Pre-deployment checklist | Checklist | |
| Quick all-in-one overview | Comprehensive prompt | |
The template YAML schema is also available at https://schema.zeabur.app/template.json and the prebuilt service schema at https://schema.zeabur.app/prebuilt.json.
如需获取最新的架构和详细文档,请从获取:
https://raw.githubusercontent.com/zeabur/zeabur-template-doc/main/| 用户需求 | 需获取的文档 | 路径 |
|---|---|---|
| 从零开始创建模板 | 分步指南 | |
| 转换docker-compose.yml | 迁移指南 | |
| 查阅YAML字段或内置变量 | 技术参考 | |
| 命名、设计模式、最佳实践 | 最佳实践 | |
| 排查模板错误 | 故障排除 | |
| 部署前检查清单 | 检查清单 | |
| 快速概览所有内容 | 综合提示 | |
模板YAML架构也可通过https://schema.zeabur.app/template.json获取,预构建服务架构可通过https://schema.zeabur.app/prebuilt.json获取。
Core Principles
核心原则
0. All services MUST use PREBUILT_V2 with Docker images
0. 所有服务必须使用带Docker镜像的PREBUILT_V2
Every service in a template MUST be with a Docker image as the source. Never use , , or source — these are NOT supported in templates.
template: PREBUILT_V2template: GITARBITRARY_GITGITHUBIf the project does not have a published Docker image (on Docker Hub, GHCR, etc.), tell the user they need to build and publish a Docker image first before a template can be created. Do not attempt to work around this.
If the user asks you to build the image, follow this workflow:
- Clone the project repo and find its (usually at repo root)
Dockerfile - Study the Dockerfile to understand build stages — use the production stage (often named or
runner)production - Study or
docker-compose.ymlfor the correct startup command, env vars, and volumes — this is the battle-tested production configdocker-compose.fullapp.yml - Build for amd64 (Zeabur servers are amd64, local Macs are arm64):
bash
docker buildx build --platform linux/amd64 --target runner -t org/image:tag --push . - After pushing, verify the Docker Hub repo is public:
New repos under org accounts often default to private. Ifbash
curl -s "https://hub.docker.com/v2/repositories/ORG/IMAGE/" | grep is_private, the user must make it public on Docker Hub.is_private: true
模板中的每个服务必须使用,并以Docker镜像作为源。 绝不要使用、或作为源——这些在模板中不受支持。
template: PREBUILT_V2template: GITARBITRARY_GITGITHUB如果项目没有已发布的Docker镜像(在Docker Hub、GHCR等平台),请告知用户在创建模板前必须先构建并发布一个Docker镜像,不要尝试绕过这一步。
如果用户要求你构建镜像,请遵循以下流程:
- 克隆项目仓库并找到其(通常位于仓库根目录)
Dockerfile - 研究Dockerfile以了解构建阶段——使用生产阶段(通常命名为或
runner)production - 查看或
docker-compose.yml以获取正确的启动命令、环境变量和卷配置——这是经过验证的生产环境配置docker-compose.fullapp.yml - 为amd64架构构建镜像(Zeabur服务器为amd64架构,本地Mac通常为arm64):
bash
docker buildx build --platform linux/amd64 --target runner -t org/image:tag --push . - 推送完成后,验证Docker Hub仓库是否公开:
组织账户下的新仓库通常默认设为私有。如果返回bash
curl -s "https://hub.docker.com/v2/repositories/ORG/IMAGE/" | grep is_private,用户必须在Docker Hub上将其设为公开。is_private: true
1. Never start from scratch
1. 绝不要从零开始
When asked to create a template, always look for existing configuration first:
- First check if a Docker image exists — search Docker Hub, GHCR (), or the project's CI/CD for published images. If none exists, stop and inform the user.
ghcr.io/org/repo - Search for the project's ,
docker-compose.yml, ordocker-compose.yamlcompose.yml - Look for Helm charts (,
Chart.yaml)values.yaml - Check the project's GitHub repo for any deployment YAML files
- Use these as the foundation to build the Zeabur template, not as a loose reference — they contain battle-tested environment variables, port mappings, volume mounts, and service dependencies
当被要求创建模板时,务必先查找现有的配置:
- 首先检查是否存在Docker镜像——在Docker Hub、GHCR()或项目的CI/CD流程中搜索已发布的镜像。如果不存在,请停止操作并告知用户。
ghcr.io/org/repo - 搜索项目的、
docker-compose.yml或docker-compose.yaml文件compose.yml - 查找Helm Chart(、
Chart.yaml)values.yaml - 检查项目的GitHub仓库中是否有任何部署YAML文件
- 以这些配置为基础构建Zeabur模板,而不是仅作为松散参考——它们包含了经过验证的环境变量、端口映射、卷挂载和服务依赖关系
2. Iterate via runtime logs — never expect one-shot success
2. 通过运行时日志迭代——不要期望一次成功
Even experienced humans cannot create a working template in one shot. The workflow is an iterative loop:
- Write/update the template YAML
- Deploy the template
- It will likely fail — check runtime logs to find the cause
- Fix the issue in the template
- Delete the project and redeploy from scratch
- Repeat until the template achieves one-click deployment success
This is the normal process, not a sign of failure. Do not try to get everything perfect before deploying — deploy early, read logs, and iterate.
即使是经验丰富的开发者也无法一次就创建出可用的模板。工作流程是一个迭代循环:
- 编写/更新模板YAML
- 部署模板
- 很可能会失败——查看运行时日志以找出原因
- 在模板中修复问题
- 删除项目并重新部署
- 重复上述步骤,直到模板实现一键部署成功
这是正常流程,并非失败的标志。不要试图在部署前就把所有内容都弄完美——尽早部署、查看日志并迭代。
3. Reuse from existing templates — never write common services from scratch
3. 复用现有模板——绝不要从零开始编写通用服务
When your template needs a common service (PostgreSQL, Redis, MySQL, MongoDB, etc.), do not write the service definition yourself. Instead:
- Search for existing templates that already use that service:
bash
npx zeabur@latest template search postgres - Find a template that includes the service you need
- Get the raw template YAML to see the exact service definition:
bash
npx zeabur@latest template get -c TEMPLATE_CODE --raw - Copy the service definition directly from that template into yours
How to judge template trustworthiness:
- Many templates are created by regular users and may not work correctly
- Prefer templates with more deployments — higher deployment count = more battle-tested
- Prefer official templates over user-submitted ones — official templates are vetted by Zeabur team
当你的模板需要通用服务(PostgreSQL、Redis、MySQL、MongoDB等)时,不要自己编写服务定义。请遵循以下步骤:
- 搜索已使用该服务的现有模板:
bash
npx zeabur@latest template search postgres - 找到包含所需服务的模板
- 获取原始模板YAML以查看确切的服务定义:
bash
npx zeabur@latest template get -c TEMPLATE_CODE --raw - 将该服务定义直接复制到你的模板中
如何判断模板的可靠性:
- 许多模板由普通用户创建,可能无法正常工作
- 优先选择部署次数多的模板——部署次数越多,经过的验证越充分
- 优先选择官方模板而非用户提交的模板——官方模板经过Zeabur团队审核
CLI Commands for the Iteration Loop
迭代循环中的CLI命令
Deploy a template:
bash
npx zeabur@latest template deploy -f YOUR_TEMPLATE.yamlFor non-interactive mode (automation):
bash
npx zeabur@latest template deploy -i=false \
-f YOUR_TEMPLATE.yaml \
--project-id PROJECT_ID \
--var PUBLIC_DOMAIN=myappList services (to get SERVICE_ID):
bash
npx zeabur@latest service list --project-id PROJECT_IDCheck runtime logs:
bash
npx zeabur@latest deployment log --service-id SERVICE_IDExecute a command inside a running service (like ):
docker execbash
npx zeabur@latest service exec --id SERVICE_ID -- SHELL_COMMANDThis is extremely useful for debugging — check file paths, env vars, test connectivity, inspect the filesystem, etc. Examples:
bash
npx zeabur@latest service exec --id SERVICE_ID -- ls /app
npx zeabur@latest service exec --id SERVICE_ID -- env | grep DATABASE
npx zeabur@latest service exec --id SERVICE_ID -- nc -z localhost 5432Restart a service (useful to clear ImagePullBackOff or force re-pull):
bash
npx zeabur@latest service restart --id SERVICE_ID -i=false -yDelete the project and start over:
bash
npx zeabur@latest project delete --id PROJECT_IDDANGEROUS OPERATION — Before deleting a project, you MUST ask the user for explicit confirmation, clearly stating the Project ID, Name, and createdAt timestamp. Never delete without confirmation.
Publish a new template:
bash
npx zeabur@latest template create -f YOUR_TEMPLATE.yamlThis returns a template URL like with a template code.
https://zeabur.com/templates/XXXXXXUpdate an existing template:
bash
npx zeabur@latest template update -c TEMPLATE_CODE -f YOUR_TEMPLATE.yaml部署模板:
bash
npx zeabur@latest template deploy -f YOUR_TEMPLATE.yaml非交互式模式(自动化):
bash
npx zeabur@latest template deploy -i=false \
-f YOUR_TEMPLATE.yaml \
--project-id PROJECT_ID \
--var PUBLIC_DOMAIN=myapp列出服务(获取SERVICE_ID):
bash
npx zeabur@latest service list --project-id PROJECT_ID查看运行时日志:
bash
npx zeabur@latest deployment log --service-id SERVICE_ID在运行中的服务内执行命令(类似):
docker execbash
npx zeabur@latest service exec --id SERVICE_ID -- SHELL_COMMAND这对调试非常有用——可用于检查文件路径、环境变量、测试连接性、查看文件系统等。示例:
bash
npx zeabur@latest service exec --id SERVICE_ID -- ls /app
npx zeabur@latest service exec --id SERVICE_ID -- env | grep DATABASE
npx zeabur@latest service exec --id SERVICE_ID -- nc -z localhost 5432重启服务(用于解决ImagePullBackOff问题或强制重新拉取镜像):
bash
npx zeabur@latest service restart --id SERVICE_ID -i=false -y删除项目并重新开始:
bash
npx zeabur@latest project delete --id PROJECT_ID危险操作——删除项目前,必须向用户明确确认,清晰说明项目ID、名称和创建时间。绝不要未经确认就删除。
发布新模板:
bash
npx zeabur@latest template create -f YOUR_TEMPLATE.yaml此命令会返回一个模板URL,例如,并附带一个模板代码。
https://zeabur.com/templates/XXXXXX更新现有模板:
bash
npx zeabur@latest template update -c TEMPLATE_CODE -f YOUR_TEMPLATE.yamlQuick Reference: Template Skeleton
快速参考:模板骨架
yaml
undefinedyaml
undefinedyaml-language-server: $schema=https://schema.zeabur.app/template.json
yaml-language-server: $schema=https://schema.zeabur.app/template.json
apiVersion: zeabur.com/v1
kind: Template
metadata:
name: ServiceName
spec:
description: |
English description (1-3 sentences)
icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/service.svg
coverImage: https://example.com/cover.webp
tags:
- Category
variables: []
readme: |
# Service Name
English documentation...
services:
- name: service-name
icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/service.svg
template: PREBUILT_V2
spec:
source:
image: image:tag
command: # MUST be inside source, alongside image
- /bin/sh
- -c
- /opt/app/startup.sh
ports:
- id: web
port: 8080
type: HTTP
volumes:
- id: data
dir: /path/to/data
configs:
- path: /opt/app/startup.sh
permission: 493 # 0755
envsubst: false
template: |
#!/bin/sh
exec node server.js
env:
VAR_NAME:
default: value
expose: true
localization:
zh-TW:
description: ...
variables: []
readme: |
# ...
zh-CN:
description: ...
variables: []
readme: |
# ...
ja-JP:
description: ...
variables: []
readme: |
# ...
es-ES:
description: ...
variables: []
readme: |
# ...
id-ID:
description: ...
variables: []
readme: |
# ...
undefinedapiVersion: zeabur.com/v1
kind: Template
metadata:
name: ServiceName
spec:
description: |
英文描述(1-3句话)
icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/service.svg
coverImage: https://example.com/cover.webp
tags:
- Category
variables: []
readme: |
# 服务名称
英文文档...
services:
- name: service-name
icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/service.svg
template: PREBUILT_V2
spec:
source:
image: image:tag
command: # 必须与image一起放在source内
- /bin/sh
- -c
- /opt/app/startup.sh
ports:
- id: web
port: 8080
type: HTTP
volumes:
- id: data
dir: /path/to/data
configs:
- path: /opt/app/startup.sh
permission: 493 # 0755
envsubst: false
template: |
#!/bin/sh
exec node server.js
env:
VAR_NAME:
default: value
expose: true
localization:
zh-TW:
description: ...
variables: []
readme: |
# ...
zh-CN:
description: ...
variables: []
readme: |
# ...
ja-JP:
description: ...
variables: []
readme: |
# ...
es-ES:
description: ...
variables: []
readme: |
# ...
id-ID:
description: ...
variables: []
readme: |
# ...
undefinedQuick Reference: Built-in Variables
快速参考:内置变量
| Variable | Purpose |
|---|---|
| Auto-generated secure password |
| Full public URL (e.g. |
| Domain only (e.g. |
| Internal hostname for inter-service communication |
| Port value by port ID (e.g. |
| External hostname (for |
| External forwarded port (for |
The pattern: for a port named , it becomes ; for , it becomes .
ZEABUR_<PORT_ID>_URLweb${ZEABUR_WEB_URL}console${ZEABUR_CONSOLE_URL}| 变量 | 用途 |
|---|---|
| 自动生成的安全密码 |
| 完整的公共URL(例如 |
| 仅包含域名(例如 |
| 服务间通信的内部主机名 |
| 通过端口ID获取端口值(例如 |
| 外部主机名(用于 |
| 外部转发端口(用于 |
ZEABUR_<PORT_ID>_URLweb${ZEABUR_WEB_URL}console${ZEABUR_CONSOLE_URL}Quick Reference: command Placement
快速参考:command的位置
IMPORTANT: MUST be inside , alongside . NOT at level.
commandsourceimagespecyaml
undefined重要提示:必须放在内,与同级。不能放在层级。
commandsourceimagespecyaml
undefinedWRONG -- command at spec level (will be IGNORED, container uses default CMD)
错误示例 -- command在spec层级(会被忽略,容器使用默认CMD)
spec:
source:
image: python:3.12-slim
command:
- /bin/sh
- -c
- /opt/app/start.sh
spec:
source:
image: python:3.12-slim
command:
- /bin/sh
- -c
- /opt/app/start.sh
CORRECT -- command inside source
正确示例 -- command在source内
spec:
source:
image: python:3.12-slim
command:
- /bin/sh
- -c
- /opt/app/start.sh
> **Note:** The external docs may show `command` at `spec` level. This is incorrect. Always place `command` inside `source` as confirmed by the JSON schema at `schema.zeabur.app/prebuilt.json`.spec:
source:
image: python:3.12-slim
command:
- /bin/sh
- -c
- /opt/app/start.sh
> **注意:** 外部文档可能显示`command`在`spec`层级,这是错误的。请始终按照`schema.zeabur.app/prebuilt.json`中的JSON架构要求,将`command`放在`source`内。Quick Reference: YAML Gotchas
快速参考:YAML注意事项
yaml
undefinedyaml
undefinedRISKY -- @ at start of value is a YAML reserved indicator (may cause parse errors)
风险 -- 值开头的@是YAML保留标记(可能导致解析错误)
description: @BotFather token
description: @BotFather token
SAFE -- quote the value or avoid @ at start
安全做法 -- 对值加引号或避免@开头
description: "Token from @BotFather for Telegram bot"
description: Telegram bot token from BotFather
undefineddescription: "来自@BotFather的Telegram机器人令牌"
description: Telegram机器人令牌(来自BotFather)
undefinedQuick Reference: Docker Image ENTRYPOINT
快速参考:Docker镜像ENTRYPOINT
Some base images have ENTRYPOINT set, which conflicts with .
command| Image | ENTRYPOINT | Problem |
|---|---|---|
| | |
| none | Safe to use |
| none | Safe to use |
If using an image with ENTRYPOINT, switch to a plain base image (e.g. ) or one without ENTRYPOINT.
python:3.12-slim-bookworm某些基础镜像设置了ENTRYPOINT,这会与冲突。
command| 镜像 | ENTRYPOINT | 问题 |
|---|---|---|
| | |
| 无 | 可安全使用 |
| 无 | 可安全使用 |
如果使用的镜像有ENTRYPOINT,请切换到无ENTRYPOINT的基础镜像(例如)。
python:3.12-slim-bookwormQuick Reference: Headless Services (no HTTP)
快速参考:无头服务(无HTTP端口)
If a service does NOT listen on any HTTP port (502 Bad Gateway), see skill for the fix.
zeabur-port-mismatch如果服务不监听任何HTTP端口(出现502 Bad Gateway错误),请查看技能获取解决方案。
zeabur-port-mismatchQuick Reference: Critical Rules
快速参考:关键规则
yaml
undefinedyaml
undefinedWRONG -- hardcoded password
错误示例 -- 硬编码密码
POSTGRES_PASSWORD:
default: mypassword123
POSTGRES_PASSWORD:
default: mypassword123
CORRECT -- use ${PASSWORD}
正确示例 -- 使用${PASSWORD}
POSTGRES_PASSWORD:
default: ${PASSWORD}
expose: true
POSTGRES_PASSWORD:
default: ${PASSWORD}
expose: true
WRONG -- PUBLIC_DOMAIN gives incomplete URL
错误示例 -- PUBLIC_DOMAIN提供的URL不完整
APP_URL:
default: https://${PUBLIC_DOMAIN}
APP_URL:
default: https://${PUBLIC_DOMAIN}
CORRECT -- ZEABUR_WEB_URL gives full URL
正确示例 -- ZEABUR_WEB_URL提供完整URL
APP_URL:
default: ${ZEABUR_WEB_URL}
readonly: true
APP_URL:
default: ${ZEABUR_WEB_URL}
readonly: true
WRONG -- other services can't reference without expose
错误示例 -- 未暴露变量,其他服务无法引用
POSTGRES_HOST:
default: ${CONTAINER_HOSTNAME}
POSTGRES_HOST:
default: ${CONTAINER_HOSTNAME}
CORRECT -- expose + readonly for connection info
正确示例 -- 暴露并设为只读,用于连接信息
POSTGRES_HOST:
default: ${CONTAINER_HOSTNAME}
expose: true
readonly: true
POSTGRES_HOST:
default: ${CONTAINER_HOSTNAME}
expose: true
readonly: true
WRONG -- referencing variables without declaring dependency
错误示例 -- 未声明依赖就引用变量
- name: app spec: env: DB: ${POSTGRES_HOST}
- name: app spec: env: DB: ${POSTGRES_HOST}
CORRECT -- declare dependency first
正确示例 -- 先声明依赖
- name: app
dependencies:
- postgresql spec: env: DB: ${POSTGRES_HOST}
---- name: app
dependencies:
- postgresql spec: env: DB: ${POSTGRES_HOST}
---Domain Binding
域名绑定
Use on the service that needs a public domain. It maps to a variable defined in with .
domainKeyspec.variablestype: DOMAINSingle domain:
yaml
domainKey: PUBLIC_DOMAINMultiple domains (different ports):
yaml
domainKey:
- port: web
variable: ENDPOINT_DOMAIN
- port: console
variable: ADMIN_ENDPOINT_DOMAIN在需要公共域名的服务上使用,它会映射到中定义的类型的变量。
domainKeyspec.variablestype: DOMAIN单域名:
yaml
domainKey: PUBLIC_DOMAIN多域名(不同端口):
yaml
domainKey:
- port: web
variable: ENDPOINT_DOMAIN
- port: console
variable: ADMIN_ENDPOINT_DOMAINCommon Database Configs
常见数据库配置
PostgreSQL
PostgreSQL
yaml
- name: postgresql
icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/postgresql.svg
template: PREBUILT_V2
spec:
source:
image: postgres:16-alpine
ports:
- id: database
port: 5432
type: TCP
volumes:
- id: data
dir: /var/lib/postgresql/data
env:
POSTGRES_USER:
default: postgres
expose: true
POSTGRES_PASSWORD:
default: ${PASSWORD}
expose: true
POSTGRES_DB:
default: mydb
expose: true
POSTGRES_HOST:
default: ${CONTAINER_HOSTNAME}
expose: true
readonly: true
POSTGRES_PORT:
default: ${DATABASE_PORT}
expose: true
readonly: true
POSTGRES_CONNECTION_STRING:
default: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
expose: true
readonly: trueyaml
- name: postgresql
icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/postgresql.svg
template: PREBUILT_V2
spec:
source:
image: postgres:16-alpine
ports:
- id: database
port: 5432
type: TCP
volumes:
- id: data
dir: /var/lib/postgresql/data
env:
POSTGRES_USER:
default: postgres
expose: true
POSTGRES_PASSWORD:
default: ${PASSWORD}
expose: true
POSTGRES_DB:
default: mydb
expose: true
POSTGRES_HOST:
default: ${CONTAINER_HOSTNAME}
expose: true
readonly: true
POSTGRES_PORT:
default: ${DATABASE_PORT}
expose: true
readonly: true
POSTGRES_CONNECTION_STRING:
default: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
expose: true
readonly: trueMySQL/MariaDB
MySQL/MariaDB
yaml
- name: mariadb
icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/mariadb.svg
template: PREBUILT_V2
spec:
source:
image: mariadb:10.6
ports:
- id: database
port: 3306
type: TCP
volumes:
- id: data
dir: /var/lib/mysql
env:
MYSQL_ROOT_PASSWORD:
default: ${PASSWORD}
expose: true
MYSQL_DATABASE:
default: mydb
expose: true
MYSQL_HOST:
default: ${CONTAINER_HOSTNAME}
expose: true
readonly: true
MYSQL_PORT:
default: ${DATABASE_PORT}
expose: true
readonly: trueyaml
- name: mariadb
icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/mariadb.svg
template: PREBUILT_V2
spec:
source:
image: mariadb:10.6
ports:
- id: database
port: 3306
type: TCP
volumes:
- id: data
dir: /var/lib/mysql
env:
MYSQL_ROOT_PASSWORD:
default: ${PASSWORD}
expose: true
MYSQL_DATABASE:
default: mydb
expose: true
MYSQL_HOST:
default: ${CONTAINER_HOSTNAME}
expose: true
readonly: true
MYSQL_PORT:
default: ${DATABASE_PORT}
expose: true
readonly: trueRedis
Redis
yaml
- name: redis
icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/redis.svg
template: PREBUILT_V2
spec:
source:
image: redis:7-alpine
ports:
- id: database
port: 6379
type: TCP
volumes:
- id: data
dir: /data
env:
REDIS_HOST:
default: ${CONTAINER_HOSTNAME}
expose: true
readonly: true
REDIS_PORT:
default: ${DATABASE_PORT}
expose: true
readonly: trueyaml
- name: redis
icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/redis.svg
template: PREBUILT_V2
spec:
source:
image: redis:7-alpine
ports:
- id: database
port: 6379
type: TCP
volumes:
- id: data
dir: /data
env:
REDIS_HOST:
default: ${CONTAINER_HOSTNAME}
expose: true
readonly: true
REDIS_PORT:
default: ${DATABASE_PORT}
expose: true
readonly: trueStandard Volume Paths
标准卷路径
| Service | Path |
|---|---|
| PostgreSQL | |
| MySQL/MariaDB | |
| MongoDB | |
| Redis | |
| MinIO | |
| 服务 | 路径 |
|---|---|
| PostgreSQL | |
| MySQL/MariaDB | |
| MongoDB | |
| Redis | |
| MinIO | |
Template Complexity Levels
模板复杂度等级
Level 1 -- Single prebuilt service (e.g., Memos, Uptime-Kuma, LobeChat):
- Just one service with image, port, and optionally a volume
- Simplest pattern, no cross-service wiring needed
Level 2 -- App + database (e.g., Ghost+MySQL, Linkwarden+PostgreSQL):
- Database service exposes vars, app service references them
- App service uses to ensure DB starts first
dependencies
Level 3 -- App + database + init/migrator (e.g., Teable, Open Mercato):
- First-run initialization or separate migrator service
- Requires wait-for-db pattern and init marker files
Level 4 -- Multi-service with multiple domains (e.g., Logto):
- Multiple ports on one service, each bound to a different domain variable
Level 5 -- Large-scale multi-service platform (e.g., Dify 12 services, Supabase 11 services):
- Reverse proxy as entry point: nginx (Dify) or Kong (Supabase) as the single domain-bound service
- Same image, different MODE: e.g., Dify runs ,
api,workerfrom the same imageworker-beat - Internal-only services: no public domain, communicate via
${CONTAINER_HOSTNAME} - Heavy use of : Nginx conf, SQL init scripts, Kong config — all injected via
configsfieldconfigs - PostgreSQL init SQL via configs: Mount to for auto execution
/docker-entrypoint-initdb.d/ - Shared secrets: Use for all internal credentials
${PASSWORD}
等级1 -- 单个预构建服务(例如Memos、Uptime-Kuma、LobeChat):
- 仅包含一个服务,包含镜像、端口,可选卷
- 最简单的模式,无需跨服务连接
等级2 -- 应用+数据库(例如Ghost+MySQL、Linkwarden+PostgreSQL):
- 数据库服务暴露变量,应用服务引用这些变量
- 应用服务使用确保数据库先启动
dependencies
等级3 -- 应用+数据库+初始化/迁移服务(例如Teable、Open Mercato):
- 首次运行初始化或独立的迁移服务
- 需要等待数据库就绪的模式和初始化标记文件
等级4 -- 多服务+多域名(例如Logto):
- 单个服务有多个端口,每个端口绑定到不同的域名变量
等级5 -- 大规模多服务平台(例如Dify的12个服务、Supabase的11个服务):
- 反向代理作为入口:使用nginx(Dify)或Kong(Supabase)作为绑定域名的单一服务
- 同一镜像,不同模式:例如Dify从同一镜像运行、
api、workerworker-beat - 仅内部服务:无公共域名,通过通信
${CONTAINER_HOSTNAME} - 大量使用:Nginx配置、SQL初始化脚本、Kong配置——全部通过
configs字段注入configs - 通过configs初始化PostgreSQL SQL:挂载到以自动执行
/docker-entrypoint-initdb.d/ - 共享密钥:所有内部凭证使用
${PASSWORD}
Writing name, description, readme, icon, and coverImage
编写name、description、readme、icon和coverImage
Where to collect information (in priority order):
- The project's GitHub repo README
- The project's official website
- Other public sources (blog posts, documentation sites, etc.)
Key rules:
- Do NOT copy-paste the original README. Write the introduction for this project's Zeabur template, not for the project itself. The readme should:
- Briefly introduce what the project is
- Focus on how to use this template (deployment steps, configuration, domain binding)
- Include important caveats and troubleshooting tips specific to Zeabur deployment
- Always include licensing and attribution. If the original project has an MIT, Apache, or other license:
- Mention the license in the readme
- Link to the original repo
- Link to the official website if available
- This is legally required -- never skip it
- icon and coverImage: Find the project's logo from their GitHub repo or official website. Use a direct URL to an image (SVG, PNG, or WebP). Always verify the URL returns HTTP 200:
Common pitfall: wrong branch name inbash
curl -s -o /dev/null -w "%{http_code}" "URL"URLs (raw.githubusercontent.comvsdevelopvsmain).master
信息收集来源(按优先级排序):
- 项目的GitHub仓库README
- 项目的官方网站
- 其他公开来源(博客文章、文档站点等)
关键规则:
- 不要直接复制粘贴原始README。请为该项目的Zeabur模板编写介绍,而非项目本身的介绍。README应包含:
- 简要介绍项目是什么
- 重点说明如何使用该模板(部署步骤、配置、域名绑定)
- 包含与Zeabur部署相关的重要注意事项和故障排除提示
- 始终包含许可证和归属信息。如果原始项目使用MIT、Apache或其他许可证:
- 在README中提及许可证
- 链接到原始仓库
- 如有官方网站,也请链接
- 这是法律要求——绝不要省略
- icon和coverImage:从项目的GitHub仓库或官方网站获取项目标志。使用指向图片的直接URL(SVG、PNG或WebP格式)。始终验证URL返回HTTP 200状态码:
常见问题:bash
curl -s -o /dev/null -w "%{http_code}" "URL"URL中的分支名称错误(raw.githubusercontent.com、develop或main混淆)。master
Localization Requirements
本地化要求
6 languages required: en-US (in ), zh-TW, zh-CN, ja-JP, es-ES, id-ID.
specTranslate: , , ,
descriptionvariables[].namevariables[].descriptionreadmeDo NOT translate: , , , URLs
keytype${VARIABLE_NAMES}需要支持6种语言:en-US(在中)、zh-TW、zh-CN、ja-JP、es-ES、id-ID。
spec需要翻译的内容:、、、
descriptionvariables[].namevariables[].descriptionreadme不要翻译的内容:、、、URL
keytype${VARIABLE_NAMES}Hard-Won Lessons (from real template challenges)
经验总结(来自实际模板开发挑战)
Wait for database readiness
等待数据库就绪
Zeabur's field only ensures services are deployed, not that they're ready to accept connections. A database container can take 5-15 seconds to initialize. Always add a wait loop before running migrations or init:
dependenciesyaml
args:
- -c
- |
echo "Waiting for PostgreSQL..."
while ! nc -z ${POSTGRES_HOST} ${POSTGRES_PORT} 2>/dev/null; do sleep 2; done
echo "PostgreSQL is ready!"
echo "Waiting for Redis..."
while ! nc -z ${REDIS_HOST} ${REDIS_PORT} 2>/dev/null; do sleep 2; done
echo "Redis is ready!"
# ... then run migrations/initNote: (netcat) is available on most Alpine-based images. If not, use or a node one-liner.
ncwget --spiderZeabur的字段仅确保服务已部署,而非已准备好接受连接。数据库容器可能需要5-15秒才能初始化。在运行迁移或初始化前,务必添加等待循环:
dependenciesyaml
args:
- -c
- |
echo "等待PostgreSQL..."
while ! nc -z ${POSTGRES_HOST} ${POSTGRES_PORT} 2>/dev/null; do sleep 2; done
echo "PostgreSQL已就绪!"
echo "等待Redis..."
while ! nc -z ${REDIS_HOST} ${REDIS_PORT} 2>/dev/null; do sleep 2; done
echo "Redis已就绪!"
# ... 然后运行迁移/初始化注意:(netcat)在大多数Alpine-based镜像中可用。如果不可用,可使用或Node.js单行命令。
ncwget --spiderStudy the project's own Dockerfile and docker-compose
研究项目自身的Dockerfile和docker-compose
Never guess startup commands. Instead:
- Read the project's to understand the build stages and the final
Dockerfile/CMDENTRYPOINT - Read and especially
docker-compose.yml(ordocker-compose.fullapp.yml) for the production startup command -- these often override the Dockerfile's CMD with init/migrate logicdocker-compose.prod.yml - Check the app's scripts to understand what
package.jsonoryarn startactually runsnpm start - The startup command in docker-compose is battle-tested -- copy it, don't reinvent it
不要猜测启动命令。请遵循以下步骤:
- 阅读项目的以了解构建阶段和最终的
Dockerfile/CMDENTRYPOINT - 阅读,尤其是
docker-compose.yml(或docker-compose.fullapp.yml)以获取生产环境启动命令——这些命令通常会覆盖Dockerfile的CMD,包含初始化/迁移逻辑docker-compose.prod.yml - 查看应用的脚本以了解
package.json或yarn start实际执行的内容npm start - docker-compose中的启动命令是经过验证的——直接复制,不要重新发明
Memory-heavy apps need lighter startup
内存密集型应用需要更轻量的启动方式
Apps that spawn workers, schedulers, and the web server all in one process may OOM on Zeabur's default allocation. Signs of OOM:
- Container starts, runs for 1-2 minutes, then crashes with no error logs (just )
BackOff: Back-off restarting failed container - No application-level crash message -- the kernel kills the process silently
Solutions:
- Run the web server directly (e.g., or
next start) instead of a CLI wrapper that spawns workers + scheduler + servernode server.js - Disable non-essential background processes via env vars (e.g., )
AUTO_SPAWN_WORKERS=false - If workers are needed, consider splitting them into a separate service
同时启动worker、调度器和Web服务器的应用可能会在Zeabur的默认资源分配下出现OOM(内存不足)。OOM的迹象:
- 容器启动后运行1-2分钟,然后无错误日志就崩溃(仅显示)
BackOff: Back-off restarting failed container - 无应用级崩溃信息——内核会静默终止进程
解决方案:
- 直接运行Web服务器(例如或
next start),而非启动worker+调度器+服务器的CLI包装器node server.js - 通过环境变量禁用非必要的后台进程(例如)
AUTO_SPAWN_WORKERS=false - 如果需要worker,考虑将其拆分为独立服务
First-run init with persistent marker
首次运行初始化与持久化标记
For apps that need first-time initialization (DB schema, seed data, admin users), use a marker file in a persistent volume:
yaml
args:
- -c
- |
if [ ! -f /app/storage/.initialized ]; then
echo "First run: initializing..."
run-init-command && touch /app/storage/.initialized
else
echo "Subsequent run: migrations only..."
run-migrate-command
fi
exec start-server-commandKey points:
- The marker file MUST be in a persistent volume, not (which is ephemeral)
/tmp/ - Use after init so the marker is only created if init succeeds
&& - Use for the final server process so it becomes PID 1 and receives signals properly
exec - Read init logs carefully for the actual default credentials -- don't assume from docs
对于需要首次初始化(数据库架构、种子数据、管理员用户)的应用,在持久化卷中使用标记文件:
yaml
args:
- -c
- |
if [ ! -f /app/storage/.initialized ]; then
echo "首次运行:正在初始化..."
run-init-command && touch /app/storage/.initialized
else
echo "后续运行:仅执行迁移..."
run-migrate-command
fi
exec start-server-command关键点:
- 标记文件必须放在持久化卷中,而非(临时目录)
/tmp/ - 在初始化命令后使用,确保只有初始化成功才创建标记
&& - 最终的服务器进程使用,使其成为PID 1并能正确接收信号
exec - 仔细查看初始化日志以获取实际默认凭证——不要仅根据文档假设
Working directory matters
工作目录很重要
When overriding /, be aware of the Dockerfile's . In monorepo apps, different commands need to run from different directories:
commandargsWORKDIRyaml
args:
- -c
- |
cd /app # root workspace for yarn workspace commands
yarn mercato init # CLI from root package.json
cd /app/apps/myapp # app directory for next start
exec next start -p 3000覆盖/时,请注意Dockerfile的。在单体仓库应用中,不同命令需要在不同目录下运行:
commandargsWORKDIRyaml
args:
- -c
- |
cd /app # yarn workspace命令的根工作区
yarn mercato init # 来自根package.json的CLI命令
cd /app/apps/myapp # next start的应用目录
exec next start -p 3000ImagePullBackOff recovery
解决ImagePullBackOff问题
When a pod is stuck in (e.g., after making a Docker Hub repo public), the Kubernetes backoff timer prevents immediate retries. Fix by restarting the service:
ImagePullBackOffbash
npx zeabur@latest service restart --id SERVICE_ID -i=false -y当Pod卡在状态(例如将Docker Hub仓库设为公开后),Kubernetes的退避计时器会阻止立即重试。可通过重启服务解决:
ImagePullBackOffbash
npx zeabur@latest service restart --id SERVICE_ID -i=false -yDisable unused monitoring agents
禁用未使用的监控代理
Many production images ship with New Relic, Datadog, or similar APM agents. These require license keys and consume memory. Add or equivalent env vars to disable them cleanly. Check if the script injects agents via -- these still run even if the agent errors out.
NEW_RELIC_ENABLED=falsestartNODE_OPTIONS='-r newrelic'许多生产镜像内置了New Relic、Datadog或类似的APM代理。这些代理需要许可证密钥并消耗内存。添加或等效环境变量以干净地禁用它们。请检查脚本是否通过注入代理——即使代理出错,它们仍会运行。
NEW_RELIC_ENABLED=falsestartNODE_OPTIONS='-r newrelic'Verify all URLs before publishing
发布前验证所有URL
Before publishing a template, verify that ALL URLs return HTTP 200:
- URL
icon - URL
coverImage - Links in
readme
Common pitfall: URLs with wrong branch name ( vs vs ). Always check:
raw.githubusercontent.comdevelopmainmasterbash
curl -s -o /dev/null -w "%{http_code}" "https://raw.githubusercontent.com/..."发布模板前,请验证所有URL都返回HTTP 200状态码:
- URL
icon - URL
coverImage - 中的链接
readme
常见问题: URL中的分支名称错误(、或混淆)。请始终检查:
raw.githubusercontent.comdevelopmainmasterbash
curl -s -o /dev/null -w "%{http_code}" "https://raw.githubusercontent.com/..."