$ sudo teach|
    $ sudo teach|
    IT school
  • Telegram
  • Партнёрам
  • Все курсы
$ sudo teach IT
OOO "SALEPROFIT"Контакты и реквизитыIT-Park Logo

Школа

  • Блог
  • Проверить сертификат

Сотрудничество

  • Стать учителем
  • Партнёрская программа
  • О проекте

Право

  • Оферта
  • Политика конфиденциальности

© 2023–2026 $ sudo teach IT™. All Rights Reserved. Public user contributions licensed under CC BY-SA 4.0 license with attribution required
TelegramGitHubYouTube
ГлавнаяБлогCI/CD для новичков: деплой «по накатанной» на GitHub Actions и проверка артефактов

CI/CD для новичков: деплой «по накатанной» на GitHub Actions и проверка артефактов

$ sudo teach IT
·24 июля 2026 г.·9 мин·54
CI/CD для новичков: деплой «по накатанной» на GitHub Actions и проверка артефактов

Создадим понятный пайплайн: тесты, линтинг, сборка артефакта и деплой с проверкой, что версия действительно та. Рассмотрим частые проблемы новичков и как их избежать.

Содержание
Как мыслить CI/CD: от коммитов к артефактамПодготовка: пример проекта и что будет деплоитьсяПример структурыПайплайн на GitHub Actions: базовая схемаОбщая идея workflowВажный принцип: версия сборки ≠ версия пакетаРеализация: workflow с проверкой артефактаПример workflowЧто здесь важноГде часто ошибаются новички1) Путают “проверку” с “просто запуском деплоя”2) Доверяют только тегам или версии из package.json3) Нет метаданных у артефакта4) Отсутствие fail-fast логики5) Забывают о jqУсиление: контроль целостности артефакта хешемРеальный деплой: как заменить “Deploy (example)” на рабочий сценарийВариант A: копирование статической сборки по SSH (scp/rsync)Вариант B: деплой в Kubernetes с фиксированным образом/артефактомВыбор артефакта и “где хранить сборку”Параллелизация и время выполнения: что можно улучшитьОтладка пайплайна: как не терять времяМини-чеклист: “деплой по накатанной” без сюрпризовВывод

CI/CD — это не “автоматизация ради автоматизации”, а способ сделать доставку изменений предсказуемой. Для новичка ключевая проблема обычно не в том, что “сложно написать YAML”, а в том, что непонятно, что именно должно происходить в пайплайне и как доказать, что деплой выполнен из правильной версии.

В этой статье мы построим понятный CI/CD-пайплайн на GitHub Actions:

  1. запуск тестов и линтинга,
  2. сборка артефакта,
  3. деплой,
  4. проверка, что версия в деплое соответствует версии артефакта, а не “чего-то похожего”.

Материал будет полезен, даже если вы не планируете немедленно деплоить в прод: структура и принципы остаются теми же. В конце я мягко упомяну курс CI-CD от теории до практики как один из способов углубиться, если хочется системно разобрать детали.


Как мыслить CI/CD: от коммитов к артефактам

Большинство “кривых” пайплайнов новичков имеют одну общую черту: деплой делается не из артефакта, а из исходников “как получится”. Например:

  • сначала собирают на одной машине,
  • потом деплоят “просто по тегу” или “пере-собирают на сервере”,
  • в итоге непонятно, что именно было смонтировано на сервере и совпадает ли оно с тем, что прошло тесты.

Правильная модель (упрощённо):

  1. CI: тесты → линтинг → сборка → создание артефакта.
  2. Проверки: артефакт имеет уникальную идентичность (версию/хеш).
  3. CD: деплой использует тот же артефакт и тот же идентификатор.

Это можно сделать даже без сложной инфраструктуры — достаточно научиться:

  • вычислять и сохранять версию сборки (например, по GITHUB_SHA),
  • сохранять метаданные вместе с артефактом,
  • в деплое проверять, что вы ставите артефакт с ожидаемым SHA/версией.

Подготовка: пример проекта и что будет деплоиться

Для конкретики предположим, что у нас есть простой Node.js-проект, который собирается в папку dist/, а деплой — это копирование сборки на “приёмник” (например, тестовый сервер или статический хостинг). Если вы работаете с другим языком, логика остаётся: тесты/линтинг → сборка → артефакт → деплой.

