Документация 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 \
  webitel-supervisor-workspace-app webitel-web-widget-app \
  webitel-flow-diagram-app webitel-agent-workspace-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)"