steelforesight/liara-deploy.md

230 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Liara Deployment Playbook (عمومی)
راهنمای عمومی دیپلوی روی Liara — جمع‌بندی مشکلات رایج و راه‌حل‌هاشون.
برای **هر پروژه‌ای** قابل استفاده‌ست. جای `<...>`ها مقدار پروژه‌ی خودت رو بذار.
> قرارداد نام‌گذاری در این سند:
> `<app>` = اسم اپ، `<frontend-app>` = اپ فرانت، `<panel-app>` = اپ بک‌اند/پنل،
> `<db-internal-host>` = هاست داخلی دیتابیس، `<TOKEN>` = API token لیارا،
> `<port>` = پورتی که اپ روش گوش می‌ده (Docker static: معمولاً 7860، Node: 3000).
---
## ۱) CLI — احراز هویت
**مشکل:** دستورها با `Authentication failed` رد می‌شن، حتی بعد از `liara login` (توکن بین شل‌ها/محیط‌ها share نمی‌شه).
**راه‌حل:** روی **هر** دستور `--api-token` بده:
```bash
liara deploy --app <app> --api-token "<TOKEN>"
```
توکن از داشبورد Liara → API.
---
## ۲) `liara deploy` روی prompt پورت هنگ می‌کنه
**مشکل:** دیپلوی روی `Enter the port your app listens to:` گیر می‌کنه و چیزی به Liara نمی‌رسه (مخصوصاً در حالت غیرتعاملی).
**راه‌حل:** پورت رو صریح بده — هم فلگ، هم `liara.json`:
```bash
liara deploy --app <app> --port <port> ...
```
```json
{ "platform": "docker", "port": <port> }
```
اپ هم باید روی `process.env.PORT` گوش بده (Liara اون رو inject می‌کنه).
---
## ۳) `Dockerfile cannot be empty`
**علت:** `.dockerignore` خود `Dockerfile` رو exclude کرده.
**راه‌حل:** `Dockerfile` رو از `.dockerignore` **بردار** — Liara باید Dockerfile رو توی آرشیو ببینه.
---
## ۴) Docker Hub از ایران بلاکه (مهم‌ترین برای Docker)
**مشکل:** `FROM <image>` با `Get "https://registry-1.docker.io/...": Client.Timeout exceeded` تایم‌اوت می‌خوره.
**راه‌حل:** image پایه رو از **میرور Liara** بکش:
```dockerfile
# ایمیج رسمی (node, nginx, postgres, python, ...):
FROM docker-mirror.liara.ir/library/<image>:<tag>
# ایمیج یوزر/سازمان:
FROM docker-mirror.liara.ir/<org>/<image>:<tag>
```
میرورهای دیگر Liara (در صورت نیاز داخل build):
| نوع | میرور |
|---|---|
| Docker Hub | `docker-mirror.liara.ir` |
| Alpine (apk) | `https://linux-mirror.liara.ir/repository/alpine/` |
| npm | `https://package-mirror.liara.ir/repository/npm/` |
> `npm ci`/`pip install` معمولاً از ایران بدون میرور کار می‌کنن؛ فقط Docker Hub همیشه مشکل‌سازه.
> اگه داخل build `apk add` داری، میرور apk رو هم ست کن.
---
## ۵) لوکیشن build
**نکته‌ی کلیدی:** **لوکیشن build ≠ لوکیشن میزبانی.** اپ همیشه روی منطقه‌ی خودش سرو می‌شه؛ `--build-location` فقط می‌گه image کجا کامپایل شه.
- build ایران + میرورهای بالا → سریع و بدون تحریم:
```bash
liara deploy --app <app> --build-location iran ...
```
- اگه از میرور استفاده نمی‌کنی، build ایران به Docker Hub نمی‌رسه (از مورد ۴ استفاده کن).
---
## ۶) متغیرهای build-time در فرانت (Vite / CRA / Next static)
**مشکل:** متغیر API URL رو به‌عنوان env روی اپ ست کردی ولی فرانت بهش وصل نشد.
**علت:** باندلرها متغیرهای `VITE_*` / `REACT_APP_*` / `NEXT_PUBLIC_*` رو **موقع build داخل باندل می‌نویسن** — env runtime روی کانتینر استاتیک بی‌اثره.
**راه‌حل:** توی Dockerfile قبل از build:
```dockerfile
ARG VITE_API_URL=https://<panel-app>.liara.run
ENV VITE_API_URL=$VITE_API_URL
RUN npm run build
```
---
## ۷) اتصال اپ به دیتابیس (Private Network)
**مشکل‌ها:**
- آدرس داخلی دیتابیس → `getaddrinfo ENOTFOUND <db-internal-host>`.
- آدرس عمومی دیتابیس از داخل اپ Liara → `ECONNREFUSED`.
**علت:** اپ‌های Liara به endpoint عمومی DB وصل نمی‌شن؛ و هاست داخلی فقط وقتی resolve می‌شه که اپ و DB **روی یک Private Network مشترک** باشن.
**راه‌حل:**
1. هم دیتابیس هم اپ رو به **یک Private Network** وصل کن.
2. **connection string کاملِ** داخلی (نه فقط host:port):
```
DATABASE_URL=postgresql://<user>:<pass>@<db-internal-host>:5432/<db>
```
3. روی شبکه‌ی داخلی TLS لازم نیست (برعکس endpoint عمومی که TLS می‌خواد).
---
## ۸) اپ موقع بوت کرش می‌کنه چون env ست نیست
**نشانه:** کانتینر `unhealthy` / `exit 255` و لاگ مثل `FATAL: <X> is not set`.
**راه‌حل:** env های حیاتی رو **قبل** از انتظارِ سالم‌بودن ست کن. تغییر env خودش ری‌استارت می‌کنه.
ست با CLI (به‌جای داشبورد):
```bash
liara env:set "KEY=VALUE" "KEY2=VALUE2" --app <app> --force --api-token "<TOKEN>"
```
> اگه کد بدون یه env حیاتی `process.exit` می‌کنه، تا ست نشه اصلاً بالا نمیاد.
---
## ۹) فایل‌سیستم Ephemeral
**مشکل‌ها:** دیتابیس فایلی (SQLite) و پوشه‌ی آپلود با هر ری‌دیپلوی پاک می‌شن؛ نوشتن/`mkdir` روی مسیرهای read-only کرش می‌کنه.
**راه‌حل:**
- دیتای دائمی → **دیتابیس مدیریت‌شده**.
- فایل/مدیا → **Object Storage** (مورد ۱۰).
- اگه واقعاً دیسک لازمه → یه **Disk** بساز و mount کن؛ مسیر رو **env-based** کن.
- هر نوشتن روی دیسک رو دفاعی بنویس که موقع بوت کرش نکنه:
```js
const dir = process.env.UPLOADS_DIR || path.join(__dirname, 'uploads');
try { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); } catch {}
```
---
## ۱۰) Object Storage (S3) برای مدیا
- S3-compatible؛ endpoint مثل `storage.iran.liara.site` + bucket + access key + secret key.
- در کد: SDK اس‌تری (`@aws-sdk/client-s3`)، `forcePathStyle: true`، endpoint = `https://<endpoint>`.
- URL عمومی فایل: `https://<bucket>.<endpoint>/<key>`.
- **باکت رو public کن** وگرنه فایل‌ها 403 می‌شن.
---
## ۱۱) پلتفرم اپ ثابته
نمی‌شه پلتفرم یه اپ رو عوض کرد (Node↔Docker↔Static). اگه اشتباه ساختی، **پاک و با پلتفرم درست دوباره بساز** (env و اتصال شبکه‌ی خصوصی رو هم از نو ست کن).
---
## ۱۲) CORS
**مشکل:** بک‌اند درخواست‌ها رو با `Not allowed by CORS` رد می‌کنه (حتی origin خودش).
**راه‌حل:** allow-list رو شامل **دامنه‌ی خود اپ + دامنه‌ی فرانت** کن:
```
ALLOWED_ORIGINS=https://<panel-app>.liara.run,https://<frontend-app>.liara.run
```
---
## ۱۳) Seed / یوزر ادمین
دیتابیس تازه خالیه → لاگین «رمز اشتباه». seed رو از Console اپ بزن. اگه اسکریپت seed یوزر موجود رو رد می‌کنه و رمز عوض نمی‌شه، از **upsert** استفاده کن.
نکته‌ی مهم برای اسکریپت‌های seed: آدرس و رمز رو **env-based** کن تا هم لوکال هم روی Liara کار کنه:
```js
const BASE = process.env.SEED_BASE || `http://localhost:${process.env.PORT || 3000}`;
```
> روش بدون TLS-dependency: اسکریپت seed که فقط `fetch` می‌زنه رو می‌تونی از ماشین خودت با `SEED_BASE=https://<panel-app>.liara.run` اجرا کنی.
---
## ۱۴) همگام‌سازی lockfile
بعد از هر تغییر وابستگی‌ها، **لوکال `npm install`** بزن تا `package-lock.json` به‌روز شه، بعد دیپلوی — وگرنه `npm ci` روی Liara به‌خاطر mismatch خطا می‌ده. `node_modules` رو پوش نکن (`.liaraignore` / `.dockerignore`).
---
## ۱۵) لاگ و exit code گمراه‌کننده
- `liara deploy` گاهی با `exit code 2` تموم می‌شه ولی واقعاً **موفق** بوده (خطا فقط مرحله‌ی خوندن لاگ بعد از دیپلوی).
- `liara logs` گاهی لاگ **کش‌شده** می‌ده.
**راه‌حل:** وضعیت واقعی رو از خروجی کامل دیپلوی (`√ Release created` / `Deployment finished successfully`) و یه **درخواست HTTP واقعی به دامنه** بگیر؛ به exit code تنها اعتماد نکن.
---
## فایل‌های پایه‌ی هر اپ
`liara.json` (Docker):
```json
{ "platform": "docker", "port": <port> }
```
`liara.json` (Node):
```json
{ "platform": "node" }
```
`.liaraignore`:
```
node_modules
.env
*.db
uploads
```
---
## چک‌لیست دیپلوی (ترتیب درست)
1. **دیتابیس** بساز → Private Network روشن.
2. **اپ بک‌اند** بساز → به همون Private Network وصلش کن.
3. env های بک‌اند رو ست کن (`DATABASE_URL` داخلیِ کامل، سکرت‌ها، `ALLOWED_ORIGINS`، کلیدهای Object Storage، `NODE_ENV=production`).
4. `package-lock.json` رو لوکال sync کن.
5. (Docker) Dockerfile: میرور `docker-mirror.liara.ir` + `ARG` برای متغیرهای build-time. `.dockerignore` نباید `Dockerfile` رو حذف کنه.
6. `liara deploy --app <app> --port <port> --build-location iran --api-token "<TOKEN>"`.
7. سلامت رو با درخواست HTTP به دامنه چک کن (نه فقط exit code).
8. **seed محتوا/ادمین** (قبل از دیپلوی فرانت، تا سایت خالی نباشه).
9. باکت Object Storage رو public کن.
10. **فرانت** رو با متغیر build-time = دامنه‌ی بک‌اند دیپلوی کن؛ `ALLOWED_ORIGINS` بک‌اند رو شامل دامنه‌ی فرانت کن.