Document Portainer stack 240 as the deploy path
Replace the legacy DSM-dir 'docker compose up -d --build' flow in AGENTS.md, COMPOSE-SETUP.md, DOCUMENTATION.md, README.md with the current deploy: sync build context to /volume1/docker/portainer/compose/240/, rebuild image if code changed, then PUT /api/stacks/240 (compose + env array, never echo masked *** values). Legacy dir marked as such; live tg IP note synced.
This commit is contained in:
@@ -55,10 +55,23 @@ container on DSM (network `bridge_hoelee`, reaches NocoDB at `http://nocodb:1038
|
||||
|
||||
## Build / deploy
|
||||
|
||||
Private build on DSM — NO registry (do not push to Docker Hub):
|
||||
Container is managed by **Portainer stack 240** (standalone; compose + build
|
||||
context live at `/volume1/docker/portainer/compose/240/` on DSM). Deploy flow:
|
||||
|
||||
```bash
|
||||
# on DSM (repo cloned to /volume1/docker/carousell-monitor)
|
||||
cd /volume1/docker/carousell-monitor
|
||||
sudo docker compose up -d --build
|
||||
```
|
||||
1. Edit code, commit, push to Gitea (`git.hoelee.com/hoelee/carousell-monitor`).
|
||||
2. Sync the build-context files to `/volume1/docker/portainer/compose/240/`
|
||||
(`monitor.py`, `healthcheck.py`, `Dockerfile`, `docker-compose.yml`).
|
||||
3. If `monitor.py` / `Dockerfile` changed, rebuild the image first (Portainer's
|
||||
standalone PUT does **not** rebuild):
|
||||
|
||||
```bash
|
||||
sudo /usr/local/bin/docker build -t carousell-monitor:latest \
|
||||
/volume1/docker/portainer/compose/240
|
||||
```
|
||||
|
||||
4. Update stack 240 via the Portainer API: `PUT /api/stacks/240?endpointId=2`
|
||||
with the repo `docker-compose.yml` as `stackFileContent` and the current env
|
||||
array (see the `portainer-api` skill; ⚠ never echo masked `***` values back).
|
||||
|
||||
Portainer recreates the container with the new config. Private build on DSM —
|
||||
NO registry (do not push to Docker Hub).
|
||||
|
||||
+24
-13
@@ -82,9 +82,8 @@ build context is the repo directory).
|
||||
- ⚠ If Telegram calls start timing out again, **re-verify the current IP**:
|
||||
`nslookup api.telegram.org` / `dig +short api.telegram.org` — Telegram rotates
|
||||
IPs. Update the pin, then redeploy.
|
||||
- Note: the **live** stack on DSM pins a slightly different IP than the repo copy —
|
||||
the live one was fixed during an earlier incident. Treat the repo value as
|
||||
the canonical starting point, and verify before assuming.
|
||||
- Note: the **live** stack pins the **same** IP as the repo (synced 2026-09-13).
|
||||
Treat the repo value as canonical; re-verify on any timeout.
|
||||
|
||||
### environment
|
||||
|
||||
@@ -192,18 +191,30 @@ Portainer shows it red, `docker inspect` reports it, and you can alert on it.
|
||||
|
||||
### A. On DSM via Portainer stack (current production)
|
||||
|
||||
1. Edit code in the repo (`D:\dev\carousell-monitor`).
|
||||
2. Commit + push to Gitea (`git.hoelee.com/hoelee/carousell-monitor`).
|
||||
3. On DSM, the deploy dir `/volume1/docker/carousell-monitor` is a **manual copy,
|
||||
not a git clone** — copy the changed files there:
|
||||
`cp monitor.py /volume1/docker/carousell-monitor/`
|
||||
(backup the old one first, per the repo's `.bak` convention).
|
||||
4. Rebuild + recreate:
|
||||
Container is owned by **Portainer stack 240** (standalone). Deploy:
|
||||
|
||||
1. Edit code in the repo (`D:\dev\carousell-monitor`), commit, push to Gitea
|
||||
(`git.hoelee.com/hoelee/carousell-monitor`).
|
||||
2. Sync the build context — Portainer's project dir holds a full manual copy
|
||||
(not a git clone): copy changed runtime files to
|
||||
`/volume1/docker/portainer/compose/240/` (`monitor.py`, `healthcheck.py`,
|
||||
`Dockerfile`, `docker-compose.yml`).
|
||||
3. If `monitor.py` / `Dockerfile` changed, rebuild the image — a standalone
|
||||
stack PUT does **not** run `--build`:
|
||||
```bash
|
||||
sudo /usr/local/bin/docker compose up -d --build
|
||||
sudo /usr/local/bin/docker build -t carousell-monitor:latest \
|
||||
/volume1/docker/portainer/compose/240
|
||||
```
|
||||
`--build` rebuilds the image from the new `monitor.py`; the NocoDB schema
|
||||
bootstrap and dedupe seeding are idempotent, so a rebuild never duplicates rows.
|
||||
4. Update the stack via the Portainer API:
|
||||
`PUT /api/stacks/240?endpointId=2` with the repo `docker-compose.yml` as
|
||||
`stackFileContent` and the **current env array** (8 entries, incl.
|
||||
`FETCH_GAP_SECONDS=1`; see the `portainer-api` skill — ⚠ Portainer masks
|
||||
secret env values, so never echo the masked `***` strings back, and keep the
|
||||
real Telegram token in `SECRETS.md`). Portainer recreates the container.
|
||||
|
||||
The old `/volume1/docker/carousell-monitor` dir is **legacy — do not
|
||||
`compose up` there anymore**; it only kept around for reference (its `.env` is
|
||||
masked and stale).
|
||||
|
||||
### B. Local dev (Windows, against LAN NocoDB)
|
||||
|
||||
|
||||
+15
-9
@@ -37,7 +37,7 @@ Nothing is pushed to any image registry — the image is built **privately on DS
|
||||
| `Dockerfile` | python:3.11-alpine + monitor.py + healthcheck.py, HEALTHCHECK |
|
||||
| `monitor.py` | Main loop: schema bootstrap, fetch/parse, NocoDB IO, Telegram |
|
||||
| `healthcheck.py` | HEALTHCHECK probe (reads `/data/health.json`) |
|
||||
| `.env` | Secrets + tunables (gitignored, NOT in the repo) |
|
||||
| `.env` | No longer used — secrets/tunables live in the **Portainer stack env** (stack 240); the legacy DSM-dir `.env` is masked and stale |
|
||||
| `DOCUMENTATION.md` | Deployment & operations manual |
|
||||
| `COMPOSE-SETUP.md` | Stack anatomy reference: compose file, Dockerfile, networks, deployment paths |
|
||||
|
||||
@@ -173,17 +173,23 @@ https://www.carousell.com.my/search/uniform?addRecent=true&canChangeKeyword=true
|
||||
|
||||
## 7. Updating the code
|
||||
|
||||
The image is built **on DSM** from this folder. To ship a code change:
|
||||
The container is owned by **Portainer stack 240**. To ship a code change:
|
||||
|
||||
```bash
|
||||
# 1) edit monitor.py / Dockerfile / compose in the repo (D:\dev\carousell-monitor)
|
||||
# 2) copy the changed file(s) to this folder, then:
|
||||
cd /volume1/docker/carousell-monitor
|
||||
sudo /usr/local/bin/docker compose up -d --build
|
||||
# 1) edit code in the repo (D:\dev\carousell-monitor), commit, push to Gitea
|
||||
# 2) sync runtime files to Portainer's build context:
|
||||
sudo cp monitor.py healthcheck.py Dockerfile docker-compose.yml \
|
||||
/volume1/docker/portainer/compose/240/
|
||||
# 3) if monitor.py / Dockerfile changed, rebuild the image (PUT doesn't --build):
|
||||
sudo /usr/local/bin/docker build -t carousell-monitor:latest \
|
||||
/volume1/docker/portainer/compose/240
|
||||
# 4) update stack 240 via Portainer API (PUT /api/stacks/240?endpointId=2,
|
||||
# repo compose as stackFileContent + current env array — see portainer-api skill;
|
||||
# ⚠ never echo masked *** values back, real Telegram token is in SECRETS.md)
|
||||
```
|
||||
|
||||
`--build` rebuilds the image and recreates the container; the NocoDB schema bootstrap
|
||||
and dedupe seeding are idempotent, so a rebuild never duplicates rows.
|
||||
Portainer recreates the container; the NocoDB schema bootstrap and dedupe
|
||||
seeding are idempotent, so a redeploy never duplicates rows.
|
||||
|
||||
---
|
||||
|
||||
@@ -219,7 +225,7 @@ Health file lives at `/data/health.json` inside the container:
|
||||
|---|---|
|
||||
| Repo (private) | `git.hoelee.com/hoelee/carousell-monitor` |
|
||||
| Local checkout | `D:\dev\carousell-monitor` |
|
||||
| DSM deploy dir | `/volume1/docker/carousell-monitor` |
|
||||
| Portainer stack | `240` (standalone; compose + build context at `/volume1/docker/portainer/compose/240/` on DSM) |
|
||||
| Container | `carousell-monitor` (network `bridge_hoelee`) |
|
||||
| NocoDB base | `Carousell` = `poqw1zjw3hnsk37` (workspace `wal4hatt`) |
|
||||
| Tables | `Listings` + `Settings` (bootstrap finds by title) |
|
||||
|
||||
@@ -47,18 +47,23 @@ docker build -t hoelee/carousell-monitor:latest .
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Deploy (DSM via Portainer)
|
||||
## Deploy (DSM via Portainer stack 240)
|
||||
|
||||
Private build — no registry. The compose at `/volume1/docker/carousell-monitor`
|
||||
is cloned from Gitea and built on DSM (`build: .`), then deployed as a Portainer
|
||||
stack with the secrets passed as stack environment variables.
|
||||
Private build — no registry. The container is owned by **Portainer stack 240**
|
||||
(standalone; compose + build context at `/volume1/docker/portainer/compose/240/`
|
||||
on DSM), deployed with secrets passed as stack environment variables.
|
||||
|
||||
```bash
|
||||
# on DSM
|
||||
cd /volume1/docker/carousell-monitor
|
||||
sudo docker compose up -d --build
|
||||
# on DSM — rebuild the image only when monitor.py / Dockerfile changed
|
||||
sudo /usr/local/bin/docker build -t carousell-monitor:latest \
|
||||
/volume1/docker/portainer/compose/240
|
||||
```
|
||||
|
||||
Then update stack 240 via the Portainer API (`PUT /api/stacks/240?endpointId=2`,
|
||||
repo compose as `stackFileContent` + current env array — see `portainer-api`
|
||||
skill; ⚠ never echo masked `***` env values back). The old
|
||||
`/volume1/docker/carousell-monitor` dir is legacy — do not `compose up` there.
|
||||
|
||||
## Files
|
||||
|
||||
- `monitor.py` — main loop, schema bootstrap, fetch/parse, NocoDB IO, Telegram.
|
||||
|
||||
Reference in New Issue
Block a user