Temporal на Ubuntu 24.04: пошаговая установка
Как только в системе появляется больше двух-трёх микросервисов, которые должны согласованно выполнять длительные операции — оформить заказ, списать деньги, отправить уведомление, откатиться при сбое — крон-джобы и очереди с ретраями на костылях начинают трещать по швам. Temporal берёт эту сложность на себя: он хранит состояние workflow в базе данных, переживает падение воркеров и рестарты сервера, и гарантирует, что шаг, который упал на середине, продолжится с того же места, а не начнётся заново. Разворачиваем его на своём VPS с Ubuntu 24.04 через Docker Compose — с внешним PostgreSQL, отдельным Web UI и первой проверкой через SDK.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое Temporal и когда он оправдан
Temporal — это движок оркестрации workflow с открытым исходным кодом (форк Uber Cadence). Вы пишете обычный код на Go, Python, Java, TypeScript или .NET, а Temporal берёт на себя:
- сохранение состояния каждого шага workflow в истории событий (event sourcing изнутри);
- автоматические ретраи activity при сбоях с настраиваемым backoff;
- durable timers — можно "заснуть" на 30 дней, и это переживёт любой рестарт;
- версионирование логики без слома работающих процессов;
- видимость выполнения через Web UI — что выполнилось, что упало, где висит.
Ставить Temporal имеет смысл, когда у вас саги между сервисами (заказ → оплата → резерв склада → доставка с компенсациями при откате), длительные процессы (онбординг, подписки, циклы согласований) или просто надоело писать ретраи и идемпотентность руками в каждом сервисе. Для одного крон-скрипта раз в час Temporal — избыточность; для 5-10 микросервисов с бизнес-процессами между ними — то, что убирает половину самодельной инфраструктуры вокруг очередей.
Требования к серверу и подготовка Ubuntu 24.04
Для теста и небольшой продакшен-нагрузки достаточно 2 vCPU и 4 ГБ RAM — это Temporal Server (frontend, history, matching, worker service в одном контейнере через auto-setup) плюс PostgreSQL. Если планируете подключать Elasticsearch для расширенного поиска по workflow (фильтры по произвольным полям, не только по стандартным атрибутам) — закладывайте от 8 ГБ RAM, Elasticsearch прожорлив к памяти сам по себе.
Начните с обновления системы и базовой гигиены:
apt update && apt upgrade -y
apt install -y curl git ca-certificates gnupg ufw
timedatectl set-timezone Europe/Moscow
Точное время на сервере важно: Temporal активно работает с таймерами и историей событий, и рассинхронизация часов между узлами кластера (если вы позже будете масштабироваться) создаёт трудноуловимые баги. Если ещё не настраивали доступ и файрвол на этом сервере — сделайте это до установки Temporal, отдельная статья про первичную настройку и безопасность Ubuntu 24.04 закрывает это за 15 минут.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверУстановка Docker и Docker Compose
Официальный и самый предсказуемый способ поднять Temporal — через Docker Compose с готовым набором образов от команды Temporal. Ставим Docker Engine из официального репозитория:
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Проверьте, что демон запущен и плагин compose доступен:
systemctl enable --now docker
docker compose version
Если предпочитаете более развёрнутый разбор с нюансами (proxy, storage driver, права пользователя без sudo) — есть отдельная статья про установку Docker на Ubuntu 24.04 с нуля.
Развёртывание Temporal Server с PostgreSQL
Демо-репозиторий temporalio/docker-compose с GitHub — самый быстрый путь для знакомства, но для сервера, который будет жить дольше выходных, лучше собрать свой docker-compose.yml с явным контролем над версией PostgreSQL, паролями и сетью. Создаём рабочую директорию и файл окружения:
mkdir -p /opt/temporal && cd /opt/temporal
cat > .env <<'EOF'
POSTGRES_USER=temporal
POSTGRES_PASSWORD=ЗАМЕНИТЕ_НА_СЛОЖНЫЙ_ПАРОЛЬ
EOF
Сам docker-compose.yml:
services:
postgresql:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- temporal-postgres:/var/lib/postgresql/data
networks: [temporal-net]
temporal:
image: temporalio/auto-setup:latest
restart: unless-stopped
depends_on: [postgresql]
environment:
- DB=postgres12
- DB_PORT=5432
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PWD=${POSTGRES_PASSWORD}
- POSTGRES_SEEDS=postgresql
- DYNAMIC_CONFIG_FILE_PATH=config/dynamicconfig/development-sql.yaml
ports:
- "127.0.0.1:7233:7233"
networks: [temporal-net]
temporal-admin-tools:
image: temporalio/admin-tools:latest
depends_on: [temporal]
environment:
- TEMPORAL_ADDRESS=temporal:7233
stdin_open: true
tty: true
networks: [temporal-net]
temporal-ui:
image: temporalio/ui:latest
restart: unless-stopped
depends_on: [temporal]
environment:
- TEMPORAL_ADDRESS=temporal:7233
- TEMPORAL_CORS_ORIGINS=https://ваш-домен
ports:
- "127.0.0.1:8080:8080"
networks: [temporal-net]
networks:
temporal-net:
driver: bridge
volumes:
temporal-postgres:
Образ auto-setup сам создаёт нужные схемы (default и visibility) в PostgreSQL при первом запуске — удобно для старта. Для по-настоящему продакшен-раскатки Temporal рекомендует прогонять схему заранее через temporal-sql-tool из CI, а сервер запускать образом без auto-setup — но для одного VPS и умеренной нагрузки auto-setup остаётся разумным компромиссом.
Обратите внимание: порты 7233 (gRPC frontend) и 8080 (UI) я привязал к 127.0.0.1 — наружу они не торчат вообще, доступ будет только через SSH-туннель или Nginx с TLS, об этом ниже. Поднимаем стек:
docker compose up -d
docker compose logs -f temporal
В логах ищите строку про успешный старт frontend и history service, ошибок подключения к PostgreSQL быть не должно. Проверить кластер изнутри сети compose:
docker compose run --rm temporal-admin-tools \
temporal operator cluster health
Ответ SERVING подтверждает, что frontend, history и matching service живы и видят друг друга.
Если вы уже используете внешний управляемый PostgreSQL (например, для других сервисов на этом же сервере) — с тюнингом параметров вроде max_connections и shared_buffers под несколько нагрузок одновременно поможет статья про тюнинг PostgreSQL, Temporal создаёт довольно много коротких транзакций и чувствителен к пулу соединений.
Web UI: доступ через Nginx с TLS
Открывать порт 8080 напрямую в интернет — плохая идея: в Temporal UI нет встроенной аутентификации из коробки (её добавляют через reverse proxy или OIDC-прокси отдельно). Проще всего закрыть доступ на уровне Nginx — TLS плюс Basic Auth, пока не настроили полноценный SSO.
Ставим Nginx и генерируем пароль для Basic Auth:
apt install -y nginx apache2-utils
htpasswd -c /etc/nginx/.temporal-htpasswd admin
Конфиг сайта /etc/nginx/sites-available/temporal:
server {
listen 80;
server_name temporal.ваш-домен.ru;
location / {
auth_basic "Temporal UI";
auth_basic_user_file /etc/nginx/.temporal-htpasswd;
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
ln -s /etc/nginx/sites-available/temporal /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
certbot --nginx -d temporal.ваш-домен.ru
Если ещё не разбирались, как правильно ставить Nginx как reverse proxy для внутренних сервисов — есть отдельный разбор Nginx как reverse proxy на Ubuntu 24.04, там же про WebSocket-заголовки, которые нужны и Temporal UI для live-обновлений списка workflow. Порт 7233 (gRPC, которым пользуются воркеры и SDK) через Nginx не проксируйте — это бинарный gRPC-протокол, для доступа воркеров с других серверов проще поднять WireGuard между машинами или белый список IP в файрволе на 7233, чем городить gRPC-прокси.
Firewall для этого сценария:
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable
7233 и 8080 сюда сознательно не добавляем — они уже закрыты на 127.0.0.1 в docker-compose и наружу не смотрят вообще, кроме как через Nginx-туннель на 443.
Первый воркер: проверка через SDK
Голый кластер бесполезен без воркера, который выполняет код workflow. Возьмём Python SDK как самый быстрый способ проверить связку. На сервере (или локальной машине, если сервер доступен по туннелю):
apt install -y python3.12-venv
python3 -m venv temporal-demo && cd temporal-demo
source bin/activate
pip install temporalio
Минимальный workflow и воркер, worker.py:
import asyncio
from datetime import timedelta
from temporalio import workflow, activity
from temporalio.client import Client
from temporalio.worker import Worker
@activity.defn
async def say_hello(name: str) -> str:
return f"Hello, {name}!"
@workflow.defn
class GreetingWorkflow:
@workflow.run
async def run(self, name: str) -> str:
return await workflow.execute_activity(
say_hello, name,
start_to_close_timeout=timedelta(seconds=10),
)
async def main():
client = await Client.connect("127.0.0.1:7233", namespace="default")
worker = Worker(
client,
task_queue="greeting-task-queue",
workflows=[GreetingWorkflow],
activities=[say_hello],
)
await worker.run()
if __name__ == "__main__":
asyncio.run(main())
Если сервер и клиент на одной машине — просто python worker.py. Если запускаете воркер удалённо, а Temporal Server на VPS — прокиньте туннель ssh -L 7233:127.0.0.1:7233 user@ваш-сервер (напрямую в интернет 7233 мы не открывали). Запустить сам workflow можно через официальный CLI temporal:
curl -sSf https://temporal.download/cli.sh | sh
export PATH="$HOME/.temporalio/bin:$PATH"
temporal workflow start \
--address 127.0.0.1:7233 \
--task-queue greeting-task-queue \
--type GreetingWorkflow \
--input '"Мир"'
Результат появится и в консоли, и — что важнее — в Web UI на https://temporal.ваш-домен.ru: там видно всю историю выполнения, каждый шаг, время, статус. Убейте воркер прямо во время выполнения workflow с искусственной задержкой — и убедитесь, что после перезапуска процесс продолжится с прерванного места, а не с начала. Это и есть та самая durability, ради которой всё затевалось.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Нужен ли Elasticsearch обязательно?
Нет. Без него доступен базовый поиск workflow по стандартным атрибутам (namespace, workflow ID, статус, временной диапазон). Elasticsearch нужен только для поиска по произвольным custom search attributes и сложных фильтров — добавляйте его отдельно, когда реально упрётесь в ограничение.
Можно ли использовать MySQL вместо PostgreSQL?
Да, Temporal поддерживает и то, и другое через одни и те же переменные окружения (меняется DB на mysql8 и добавляются соответствующие креды). PostgreSQL чаще выбирают за более предсказуемое поведение под конкурентной записью истории событий.
Как обновлять версию Temporal без потери данных?
Схема БД версионируется отдельно от образа сервера. Перед обновлением проверьте changelog на breaking changes в схеме, сделайте бэкап PostgreSQL — процедура та же, что для резервного копирования Docker volume — и обновляйте образы по одному: сначала postgresql, затем temporal, затем temporal-ui.
Что если воркер упал посреди activity?
Ничего специально делать не нужно — Temporal видит, что activity не подтвердил завершение по heartbeat или таймауту, и переотправляет её другому доступному воркеру согласно retry policy. Ради этого весь проект и существует.
Сколько ресурсов закладывать на продакшен?
Однозначного числа никто не даст — зависит от числа workflow в секунду и объёма истории каждого. Для старта достаточно 2-4 vCPU и 4-8 ГБ RAM с вертикальным апгрейдом при росте нагрузки; о горизонтальном масштабировании history/matching service имеет смысл думать, когда однонодовая установка реально упрётся в потолок.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →