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.
Что сделать после занятия
- [ ] Перенесите все секреты из скриптов в Jenkins Credentials; проверьте, что в логе они замаскированы.
- [ ] Создайте таблицу «5 типовых ошибок CI» для вашего проекта с симптомом и fix.
- [ ] Намеренно сломайте пайплайн (неверный credentialsId) и восстановите по логу — тренировка on-call.