• Предисловие

  • Ansible и Temporal

  • Простой рабочий процесс

  • Рабочие процессы длительного выполнения с использованием точек контроля

  • Динамическое параллельное выполнение

  • Утверждения с участием человека

  • Оркестрация в кросс-облачных средах

  • Событийно-ориентированный Ansible (EDA) на стероидах

  • Рабочие процессы с поддержкой состояния и восстановлением

  • Отладка с "перемоткой времени"

  • Цепочка интеграции между инструментами

  • Динамический инвентарь Ansible

  • GitLab

  • Terraform

  • Миграции баз данных

  • Самообслуживание (self-service) с использованием Temporal

  • Послесловие

Оригинал статьи с диаграммами

Предисловие

Когда речь идет об оркестрации сложных рабочих процессов в гибридных облачных средах, Temporal выделяется как один из лучших инструментов с открытым исходным кодом. Он не пытается заменить такие инструменты, как Terraform или Ansible, а вместо этого дополняет их, добавляя уровень надежности, масштабируемости и гибкости.

Например, в то время как Terraform отлично справляется с предоставлением инфраструктуры, а Ansible управляет конфигурацией, Temporal связывает все воедино. Он гарантирует, что рабочие процессы могут восстанавливаться после сбоев, адаптироваться к условиям выполнения и бесшовно интегрироваться с внешними системами, такими как инструменты мониторинга, CMDB или процессы утверждения. И поскольку это программное обеспечение с открытым исходным кодом, оно избегает привязки к конкретному поставщику, поддерживая практически любой технологический стек.

Основная ценность оркестратора рабочих процессов заключается в его способности обрабатывать длительные, динамические процессы без потери эффективности. Будь то ожидание прохождения проверок работоспособности виртуальной машины, запуск развертывания Kubernetes или обновление CMDB после предоставления ресурсов, Temporal обеспечивает плавное выполнение задач. Речь идет не о создании чего-то нового, а о том, чтобы сделать существующие инструменты более эффективными при совместной работе.

Еще одним преимуществом является способность Temporal обрабатывать длительные процессы, которые часто возникают в операциях второго дня. Например, если вы переносите рабочие нагрузки между облаками или выполняете поэтапное обновление в кластере Kubernetes, Temporal отслеживает прогресс и гарантирует, что рабочий процесс продолжится с того места, где он был прерван — даже в случае сбоя или прерывания. Это делает его идеальным для таких задач, как обновление баз данных, откат приложений или проверки на соответствие требованиям, где согласованность и надежность имеют ключевое значение.

Короче говоря, Temporal помогает ИТ-командам работать быстрее и эффективнее, не жертвуя при этом контролем или управлением, что именно требуется современным предприятиям в быстро меняющемся мире гибридных облаков.

Ansible и Temporal

Temporal решает проблемы автоматизации рабочих процессов, предоставляя надежную основу для управления сложными, длительными процессами, требующими надежности, масштабируемости и отказоустойчивости. Без Temporal выполнение Ansible-плейбуков или аналогичных задач автоматизации может столкнуться с такими проблемами, как сбои выполнения из-за временных ошибок, отсутствие видимости текущих процессов, неспособность возобновить рабочие процессы после сбоев системы и сложность координации нескольких зависимых задач. Temporal гарантирует, что рабочие процессы смогут корректно восстанавливаться после сбоев, сохранять состояние между повторными попытками и позволять динамически адаптироваться к условиям выполнения. Он также обеспечивает бесшовную интеграцию различных инструментов и систем в рамках одного рабочего процесса, упрощая оркестрацию многоступенчатых операций, которые могут включать не только Ansible, но и другие инструменты управления инфраструктурой или приложениями. Обрабатывая сложности координации задач, повторных попыток и управления состоянием, Temporal позволяет разработчикам сосредоточиться на определении логики своих рабочих процессов, не беспокоясь о базовых механизмах выполнения.

Оркестрация
Оркестрация

