снизить трение поставки через стандартизированную внутреннюю платформу
Создание Internal Developer Platform: от разрозненных CI/CD-скриптов к унифицированному деплою
13 минут
Когда у каждой команды свой стиль пайплайнов, поставка замедляется, а платформенные риски растут. В статье — как построить IDP со слоем абстракции деплоя, каталогом сервисов, policy gate и централизованными секретами.
Почему фрагментированный CI/CD со временем замедляет поставку
Большинство команд начинают с практичных скриптов под конкретную задачу: Jenkins job в одном сервисе, GitHub Actions в другом, кастомный shell-путь для деплоя, который поддерживают два человека. Проблема не в одном инструменте, а в том, что каждая команда развивает собственные соглашения по окружениям, секретам, approvals и rollback. Со временем это создаёт скрытую вариативность деплоя, силосы знаний и policy gaps, которые особенно болезненны во время инцидентов. Разработчики тратят время на различия платформы вместо продуктовой разработки.
IDP как слой абстракции, а не замена всего CI/CD
Internal Developer Platform (IDP) должен оборачивать существующие системы поставки, а не требовать big-bang миграции. Платформа даёт единый интерфейс деплоя и маршрутизирует запрос в нужный workflow, кластер и approval chain. Разработчик формулирует намерение, а платформа разрешает операционные детали. Это снижает когнитивную нагрузку и позволяет платформенной команде централизованно применять стандарты.
# Unified command used by developers
idp deploy api-service --version v2.3.1 --env staging
# Platform resolves behind the scenes:
# 1) environment -> cluster + namespace
# 2) service metadata from catalog
# 3) secret references from vault path
# 4) workflow trigger with validated inputs
# 5) status updates to platform dashboardКаталог сервисов: контракт между командами и платформой
Работающему IDP нужно каноническое описание сервиса. Каталог должен включать ownership, репозиторий, цели деплоя, обязательные секреты, runtime-ограничения и ожидания по надёжности. Это контракт: команды описывают намерение и требования сервиса, а платформа исполняет их единообразно. Держите каталог в Git, ревьювьте каждое изменение и версионируйте его как код приложения.
apiVersion: idp.angri-tech.org/v1
kind: Service
metadata:
name: api-gateway
owner: platform-team
spec:
repository:
url: https://github.com/angri-tech/api-gateway
branch: main
deployment:
targets:
- name: staging
cluster: eks-staging-us-east-1
namespace: api-gateway-staging
autoDeploy: true
- name: production
cluster: eks-prod-us-east-1
namespace: api-gateway-prod
approvalRequired: true
approvers:
- platform-team-leads
secrets:
- path: secret/api-gateway/database
required: true
resources:
cpu:
request: 500m
limit: 2000m
memory:
request: 512Mi
limit: 2Gi
slo:
availability: 99.9Policy gate и централизованные секреты — обязательная часть
Без enforcement платформенные стандарты становятся рекомендациями, которые обходят под дедлайном. Добавьте policy gate, который валидирует запрос на деплой до выполнения: актуальность security scan, обязательные resource limits, SLO для production и совместимость зависимостей. Параллельно централизуйте секреты в Vault или cloud secret manager и инжектите их в runtime. Разработчики должны ссылаться на секреты как зависимости, а не работать с сырыми значениями.
func EvaluateDeployment(ctx context.Context, req DeploymentRequest) PolicyResult {
var result PolicyResult
scanStatus, err := getLatestScanStatus(ctx, req.ServiceName, req.Version)
if err != nil || scanStatus.AgeHours > 24 {
result.Errors = append(result.Errors, PolicyViolation{
Policy: "security-scan-required",
Resource: req.ServiceName,
Message: "No recent security scan found",
Remediation: "Run: idp security-scan <service>",
})
}
if req.ServiceCatalog.Spec.Resources.CPU.Request == "" {
result.Errors = append(result.Errors, PolicyViolation{
Policy: "cost-tag-required",
Resource: req.ServiceName,
Message: "No CPU resource requests defined",
Remediation: "Add resources.cpu.request to service-catalog.yaml",
})
}
if req.Environment == "production" && req.ServiceCatalog.Spec.SLO.Availability == 0 {
result.Errors = append(result.Errors, PolicyViolation{
Policy: "slo-required-production",
Resource: req.ServiceName,
Message: "Production services must define an SLO",
Remediation: "Add slo.availability to service-catalog.yaml",
})
}
result.Passed = len(result.Errors) == 0
return result
}Опорный workflow: деплой через IDP в GitHub Actions
Workflow должен быть коротким и предсказуемым: валидация входных параметров, аутентификация в кластер, получение runtime-секретов, деплой с immutable image tag и отчёт статуса обратно в platform API. Делайте этот flow переиспользуемым между сервисами, чтобы команды не дублировали логику деплоя в каждом репозитории.
name: IDP Service Deployment
on:
workflow_dispatch:
inputs:
service:
required: true
version:
required: true
environment:
required: true
cluster:
required: true
namespace:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Validate inputs
run: |
test -n "${{ inputs.service }}"
test -n "${{ inputs.version }}"
- name: Authenticate to Kubernetes
uses: azure/k8s-set-context@v1
with:
kubeconfig: ${{ secrets.KUBECONFIG }}
context: ${{ inputs.cluster }}
- name: Fetch secrets from Vault
uses: hashicorp/vault-action@v2
with:
method: kubernetes
url: https://vault.internal.angri-tech.org
secrets: |
secret/data/${{ inputs.service }}/${{ inputs.environment }} DATABASE_URL
- name: Deploy with Helm
run: |
helm upgrade --install "${{ inputs.service }}" ./charts/${{ inputs.service }} \
--namespace "${{ inputs.namespace }}" \
--set image.tag="${{ inputs.version }}" \
--wait --timeout 5mОперируйте платформой как внутренним продуктом
Относитесь к platform engineering как к продуктовой разработке для внутренних пользователей. Измеряйте adoption и трение метриками: deployment frequency, lead time, policy failure rate, время на платформенный toil. Стройте paved road, который проще, чем обход платформы. Обнаруживайте drift между каталогом и runtime-состоянием, но избегайте неожиданных auto-remediation в production без явного ownership. Начните с одного сервиса или команды, докажите сокращение трения и масштабируйте паттерны итеративно. Цель не в идеальной платформе за квартал, а в том, чтобы каждый следующий деплой был безопаснее и быстрее предыдущего.
Если процессы выката уже различаются по окружениям, начните с карты проблем по подходу к узким местам release-пайплайна.
Когда API платформы стабилизирован, декларативное управление выкатом проще внедрять через GitOps с Argo CD и Flux.
