173 lines
9.6 KiB
Markdown
173 lines
9.6 KiB
Markdown
# 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 для Балды
|