Пример структуры

code
.
├── package.json
├── .eslintrc.cjs
├── src/
└── dist/ (создаётся при сборке)

В package.json допустимы скрипты:

  • lint: линтинг
  • test: тесты
  • build: сборка

Пайплайн на GitHub Actions: базовая схема

На GitHub Actions пайплайн задаётся в .github/workflows/<name>.yml. Мы сделаем несколько шагов и (важно) разделим задачу на CI и CD. Это повышает прозрачность и помогает новичкам видеть границы ответственности.

Общая идея workflow

  • Триггеры:
    • на push в main (для автоматических релизов в тест),
    • на workflow_dispatch (для ручного запуска, полезно при отладке).
  • CI job:
    • чек-аут кода,
    • установка зависимостей,
    • тесты,
    • линтинг,
    • сборка,
    • генерация артефакта,
    • вычисление метаданных версии,
    • загрузка артефакта как artifact.
  • CD job:
    • скачивание artifact,
    • проверка метаданных (что SHA совпадает с ожидаемым),
    • деплой.

Важный принцип: версия сборки ≠ версия пакета

Чтобы корректно проверить “версию в деплое”, нужно определить, что именно считаем версией.

Практичный выбор для старта:

  • BUILD_SHA = GITHUB_SHA (хеш конкретного коммита),
  • BUILD_NUMBER = GITHUB_RUN_NUMBER (номер запуска),
  • при желании — можно дополнить семантической версией из package.json.

Для доказательства соответствия достаточно SHA: он уникален для кода.

Подводный камень: новички часто пытаются сравнивать package.json версия/тег, но забывают, что:

  • версия может не обновляться,
  • релиз может создаваться из не той ветки,
  • теги могут “переезжать” (особенно в ручных сценариях).

Коммитный SHA надёжнее как идентификатор сборки.


Реализация: workflow с проверкой артефакта

Создадим файл .github/workflows/ci-cd.yml.

Пример workflow

code
name: CI/CD

on:
  push:
    branches: [ "main" ]
  workflow_dispatch:

