GitOps + Terraform: tofu-controller вместо пайплайнов

GitOps не заканчивается на Kubernetes

Terraform отлично справляется с развёртыванием и управлением инфраструктурой, но во многих командах его по-прежнему запускают через:

  • CI-пайплайны

  • Ручной terraform apply

  • Задания по расписанию

У такого подхода есть существенные недостатки:

  • Нет непрерывной сверки состояния

  • Обнаружение дрейфа выполняется вручную

  • Логика выполнения существует вне кластера

  • Слабая наблюдаемость и аудируемость

GitOps предлагает:

  • Единственный источник истины (Git)

  • Непрерывную сверку состояния

  • Декларативное описание желаемого состояния

  • Лучшую прослеживаемость изменений

Недостающее звено — способ вписать Terraform в эту модель.

Знакомство с tofu-controller

tofu-controller — это Kubernetes-контроллер, который запускает OpenTofu/Terraform как согласуемый ресурс прямо внутри кластера.

На высоком уровне он:

  • Вводит пользовательское определение ресурса (Custom Resource Definition, CRD) для Terraform

  • Отслеживает Git-репозитории с Terraform-кодом

  • Выполняет plan/apply внутри Kubernetes

  • Непрерывно сверяет состояние

  • Автоматически обнаруживает и устраняет дрейф

Благодаря этому Terraform превращается в непрерывно согласуемый GitOps-ресурс.

Наш форк tofu-controller

Одна из сложностей при запуске Terraform через Kubernetes-контроллеры — ограничение на размер плана Terraform. По умолчанию Kubernetes Secrets не могут превышать 1 МБ, что может стать проблемой для больших инфраструктурных планов.

Функция гибридного хранилища планов (hybrid plan storage) в нашем форке tofu-controller решает эту проблему эффективно.

Как это работает

Контроллер автоматически выбирает оптимальную стратегию хранения в зависимости от размера плана:

  • Chunked Secrets (< 900 КБ): план разбивается на несколько Kubernetes Secrets, каждый не превышает 1 МБ

  • Ephemeral Volumes (≥ 900 КБ): большие планы хранятся в эфемерных томах, локальных для пода

  • Legacy Single Secret: полная обратная совместимость с существующими развёртываниями

Настраиваемый порог и поведение при резервном переключении

Порог по умолчанию составляет 900 КБ, но его можно изменить.

При использовании хранилища на основе Secrets с включённым автоматическим резервным переключением (auto-fallback) контроллер автоматически переходит на хранилище в томах, как только план превышает заданный максимальный размер Secret.

Хранилище в Secrets с автоматическим резервным переключением (пример)

storageConfig:
  type: secret              # Для небольших планов используются Secrets
  autoFallback: true        # Переключение на тома при превышении лимита
  maxSecretSize: 900000     # Настраиваемый порог (900 КБ)
  volumeMountPath: "/tmp/tf-storage"

Хранилище только в томах (пример)

storageConfig:
  type: volume
  volumeMountPath: "/tmp/tf-storage"

Преимущества

  • Неограниченный размер плана при использовании томов

  • Обратная совместимость с существующими развёртываниями

  • Эффективность: небольшие планы используют Secrets, крупные — тома

  • Автоматическая очистка: данные планов не остаются бесхозными

  • Проверено в продакшне в корпоративных средах

Эта функция позволяет командам безопасно запускать Terraform-планы любого размера с помощью tofu-controller, обеспечивая бесперебойность GitOps-процессов даже при работе с крупной инфраструктурой.

Общая архитектура

Типичный процесс выглядит так:

  1. Terraform-код хранится в Git-репозитории

  2. GitOps-движок (Flux или Argo CD) синхронизирует манифесты в кластер

  3. Применяется Terraform CR

  4. tofu-controller:

    • Получает Terraform-модуль

    • Применяет его

    • Сохраняет состояние и управляет им

  5. Любой дрейф автоматически устраняется

Схема архитектуры GitOps с tofu-controller

Git становится источником истины — не пайплайны.

Сценарий 1: управление ресурсами Grafana через GitOps

Grafana — отличный кандидат для GitOps:

  • Дашборды

  • Источники данных (datasources)

  • Папки

  • Правила оповещения

Эти ресурсы, как правило, используются несколькими командами и окружениями, и они выигрывают от версионирования и код-ревью.

Зачем использовать Terraform для Grafana?

Terraform-провайдер Grafana позволяет управлять:

  • Дашбордами, источниками данных, папками и оповещениями как кодом

  • Источниками данных единообразно во всех окружениях

  • Структурой папок и правами доступа

