Webitel: Документація

Upgrade Notes 26.02-26.04

В рамках нового релізу збірку deb-пакетів Webitel перенесено з Bamboo на GitHub Actions. Разом із цим змінено процес формування версій, package revision тепер прив'язаний до GitHub Actions workflow run, а пакети публікуються в новий закритий S3 APT-репозиторій із новим GPG-ключем підпису.

Міграція також додає підтримку Debian 13 поряд із Debian 12 і переводить збірку частини пакетів у мультиархітектурний режим:

  • backend-сервіси тепер збираються для amd64 та arm64;

  • frontend-пакети публікуються як architecture-independent (all);

  • PostgreSQL-екстеншн і модулі FreeSWITCH поки залишаються amd64-only.

Для Debian 13 підтримуваною комбінацією є PostgreSQL 18 і пакет webitel-postgresql-18; для Debian 12 залишається PostgreSQL 15 і webitel-postgresql-15. Оновлення Debian 12 → Debian 13 для інсталяцій з Webitel PostgreSQL-екстеншном потрібно планувати разом із мажорним оновленням PostgreSQL 15 → 18.

У складі пакетів є кілька практичних змін: частина frontend-пакетів отримала суфікс -app, backend-бінарники та частина systemd-юнітів отримали префікс webitel-, systemd-юніти більше не постачаються через webitel-common, а сервісні backend-пакети тепер містять maintainer-скрипти.

Алгоритм

Перед оновленням виконайте резервне копіювання бази даних

Зупинка сервісів Webitel

Bash
systemctl stop webitel-api webitel-app webitel-uac messages-bot messages-srv \
  engine call_center storage flow_manager rabbitmq-server webitel-logger \
  webitel-cases webitel-media-exporter consul freeswitch ngcp-rtpengine-daemon \
  opensips grafana-server nginx

Видалення застарілого Webitel репозиторію

Bash
rm -f /etc/apt/sources.list.d/webitel.list
rm -f /etc/apt/auth.conf.d/webitel.conf
rm -f /usr/share/keyrings/webitel-repo.gpg

Dist-upgrade Debian 12 → 13

Виконується тільки при переході на Debian 13.
Якщо інсталяція залишається на Debian 12, пропустіть цей крок

Тимчасово вимкніть кастомні APT-репозиторії, переключіть Debian sources на trixie, виконайте оновлення і перезавантажте сервер:

Bash
find /etc/apt/sources.list.d -type f \( -name '*.list' -o -name '*.sources' \) \
  -exec mv {} {}.disabled \;

sed -i 's/bookworm/trixie/g' /etc/apt/sources.list

apt update
apt upgrade --without-new-pkgs
apt full-upgrade

reboot

Після перезавантаження поверніть кастомні репозиторії та оновіть codename там, де репозиторій підтримує Debian 13:

Bash
find /etc/apt/sources.list.d -type f -name '*.disabled' \
  -exec sh -c 'for f do mv "$f" "${f%.disabled}"; done' sh {} +

find /etc/apt/sources.list.d -type f \( -name '*.list' -o -name '*.sources' \) \
  -exec sed -i 's/bookworm/trixie/g' {} +

apt update

Підключення S3 APT-репозиторію Webitel

Потрібно отримати актуальні AccessKeyId та SecretAccessKey

Add Webitel Debian repository script
Bash
apt-get install -y apt-transport-s3

ACCESS_KEY=КЛІЄНТСЬКИЙ_KEY_ID
ACCESS_SECRET=КЛІЄНТСЬКИЙ_SECRET_KEY 
tee /etc/apt/s3auth.conf <<EOF
AccessKeyId = ${ACCESS_KEY}
SecretAccessKey = ${ACCESS_SECRET}
Region = eu-central-1
EOF

chmod 600 /etc/apt/s3auth.conf

tee /tmp/webitel-apt-repo.gpg.pub <<'EOF'
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
WnIqg8eIFg==
=mffO
-----END PGP PUBLIC KEY BLOCK-----
EOF

gpg --dearmor < /tmp/webitel-apt-repo.gpg.pub > /usr/share/keyrings/webitel-apt-repo.gpg

. /etc/os-release
echo "deb [signed-by=/usr/share/keyrings/webitel-apt-repo.gpg] s3://webitel-apt-repo ${VERSION_CODENAME} 26.4-releases" \
  > /etc/apt/sources.list.d/webitel.list

apt update

PostgreSQL 15 → 18

Виконується тільки після міграції на Debian 13

Підготуйте змінні та перевірте диск перед встановленням/запуском upgrade.

Bash
export OLD_PG_MAJOR=15
export NEW_PG_MAJOR=18

export OLD_BIN_DIR="/usr/lib/postgresql/${OLD_PG_MAJOR}/bin"
export NEW_BIN_DIR="/usr/lib/postgresql/${NEW_PG_MAJOR}/bin"