Простой рабочий процесс

Этот Python-скрипт демонстрирует, как использовать Temporal для выполнения Ansible-плейбука, например, такого, который обновляет системные пакеты на сервере. Он настраивает рабочий процесс и активность для выполнения плейбука надежным способом, с такими функциями, как повторные попытки, потоковая передача вывода в реальном времени и корректное завершение работы.

Активность execute_ansible_playbook выполняет команду ansible-playbook, используя asyncio для захвата и отображения вывода по мере его появления. Вы можете передать файл плейбука и, опционально, файл инвентаря. Если что-то пойдет не так и плейбук завершится ошибкой, скрипт вызовет исключение, а Temporal автоматически повторит операцию до трех раз перед тем, как остановиться.

AnsibleWorkflow определяет логику рабочего процесса, которая, по сути, вызывает активность для запуска плейбука. Она настроена с таймаутами и политиками повторных попыток для обработки случаев, когда выполнение плейбука занимает много времени или сталкивается с временными проблемами.

При запуске скрипта он подключается к серверу Temporal, запускает воркер для прослушивания задач и немедленно инициирует рабочий процесс для выполнения указанного плейбука. Например, вы можете указать плейбук, такой как update_packages.yml, который может использовать Ansible-модули, такие как apt или yum, для обновления пакетов на ваших серверах. Скрипт гарантирует, что плейбук выполняется плавно, потоково выводит его результаты в реальном времени и обрабатывает прерывания или ошибки, не теряя информации о текущем состоянии.

Этот подход отлично подходит для автоматизации задач, таких как обновление пакетов на серверах, где ключевыми факторами являются надежность и видимость. Используя Temporal, вы получаете встроенные повторные попытки, отказоустойчивость и возможность легко отслеживать и отлаживать процесс, если что-то пойдет не по плану.

import asyncio
import uuid
import sys
import os
import signal
import argparse
from datetime import timedelta
from temporalio import workflow, activity
from temporalio.client import Client
from temporalio.worker import Worker
from temporalio.common import RetryPolicy

# --- Activity Definition ---
@activity.defn
async def execute_ansible_playbook(playbook_path: str, inventory_path: str = None) -> str:
    """Execute ansible-playbook with live output."""
    cmd = ["ansible-playbook", playbook_path]
    if inventory_path:
        cmd.extend(["-i", inventory_path])

    proc = await asyncio.create_subprocess_exec(
        *cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE
    )

    output = []
    while True:
        stdout_chunk = await proc.stdout.read(1024)
        stderr_chunk = await proc.stderr.read(1024)

        if not stdout_chunk and not stderr_chunk:
            break

        if stdout_chunk:
            sys.stdout.write(stdout_chunk.decode())
            sys.stdout.flush()
            output.append(stdout_chunk.decode())

        if stderr_chunk:
            sys.stderr.write(stderr_chunk.decode())
            sys.stderr.flush()
            output.append(f"ERROR: {stderr_chunk.decode()}")

    exit_code = await proc.wait()
    if exit_code != 0:
        raise RuntimeError(f"Playbook failed with exit code {exit_code}")

    return "".join(output)

# --- Workflow Definition ---
@workflow.defn
class AnsibleWorkflow:
    @workflow.run
    async def run(self, params: dict) -> str:
        return await workflow.execute_activity(
            execute_ansible_playbook,
            args=[params["playbook_path"], params.get("inventory_path")],
            start_to_close_timeout=timedelta(minutes=15),
            retry_policy=RetryPolicy(
                initial_interval=timedelta(seconds=30),
                maximum_interval=timedelta(minutes=2),
                maximum_attempts=3
            )
        )

