CI/CD — не Jenkins на 40 job’ов. Для личного и small-team git хватает короткого честного pipeline: проверка → артефакт → выкладка → smoke 🚦
Цели, не buzzwords #
- main всегда собирается.
- Деплой повторяемый (не «я с ноутбука rsync’нул»).
- Откат понятен (предыдущий артефакт / предыдущий commit).
Continuous Deployment на каждый push — только если smoke автоматический. Иначе — CD до staging, prod вручную/по tag.
Минимальные стадии #
lint/test → build → deploy → smoke| Стадия | Примеры |
|---|---|
| lint/test | hugo --minify, go test, shellcheck |
| build | docker image, static public/ |
| deploy | rsync, kubectl, compose pull |
| smoke | curl -f, health endpoint |
На PR — lint/test (+ build без deploy). На main / tag — всё.
Секреты #
- в secrets CI, не в yaml;
- отдельный deploy-ключ без sudo;
- rotate, если runner когда-либо светился.
# идея
env:
SSH_KEY: ${{ secrets.SSH_KEY }}Concurrency #
Не деплойте два push’а параллельно в один host:
concurrency:
group: deploy-blog
cancel-in-progress: false # или true — осознанноPin всего #
FROM hugo:0.164.0
# не :latestimage: git.example.com/evgeny/blog:1.4.2Digest — ещё лучше для prod.
Пример каркаса (Forgejo/GHA-like) #
on:
push:
branches: [main]
jobs:
deploy:
runs-on: docker
steps:
- uses: actions/checkout@v4 # или ручной git fetch
- run: hugo --minify
- run: pagefind --site public
- run: rsync -az --delete public/ deploy@host:/srv/www/site/
- run: curl -fsS https://site/ >/dev/nullУ вас на blog — ещё generate-og и кэш _gen; принцип тот же.
Антипаттерны #
| Нет | Да |
|---|---|
docker compose pull с ноутбука в prod | CI с аудитом |
latest везде | pin version |
sudo chown после rsync | --chmod + правильные группы |
| деплой без smoke | curl -f / healthcheck |
| один job «make all» 40 мин | кэш + параллель тестов |
Откат #
- Git revert / previous tag → pipeline.
- Или оставить previous release directory и symlink
current. - Для ВМ — PBS restore (редко, но путь должен быть).
Итог #
Короткий pipeline, secrets, pin, concurrency, smoke. Когда это зелёное месяц — добавляйте matrix и coverage, не наоборот 📦