export OLD_DATA_DIR="/var/lib/postgresql/${OLD_PG_MAJOR}/main"
export NEW_DATA_DIR="/var/lib/postgresql/${NEW_PG_MAJOR}/main"

du -sh "${OLD_DATA_DIR}"
df -h "${OLD_DATA_DIR}"

За замовчуванням, щоб зменшити ризики, для оновлення потрібне вільне місце приблизно на рівні поточного PostgreSQL data directory + tablespaces, із запасом під WAL, службові файли та тимчасові операції (частіше це x2 розміру OLD_DATA_DIR).

Проте, для великих за розміром БД (або ж в разі недостатнього вільного місця на диску) якщо ризики та відновлення або з бекапу, або завдяки репліці, прийнятні, доступний режим оновлення через hard links, який не копіює файли та, відповідно, не потребує додаткового вільного місця. Після успішного оновлення через hard links старий кластер PostgreSQL 15 стає непридатним для запуску.

Детальніше в наступних кроках

Встановлення пакетів

Версія timescaledb у новому кластері повинна збігатись із версією у старому на момент оновлення:

Bash
apt update
apt install postgresql-18 postgresql-client-18

TIMESCALEDB_VERSION=$(dpkg-query -W -f='${Version}' timescaledb-2-postgresql-${OLD_PG_MAJOR})
apt install "timescaledb-2-postgresql-${NEW_PG_MAJOR}=${TIMESCALEDB_VERSION}"

Підготовка кластерів

Перевірте наявні кластери БД. Якщо 18/main не створився автоматично, створіть його вручну. Перед pg_upgrade обидва кластери мають бути зупинені:

Bash
pg_lsclusters

OLD_LOCALE=$(su postgres -c "psql -tAc 'SHOW lc_collate' postgres" | tr -d ' ')
OLD_ENCODING=$(su postgres -c "psql -tAc 'SHOW server_encoding' postgres" | tr -d ' ')

if ! pg_lsclusters | awk '{print $1 "/" $2}' | grep -qx "${NEW_PG_MAJOR}/main"; then
  pg_createcluster "${NEW_PG_MAJOR}" main -- \
    --locale="${OLD_LOCALE}" \
    --encoding="${OLD_ENCODING}"
fi

systemctl stop postgresql

Перевірка pg_upgrade

Щоб використати hard links під час оновлення додайте флаг --link

Bash
su postgres -c "${NEW_BIN_DIR}/pg_upgrade \
  --old-bindir=${OLD_BIN_DIR} \
  --new-bindir=${NEW_BIN_DIR} \
  --old-datadir=${OLD_DATA_DIR} \
  --new-datadir=${NEW_DATA_DIR} \
  --check"

Якщо --check завершився з помилкою, не запускайте pg_upgrade до усунення причини

Запуск pg_upgrade

Щоб використати hard links під час оновлення додайте флаг --link

Bash
su postgres -c "${NEW_BIN_DIR}/pg_upgrade \
  --old-bindir=${OLD_BIN_DIR} \
  --new-bindir=${NEW_BIN_DIR} \
  --old-datadir=${OLD_DATA_DIR} \
  --new-datadir=${NEW_DATA_DIR}"

Оновлення конфігурації PostgreSQL 18

pg_upgrade самостійно не мігрує конфігураційні файли, а тому потрібно зробити це вручну для:

  • /etc/postgresql/18/main/postgresql.conf

  • /etc/postgresql/18/main/pg_hba.conf

Bash
timescaledb-tune \
  --quiet --yes \
  --pg-version=${NEW_PG_MAJOR} \
  --conf-path=/etc/postgresql/${NEW_PG_MAJOR}/main/postgresql.conf

Старт PostgreSQL 18 і оновлення TimescaleDB

Bash
systemctl disable postgresql@${OLD_PG_MAJOR}-main
systemctl enable postgresql@${NEW_PG_MAJOR}-main
systemctl start postgresql@${NEW_PG_MAJOR}-main

pg_lsclusters

su postgres -c "psql webitel -c 'ALTER EXTENSION timescaledb UPDATE;'"

Оновлення статистики PostgreSQL 18

Перед стартом сервісів:

Bash
su postgres -c "vacuumdb --all --analyze-in-stages --missing-stats-only --jobs=$(nproc)"

Оновлення Webitel-пакетів

Bash
apt update
apt upgrade
apt install webitel-postgresql-18 webitel-postgresql-migrations-18 \
  webitel-supervisor-workspace-app webitel-web-widget-app \
  webitel-flow-diagram-app webitel-agent-workspace-app

apt reinstall webitel-admin-app webitel-audit-app webitel-auth-app \
  webitel-crm-app webitel-history-app webitel-meetings-app 

Перейменування systemd unit-файлів і шляхів до бінарників

Скрипт зберігає enabled state старих unit-файлів, робить backup, перейменовує unit-файли, оновлює ExecStart binary path і додає Alias зі старою назвою:

Migrate systemd units script
Bash
touch /tmp/migrate-webitel-systemd-units.sh
chmod +x /tmp/migrate-webitel-systemd-units.sh
tee /tmp/migrate-webitel-systemd-units.sh <<'EOF'
#!/bin/bash
set -euo pipefail

# old_unit:new_unit[:old_binary:new_binary]
pairs=(
  "engine:webitel-engine"
  "call_center:webitel-call-center"
  "flow_manager:webitel-flow-manager"
  "messages-bot:webitel-messages-bot:messages:webitel-messages"
  "messages-srv:webitel-messages-srv:messages:webitel-messages"
  "storage:webitel-storage"
)

units_to_enable=""
backup_suffix=".pre-26.4.bak"

for pair in "${pairs[@]}"; do
  IFS=: read -r old new old_bin new_bin <<< "$pair"
  old_bin=${old_bin:-$old}
  new_bin=${new_bin:-$new}

  old_file="/etc/systemd/system/${old}.service"
  new_file="/etc/systemd/system/${new}.service"

  [ -f "$old_file" ] || continue

  cp -a "$old_file" "${old_file}${backup_suffix}"

  if systemctl is-enabled --quiet "${old}.service" 2>/dev/null; then
    units_to_enable+=" ${new}.service"
  fi

  systemctl disable "${old}.service" 2>/dev/null || true
  mv "$old_file" "$new_file"

  sed -i "s|/usr/local/bin/${old_bin}\b|/usr/local/bin/${new_bin}|g" "$new_file"

  if ! grep -q '^\[Install\]' "$new_file"; then
    printf '\n[Install]\nWantedBy=multi-user.target\n' >> "$new_file"
  fi

  if ! grep -qE "^Alias=${old}\.service$" "$new_file"; then
    sed -i "/^\[Install\]/a Alias=${old}.service" "$new_file"
  fi

  if [ ! -x "/usr/local/bin/${new_bin}" ]; then
    echo "WARNING: /usr/local/bin/${new_bin} not found or not executable"
  fi
done

systemctl daemon-reload
[ -n "$units_to_enable" ] && systemctl enable $units_to_enable
EOF

/tmp/migrate-webitel-systemd-units.sh

Після перевірки сервісів backup unit-файлів можна видалити:

find /etc/systemd/system -type f -name '*.service.pre-26.4.bak' -delete

Міграція схеми БД

Міграція береться з webitel-postgresql-migrations. PostgreSQL major визначається автоматично. timescaledb.restoring скидається через trap навіть при помилці міграції.

Bash
touch /tmp/migrate-webitel-schema.sh
chmod +x /tmp/migrate-webitel-schema.sh
tee /tmp/migrate-webitel-schema.sh <<'EOF'
#!/bin/bash
set -euo pipefail

DB="webitel"
PG_MAJOR=$(su postgres -c "psql -tAc 'SHOW server_version_num'" | awk '{print int($1/10000)}')
MIGRATION="/usr/share/postgresql/${PG_MAJOR}/webitel/migration/26.02-26.4.sql"

if [ ! -f "$MIGRATION" ]; then
  echo "Migration file not found: $MIGRATION" >&2
  exit 1
fi

cleanup() {
  su postgres -c "psql ${DB} -qxc \"ALTER DATABASE ${DB} RESET timescaledb.restoring;\"" || true
}

trap cleanup EXIT

su postgres -c "psql ${DB} -qxc \"ALTER DATABASE ${DB} SET timescaledb.restoring='on';\""
su postgres -c "psql -v ON_ERROR_STOP=1 -1 -f ${MIGRATION} ${DB}"
EOF

/tmp/migrate-webitel-schema.sh

Зведення конфігурації

Перевірте та оновіть відповідно до актуальних файлів конфігурації:

  • OpenSIPs

  • FreeSWITCH

Очищення і перезапуск сервісів

Перезапускайте сервіси групами в порядку залежностей:

Bash
apt --purge autoremove

systemctl restart consul
systemctl restart postgresql
systemctl restart rabbitmq-server

systemctl restart freeswitch ngcp-rtpengine-daemon opensips

systemctl restart webitel-engine webitel-call-center webitel-flow-manager \
  webitel-storage webitel-messages-srv webitel-messages-bot webitel-api \
  webitel-uac webitel-app webitel-cases webitel-logger webitel-media-exporter \
  grafana-server nginx

Видалення старого PostgreSQL 15

Лише у разі оновлення PostgreSQL 15 → 18 та після перевірки стабільності роботи PostgreSQL 18 і Webitel

Bash
pg_dropcluster --stop 15 main

apt --purge remove postgresql-15 postgresql-client-15 \
    timescaledb-2-postgresql-15 webitel-postgresql-15

apt --purge autoremove

Оновлення статистики PostgreSQL 18

Після оновлення сервісів (може працювати паралельно):

Bash
su postgres -c "PGOPTIONS='-c vacuum_cost_delay=0' vacuumdb --all --analyze-only --jobs=$(nproc)"