MLOps Path

3.2.4 · блок 3

Секреты в CI и типичные отказы пайплайна

Секреты в CI и типичные отказы пайплайна

Зачем это нужно

Пайплайн без секретов редок: пароль registry, API-ключ облака, токен Git. Одна строка password = "sk-123" в Jenkinsfile — инцидент безопасности и учебный провал. Второй навык — диагностика: Jenkins красный в половине случаев из-за окружения, а не из-за кода. Умение читать лог stage и чинить типовые сбои экономит часы всей команде.

Основные идеи

Credentials в Jenkins. Секреты хранят в Credentials Store (глобально или на folder). В pipeline — только ID, не значение:


withCredentials([
    string(credentialsId: 'minio-access-key', variable: 'MINIO_KEY')
]) {
    sh 'python upload.py --key "$MINIO_KEY"'
}

Типы: Username/Password, Secret text, SSH key, Secret file. Jenkins маскирует секреты в логах (но осторожно с set +x и echo).

Не секреты в Git. Запрещено: .env с паролями в repo, ARG REGISTRY_PASSWORD в Dockerfile, base64 «для obscurity». Правильно: .env.example без значений; runtime — Kubernetes Secret или Jenkins credentials.

Binding в Docker login. Пароль в stdin, не в командной строке (иначе виден в ps):


sh 'echo "$REG_PASS" | docker login registry -u "$REG_USER" --password-stdin'

Типичные отказы и что проверять

| Симптом | Частая причина |

|---------|----------------|

| `docker: not found` | Docker не установлен на agent или нет label |

| `permission denied` при docker | User agent не в группе `docker` |

| `unauthorized: authentication required` | Неверный credentialsId или истёк токен |

| `pytest: command not found` | Зависимости не установлены в stage до test |

| Flaky test | Гонка, зависимость от сети, время |

| Out of disk | Нет `cleanWs()`, копятся слои Docker |

| Timeout | Обучение модели в CI без GPU — вынести в nightly |

Flaky builds. Нестабильный пайплайн подрывает доверие. Фиксируйте: seed для тестов, mock внешних API, retry только там, где оправдано (network blip), не для падающих assert.

Безопасность ML-артефактов. Registry credentials дают push; отдельные read-only credentials — для pull в k8s (imagePullSecrets). Модель не должна утекать через публичный лог (не печатайте содержимое Secret).

Отказоустойчивость процесса. CI упал — PR не мержим. CD (Helm/Argo) не обновляет prod, если новый образ не собран. Явная связь: нет зелёного CI → нет нового тега → нет деплоя.

Как это выглядит на практике

Сценарий 1: push падает с 401.

1. Открыть лог stage Push.

2. Проверить credentialsId в Jenkins (Manage Credentials).

3. Перевыпустить token в registry, обновить secret в Jenkins.

4. Rebuild без изменения кода.

Сценарий 2: «работало вчера».

1. Compare: обновился ли базовый образ python:3.11-slim?

2. Зафиксировать digest базового образа в Dockerfile или lockfile.

3. Добавить --pull только по расписанию, не на каждый PR.

Сценарий 3: секрет попал в Git (учебный fire-drill).

1. Немедленно rotate credential.

2. Удалить из истории git (BFG / git filter-repo) — с помощью преподавателя.

3. Включить pre-commit hook или scanning (gitleaks) — тема смежная.

Postmortem в Confluence: что сломалось, как обнаружили, как предотвратить — навык из блока 1.

Что сделать после занятия

Официальные материалы

Открыть интерактивную версию