В сочетании с GitOps это даёт:

  • Аудируемые изменения

  • Простые откаты

  • Идентичность окружений

Terraform CR (пример)

apiVersion: infra.contrib.fluxcd.io/v1alpha2
kind: Terraform
metadata:
  name: tofu-controller
  namespace: flux-system
spec:
  interval: 1m
  approvePlan: auto
  alwaysCleanupRunnerPod: false
  path: ./grafana-resources
  # Настройка удалённого бэкенда для хранения состояния Terraform
  # за пределами кластера (Azure Storage Account)
  backendConfig:
    customConfiguration: |
      backend "azurerm" {
      ...
   }
  sourceRef:
    kind: GitRepository
    name: monitoring-resources
    namespace: flux-system
  varsFrom:
    - kind: Secret
      name: grafana-api-token-production
  storageConfig:
    type: volume
    volumeMountPath: "/tmp/tf-storage"

Структура GitOps-репозитория (пример)

grafana-resources/
├── main.tf
├── providers.tf
├── folders.tf
├── alert-rules.tf
├── dashboard-render/
│ ├── dashboards/
│ │ └── k8s-dashboards.json
│ └── generated/
│ │ └── k8s-dashboards.tf
└── datasources.tf

Провайдеры (пример)

terraform {
  required_providers {
    grafana = {
      source  = "grafana/grafana"
      version = "4.8.0"
    }
  }
}

provider "grafana" {
  url  = "http://grafana-grafana.grafana.svc.cluster.local"
  auth = var.api_token
}

После коммита:

  • Flux синхронизирует манифест

  • tofu-controller применяет Terraform-код

  • Ресурсы Grafana проходят ревью через pull request и непрерывно согласуются

Ресурсы Grafana в GitOps-процессе под управлением tofu-controller

Ресурсы Grafana теперь живут в виде кода, полностью управляемого через GitOps.

Сценарий 2: управление ресурсами HashiCorp Vault через GitOps

Vault нередко воспринимается как «особая» система из-за требований к безопасности. Но именно это делает его идеальным кандидатом для декларативного управления.

Чем можно управлять с помощью Terraform?

С помощью Vault-провайдера можно управлять:

  • Политиками

  • Методами аутентификации (Kubernetes, JWT, OIDC)

  • Ролями и правами доступа

Соображения безопасности

Несколько важных моментов:

  • Состояние Terraform необходимо защитить

  • Учётные данные следует передавать через Kubernetes Secrets

  • Доступ должен строиться по принципу минимальных привилегий

tofu-controller хорошо вписывается в эту модель, потому что:

  • Выполнение происходит внутри кластера

  • Доступ контролируется через Kubernetes RBAC

  • Секреты не хранятся в пайплайнах

Vault-политика через Terraform (пример)

resource "vault_policy" "microservice_policy" {
  name   = "microservice_policy"
  policy = <<EOT
{
  "path": {
    "secret/data/microservice-name/region-1/environment-1": {
      "capabilities": ["list","read"]
    }
  }
}
EOT
}

При таком подходе:

  • Конфигурация Vault проходит ревью через pull request

  • Дрейф обнаруживается автоматически

  • Конфигурация безопасности становится воспроизводимой

Это безопасность как код (security as code), обеспечиваемая GitOps.

GitOps с tofu-controller против традиционных пайплайнов

Традиционный CI/CD

  • Пайплайн в центре всего

  • Ручное обнаружение дрейфа

  • Скрипты повсюду

GitOps с tofu-controller

  • Непрерывная сверка состояния

  • Кластер в центре всего

  • Автоматическое исправление дрейфа

  • Декларативные CRD

Когда tofu-controller оправдан?

Хорошо подходит

  • Платформы, построенные вокруг Kubernetes

  • Команды платформенной инженерии (platform engineering)

  • Общая инфраструктура и инструментарий

  • Зрелая GitOps-культура

Может не подойти

  • Сильно эфемерная инфраструктура

  • Команды, только начинающие знакомство с Terraform или GitOps

  • Среды без Kubernetes

Как и с любым инструментом, контекст решает всё.

Заключение

GitOps не обязан ограничиваться Kubernetes-манифестами.

Используя tofu-controller, вы можете включить Terraform в GitOps-процесс и управлять внешними системами единообразно, декларативно и с полным аудитом.

  • Grafana превращается в наблюдаемость как код (observability as code)

  • Vault превращается в безопасность как код (security as code)

Если вы уже используете Terraform и GitOps, tofu-controller может оказаться тем самым недостающим звеном между ними.

Статья написана при участии и вкладе João Leão и Ricardo Ramos.

© 2026 meganuke