Skip to main content
Discover Packs Jobs Registries Requests Docs About GitHub

lhaig / pack-temporal

Published by Lance Haig | View Source

pack
0 stars
Description
Temporal Nomad Pack - Deploy Temporal Server, UI, and PostgreSQL to Nomad
License
MPL-2.0
Tags
#postgresql #temporal #workflow #orchestration #durable-execution #grpc
Download Status
Completed (v0.1.0) Mar 07, 19:13
Versions
Select a version to see its documentation and run command.
Quick Run (v0.1.0)
ramble pack run lhaig/pack-temporal@v0.1.0
metadata.hcl
app {
  url = "https://github.com/lhaig/pack-temporal"
}

pack {
  name        = "temporal"
  description = "Temporal is a durable execution platform for building crash-proof applications with a server, UI, and PostgreSQL backend."
  version     = "0.0.1"
}
README
# Temporal Nomad Pack Deploy [Temporal](https://temporal.io/), a durable execution platform for building crash-proof applications, to HashiCorp Nomad via [Ramble](https://ramble.openwander.org/). This pack deploys the Temporal Server (with automatic schema setup), Web UI, and a PostgreSQL sidecar. Elasticsearch can optionally be added for advanced visibility features. ## Prerequisites 1. **Secrets** stored in [Nomad Variables](https://developer.hashicorp.com/nomad/docs/concepts/variables): ```bash nomad var put nomad/jobs/temporal \ postgres_user="temporal" \ postgres_password="changeme" ``` 2. **Storage** for PostgreSQL data. Choose one approach: **Docker bind mount** (default): ```bash mkdir -p /opt/temporal/postgres # If using Elasticsearch: mkdir -p /opt/temporal/elasticsearch ``` **Nomad host volume**: Configure a [host volume](https://developer.hashicorp.com/nomad/docs/configuration/client#host_volume-block) named `temporal-postgres` in your Nomad client config. **CSI volume**: Register a CSI volume before deploying. See `examples/volumes-postgres.hcl` for a template: ```bash # Edit the plugin_id to match your CSI plugin nomad volume create examples/volumes-postgres.hcl # If using Elasticsearch: nomad volume create examples/volumes-elasticsearch.hcl ``` ## Usage ### Basic deployment with sidecars ```bash ramble pack run temporal ``` This deploys the Temporal Server, Web UI, and a PostgreSQL sidecar. Secrets (postgres credentials) are read from the Nomad Variable at `nomad/jobs/temporal`. ### With Traefik routing (UI only) ```bash ramble pack run temporal \ -v traefik_host="temporal.example.com" ``` ### Using a variable file Create a `temporal.vars.hcl` file with your configuration: ```hcl traefik_host = "temporal.example.com" log_level = "warn" ``` ```bash ramble pack run temporal -f temporal.vars.hcl ``` ### External PostgreSQL Secrets are still read from Nomad Variables - store the external credentials there: ```bash nomad var put nomad/jobs/temporal \ postgres_user="temporal" \ postgres_password="changeme" ``` ```bash ramble pack run temporal \ -v postgres_url="db.example.com" \ -v postgres_port=5432 ``` ### With Elasticsearch for advanced visibility ```bash ramble pack run temporal \ -v enable_elasticsearch=true ``` ### With Nomad host volumes ```bash ramble pack run temporal \ -v postgres_volume_type="host" \ -v postgres_volume_source="temporal-postgres" ``` ### With CSI volumes First register the volume (see `examples/volumes-postgres.hcl`): ```bash nomad volume create examples/volumes-postgres.hcl ``` Then deploy: ```bash ramble pack run temporal \ -v postgres_volume_type="csi" \ -v postgres_volume_source="temporal-postgres" ``` ### Server only (no UI) ```bash ramble pack run temporal \ -v enable_ui=false ``` ## Connecting Workers This pack deploys the Temporal **Server** infrastructure. To run workflows, you need to deploy **workers** that connect to the server's gRPC frontend. Workers are application-specific - they contain your workflow and activity code. They connect to the Temporal Server via gRPC on port 7233. ### Worker concepts - **Workflow**: Your durable business logic, written as deterministic code. Temporal guarantees it runs to completion even through crashes and restarts. - **Activity**: Individual units of work (API calls, database queries, file I/O) that workflows orchestrate. Activities can be retried independently. - **Worker**: A process that polls a task queue, picks up workflow and activity tasks, and executes them. You can run many workers for scalability. - **Task Queue**: A named queue that routes work from clients to workers. Workers register which workflows and activities they handle. ### Example worker (Go) See `examples/worker.nomad.hcl` for a complete Nomad job that runs a Go-based Temporal worker. The key configuration is pointing the worker at the Temporal Server's gRPC address via Nomad service discovery: ```go c, err := client.Dial(client.Options{ HostPort: "temporal.service.nomad:7233", }) ``` ### Example worker (Python) ```python from temporalio.client import Client from temporalio.worker import Worker client = await Client.connect("temporal.service.nomad:7233") worker = Worker(client, task_queue="my-queue", workflows=[MyWorkflow], activities=[my_activity]) await worker.run() ``` ### Example worker (TypeScript) ```typescript import { NativeConnection, Worker } from '@temporalio/worker'; const connection = await NativeConnection.connect({ address: 'temporal.service.nomad:7233' }); const worker = await Worker.create({ connection, taskQueue: 'my-queue', workflowsPath: require.resolve('./workflows') }); await worker.run(); ``` ### Deploying workers on Nomad Workers are just Docker containers running your application code. Deploy them as separate Nomad jobs that use Nomad service discovery to find the Temporal Server. See `examples/worker.nomad.hcl` for a template. ## Variables ### General | Variable | Description | Default | |----------|-------------|---------| | `job_name` | Override job name | `temporal` | | `region` | Nomad region | `""` | | `datacenters` | Target datacenters | `["*"]` | ### Temporal Server | Variable | Description | Default | |----------|-------------|---------| | `temporal_version` | Server Docker image tag | `1.26.2` | | `num_history_shards` | History shards (power of 2, immutable after first deploy) | `512` | | `log_level` | Log level (debug, info, warn, error, fatal) | `info` | | `default_namespace` | Default namespace name | `default` | | `skip_default_namespace_creation` | Skip default namespace creation | `false` | | `server_cpu` | CPU in MHz | `500` | | `server_memory` | Memory in MB | `512` | ### Temporal UI | Variable | Description | Default | |----------|-------------|---------| | `enable_ui` | Deploy the Web UI | `true` | | `ui_version` | UI Docker image tag | `2.34.0` | | `ui_cpu` | CPU in MHz | `200` | | `ui_memory` | Memory in MB | `256` | ### Secrets | Variable | Description | Default | |----------|-------------|---------| | `nomad_var_path` | Nomad Variable path for secrets (`postgres_user`, `postgres_password`) | `nomad/jobs/temporal` | ### PostgreSQL | Variable | Description | Default | |----------|-------------|---------| | `enable_postgres` | Deploy PostgreSQL sidecar | `true` | | `postgres_url` | External PostgreSQL host (disables sidecar) | `""` | | `postgres_port` | External PostgreSQL port | `5432` | | `postgres_user` | Fallback username (if not in Nomad Variable) | `temporal` | | `postgres_db` | Database name | `temporal` | | `postgres_db_visibility` | Visibility database name | `temporal_visibility` | | `postgres_version` | Docker image tag | `16-alpine` | | `postgres_cpu` | CPU in MHz | `300` | | `postgres_memory` | Memory in MB | `512` | | `postgres_host_data_path` | Host path for data (bind mode) | `/opt/temporal/postgres` | | `postgres_volume_type` | Volume type: `bind`, `host`, or `csi` | `bind` | | `postgres_volume_source` | Nomad volume name (host/csi mode) | `temporal-postgres` | | `postgres_csi_plugin_id` | CSI plugin ID (csi mode) | `""` | | `postgres_csi_access_mode` | CSI access mode | `single-node-writer` | | `postgres_csi_attachment_mode` | CSI attachment mode | `file-system` | ### Elasticsearch | Variable | Description | Default | |----------|-------------|---------| | `enable_elasticsearch` | Deploy Elasticsearch job | `false` | | `elasticsearch_url` | External ES URL | `""` | | `elasticsearch_version` | Docker image tag | `7.17.24` | | `elasticsearch_cpu` | CPU in MHz | `500` | | `elasticsearch_memory` | Memory in MB | `1024` | | `elasticsearch_host_data_path` | Host path for data (bind mode) | `/opt/temporal/elasticsearch` | | `elasticsearch_volume_type` | Volume type: `bind`, `host`, or `csi` | `bind` | | `elasticsearch_volume_source` | Nomad volume name (host/csi mode) | `temporal-elasticsearch` | | `elasticsearch_csi_plugin_id` | CSI plugin ID (csi mode) | `""` | | `elasticsearch_csi_access_mode` | CSI access mode | `single-node-writer` | | `elasticsearch_csi_attachment_mode` | CSI attachment mode | `file-system` | ### Service Discovery | Variable | Description | Default | |----------|-------------|---------| | `register_service` | Register with Nomad | `true` | | `service_name` | Service name | `temporal` | | `service_tags` | Service tags | `["temporal", "workflow"]` | | `traefik_host` | Traefik routing hostname (UI only) | `""` | ## Jobs | Job | Type | Description | |-----|------|-------------| | `temporal` | service | Server + UI + PostgreSQL sidecar | | `temporal-elasticsearch` | service | Advanced visibility (only when `enable_elasticsearch=true`) | ## Architecture ``` +---------------------+ | Traefik | +----------+----------+ | Host(temporal.example.com) | v +--------+--------+ | Temporal UI | | :8080 | +--------+--------+ | v +--------------+--------------+ | Temporal Server | | (auto-setup) | | :7233 (gRPC) | +---------+--+----------------+ | | +---------+ +----------+ | | v v +------+------+ +----------+----------+ | PostgreSQL | | Elasticsearch (opt) | | :5432 | | :9200 | +------+------+ +----------+----------+ | | v v [bind/host/csi] [bind/host/csi] +------------------------------+ | Your Workers | | (separate Nomad jobs) | | Connect to :7233 gRPC | +------------------------------+ ``` ## License MPL-2.0