async def run_workflow_and_worker(playbook_path: str, inventory_path: str = None):
    """Start worker and execute workflow automatically"""
    shutdown_event = asyncio.Event()
    client = None
    worker = None

    def signal_handler():
        shutdown_event.set()

    loop = asyncio.get_running_loop()
    loop.add_signal_handler(signal.SIGINT, signal_handler)
    loop.add_signal_handler(signal.SIGTERM, signal_handler)

    try:
        # Connect to Temporal
        client = await Client.connect("localhost:7233")

        # Start worker
        worker = Worker(
            client,
            task_queue="ansible-queue",
            workflows=[AnsibleWorkflow],
            activities=[execute_ansible_playbook],
            graceful_shutdown_timeout=timedelta(seconds=5)
        )

        # Run worker in background
        worker_task = asyncio.create_task(worker.run())

        # Execute workflow
        print(f"Executing playbook: {playbook_path}")
        result = await client.execute_workflow(
            AnsibleWorkflow.run,
            args=[{"playbook_path": playbook_path, "inventory_path": inventory_path}],
            id=f"ansible-{uuid.uuid4()}",
            task_queue="ansible-queue",
            execution_timeout=timedelta(minutes=20)
        )

        print("\nPlaybook execution result:")
        print(result)

    except Exception as e:
        print(f"Error: {str(e)}")
        raise
    finally:
        # Clean shutdown
        shutdown_event.set()
        if worker:
            await worker.shutdown()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--playbook", required=True, help="Path to playbook file")
    parser.add_argument("--inventory", help="Path to inventory file")
    args = parser.parse_args()

    # Validate paths
    if not os.path.exists(args.playbook):
        print(f"Error: Playbook not found at {args.playbook}")
        sys.exit(1)
    if args.inventory and not os.path.exists(args.inventory):
        print(f"Error: Inventory file not found at {args.inventory}")
        sys.exit(1)

    try:
        asyncio.run(run_workflow_and_worker(args.playbook, args.inventory))
    except KeyboardInterrupt:
        print("\nProcess stopped by user")
        sys.exit(0)
    except Exception as e:
        print(f"\nError: {str(e)}")
        sys.exit(1)

Эта команда выводит список всех рабочих процессов типа AnsibleWorkflow, которые в данный момент отслеживаются Temporal:

tctl workflow list --query "WorkflowType='AnsibleWorkflow'"

Эта команда запускает новый экземпляр AnsibleWorkflow для выполнения плейбука apt_update.yml:

tctl workflow run \
    --taskqueue ansible-queue \
    --workflow_type AnsibleWorkflow \
    --input '"apt_update.yml"'

Параметр --inventory является необязательным в данном случае.

Эта команда извлекает подробную информацию о конкретном экземпляре рабочего процесса, идентифицируемого по его идентификатору:

tctl workflow show -w ansible-1dcbe2e1-8b10-4616-8e11-948cb81d83b1

Веб-интерфейс Temporal упрощает управление рабочими процессами, предоставляя интуитивно понятный интерфейс для проверки статусов, просмотра деталей и выполнения действий, таких как отмена рабочих процессов при необходимости.

Temporal
Temporal

Эта задача (job) в GitLab pipeline, ansible_workflows, автоматизирует выполнение Ansible-плейбука, такого как apt_update.yml, для обновления системных пакетов. Она выполняется на этапе deploy с использованием shell-исполнителя и запускает Python-скрипт (ansible.py), который оркестрирует выполнение плейбука через Temporal.

Скрипт использует Temporal для надежного выполнения плейбука с такими функциями, как повторные попытки и потоковая передача вывода в реальном времени. Если плейбук завершается ошибкой, pipeline отражает эту ошибку, что упрощает процесс отладки. Такая настройка интегрирует обновления инфраструктуры в ваш CI/CD-процесс, обеспечивая надежные и автоматизированные развертывания.

ansible_workflows:
  stage: deploy
  tags:
    - shell
  script:
    - python3 ansible.py --playbook apt_update.yml
GitLab
GitLab

Рабочие процессы длительного выполнения с использованием точек контроля

