Files
obsidian-vault/personal/projects/balda/mattermost-kraken-deploy.md
T

173 lines
9.6 KiB
Markdown
Raw 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.
# Mattermost на Kraken — деплой (arm64)
> Создано 2026-09-26. Статус: **в работе** — образ собирается, контейнеры поднимаются.
> Часть проекта [[personal/projects/balda/balda-mm-delegation-plan]].
---
## 🔴 Главная находка: официального arm64-образа Mattermost НЕТ
`mattermost/mattermost-team-edition` — **только `linux/amd64`**. Проверено `docker manifest inspect`
по тегам `latest`, `release-12`, `release-10`, `11.11.1`, `10.11.24`, `9.11`, `release-8` —
везде `architecture: amd64`. То же у `mattermost-enterprise-edition` и `mattermost-preview`.
Официальная позиция Mattermost (KB `53131125053204`, на 2026-09-01):
**ARM64 «Not officially supported for production, no roadmap commitment».** Публикуются
некоторые arm64-сборки, но production не поддерживается; официально поддержан только amd64.
⚠️ **`linuxserver/mattermost` НЕ существует** — `pull access denied`. На Docker Hub его нет.
Не искать его снова (я потратил на это время).
### Решение: собираем образ сами из ОФИЦИАЛЬНОГО бинаря
Mattermost **публикует arm64-бинарники** на release-сервере — просто не пакует их в образы.
Поэтому образ собирается локально на Kraken из официального tarball. Это production-путь:
свой Dockerfile + upstream-бинарь, **без сторонних community-образов**.
Проверка доступности (HTTP 200, `content-length: 157689127`):
```
https://releases.mattermost.com/11.11.1/mattermost-team-11.11.1-linux-arm64.tar.gz
```
Работает и `mattermost-<ver>-linux-arm64.tar.gz` (без `team`). Префикс `mattermost-team-` —
Team Edition, это то, что нужно.
**Альтернативы, которые НЕ выбраны:**
| Вариант | Почему нет |
|---|---|
| `cyberman443/mattermost-arm64` | сторонний, 5 мес. давности, непроверенная сборка |
| `ghcr.io/antonsatt/mattermost-arm64` | сторонний; CI собирает weekly, но доверия меньше, чем своему Dockerfile |
| `mmtrt/…`, `ctlove0523/…`, `bitnami/mattermost` | не существуют / нет arm64 |
Референс структуры Dockerfile: `github.com/AntonSatt/mattermost-arm64` (там `ubuntu:noble` +
официальный tarball; **нюанс — в их ARG по умолчанию enterprise-путь без `-team`**, у нас явно team).
---
## Файлы и пути
| Что | Путь |
|---|---|
| Каталог compose | `/home/kraken/mattermost/` |
| `docker-compose.yml` | `/home/kraken/mattermost/docker-compose.yml` (0600) |
| `.env` (пароль postgres) | `/home/kraken/mattermost/.env` (0600, 3 строки) |
| Данные и тома | `/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker/mattermost/{postgres,data,logs,plugins,config,client-plugins,bleve-indexes}` |
| Dockerfile сборки | `/home/kraken/mattermost-build/Dockerfile` |
| Образ | `mattermost-team-arm64:11.11.1` (+ `:latest`) |
| Скрипты деплоя (Mac) | `/tmp/mm-deploy/deploy-mattermost.sh`, `/tmp/mm-deploy/build-mattermost-arm64.sh` |
⚠️ Путь `49e8f586…` — **симлинк** на реальный `6194539b…`. Все сервисы используют старый путь.
### `.env` формат (3 строки, значения не в доке)
```
PGPW=<24 байта, openssl rand -hex 24>
PGUSR=mmuser
PGDBNAME=mattermost
```
Генерируется **на хосте** при первом запуске скрипта; повторный запуск не перезаписывает
(`if [ -s .env ]; then exists_kept`).
### `docker-compose.yml` — ключевые параметры
| Ключ | Значение | Почему |
|---|---|---|
| образ MM | `mattermost-team-arm64:11.11.1` | вместо официального amd64 |
| порт | `8065:8065` | был свободен (проверено `ss -tln`) |
| postgres | `postgres:16-alpine` | arm64 есть |
| `MM_SQLSETTINGS_DRIVERNAME` | `postgres` | |
| `MM_SQLSETTINGS_DATASOURCE` | `postgres://mmuser:<PGPW>@postgres:5432/mattermost?sslmode=disable&connect_timeout=10` | пароль подставляется **в момент генерации compose** из `.env` |
| `MM_SERVICESETTINGS_SITEURL` | `http://192.168.1.14:8065` (LAN, временно) | → поменять на `https://mm.qentra.top` после настройки туннеля |
| `MM_SERVICESETTINGS_ENABLELOCALMODE` | `true` | нужен для healthcheck `mmctl --local` |
| `MM_FILESETTINGS_DIRECTORY` | `/mattermost/data` | |
| healthcheck MM | `curl -fsS http://localhost:8065/api/v4/system/ping` | curl есть в ubuntu:noble-базе |
| healthcheck PG | `pg_isready -U mmuser -d mattermost` | |
| `restart` | `unless-stopped` | |
| `depends_on` | postgres `service_healthy` | MM не стартует раньше БД |
| сеть | bridge `mm-net` (не `host`) | MM не требует host-сети, в отличие от cloudflared |
**Питфолл:** `MM_SQLSETTINGS_DATASOURCE` — это URL, Mattermost читает env **литерально**,
интерполяция `${PGPW}` внутри значения не работает. Поэтому DSN собирается на хосте
через `printf` при записи compose, а не через `env_file`.
---
## Команды
```bash
# Сборка образа (на Kraken, ~минуты; запускать в background)
bash /tmp/mm-deploy/build-mattermost-arm64.sh
# Деплой (идемпотентный)
bash /tmp/mm-deploy/deploy-mattermost.sh
# Проверка
ssh kraken "curl -s http://localhost:8065/api/v4/system/ping"
ssh kraken "docker ps --format '{{.Names}}\t{{.Status}}' | grep -E 'mattermost|mm-postgres'"
```
### Питфоллы, найденные на месте
1. **`/srv/.../docker/` — `root:root 755`** → `kraken` НЕ может создать подкаталог.
Нужен `sudo -n mkdir -p` + `sudo -n chown -R 1000:1000`. `sudo -n true` на Kraken
работает **без пароля** (проверено, exit 0).
2. **`sudo` через SSH требует `< /dev/null`** — иначе `Connection closed by remote host`.
(Подтверждено, питфолл из `kraken-access` актуален.)
3. **Нет `ifconfig`** на Kraken — использовать `ip addr` / `ss`.
4. **Один ssh-heredoc вместо десятка round-trip'ов** — `ssh kraken 'bash -s' <<'REMOTE'`.
Быстрее и надёжнее, чем отдельные вызовы.
5. **`docker manifest inspect` на приватном/несуществующем образе** даёт
`unauthorized: authentication required`, а не `not found` — не путать с «образ существует».
---
## Cloudflare Tunnel — что настроить (делает Alex)
Туннель `kraken` уже существует, remote-managed по `TUNNEL_TOKEN`, `network_mode: host`.
**Zero Trust → Networks → Tunnels → `kraken` → Public Hostnames → Add:**
| Поле | Значение |
|---|---|
| Subdomain | `mm` |
| Domain | `qentra.top` |
| Path | *(пусто)* |
| Service Type | `HTTP` |
| URL | `localhost:8065` |
⚠️ **`httpHostHeader` НЕ ставить** — в отличие от `kraken.qentra.top`, где он обязателен.
⚠️ Без Access-Applications хостнейм `mm.qentra.top` **публично открыт в интернет**.
В Team Edition регистрация по умолчанию `open` — закрывать политикой Access или
выключать самостоятельную регистрацию в System Console.
**После добавления хостнейма** — поменять `MM_SERVICESETTINGS_SITEURL` на `https://mm.qentra.top`
и перезапустить MM. Иначе MM отдаёт ссылки на `192.168.1.14`, и WebSocket-клиент может не подключиться.
**Приёмка = вход в `https://mm.qentra.top` в браузере**, не «curl отвечает».
---
## Состояние (2026-09-26)
| Шаг | Статус |
|---|---|
| Каталоги на HDD | ✅ созданы, `kraken:kraken` |
| `.env` с паролем | ✅ создан, 0600, значения не логировались |
| `docker-compose.yml` | ✅ записан, проверено: DSN без плейсхолдера |
| Dockerfile + сборка arm64-образа | 🔄 запущена в фоне |
| `docker compose up -d` | ⏳ ожидает образ |
| Проверка `/api/v4/system/ping` | ⏳ |
| Cloudflare hostname `mm.qentra.top` | ⏳ делает Alex |
| `SITEURL` → внешний | ⏳ после туннеля |
## Связанные заметки
- [[personal/projects/balda/balda-mm-delegation-plan]] — общий план MM + делегирования
- [[family/how-to/kraken-access]] — доступ к Kraken, cloudflared, порты
- [[family/how-to/openmediavault-rpi5]] — структура Docker на Kraken
- [[personal/tech/docker-data-root-mount-race]] — почему том на HDD, а не на SD
- [[personal/projects/balda/balda-mattermost-connector]] — коннектор MM для Балды