diff --git a/ct/temporal.sh b/ct/temporal.sh new file mode 100644 index 0000000000..e3304ec57a --- /dev/null +++ b/ct/temporal.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +_CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/DevScripts/main" +_cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func" +source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func") +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Renan Bastos (renanbastos93) +# License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE +# Source: https://github.com/temporalio/temporal + +APP="Temporal" +var_tags="${var_tags:-workflow;automation}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-8}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +#var_arm64="${var_arm64:-yes}" # unset = ask the user; server, UI and CLI all ship linux_arm64 assets, but not yet run on arm64 +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/temporal ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "temporal" "temporalio/temporal"; then + msg_info "Stopping Temporal" + systemctl stop temporal-ui temporal + msg_ok "Stopped Temporal" + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "temporal" "temporalio/temporal" "prebuild" "latest" "/opt/temporal" "temporal_*_linux_$(arch_resolve).tar.gz" + + msg_info "Migrating Temporal Database" + set -a && source /etc/temporal/temporal.env && set +a + $STD /opt/temporal/temporal-sql-tool --db temporal update-schema --schema-name postgresql/v12/temporal + $STD /opt/temporal/temporal-sql-tool --db temporal_visibility update-schema --schema-name postgresql/v12/visibility + msg_ok "Migrated Temporal Database" + + msg_info "Starting Temporal" + systemctl start temporal temporal-ui + msg_ok "Started Temporal" + msg_ok "Updated Temporal successfully!" + fi + + if check_for_gh_release "temporal-ui" "temporalio/ui-server"; then + msg_info "Stopping Temporal UI" + systemctl stop temporal-ui + msg_ok "Stopped Temporal UI" + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "temporal-ui" "temporalio/ui-server" "prebuild" "latest" "/opt/temporal-ui" "ui-server_*_linux_$(arch_resolve).tar.gz" + + msg_info "Starting Temporal UI" + systemctl start temporal-ui + msg_ok "Started Temporal UI" + msg_ok "Updated Temporal UI successfully!" + fi + + if check_for_gh_release "temporal-cli" "temporalio/cli"; then + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "temporal-cli" "temporalio/cli" "prebuild" "latest" "/opt/temporal-cli" "temporal_cli_*_linux_$(arch_resolve).tar.gz" + msg_ok "Updated Temporal CLI successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}" +echo -e "${INFO}${YW}gRPC endpoint for workers and SDKs: ${IP}:7233${CL}" diff --git a/install/temporal-install.sh b/install/temporal-install.sh new file mode 100644 index 0000000000..dbf7667dc8 --- /dev/null +++ b/install/temporal-install.sh @@ -0,0 +1,206 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Renan Bastos (renanbastos93) +# License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE +# Source: https://github.com/temporalio/temporal + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +PG_VERSION="17" setup_postgresql +PG_DB_NAME="temporal" PG_DB_USER="temporal" PG_DB_SCHEMA_PERMS="true" setup_postgresql_db + +fetch_and_deploy_gh_release "temporal" "temporalio/temporal" "prebuild" "latest" "/opt/temporal" "temporal_*_linux_$(arch_resolve).tar.gz" +fetch_and_deploy_gh_release "temporal-ui" "temporalio/ui-server" "prebuild" "latest" "/opt/temporal-ui" "ui-server_*_linux_$(arch_resolve).tar.gz" +fetch_and_deploy_gh_release "temporal-cli" "temporalio/cli" "prebuild" "latest" "/opt/temporal-cli" "temporal_cli_*_linux_$(arch_resolve).tar.gz" + +msg_info "Configuring Temporal" +mkdir -p /etc/temporal/config/dynamicconfig /etc/temporal/ui +ln -sf /opt/temporal-cli/temporal /usr/local/bin/temporal +cat </etc/temporal/temporal.env +SQL_PLUGIN=postgres12 +SQL_HOST=127.0.0.1 +SQL_PORT=5432 +SQL_USER=temporal +SQL_PASSWORD=${PG_DB_PASS} +EOF +chmod 600 /etc/temporal/temporal.env +cat <<'EOF' >/etc/temporal/config/production.yaml +# enable-template +log: + stdout: true + level: info + +persistence: + defaultStore: postgres-default + visibilityStore: postgres-visibility + numHistoryShards: 4 + datastores: + postgres-default: + sql: + pluginName: {{ env "SQL_PLUGIN" | quote }} + databaseName: "temporal" + connectAddr: {{ printf "%s:%s" (env "SQL_HOST") (env "SQL_PORT") | quote }} + connectProtocol: "tcp" + user: {{ env "SQL_USER" | quote }} + password: {{ env "SQL_PASSWORD" | quote }} + maxConns: 20 + maxIdleConns: 20 + maxConnLifetime: "1h" + postgres-visibility: + sql: + pluginName: {{ env "SQL_PLUGIN" | quote }} + databaseName: "temporal_visibility" + connectAddr: {{ printf "%s:%s" (env "SQL_HOST") (env "SQL_PORT") | quote }} + connectProtocol: "tcp" + user: {{ env "SQL_USER" | quote }} + password: {{ env "SQL_PASSWORD" | quote }} + maxConns: 10 + maxIdleConns: 10 + maxConnLifetime: "1h" + +global: + membership: + maxJoinDuration: 30s + broadcastAddress: "127.0.0.1" + +services: + frontend: + rpc: + grpcPort: 7233 + membershipPort: 6933 + bindOnIP: "0.0.0.0" + + matching: + rpc: + grpcPort: 7235 + membershipPort: 6935 + bindOnLocalHost: true + + history: + rpc: + grpcPort: 7234 + membershipPort: 6934 + bindOnLocalHost: true + + worker: + rpc: + grpcPort: 7239 + membershipPort: 6939 + bindOnLocalHost: true + +clusterMetadata: + enableGlobalNamespace: false + failoverVersionIncrement: 10 + masterClusterName: "active" + currentClusterName: "active" + clusterInformation: + active: + enabled: true + initialFailoverVersion: 1 + rpcName: "frontend" + rpcAddress: "127.0.0.1:7233" + +dcRedirectionPolicy: + policy: "noop" + +archival: + history: + state: "disabled" + visibility: + state: "disabled" + +namespaceDefaults: + archival: + history: + state: "disabled" + visibility: + state: "disabled" + +dynamicConfigClient: + filepath: "/etc/temporal/config/dynamicconfig/production.yaml" + pollInterval: "60s" +EOF +cat </etc/temporal/config/dynamicconfig/production.yaml +limit.maxIDLength: + - value: 255 + constraints: {} +EOF +cat </etc/temporal/ui/production.yaml +temporalGrpcAddress: 127.0.0.1:7233 +port: 8080 +enableUi: true +defaultNamespace: default +cors: + cookieInsecure: true + allowOrigins: + - http://${LOCAL_IP}:8080 +EOF +msg_ok "Configured Temporal" + +msg_info "Initializing Temporal Database" +set -a && source /etc/temporal/temporal.env && set +a +$STD /opt/temporal/temporal-sql-tool --db temporal_visibility create-database +$STD /opt/temporal/temporal-sql-tool --db temporal setup-schema -v 0.0 +$STD /opt/temporal/temporal-sql-tool --db temporal update-schema --schema-name postgresql/v12/temporal +$STD /opt/temporal/temporal-sql-tool --db temporal_visibility setup-schema -v 0.0 +$STD /opt/temporal/temporal-sql-tool --db temporal_visibility update-schema --schema-name postgresql/v12/visibility +msg_ok "Initialized Temporal Database" + +msg_info "Creating Services" +cat </etc/systemd/system/temporal.service +[Unit] +Description=Temporal Server +After=network.target postgresql.service +Requires=postgresql.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/temporal +EnvironmentFile=/etc/temporal/temporal.env +ExecStart=/opt/temporal/temporal-server --root /etc/temporal --env production --allow-no-auth start +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF + +cat </etc/systemd/system/temporal-ui.service +[Unit] +Description=Temporal UI +After=network.target temporal.service +Wants=temporal.service + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/temporal-ui +ExecStart=/opt/temporal-ui/ui-server --root /etc/temporal --config ui --env production start +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now temporal temporal-ui +msg_ok "Created Services" + +msg_info "Creating Default Namespace" +for _ in {1..60}; do + temporal operator cluster health &>/dev/null && break + sleep 1 +done +$STD temporal operator namespace create --namespace default +msg_ok "Created Default Namespace" + +motd_ssh +customize +cleanup_lxc diff --git a/json/temporal.json b/json/temporal.json new file mode 100644 index 0000000000..6ff0e5b312 --- /dev/null +++ b/json/temporal.json @@ -0,0 +1,49 @@ +{ + "name": "Temporal", + "slug": "temporal", + "categories": [ + 20 + ], + "date_created": "2026-11-09", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 8080, + "documentation": "https://docs.temporal.io/", + "website": "https://temporal.io/", + "repository": "https://github.com/temporalio/temporal", + "logo": "https://cdn.jsdelivr.net/gh/temporalio/ui@main/src/lib/vendor/apple-touch-icon.png", + "description": "Temporal is an open-source durable execution platform. Workflows written in Go, Java, Python, TypeScript, .NET, PHP or Ruby keep their state across crashes, restarts and retries, and the server handles timers, retries, signals and schedules so application code does not have to.", + "install_methods": [ + { + "type": "default", + "script": "ct/temporal.sh", + "config_path": "/etc/temporal/config/production.yaml", + "resources": { + "cpu": 2, + "ram": 2048, + "hdd": 8, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "The gRPC endpoint on port 7233 and the UI on 8080 have no authentication. Keep the container on a trusted network or put it behind a firewall and a TLS proxy.", + "type": "warning" + }, + { + "text": "Point workers and SDK clients at :7233. The temporal CLI is installed in the container and already talks to the local server; the default namespace is created with a 72h retention.", + "type": "info" + }, + { + "text": "The database password lives in /etc/temporal/temporal.env; the server config in /etc/temporal/config/production.yaml reads it from there. Restart temporal after changing either file.", + "type": "info" + } + ] +}