Проблема: Ansible-плейбуки завершаются ошибкой при выполнении задач длительного времени (например, при предоставлении облачных ресурсов или развертывании, занимающем несколько часов). Решение: Использовать Temporal-рабочие процессы для автоматического возобновления работы после сбоев. Прогресс фиксируется в точках контроля (например, "50% виртуальных машин развернуто") даже в случае аварийного завершения процесса.

@workflow.defn
class AnsibleWorkflow:
    async def run(self, playbook: str):
        while not workflow.is_replaying():
            result = await workflow.execute_activity(
                run_ansible_playbook,
                args=[playbook],
                start_to_close_timeout=timedelta(hours=6),
                heartbeat_timeout=timedelta(minutes=5),
            )
            if result.failed:
                await asyncio.sleep(300)  # Retry after 5 minutes

Динамическое параллельное выполнение

Проблема: Возможности Ansible для асинхронного выполнения ограничены — сложно управлять тысячами узлов динамически. Решение: Рабочие процессы с разветвлением и сборкой результатов (например, развертывание 500 виртуальных машин параллельно с последующим агрегированием результатов).

@workflow.defn
class ProdDeploymentWorkflow:
    async def run(self):
        await run_ansible_playbook("deploy_staging.yml")
        if workflow.is_replaying():
            await workflow.wait_for_signal("prod_approval")
        else:
            await send_slack_approval_request()
            await workflow.wait_for_signal("prod_approval")  # Blocks until approved
        await run_ansible_playbook("deploy_prod.yml")

Утверждения с участием человека

Проблема: Ansible Tower требует ручных статических утверждений. Решение: Динамические паузы (например, "Ожидание утверждения в Slack перед удалением базы данных в продакшене").

@workflow.defn
class ProdDeploymentWorkflow:
    async def run(self):
        await run_ansible_playbook("deploy_staging.yml")
        if workflow.is_replaying():
            await workflow.wait_for_signal("prod_approval")
        else:
            await send_slack_approval_request()
            await workflow.wait_for_signal("prod_approval")  # Blocks until approved
        await run_ansible_playbook("deploy_prod.yml")

Оркестрация в кросс-облачных средах

Проблема: Ansible сам по себе не может координировать рабочие процессы в AWS, Azure и GCP. Решение: Temporal-рабочие процессы оркестрируют мультиоблачные плейбуки.

async def migrate_to_aws():
    await run_ansible_playbook("azure_shutdown.yml")
    await run_ansible_playbook("aws_provision.yml")
    if await check_aws_health():
        await run_ansible_playbook("cutover_dns.yml")

Событийно-ориентированный Ansible (EDA) на стероидах

Проблема: Ansible EDA реагирует только на простые события (например, вебхуки). Решение: Цепочки сложных событий (например, "Если загрузка CPU > 90% в течение 5 минут, выполнить масштабирование, уведомить PagerDuty и создать тикет").

async def auto_scale_workflow():
    while True:
        metrics = await fetch_cloud_metrics()
        if metrics.cpu > 90:
            await run_ansible_playbook("scale_out.yml")
            await page_team()
            await workflow.sleep(timedelta(minutes=5))  # Cooldown

Рабочие процессы с поддержкой состояния и восстановлением

Проблема: Ansible не сохраняет информацию о предыдущих запусках. Решение: Temporal запоминает состояние (например, "Повторить попытку только для узлов, которые завершились ошибкой после сбоя").

async def patch_workflow():
    hosts = await get_hosts()
    for host in hosts:
        try:
            await run_ansible_playbook(f"patch.yml -l {host}")
        except ActivityError:
            await log_failed_host(host)
    if workflow.is_replaying():
        await retry_failed_hosts()  # Only retries what crashed

Отладка с "перемоткой времени"

Проблема: Отладка сбоев Ansible болезненна. Решение: Точное воспроизведение рабочих процессов (например, "Посмотреть, почему плейбук завершился ошибкой 3 дня назад").

Веб-интерфейс Temporal показывает полную историю + входные и выходные данные для каждого шага.

Цепочка интеграции между инструментами

