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-процессов даже при работе с крупной инфраструктурой.
Общая архитектура
Типичный процесс выглядит так:
-
Terraform-код хранится в Git-репозитории
-
GitOps-движок (Flux или Argo CD) синхронизирует манифесты в кластер
-
Применяется Terraform CR
-
tofu-controller:
-
Получает Terraform-модуль
-
Применяет его
-
Сохраняет состояние и управляет им
-
-
Любой дрейф автоматически устраняется
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.
Сценарий 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.