25 мая 2013 г. Django Nginx Jenkins CI Debian

Debian. Continuous Integration сервер Jenkins для непрерывного тестирования Django-проектов

Сегодня я расскажу как реализовать непрерывное тестирование Django-проекта с помощью Jenkins CI. Мы также будем собирать и выводить разного рода отчеты по тестам, для этого мы установим и настроим дополнительные плагины. Следующие статьи будут о том, как развернуть Jenkins-ноды на FreeBSD, как запустить BDD-тесты с поддержкой Selenium WebDriver через Lettuce и splinter.

В качестве поставщика тестируемого кода будем использовать git, в качестве транспорта для него будем использовать ssh (у меня для этого используется gitolite), адрес сервера будет git.example.org. Адрес сервиса с запущенным Jenkins будет http://jenkins.example.org/.

Ранее, я уже упоминал о Jenkins, там же я говорил о Attlassian Bamboo и Hudson, но для своих проектов я выбрал Jenkins за его простоту, функциональность, количество полезных плагинов и истории-успеха среди Django-проектов. Что касается Hudson, то Jenkins это его форк, о причинах разделения проектов вы можете почитать в статье на хабре.

Кстати, любителям SaaS можно не устанавливать Jenkins, а воспользоваться ShiningPanda.

Терминология

В терминологии Jenkins слово Job и Project это одно и тоже, мы же просто будем называть их "задачами".

Термин Build (далее билд) - это результат выполненой задачи, может находится в трех оконченных состояниях:

  • SUCCESS (успешный билд, за всю работы задачи небыло ошибок);
  • FAILED (произошла какая-то ошибка);
  • ABORTED (билд был прерван по какой-либо причине, в осноновном это - ручное прерывание).

Термином View (а конкретно "List View") обозначается некая страница, на которой перечислены задачи, настраивается она либо выбором через чекбоксы, либо по совпадению по заданному паттерну с именами задач.

В процессе чтения статьи вы встретите переменные окружения:

  • $JENKINS_HOME - это путь до домашнего каталога Jenkins, скорее всего это "/var/lib/jenkins". Там будут храниться все конфиги Jenkins, задачи, билды и т.д., вообщем всё что относится к Jenkins.
  • $WORKSPACE - путь до каталога, в котором выполняется задача;

Установка Jenkins на Debian

Добавляем ключ и репозиторий:

wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'

Обновляемся и устанавливаем:

sudo apt-get update
sudo apt-get install openjdk-8-jre jenkins

Инструкции взяты отсюда.

Настройка Jenkins

Открываем на редактирование /etc/default/jenkins и добавляем следующие директивы:

# Указываем нужный порт,
# на который далее мы будем проксировать через Nginx
PORT=8090

# Устанавливаем нужную нам кодировку,
# чтобы текст, который попал в stdout (например из тестов) выводился корректно.
# А также устанавливаем нужную таймзону, у меня это UTC
JAVA_ARGS="-Dfile.encoding=UTF8 -Duser.timezone=UTC"

Теперь запустим Jenkins:

sudo service jenkins start