Проблема: Ansible не может бесшовно вызывать Terraform и Kubernetes. Решение: Объединить инструменты в одном рабочем процессе.

Динамический инвентарь Ansible

Вот как создать динамический инвентарь Ansible, используя рабочий процесс Temporal, который получает данные о хостах из CMDB через REST API, обеспечивая управление инфраструктурой в реальном времени и отказоустойчивость:

Рабочий процесс Temporal → Получает данные CMDB (REST API) → Генерирует динамический инвентарь → Запускает Ansible

def fetch_cmdb_hosts(cmdb_api_url: str, token: str) -> dict:
    headers = {"Authorization": f"Bearer {token}"}
    response = requests.get(f"{cmdb_api_url}/hosts", headers=headers)
    response.raise_for_status()
    return response.json()

def generate_inventory(cmdb_data: dict) -> dict:
    inventory = {
        "_meta": {"hostvars": {}},
        "all": {"hosts": []},
        "web": {"hosts": []},
        "db": {"hosts": []}
    }
    
    for host in cmdb_data["hosts"]:
        inventory["all"]["hosts"].append(host["name"])
        inventory["_meta"]["hostvars"][host["name"]] = {
            "ansible_host": host["ip"],
            "ansible_user": host["user"],
            "ansible_become": True
        }
        if host["role"] == "web":
            inventory["web"]["hosts"].append(host["name"])
        elif host["role"] == "db":
            inventory["db"]["hosts"].append(host["name"])
    
    return inventory

GitLab

Для интеграции рабочего процесса Ansible на основе Temporal с вебхуком GitLab можно настроить GitLab так, чтобы он запускал рабочий процесс при возникновении определенных событий (например, при отправке изменений в ветку, создании запроса на слияние или создании тега).

Terraform

Использование Terraform и Temporal вместе предоставляет мощную комбинацию для автоматизации инфраструктуры, решая проблемы, которые возникают при использовании каждого из этих инструментов по отдельности. Terraform эффективен в декларативном описании и развертывании инфраструктуры, но требует создания пользовательских провайдеров для новых или нишевых сервисов, что может быть трудоемким в разработке и поддержке. С другой стороны, Temporal предоставляет надежный уровень оркестрации для автоматизации рабочих процессов, включая взаимодействие с API, без необходимости создания пользовательских провайдеров. Например, вы можете использовать Temporal для бесшовной автоматизации взаимодействия с такими сервисами, как Equinix Metal, GoDaddy или VMware через их REST API, организуя сложные, поддерживающие состояние рабочие процессы, которые Terraform в одиночку не способен обработать. В то время как Terraform фокусируется на описании и управлении инфраструктурой как кодом, Temporal дополняет его, обеспечивая динамические, отказоустойчивые и долгосрочные операции, такие как повторные попытки, утверждения и координация между сервисами. Вместе эти инструменты позволяют командам использовать сильные стороны Terraform в развертывании инфраструктуры, полагаясь на Temporal для автоматизации рабочих процессов, создавая более гибкое и масштабируемое решение, чем при использовании каждого из инструментов по отдельности.

Пример конвейера GitLab (.gitlab-ci.yml), который интегрируется с рабочим процессом Temporal для развертывания виртуальной машины VMware с использованием Terraform. Этот конвейер предполагает, что сервер Temporal и рабочий узел уже настроены, и использует предоставленный ранее рабочий процесс Temporal на основе Python.

stages:
  - setup
  - terraform-init
  - terraform-plan
  - terraform-apply
  - temporal-workflow

variables:
  TERRAFORM_DIR: "terraform"
  TEMPORAL_TASK_QUEUE: "vmware-task-queue"

setup-dependencies:
  stage: setup
  image: python:3.9
  script:
    - apt-get update && apt-get install -y terraform
    - pip install temporalio requests
  artifacts:
    paths:
      - $TERRAFORM_DIR

