- PVSM.RU - https://www.pvsm.ru -
В больших проектах, состоящих из десятков и сотен взаимодействующих сервисов, всё чаще становится обязательным подход к документации как к коду — docs as code [1].
Я покажу, как можно применять эту философию в реалиях classified-сервиса, а точнее, начну с первого этапа её внедрения: автоматизации обновления данных в документации.
Принцип «документация как код» подразумевает использование при написании документации того же инструментария, что и при создании кода: языков разметки текста, систем контроля версий, code review и авто-тестов. Главная цель: создать условия для совместной работы всей команды над итоговым результатом — полноценной базой знаний и инструкций по использованию отдельных сервисов продукта. Далее я расскажу о конкретных инструментах, выбранных нами для решения этой задачи.
В качестве языка разметки текста мы решили использовать наиболее универсальный — reStructuredText [2]. Помимо большого количества директив, которые предоставляют все основные функции для структурирования текста, этот язык поддерживает ключевые конечные форматы, в том числе необходимый для нашего проекта HTML.
Файлы конвертируются из .rst в .html посредством генератора документации Sphinx [3]. Он позволяет создавать статические сайты, для которых можно делать собственные или использовать уже готовые темы оформления [4]. В нашем проекте используются две готовые темы — stanford-theme [5] и bootstrap-theme [6]. Вторая содержит подтемы, позволяющие задавать разные цветовые схемы для ключевых элементов интерфейса.
Для удобного и быстрого доступа к актуальной версии документации мы используем статический сайт, хостом для которого служит виртуальная машина, доступная из локальной сети команды разработки.
Исходные файлы проекта хранятся в Bitbucket-репозитории, причём сайт генерируется только из файлов, содержащихся в ветке master. Обновить в ней данные можно только через pull-request, что позволяет проверять все новые разделы документации перед тем, как они будут опубликованы в общем доступе.
Поскольку между завершением нового раздела документации и его отправкой на сайт нужно проверять его содержание, ключевым во всей цепочке становится сам процесс сборки сайта и обновления данных на хосте. Эта процедура должна повторяться каждый раз после того, как pull-request с обновлением сливается с главной веткой проекта.
Реализовать подобную логику позволяет Jenkins [7] — система непрерывной интеграции разработки, в нашем случае — документации. Подробнее о настройке я расскажу в разделах:
Для сборки и обновления документации на сайте необходимо зарегистрировать в качестве агента Jenkins [7] заранее подготовленную для этого машину.
Согласно требованиям Jenkins [11], на всех компонентах, входящих в систему, включая мастер-машину и все зарегистрированные агентские узлы, должна быть установлена JDK или JRE. В нашем случае будет использоваться JDK 8 [12], для установки которой достаточно выполнить команду:
sudo apt-get -y install java-1.8.0-openjdk git
Мастер-машина будет подключаться к агенту для выполнения на нём назначенных задач. Для этого на агенте необходимо создать пользователя, под которым будут выполняться все операции, и в домашней папке которого будут храниться все генерируемые Jenkins [7]-файлы. В Linux-системах достаточно выполнить команду:
sudo adduser jenkins --shell /bin/bash
su jenkins
Для установки соединения между мастер-машиной и агентом необходимо настроить SSH и добавить необходимые ключи авторизации. Сгенерируем ключи на агенте, после чего для пользователя jenkins добавим публичный ключ в файл authorized_keys
.
Собирать сайт с документацией будем в Docker-контейнере, использующем готовый образ python:3.7 [13]. Для установки Docker на агенте следуйте инструкциям официальной документации [14]. Чтобы завершить процесс установки, необходимо переподключиться к агенту. Проверим корректность установки, выполнив команду, которая загружает тестовый образ:
docker run hello-world
Чтобы не приходилось запускать команды Docker от имени суперпользователя (sudo), достаточно добавить в созданную на этапе установки группу docker пользователя, от имени которого будут выполняться команды.
sudo usermod -aG docker $USER
Поскольку подключение к агенту требует авторизации, в настройках Jenkins необходимо добавить соответствующие учётные данные. Подробная инструкция о том, как это делать на Windows-машинах, представлена в официальной документации Jenkins [15].
ВАЖНО: Идентификатор, который задаётся в разделе Настроить Jenkins -> Управление средами сборки -> Имя узла -> Настроить в параметре Метки, в дальнейшем используется в Jenkinsfile [16] для указания агента, на котором будут выполнены все операции.
В корне репозитория проекта хранится Jenkinsfile [16], который содержит инструкции по:
Инструкции задаются с помощью специальных директив, применение которых мы рассмотрим далее на примере используемого в проекте файла.
В начале Jenkinsfile [16] укажем метку агента в Jenkins [7], на котором будут выполняться все операции. Для этого необходимо использовать директиву agent [17]:
agent {
label 'название-метки'
}
Для выполнения команды сборки сайта sphinx-build необходимо задать переменные среды, в которых будут храниться актуальные пути к данным. Также для обновления информации на хосте необходимо заранее указать пути, где хранятся данные сайта с документацией. Присвоить эти значения переменным позволяет директива environment [18]:
environment {
SPHINX_DIR = '.' //папка, в которой установлен Sphinx
BUILD_DIR = 'project_home_built' //папка с собранным сайтом
SOURCE_DIR = 'project_home_source' //папка с исходными .rst и .md файлами
DEPLOY_HOST = 'username@127.1.1.0:/var/www/html/' //пользоатель@IP_адрес_хоста:папка_с_сайтом
}
Основные инструкции, которые будут выполняться в Jenkinsfile [16], содержатся внутри директивы stages [19], которая состоит из разных шагов, описываемых директивами stage [20]. Простой пример трёхэтапного CI-pipeline:
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building..'
}
}
stage('Test') {
steps {
echo 'Testing..'
}
}
stage('Deploy') {
steps {
echo 'Deploying....'
}
}
}
}
Сначала запустим Docker-контейнер с готовым образом python:3.7 [13]. Для этого воспользуемся командой docker run [21] с флагами --rm [22] и -i [23]. Затем последовательно сделаем следующее:
stage('Install Dependencies') {
steps {
sh '''
docker run --rm -i python:3.7
python3 -m pip install --user --upgrade pip
python3 -m pip install --user virtualenv
python3 -m virtualenv pyenv
. pyenv/bin/activate
pip install -r ${SPHINX_DIR}/requirements.txt
'''
}
}
Теперь соберём сайт. Для этого необходимо выполнить команду sphinx-build [25] со следующими флагами:
-q
: записывать в лог только предупреждения и ошибки;
-w
: записывать лог в указанный после флага файл;
-b
: имя сборщика сайта;
-d
: указать директорию для хранения кешированных файлов — doctree pickles.
Перед запуском сборки, с помощью команды rm -rf
удалим предыдущую сборку сайта и логи. В случае ошибки на одном из этапов в консоли Jenkins [7] появится лог выполнения sphinx-build [25].
stage('Build') {
steps {
// clear out old files
sh 'rm -rf ${BUILD_DIR}'
sh 'rm -f ${SPHINX_DIR}/sphinx-build.log'
sh '''
${WORKSPACE}/pyenv/bin/sphinx-build -q -w ${SPHINX_DIR}/sphinx-build.log
-b html
-d ${BUILD_DIR}/doctrees ${SOURCE_DIR} ${BUILD_DIR}
'''
}
post {
failure {
sh 'cat ${SPHINX_DIR}sphinx-build.log'
}
}
}
И в завершение обновим информацию на хосте, обслуживающем доступный в локальной среде сайт с документацией продукта. В текущей реализации хостом служит та же виртуальная машина, которая зарегистрирована в качестве Jenkins-агента для выполнения задач по сборке и обновлению документации.
В качестве инструмента синхронизации используем утилиту rsync [26]. Для её корректной работы необходимо настроить подключение по SSH между Docker-контейнером, в котором собирался сайт с документацией, и хостом.
Чтобы можно было с помощью Jenkinsfile [16] настраивать подключение по SSH, в Jenkins [7] нужно установить следующие плагины [27]:
sshagent
для предоставления учётных данных вида имя_пользователя/ключ.После установки плагинов необходимо указать актуальные учётные данные для подключения к хосту, заполнив форму в разделе Credentials:
sshagent
для указания конкретных учётных данных (docs-deployer
);/var/html
хоста);Ниже представлен код скрипта, который подключается по SSH и обновляет информацию на хосте, используя заданные на этапе подготовки среды системные переменные с путями к необходимым данным. Результат выполнения команды rsync [26] записывается в лог, который будет выводиться в консоли Jenkins [7] в случае ошибок синхронизации.
stage('Deploy') {
steps {
sshagent(credentials: ['docs-deployer']) {
sh '''
#!/bin/bash
rm -f ${SPHINX_DIR}/rsync.log
RSYNCOPT=(-aze 'ssh -o StrictHostKeyChecking=no')
rsync "${RSYNCOPT[@]}"
--delete
${BUILD_DIR_CI} ${DEPLOY_HOST}/
'''
}
}
post {
failure {
sh 'cat ${SPHINX_DIR}/rsync.log'
}
}
}
Существует много способов организовать взаимодействие Jenkins [7] и Bitbucket [30], но в нашем проекте мы решили использовать плагин Parameterized Builds for Jenkins [31]. В официальной документации есть подробная инструкция по установке [32] плагина, а также приведены настройки, которые должны быть заданы для обеих систем. Для работы с этим плагином необходимо создать пользователя Jenkins [7] и сгенерировать для него специальный токен, который позволит этому пользователю авторизоваться в системе.
Для создания нового пользователя в Jenkins [7] необходимо перейти в раздел Настройки Jenkins -> Управление пользователями -> Создать пользователя, и в форме заполнить все необходимые учётные данные.
Механизм аутентификации, позволяющий сторонним скриптам или приложениям использовать API Jenkins без фактической передачи пароля пользователя, представляет собой специальный API-токен, который можно сгенерировать для каждого пользователя Jenkins [7]. Для этого:
Теперь в настройках сервера Bitbucket [30] можно указывать пользователя по умолчанию для подключения к Jenkins [7].
Если раньше процесс состоял из нескольких шагов:
то теперь достаточно нажать одну кнопку Merge в Bitbucket. Если после проверки не требуется вносить изменения в исходные файлы, то актуальная версия документации обновляется сразу же после подтверждения корректности данных.
Это значительно облегчает задачу технического писателя, избавляя его от большого количества ручных действий, а руководители проектов получают удобный инструмент для отслеживания дополнений документации и обратной связи.
Автоматизация этого процесса — первый шаг в построении инфраструктуры по управлению документацией. В дальнейшем мы планируем добавить автоматические тесты, которые будут проверять корректность внешних ссылок, используемых в документации, а также хотим создать интерактивные объекты интерфейса, встраиваемые в готовые темы для Sphinx [3].
Спасибо дочитавшим за внимание, скоро мы продолжим делиться подробностями создания документации в нашем проекте!
Автор: Алексей Солнцев
Источник [33]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/323950
Ссылки в тексте:
[1] docs as code: https://www.writethedocs.org/guide/docs-as-code/
[2] reStructuredText: http://docutils.sourceforge.net/rst.html
[3] Sphinx: https://www.sphinx-doc.org/en/master/index.html
[4] темы оформления: https://sphinx-themes.org/
[5] stanford-theme: https://pypi.org/project/stanford-theme/
[6] bootstrap-theme: https://pypi.org/project/sphinx-bootstrap-theme/
[7] Jenkins: https://jenkins.io/
[8] Добавление нового узла в Jenkins: #dobavlenie-novogo-uzla-v-jenkins
[9] Описание Jenkinsfile: #opisanie-jenkinsfile
[10] Интеграция Jenkins и Bitbucket: #integraciya-jenkins-i-bitbucket
[11] требованиям Jenkins: https://jenkins.io/doc/administration/requirements/java/
[12] JDK 8: https://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html
[13] python:3.7: https://hub.docker.com/_/python
[14] официальной документации: https://docs.docker.com/install/linux/docker-ce/ubuntu/
[15] официальной документации Jenkins: https://wiki.jenkins.io/display/JENKINS/Step+by+step+guide+to+set+up+master+and+agent+machines+on+Windows
[16] Jenkinsfile: https://jenkins.io/doc/book/pipeline/jenkinsfile/
[17] директиву agent: https://jenkins.io/doc/book/pipeline/syntax/#agent
[18] директива environment: https://jenkins.io/doc/book/pipeline/syntax/#environment
[19] директивы stages: https://jenkins.io/doc/book/pipeline/syntax/#stages
[20] директивами stage: https://jenkins.io/doc/book/pipeline/syntax/#stage
[21] docker run: https://docs.docker.com/engine/reference/run/
[22] --rm: https://docs.docker.com/engine/reference/run/#clean-up---rm
[23] -i: https://docs.docker.com/engine/reference/run/#foreground
[24] python virtualenv: https://virtualenv.pypa.io/en/latest/
[25] sphinx-build: https://www.sphinx-doc.org/en/master/man/sphinx-build.html
[26] rsync: https://rsync.samba.org/
[27] установить следующие плагины: https://jenkins.io/doc/book/managing/plugins/
[28] SSH Agent Plugin: https://plugins.jenkins.io/ssh-agent
[29] SSH Credentials Plugin: https://wiki.jenkins.io/display/JENKINS/SSH+Agent+Plugin
[30] Bitbucket: https://bitbucket.org/product/
[31] Parameterized Builds for Jenkins: https://marketplace.atlassian.com/apps/1213179/parameterized-builds-for-jenkins?hosting=server&tab=overview
[32] инструкция по установке: https://github.com/KyleLNicholls/parameterized-builds
[33] Источник: https://habr.com/ru/post/459640/?utm_source=habrahabr&utm_medium=rss&utm_campaign=459640
Нажмите здесь для печати.