После запуска Jenkins вы можете увидеть текущую кодировку и таймзону в разделе "Manage Jenkins" > "System Information" (прямой адрес http://jenkins.example.com:8090/systemInfo ).

Теперь произведем базовые настройки Jenkins, перейдите в "Manage Jenkins" > "Configure System":

  • В секции Jenkins Location укажем следующее:
    • В поле Jenkins URL укажите адрес https://jenkins.example.org/;
    • В поле System Admin E-mail Address укажите почту, от которой будут приходить письма от Jenkins, например "jenkins@example.org".

  • Далее, нам надо настроить отправку уведомлений по почте, переходим в секцию E-mail Notification и настраиваем SMTP:

    • В поле SMTP server указываем "localhost", либо другой обслуживающий ваш сервер почтовый сервер. Если используете локальный sendmail, то установите его.

  • В секции Git plugin:

    • В поле Global Config user.name Value укажите "Jenkins";
    • В поле Global Config user.email Value укажите "jenkins@example.org".

Настроим проксирование через Nginx

Вот пример конфига для Nginx, работать будем через самописный ssl-сертификат и добавим base-auth:

server {
    listen 443 ssl;
    server_name jenkins.example.org;

    ssl_protocols SSLv3 TLSv1;
    ssl_certificate /etc/nginx/certs/jenkins.pem;
    ssl_certificate_key /etc/nginx/certs/jenkins.key;

    location / {
        auth_basic "Password, please!";
        auth_basic_user_file /etc/nginx/auth-file;
        proxy_read_timeout 300;
        proxy_send_timeout 300;
        proxy_pass http://localhost:8090;
    }
}
server {
    listen 80;
    server_name jenkins.example.org;
    return 301 https://jenkins.example.org$request_uri;
}

Сгенерируем пару логин/пароль для "base-auth" авторизации:

htpasswd -cb /etc/nginx/auth-file jenkins MY_SECRET_PASSWORD

Сгенерируем самописный ssl-сертификат для шифрования трафика:

mkdir /etc/nginx/certs
cd /etc/nginx/certs
openssl req -new -x509 -nodes -newkey rsa:1024 -days 3650 -keyout jenkins.key -out jenkins.pem \
-subj "/C=RU/ST=/L=/O=/OU=/CN=jenkins.example.org/emailAddress=jenkins@example.org"

Для применения настроек перезагрузим Nginx:

nginx -s reload

Не забудем скрыть порт 8090 за фаерволлом:

iptables -t filter -A INPUT -i lo -p tcp --dport 8090 -j ACCEPT
iptables -t filter -A INPUT -i eth0 -p tcp --dport 8090 -j DROP

Где "eth0" - внешний сетевой интерфейс.

Теперь сохраним наши правила в "/etc/iptables.rules":
iptables-save > /etc/iptables.rules
И добавим в автозагрузку:
echo "pre-up iptables-restore < /etc/iptables.rules" >> /etc/network/interfaces

Если быть точнее, то надо в секцию вашего интерфейса добавить pre-up, но так как чаще всего именно в конце файла определён нужный интерфейс, то рекомендация выше будет верна. Развернутый пример:
auto eth0
iface eth0 inet static
        hwaddress aa:bb:cc:dd:ee:ff
        address   203.0.113.42
        netmask   255.255.240.0
        gateway   203.0.113.1
        pre-up iptables-restore < /etc/iptables.rules

Установка плагинов

Переходим в "Manage Jenkins" > "Manage Plugins" > "Available", выбираем:

  • GIT plugin, с ним также установится плагин Git Client Plugin - так как мы пользуемся git, то очевидно что надо установить плагин для работы с этой SCM;
Если у вас возникли проблемы с GIT plugin, и его версия 1.3.0, а версия GIT client plugin 1.0.4, то прочитайте комментарии к багу JENKINS-17204, там есть мой комментарий, который вам непременно поможет. А если вкратце, то в новой версии плагина есть баг, и надо просто откатиться на версию назад.
  • AnsiColor Plugin (форк и более свежий оригинал на GitHub) - с помощью него можно лицезреть цветные логи, которые генерирует ваша программа (например в harvest есть verbose-режим с цветный выводом и т.п.);
В настройках задачи установите чекбокс на Color ANSI Console Output и выберите нужный ANSI color map, у меня это "xterm".
  • Timestamper - будет выводить текущее время на каждую строчку вывода лога из консоли;
В настройках задачи установите чекбокс на Add timestamps to the Console Output.
  • xUnit Plugin - если ваши тесты умеют генерировать отчеты в формате xUnit (а Lettuce и django-jenkins это умеют делать), то вы сможете выводить информацию о результатах тестирования в удобном для человека виде (графики и таблицы), например вот так:

Вывод графика выполнения тестов

  • Build-timeout Plugin - будет прерывать зависшие задачи в Jenkins;
  • Cron Column Plugin - выводит информацию о заданных периодах выполнения задачи при выводе списка ваших задач.

Опционально можно дополнить следующими плагинами:

  • Cobertura Plugin - для вывода отчета о покрытии кода тестами (code coverage);
  • Violations - для вывода отчетов по результатам работы pylint, pyflakes и pep8.

Violations

Настройка git-плагина

Входим на сервер, где вы установили Jenkins и выполняем следующее:

sudo su - jenkins
mkdir ~/.ssh && cd ~/.ssh
emacs config

Помещаем в файл config следующие строки:

Host git.example.org
    HostName       git.example.org
    User           git
    IdentityFile   ~/.ssh/git_example_org
    IdentitiesOnly yes

Теперь создадим ключи для авторизации:

ssh-keygen -t rsa

Добавляем в gitolite (либо в GitHub, Assembla и т.д., смотря чем вы пользуетесь) созданный публичный ключ ~/.ssh/git_example_org.pub.

Тут же на сервере, не помешает указать пользователя для git:

git config --global user.email "jenkins@example.org"
git config --global user.name "Jenkins"

Проверяем работоспособность ssh-ключей и настроек:

git clone git@git.example.org:repo-name.git /tmp/test

Устанавливаем и настраиваем django-jenkins

Это приложение позволяет упростить процесс интеграции с Jenkins CI, нам оно поможет сгенерировать нужные для нас отчеты. Создайте отдельный "settings" в проекте для него, например project/settings/jenkins.py:

import settings

# Добавим это приложение в INSTALLED_APPS
INSTALLED_APPS = settings.INSTALLED_APPS + (
    'django_jenkins',
)

# Укажем нужные нам ранеры
JENKINS_TASKS = (
    # 'django_jenkins.tasks.with_coverage',
    # 'django_jenkins.tasks.django_tests',
    'django_jenkins.tasks.dir_tests',
    'django_jenkins.tasks.run_pep8',
    'django_jenkins.tasks.run_pyflakes',
    'django_jenkins.tasks.run_pylint',
    # 'django_jenkins.tasks.run_jslint',
    # 'django_jenkins.tasks.run_csslint',
    # 'django_jenkins.tasks.run_sloccount',
    # 'django_jenkins.tasks.lettuce_tests',
)

# И какие приложения нужно тестировать
PROJECT_APPS = (
    'app1',
    'app2',
)

Также, при вызове команды manage.py jenkins можно передать дополнительные опции для указанных в JENKINS_TASKS раннеров, для этого смотрите manage.py jenkins --help.

Теперь установим в проект django-jenkins, а также указынные нами зависимости:

echo "
django-jenkins
pep8
pyflakes
pylint
" >> requirements/tests.txt
pip install --upgrade -r requirements/tests.txt

Оригинальный репозиторий проекта находится на GitHub, установить можно с PyPI. Также рекомендую к прочтению туториал.

Добавление и настройка задачи (Job/Project)

Для добавления задачи необходимо нажать на "New Job", выбирать "Build a free-style software project".

В секции "Source Code Management" выбрать чекбокс на "Git Repositories". В "Repository URL" вставляем git@git.example.org:repo-name.git, а в "Branches to build" указываем нужную ветку, например "master".

Теперь настроим "Poll SCM" > "Schedule" (будем каждые 2 минуты проверять изменения в репозитории, если появились изменения, то запускается новый билд):

*/2 * * * *

Добавим секцию для запуска тестов "Build" > "Add build step" > "Execute shell":

# Создаем каталог виртуального окружения
virtualenv --no-site-packages --distribute venv
# Сделаем symlink на файл настроек для django_jenkins
ln -fs $WORKSPACE/project/settings/jenkins.py $WORKSPACE/project/local_settings.py
# Устанавливаем зависимости для проекта и тестов
venv/bin/pip install --upgrade -r requirements/base.txt
venv/bin/pip install --upgrade -r requirements/tests.txt
# Запускаем тесты с использованием django_jenkins
venv/bin/python ./manage.py jenkins --verbosity=2 --output-dir=reports

Я обычно это всё выделяю в sh-скрипт и кладу в репозиторий, после чего просто указываю его для вызова.

Теперь вы можете запустить задачу вручную, нажав "Build Now". Либо добавить коммит в репозиторий и через 2 минуты самостоятельно запустится задача.

После запуска тестов у вас должен появится каталог $WORKSPACE/reports, где будут хранится разного рода отчеты (xUnit, pep8, pylint и т.д.).

Бекап Jenkins

Я честно пробовал пользоваться плагином для бекапа thinBackup, но у него есть огромная проблема - он останавливает Jenkins для того чтобы сделать бекап.

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

cd /var/lib/jenkins/jobs
for JOB in *; do
    BACKUP_JOB_DIR="/var/lib/jenkins/Backups/configs/$JOB"
    mkdir -p $BACKUP_JOB_DIR
    cp "$JOB/config.xml" "$BACKUP_JOB_DIR/config.xml";
    # git commit =am "Autocommit (`hostname`): `date`"
done

Просто создаете еще одну задачу, которая будет переодически бекапить конфиги.

Напоследок

Под строкой поиска находится ссылка ENABLE AUTO REFRESH, нажмите её чтобы автоматически обновлять страницу и сделать Jenkins более интерактивным.

Рекомендую почитать:

Комментарии

http://openid-provider.appspot.com/alexey.diyan 27 мая 2013 г. 11:17

как запустить BDD-тесты с поддержкой Selenium WebDriver через Lettuce и splinter.

Вы рассматривали какие-нибудь альтернативы помимо splinter? Использовать Selenium WebDriver или что-то совершенно другое.

Что для вас было решающим при определении выбора splinter?

splinter это обвязка вокруг селениума и других драйверов, как zope.testbrowser

Я выбрал splinter потому что он мне показался самым удобным и популярным

Как насчет (CasperJS + PhantomJS + GPU)

А сравнительные тесты перформанса где посмотреть?

Входим на сервер, где вы установили Jenkins и выполняем следующее

вы явно делаете что то не так, настройка доступа к git производится на вкладке Credentials

@ALex_hha, для настройки нод использую Credentials, но для настройки гита это неудобно, потому что часто приходится вручну обновлять гит из консоли. Мой вариант закрывает сразу две потребности

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

Markdown