понедельник, 3 мая 2021 г.

Что Ethernet-инженеру нужно знать о CI/CD


Ооо, да...

Рассмотрим реальный базовый CI/CD на примере Github actions. Тестируем код, деплоим на тестовую машину, запускаем код на реальных железках и деплоим в прод.

Когда-то давно уже писал подобные статейки(раздватри и самая популярная статья в блоге за все время...), сегодня же поговорим о нашумевшем, я бы даже сказал, "хайповом" сиайсиди.

Надо заявить, что я не девопс и не релиз инженер. Поигрывал я как-то с "дженкинс" и "гитлаб", но это было так давно, что почти неправда. А как-то меня даже приглашали работать девопсом... Так что в этой заметке не мне вас учить "как писать пайплайны". Я в первую очередь сетевой инженер. Девопсов просьба строго не судить, а вносить конструктивные предложения. Погнали!

Что же вообще такое CI/CD и зачем оно нужно?

Я скажу так, я никогда не любил терминологические войны, поэтому расскажу как я это понимаю. Из моего опыта под CI/CD обычно понимают сам подход к разработке вместе со всем комплексом мер по доставке этого кода в продакшн. То есть в CI/CD мире вам достаточно сделать изменение в коде для того чтобы запустить отправку этого кода в прод. Если добавить терминов, то вы "мержите" ваше изменение с определенной веткой кода, что запускает "пайплайн". Последнее это некая сущность способная потестировать и правильно задеплоить ваш код туда где он будет исполняться. Понятное дело, что в этом случае все это должно происходить безопасно для сервиса.

Термин CI/CD неразрывно связан с GIT (или любой другой системой управления версиями). Некие события в этой системе управления кодом являются тригерами, которые запускают некие процессы (обычно называются "пайплайнами"), которые и доводят код до прода через определенные стадии. По опыту могу сказать, что зачастую это довольно сложная логика, которая может занимать дни. Поэтому тут не все так просто... Каждый юзкейс разный.

Реализовать что-то подобное можно на разных платформах, в том числе и на всем известном Github. На сколько я понимаю, Github это не самая лучшая и удобная реализация CI/CD. Однако, учитывая широкое распространение, Github Actions как минимум заслуживает рассмотрения. 

Итак, ближе к сути. 

В прошлом посте я описывал свой уютный скриптик для "раскатки" конфигурации на VyOS устройства через API. Держу я свой код на Github, поэтому именно на нем я и покажу как можно реализовать что-то более или менее похожее на CI/CD. По крайней мере мои "домашние" запросы получившееся вполне устраивает. 

Что я буду реализовывать?

Мой юзкейс будет простым донельзя. 

После push'a в ветку main или при создании pull request'a в тот же main я буду:
  • Тестировать код
    • Запуск на разных версиях
    • Запуск flake8 (это проверка на соответствие pep8, короче пробельчики, длинна строк и все такое)
    • Запуск тестов
  • Деплоить на тестовую машину
    • Запуск реального кода на реальных тестовых VyOS железках
  • Деплоить на прод машину
Понятное дело, что это не самый развитой юзкейс, но смысл всего происходящего ухватить можно.

Единственное, что нам нужно сделать для того чтобы запускать Actions (в терминах Github это и есть CI/CD) это создать YAML файл в определенном месте и место это

.github/workflows

Actions довольно развитой инструмент с хорошей документацией и большим набором community дополнений. Я верю, что мой читатель сможет разобраться в теме. Я же расскажу про свою реализацию.

В моем случае я использую один workflow названный main.yaml. Разберем его построчно.

Основной блок

Здесь указываем само имя и когда воркфлоу запускать. В моем случае это PUSH в main и PULL_REQUEST. 

name: MAIN
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:

Последнее, к слову, на самом деле очень удобно. Перед тем как изменения смержить с мастер веткой видно все ли с ними в порядке. Например вот тут на вкладке checks видно, что все тесты завершились успешно. 



Это является еще одной галочкой перед мержем кода в прод. Понятное дело, что в моем случае это вообще не надо. Я владелец кода, я же создал pull request, я же его и смержил. Но, если вас уже двое, то это имеет смысл. 

Ах да, указав workflow_dispatch мы разрешаем запуск воркфлоу руками.

Build-and-test

Далее у меня идет секция, где я тестирую код.