terraform-init:
  stage: terraform-init
  image: hashicorp/terraform:latest
  script:
    - cd $TERRAFORM_DIR
    - terraform init
  artifacts:
    paths:
      - $TERRAFORM_DIR/.terraform

terraform-plan:
  stage: terraform-plan
  image: hashicorp/terraform:latest
  script:
    - cd $TERRAFORM_DIR
    - terraform plan -out=tfplan
  dependencies:
    - terraform-init
  artifacts:
    paths:
      - $TERRAFORM_DIR/tfplan

terraform-apply:
  stage: terraform-apply
  image: hashicorp/terraform:latest
  script:
    - cd $TERRAFORM_DIR
    - terraform apply -auto-approve tfplan
  dependencies:
    - terraform-plan

temporal-workflow:
  stage: temporal-workflow
  image: python:3.9
  script:
    - apt-get update && apt-get install -y git
    - pip install temporalio requests
    - git clone https://github.com/your-repo/temporal-vmware-workflow.git 
    - cd temporal-vmware-workflow
    - python run_workflow.py --task-queue $TEMPORAL_TASK_QUEUE --terraform-dir $TERRAFORM_DIR
  dependencies:
    - terraform-apply

Рабочий процесс на основе Temporal для развертывания виртуальных машин VMware с использованием Terraform является гораздо более гибким, чем традиционные настройки Terraform. В отличие от простого Terraform, который ограничен только предоставлением ресурсов, Temporal выступает в роли уровня оркестрации, который может легко интегрироваться с внешними системами, такими как инструменты мониторинга, CMDB и другие сервисы. Например, после того как Terraform предоставляет виртуальную машину, рабочий процесс может автоматически обновить CMDB, запустить проверку состояния в системе мониторинга или отправить уведомления заинтересованным сторонам.

Temporal также эффективно обрабатывает повторные попытки и сбои, гарантируя, что рабочий процесс продолжится даже в случае сбоя на этапе, таком как обновление CMDB. Он поддерживает динамическое принятие решений, например, запрос к системе мониторинга для определения, следует ли продолжать выполнение, и может приостановить выполнение для получения одобрения человека, если это необходимо. Это делает его идеальным для сложных реальных сценариев, где развертывание инфраструктуры не ограничивается только предоставлением ресурсов — оно включает бесшовную интеграцию с множеством инструментов и процессов.

@activity.defn
async def run_terraform_init(working_dir: str) -> str:
    result = subprocess.run(["terraform", "init"], cwd=working_dir, capture_output=True, text=True)
    if result.returncode != 0:
        raise Exception(f"Terraform init failed: {result.stderr}")
    return result.stdout
...
@activity.defn
async def run_terraform_apply(working_dir: str) -> str:
    result = subprocess.run(["terraform", "apply", "-auto-approve", "tfplan"], cwd=working_dir, capture_output=True, text=True)
    if result.returncode != 0:
        raise Exception(f"Terraform apply failed: {result.stderr}")
    return result.stdout
...

Миграции баз данных

Крупные миграции баз данных, особенно для производственных систем с объемом данных 500 ГБ или более, могут быть невероятно сложными и рискованными. Инструменты вроде Liquibase отлично подходят для управления изменениями схемы и версионирования, но когда дело доходит до надежного выполнения этих миграций — особенно в распределенных или гибридных средах — они часто не справляются самостоятельно. Именно здесь Temporal демонстрирует свои преимущества.

Temporal добавляет уровень оркестрации, который гарантирует плавное выполнение миграций, даже для огромных баз данных. Например, миграция производственной базы данных объемом более 500 ГБ может включать такие шаги, как резервное копирование данных, применение изменений схемы, проверку миграции и откат, если что-то пойдет не так. Temporal координирует эти шаги, автоматически повторяет выполнение проваленных задач и отслеживает прогресс, чтобы избежать перезапуска процесса в случае его прерывания.