jobs:
  ci:
    runs-on: ubuntu-latest
    outputs:
      build_sha: ${{ steps.meta.outputs.build_sha }}
      build_id: ${{ steps.meta.outputs.build_id }}
      artifact_name: ${{ steps.meta.outputs.artifact_name }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Test
        run: npm test

      - name: Build
        run: npm run build

      - name: Create build metadata
        id: meta
        shell: bash
        run: |
          BUILD_SHA="${GITHUB_SHA}"
          BUILD_NUMBER="${GITHUB_RUN_NUMBER}"
          ARTIFACT_NAME="web-${BUILD_SHA}.tar.gz"
          BUILD_ID="${BUILD_SHA}-${BUILD_NUMBER}"

          echo "build_sha=${BUILD_SHA}" >> "$GITHUB_OUTPUT"
          echo "build_id=${BUILD_ID}" >> "$GITHUB_OUTPUT"
          echo "artifact_name=${ARTIFACT_NAME}" >> "$GITHUB_OUTPUT"

          # пишем метаданные рядом с артефактом
          cat > dist/build-metadata.json <<EOF
          {
            "build_sha": "${BUILD_SHA}",
            "build_id": "${BUILD_ID}",
            "git_ref": "${GITHUB_REF}",
            "built_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
          }
          EOF

      - name: Package artifact
        shell: bash
        run: |
          ARTIFACT_NAME="web-${GITHUB_SHA}.tar.gz"
          tar -czf "$ARTIFACT_NAME" -C dist .

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ steps.meta.outputs.artifact_name }}
          path: web-${{ github.sha }}.tar.gz
          if-no-files-found: error

  cd:
    needs: ci
    runs-on: ubuntu-latest
    env:
      EXPECTED_BUILD_SHA: ${{ needs.ci.outputs.build_sha }}
      EXPECTED_ARTIFACT: ${{ needs.ci.outputs.artifact_name }}
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: ${{ env.EXPECTED_ARTIFACT }}
          path: ./artifact

      - name: Verify artifact metadata (before deploy)
        shell: bash
        run: |
          set -euo pipefail

          cd artifact
          tar -xzf ./*.tar.gz

          # dist/build-metadata.json должен быть внутри
          ACTUAL_SHA="$(jq -r '.build_sha' dist/build-metadata.json)"
          echo "Expected build_sha: ${EXPECTED_BUILD_SHA}"
          echo "Actual build_sha:   ${ACTUAL_SHA}"

          if [ "${ACTUAL_SHA}" != "${EXPECTED_BUILD_SHA}" ]; then
            echo "ERROR: Build SHA mismatch. Refusing deploy."
            exit 1
          fi

          echo "Artifact verification passed."

      - name: Deploy (example: copy to server)
        shell: bash
        run: |
          set -euo pipefail

          # Пример: имитируем деплой
          # В реальном проекте тут может быть scp/rsync, kubectl set image и т.д.
          echo "Deploying build for ${EXPECTED_BUILD_SHA}..."

          ls -la artifact/dist
          # TODO: заменить на реальные шаги деплоя

          # Дополнительно: можно записать build_sha на сервере,
          # чтобы потом проверять, что именно установлено.

Что здесь важно

  1. CI job:

    • после сборки создаёт dist/build-metadata.json с build_sha,
    • упаковывает dist в .tar.gz,
    • загружает архив в artifacts.
  2. CD job:

    • скачивает тот же artifact по имени,
    • распаковывает,
    • читает dist/build-metadata.json,
    • сравнивает actual build_sha с expected build_sha,
    • если не совпало — деплой прерывается.

Это и есть “проверка, что версия действительно та”: мы связываем деплой с конкретным артефактом, который прошёл CI.


Где часто ошибаются новички

1) Путают “проверку” с “просто запуском деплоя”

Если вы деплоите прямо из исходников (например, git pull && npm run build на сервере), то “проверка” тестами в CI теряет смысл: сервер собрал своё, не CI-шное.

Решение: деплой должен использовать artifact, а не свежескачанный код.

2) Доверяют только тегам или версии из package.json

Тег может не соответствовать реальности, версия в package.json может не обновляться, а “последний” коммит на ветке может отличаться от того, что вы думали.

Решение: использовать идентификатор сборки на базе GITHUB_SHA (или вычисленного хеша артефакта).

3) Нет метаданных у артефакта

Даже если вы деплоите artifact, без метаданных вы не докажете соответствие. Проверять “какое-то содержимое” ненадёжно.

Решение: положить рядом с артефактом build-metadata.json и проверять поля.

4) Отсутствие fail-fast логики

Если проверка проходит после распаковки/деплоя или где-то “мягко” (например, || true), инциденты превращаются в расследования.

Решение: при несовпадении версии — немедленный exit 1 в CD job.

5) Забывают о jq

В примере выше используется jq. На ubuntu-latest он обычно доступен, но если у вас свой runtime/образ — добавьте установку.

Например:

code
sudo apt-get update
sudo apt-get install -y jq

Усиление: контроль целостности артефакта хешем

SHA коммита — отличный идентификатор, но можно добавить ещё и контроль целостности самого архива.

Идея:

  • на CI считаем sha256sum от .tar.gz,
  • сохраняем это значение в метаданных,
  • на CD пересчитываем хеш архива и сверяем.

Это особенно полезно при сетевых проблемах, если artifact “переупаковывают”, или при усложнении цепочки.

Пример: добавить хеш в build-metadata.json можно так (в CI):

code
HASH="$(sha256sum "$ARTIFACT_NAME" | awk '{print $1}')"

cat > dist/build-metadata.json <<EOF
{
  "build_sha": "${BUILD_SHA}",
  "build_id": "${BUILD_ID}",
  "artifact_sha256": "${HASH}",
  "built_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
}
EOF

А на CD:

  • вычисляете actual_artifact_sha256 от скачанного архива,
  • сравниваете с dist/build-metadata.json.

Реальный деплой: как заменить “Deploy (example)” на рабочий сценарий

В примере мы имитировали деплой. На практике есть два базовых пути для новичка:

Вариант A: копирование статической сборки по SSH (scp/rsync)

Если вы деплоите статический сайт на сервер с папкой, то CD job может выглядеть так:

code
      - name: Deploy via rsync
        shell: bash
        run: |
          set -euo pipefail

          ARTIFACT_DIR="artifact/dist"

          # Замените на ваши значения
          SSH_HOST="${{ secrets.SSH_HOST }}"
          SSH_USER="${{ secrets.SSH_USER }}"
          SSH_PORT="${{ secrets.SSH_PORT || 22 }}"
          SSH_DEST="${{ secrets.SSH_DEST }}"

          rsync -avz --delete -e "ssh -p ${SSH_PORT}" \
            "${ARTIFACT_DIR}/" \
            "${SSH_USER}@${SSH_HOST}:${SSH_DEST}/"

Вариант B: деплой в Kubernetes с фиксированным образом/артефактом

Если вы упаковываете в контейнер, то вместо “tar.gz” будет Docker image. Принцип тот же: деплой должен ссылаться на тот образ, который был собран и протестирован, а метаданные/labels должны позволять проверить соответствие.

Если вы ещё не дошли до контейнеров — не усложняйте. Начните с artifact.


Выбор артефакта и “где хранить сборку”

GitHub Actions artifacts — удобный способ для связки CI и CD внутри одного workflow. Но важно понимать ограничения:

  • artifacts хранятся ограниченное время (по умолчанию недолго, можно настроить),
  • это не универсальная “база релизов”,
  • в больших системах обычно используют registry (Docker), S3-like хранилище, пакеты и т.п.

Для учебных целей и стартовых команд artifacts хватает: вы сохраняете “что деплоилось” в рамках конкретного прогона.

Если же вы планируете промышленные релизы, добавляйте внешний storage релизов и подписывайте артефакты.


Параллелизация и время выполнения: что можно улучшить

Новичкам часто кажется, что “чем больше шагов — тем медленнее”, но на деле правильная параллелизация уменьшает ожидание.

Например:

  • линтинг и тесты можно делать параллельно,
  • сборку запускать только после успешных линтинга/тестов.

Однако при использовании artifact и проверок лучше сохранять простоту на старте. Сложные матрицы (matrix) и параллели могут скрыть причинно-следственные связи.


Отладка пайплайна: как не терять время

Когда что-то ломается, обычно причина одна из трёх:

  1. Сломались тесты/линтинг — логично, надо чинить код.
  2. Не создаётся artifact или не совпадает имя — типичная ошибка с name: ... и path: ....
  3. CD не находит метаданные — забыли положить build-metadata.json в нужное место или распаковали не туда.

Практический совет: добавляйте временную диагностику в CD:

code
ls -R
find . -maxdepth 4 -type f

Потом удалите, когда всё стабилизируется.


Мини-чеклист: “деплой по накатанной” без сюрпризов

Перед тем как считать пайплайн “готовым”, проверьте:

  • CI запускает тесты и линтинг перед сборкой.
  • CD деплоит не исходники, а артефакт.
  • Артефакт содержит метаданные сборки (build_sha).
  • CD проверяет build_sha до начала деплоя.
  • При несовпадении версии CD падает с ошибкой (exit 1).
  • Артефакт однозначно идентифицирован (например, имя содержит GITHUB_SHA).

Этот набор даёт реальную воспроизводимость. И главное — новичку становится понятно, почему пайплайн доверять можно.


Вывод

GitHub Actions позволяет собрать CI/CD-пайплайн “по накатанной” даже без сложных платформ. Главное — мыслить не как “написать workflow”, а как “связать доказательство”: тесты и линтинг должны относиться к той же сборке, которую вы деплоите.

Самая полезная практика для новичка — сделать артефакт носителем идентичности (например, build_sha) и проверять эту идентичность в CD перед изменением окружения. Тогда “деплой прошёл” означает не “что-то обновилось”, а “обновилось то самое, что собрано и проверено”.

Если хотите дальше разобраться глубже (роль релизов, управление окружениями, правильная стратегия версий, шаблоны пайплайнов и типовые архитектурные решения), можно начать с материала CI-CD от теории до практики — как структурированный путь от концепций к рабочим примерам.


Войдите, чтобы поставить лайк и оставить комментарий.

Автор

$ sudo teach IT

CI-CD от теории до практики

Курс по теме

CI-CD от теории до практики

Вы освоите работу с GitLab Cloud и GitHub Actions, научитесь настраивать раннеры, писать конфигурационные файлы, интегрировать CI/CD с Docker и автоматизировать деплой.

Открыть курс

Продолжите обучение

Все курсы
Python – для начинающих!

Python – для начинающих!

С нуля до профессионального уровня. Подходит для всех. Учитесь каждый день и овладейте самым популярным языком программирования.

Перейти к курсу
Приложения для iPhone и Apple Watch на SwiftUI

Приложения для iPhone и Apple Watch на SwiftUI

Разработка приложений для iPhone и Apple Watch на SwiftUI: навигация, SwiftData, виджеты, часы, выпуск. Нужен Mac с Xcode 27, сами устройства не нужны.

Перейти к курсу
Ботостроение Telegram

Ботостроение Telegram

Лёгкий, быстрый и доступный способ познакомиться с миром ботостроения в Telegram. Видео, конспекты, практика и помощь – всё у нас на курсе.

Перейти к курсу
Приложения для macOS на SwiftUI

Приложения для macOS на SwiftUI

Разработка приложений для Mac на SwiftUI: окна и меню, Liquid Glass, SwiftData, сеть, выпуск. Нужен Mac с macOS 27 и Xcode 27.

Перейти к курсу

Другие статьи

Деплой без сюрпризов: как подготовить Docker-образ, переменные окружения и healthcheck
деплой

Деплой без сюрпризов: как подготовить Docker-образ, переменные окружения и healthcheck

Разберём практический чек-лист подготовки контейнера к продакшену: как собрать воспроизводимый образ, как правильно прокидывать конфиги/секреты через окружение и как настроить healthcheck, чтобы деплой не “успевал” раньше готовности сервиса.

18 сентября 2026 г.
1030
FastAPI для новичков: как организовать структуру проекта, чтобы не писать всё в одном файле
fastapi

FastAPI для новичков: как организовать структуру проекта, чтобы не писать всё в одном файле

Разложим приложение на роуты, сервисы и слой моделей, настроим зависимости и обработчики ошибок. Цель — база для дальнейшего роста без будущего “рефакторинга на боль”.

26 июля 2026 г.
630
Создание Telegram бота в 2026 легко и просто! Полный курсы!
создание

Создание Telegram бота в 2026 легко и просто! Полный курсы!

19 июня 2026 г.
1421
Как выбрать, куда идти в IT: веб, боты, данные — без хаоса
выбрать

Как выбрать, куда идти в IT: веб, боты, данные — без хаоса

Разберём самые понятные направления для новичка (веб, боты, аналитика/данные) и чем они отличаются по шагам обучения. В конце вы получите простой план, как проверить, что вам подходит, и какой стартовый путь выбрать.

5 октября 2026 г.
580
Путь от README до демо: как собрать портфолио разработчика, чтобы его хотели смотреть
путь

Путь от README до демо: как собрать портфолио разработчика, чтобы его хотели смотреть

Разберём структуру репозитория, как упаковать проект в понятную историю (проблема → решение → запуск → метрики качества) и какие артефакты повышают доверие: скринкасты, архитектурная схема, чек-лист продакшн-готовности.

17 сентября 2026 г.
1070
Как понять, какой язык программирования учить первым: простой тест и выбор
понять

Как понять, какой язык программирования учить первым: простой тест и выбор

Помогу новичку выбрать первый язык без стресса: объясню варианты по целям (веб, боты, анализ данных), что учить в первую очередь и как не потратить месяцы впустую. В конце — краткий план старта на ближайшие недели.

2 октября 2026 г.
630

Комментарии

Станьте первым в обсуждении

Поделитесь мнением о статье или задайте вопрос автору

Содержание

Как мыслить CI/CD: от коммитов к артефактамПодготовка: пример проекта и что будет деплоитьсяПример структурыПайплайн на GitHub Actions: базовая схемаОбщая идея workflowВажный принцип: версия сборки ≠ версия пакетаРеализация: workflow с проверкой артефактаПример workflowЧто здесь важноГде часто ошибаются новички1) Путают “проверку” с “просто запуском деплоя”2) Доверяют только тегам или версии из package.json3) Нет метаданных у артефакта4) Отсутствие fail-fast логики5) Забывают о jqУсиление: контроль целостности артефакта хешемРеальный деплой: как заменить “Deploy (example)” на рабочий сценарийВариант A: копирование статической сборки по SSH (scp/rsync)Вариант B: деплой в Kubernetes с фиксированным образом/артефактомВыбор артефакта и “где хранить сборку”Параллелизация и время выполнения: что можно улучшитьОтладка пайплайна: как не терять времяМини-чеклист: “деплой по накатанной” без сюрпризовВывод