build-and-test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
python-version: [3.5, 3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
flake8 . --max-line-length=130 --statistics --exclude test*
- name: Test with pytest
run: |
pytest --doctest-modules --junitxml=test-report/test-results-${{ matrix.python-version }}.xml

Здесь можно видеть несколько шагов (steps) которые в моем случае запускаются параллельно на нескольких версиях python на ubuntu. Это можно видеть в секции strategy.

Шаги:
  • Забираем код
  • Устанавливаем python
  • Устанавливаем зависимости (pytest, flake8, все из requirements)
  • Проверяем код Flake8 (соотвествие рекомендациям PEP8)
  • Запускаем тесты из директории с тестами (строго не судить)

Долгое время я жил с таким простым набором и горя не знал. Вот несколько примеров запуска воркфлоу
- Flake8 запоролся (пробел после строки)

- Тест не прошел (ошибка в коде и тест это заметил)


В общем и целом мы видим как одна и та же последовательностей операций запускается на разных версиях Python. 


По каждому шагу видна дополнительная информация, если вдруг надо углубится.


Deploy-to-gamma

После прохождения тестов описанных выше я загружаю код на хост в лабе, который подключен к 4 VyOS инстансам. Моя цель -  запустить скрипт и убедиться, что он все еще может работать. На этом шаге можно навернуть дополнительную логику, но я хочу остаться в рамках базовых проверок.

deploy-to-gamma:
needs: build-and-test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: SCP
uses: appleboy/scp-action@master
with:
host: ${{ secrets.TEST_HOST }}
username: ${{ secrets.USERNAME }}
port: ${{ secrets.TEST_PORT }}
password: ${{ secrets.PASSWORD }}
source: "."
target: "vyos_cfg_v2"
- name: pip update
uses: garygrossgarten/github-action-ssh@release
with:
command: pip3 install -r vyos_cfg_v2/requirements.txt
host: ${{ secrets.TEST_HOST }}
username: ${{ secrets.USERNAME }}
port: ${{ secrets.TEST_PORT }}
password: ${{ secrets.PASSWORD }}
- name: Is vyos_cfg_v2 runnable
uses: garygrossgarten/github-action-ssh@release
with:
command: |
cd vyos_cfg_v2
python3 vyos_cfg_v2.py -i inventory.yaml -d deployment.yaml --brave --skip-save
host: ${{ secrets.TEST_HOST }}
username: ${{ secrets.USERNAME }}
port: ${{ secrets.TEST_PORT }}
password: ${{ secrets.PASSWORD }}
Для того чтобы копировать код на машины и запускать там команды, нам нужны явки и пароли, которые можно добавить в виде пременных в настройках репозитория. 


После этого мы можем обращаться к ним в workflow.

В job'e ниже мы видим новую директиву - needs. Она позволяет строить базовые зависимости в воркфлоу. Если тесты прошли успешно, можно пробовать деплоить на тестовую машину.

Итак, что у нас по шагам.
  • Копируем код на тестовую машину по SCP
  • Запускаем обновление зависимостей pip
  • Запускаем скрипт на тестовых железках
В моем случае скрипт просто должен запустится для завершения этой части воркфлоу. deploy-to-gamma будет считаться провальным, если скрипт "крашнется" по тем или иным причинам. Это не очень круто, хорошо бы иметь более специфичные проверки. Однако запустить скрипт на реальных тестовых железках уже большое дело.

Как видно на примере успешного исполнения, скрипт выполнился. 


Вот, пример того, как скрипт не смог. Соотвественно эта часть воркфлоу не считается завершенной успешно.


Как я говорил, needs позволяет устанавливать простые зависимости между частями воркфлоу. Это видно и в интерфейсе.



Deploy-to-prod

Следующая часть носит гордое название, но на деле это упрощенная копия предыдущего шага. В моем случае я просто копирую код на машину с которой управляю своими железками.

Со всем синтаксисом мы уже знакомы, изменились только переменные. Это, например, PROD_HOST вместо TEST_HOST.

deploy-to-prod:
needs: deploy-to-gamma
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: SCP
uses: appleboy/scp-action@master
with:
host: ${{ secrets.PROD_HOST }}
username: ${{ secrets.USERNAME }}
port: ${{ secrets.PROD_PORT }}
password: ${{ secrets.PASSWORD }}
source: "."
target: "vyos_cfg_v2"
- name: pip update
uses: garygrossgarten/github-action-ssh@release
with:
command: pip3 install -r vyos_cfg_v2/requirements.txt
host: ${{ secrets.PROD_HOST }}
username: ${{ secrets.USERNAME }}
port: ${{ secrets.PROD_PORT }}
password: ${{ secrets.PASSWORD }}

На этом шаге я не запускаю код, а только обновляю зависимости через pip.

Весь процесс

Итак, что мы имеем. Допустим мы сделали PUSH наших изменений в main ветку. Автоматически начинает работать воркфлоу, которая состоит из трех этапов. Тестирование кода, деплой в тестовую среду и запуск там и деплой в прод. В случае провала мы получим сообщение в почту.

Сам интерфейс.


В нашем случае, билд на разных версиях python прошел успешно.


Код копируется на тестовую машину и запускается на четырех VyOS устройствах.


В случае успеха, код копируется на реальную боевую машину.


После чего мои cron job'ы уже будут использовать новую версия скрипта.

Итоги

  • Такой вот простой воркфлоу позволяет автоматизировать доставку моих изменений до реальной машины с которой я управляю своей инфраструктурой. 
  • Не надо идти на машину, делать git pull и все прочее.
  • Я полагаюсь на pytest и запуск скрипта в тестовой среде на реальных железках, что должно обезопасить меня от каких-то крупных косяков. В моем случае этого достаточно. Для "боевого" сценария нужно добавлять больше проверок.
  • Вопрос безопасности тут не обсуждался. Как минимум нужно использовать авторизацию по ключам.
  • Не факт, что Github это лучший выбор. Думаю, я бы перевел все это в on-premises Gitlab.
Используйте CI/CD с умом и будьте счастливы!

Комментариев нет:

Отправить комментарий