Он также идеально подходит для обработки длительных операций, которые могут занять часы или даже дни. Если во время миграции возникнет проблема — например, сбой сети или скачок нагрузки на базу данных — Temporal может приостановить рабочий процесс и возобновить его, когда условия улучшатся. А поскольку реальные миграции часто требуют участия человека, Temporal может приостановить выполнение для получения одобрения перед внесением критических изменений, таких как изменение схемы в производственной среде, и продолжить после получения разрешения.

Интеграция с инструментами мониторинга, системами резервного копирования и другими внешними сервисами позволяет Temporal гарантировать, что все остается синхронизированным на протяжении всей миграции. Независимо от того, перемещаете ли вы терабайты данных между регионами или применяете деликатные обновления схемы в работающей системе, Temporal заполняет пробел между возможностями Liquibase и операционной сложностью современного управления базами данных.

Ниже представлен один файл на языке Go, который реализует рабочий процесс Temporal для оркестрации миграции схемы базы данных с использованием Liquibase.

// Activity: Backup the database
func BackupDatabase(ctx context.Context, databaseURL string) error {
    cmd := exec.CommandContext(ctx, "pg_dump", "-Fc", "-f", "/backups/db_backup.dump", databaseURL)
    if err := cmd.Run(); err != nil {
        return fmt.Errorf("failed to execute backup command: %w", err)
    }
    return nil
}

// Activity: Run Liquibase update
type LiquibaseInput struct {
    DatabaseURL   string
    ChangelogFile string
}

func RunLiquibaseUpdate(ctx context.Context, input LiquibaseInput) error {
    cmd := exec.CommandContext(ctx, "liquibase", "--url", input.DatabaseURL, "--changeLogFile", input.ChangelogFile, "update")
    if err := cmd.Run(); err != nil {
        return fmt.Errorf("liquibase update failed: %w", err)
    }
    return nil
}

// Activity: Validate the migration
func ValidateMigration(ctx context.Context, databaseURL string) error {
    // Example: Run a query to check if the schema is applied correctly
    cmd := exec.CommandContext(ctx, "psql", "-c", "SELECT * FROM information_schema.tables WHERE table_schema = 'public';", databaseURL)
    if err := cmd.Run(); err != nil {
        return fmt.Errorf("validation query failed: %w", err)
    }
    return nil
}

Самообслуживание (self-service) с использованием Temporal

Предоставление безопасной самообслуживаемой инфраструктуры для разработчиков в крупных организациях является сложной задачей. Традиционные подходы часто требуют создания пользовательских инструментов или поддержки сложных провайдеров Terraform для каждого сервиса.

Более простая альтернатива заключается в оркестрации существующих REST API (Keycloak, Vault и т. д.) через рабочие процессы Temporal. Этот подход:

Устраняет необходимость в пользовательских провайдерах Terraform или внутренних инструментах
Использует нативные API целевых систем, таких как Vault, для управления пространствами имен и AppRole
Обеспечивает безопасность за счет встроенных рабочих процессов утверждений и аудитных журналов
Масштабируется между командами без создания технического долга из-за фрагментированных решений
Temporal управляет оркестрацией, повторными попытками и состоянием, взаимодействуя напрямую с API каждой системы. Это снижает накладные расходы на обслуживание по сравнению с управлением множеством провайдеров Terraform или пользовательских сервисов.

Послесловие

Temporal выступает в роли хореографа, координируя взаимодействие между Ansible и Terraform для создания более гибких и отказоустойчивых рабочих процессов. В то время как Terraform предоставляет инфраструктуру через декларативные манифесты, а Ansible управляет конфигурацией систем, Temporal обеспечивает надежную оркестрацию этих процессов, добавляя такие возможности, как автоматические повторные попытки, точки контроля состояния и динамическое принятие решений. Это позволяет объединить разрозненные задачи в единую цепочку, где каждый инструмент выполняет свою роль, а Temporal гарантирует целостность и завершенность всего процесса, даже в случае сбоев или длительных операций.

Комментарии (0)