Введение
Многие начинающие веб разработчики размышляют о том, где бы разместить свое творение. Обычно для этих целей применяются машины под управлением *NIX подобных систем. Мой выбор остановился на Raspberry PI, поскольку малинка:
- работает под управлением полноценного Linux,
- долгое время лежит на столе и пылится.
Я хочу рассказать о том, как настроить сервер, работающий в сети с динамическим внешним IP адресом. Для запуска крупных проектов такое решение не годится, а для демонстрации своего портфолио и персонального применения вполне подойдет.
Нам понадобятся
- Raspberry PI модели B, B+ или Raspberry PI 2 (поскольку на платах этих моделей имеется Ethernet) с установленной Raspbian и активированным SSH сервером. О настройке можно почитать здесь, здесь или здесь. Помимо Raspian для малинки существует большое количество альтернативных дистрибутивов. Тут, как говорится, «на любой вкус и цвет».
- Рабочее Django приложение.
- Роутер с поддержкой DDNS. Этот пункт не обязателен, поскольку DDNS можно настроить на самой малинке.
Я буду работать с малинкой модели B+.
Подготовка
На малинке установлена Raspbian 7.8.
Для начала необходимо найти малинку в сети, чтобы подключиться к ней по ssh.
nmap -sP 192.168.1.1/24 | grep raspberry
В моем случае в сети две малинки, одна из которых моя с IP адресом 192.168.1.100. В некоторых сетях nmap не показывает сетевые имена устройств.
В этом случае найти raspberry pi можно по MAC-адресу, который имеет префикс B8:27:EB.
sudo nmap -sP -n 192.168.1.1/24 | grep -B 2 B8:27:EB
Параметр -B для grep определяет какое количество предшествующих строк следует вывести.
Подключаемся к малинке по ssh.
ssh pi@192.168.1.100
Для начала разгоним малинку до 1 ГГц с помощью raspi-config.
Устанавливаем питоновский менеджер пакетов
sudo apt-get install python-pip
Переходим к установке необходимых пакетов. В моем web приложении используется СУБД MySQL. В качестве Frontend и Backend используется nginx и gunicorn соответственно.
sudo apt-get install nginx gunicorn mysql-client mysql-server python-mysqldb
В процессе установки mysql необходимо ввести данные для root пользователя СУБД. python-mysqldb — драйвер, необходимый при работе с моделями в Django. Django установим из питоновских репозиториев.
sudo pip install django
На момент написания статьи актуальные версии nginx и gunicorn в репозиториях для малинки 1.2.1 и 0.14.5 соответственно. Версия MySQL для малинки 5.5. Так же для работы с Django необходимо установить SciPy.
sudo apt-get install python-scipy
nginx 1.2.1 устарел. Более новый можно собрать из исходников. Свежий gunicorn можно установить из питоновских репозиториев.
Настройка сервера
Размещаем web-приложение на малинке (например в /home/pi).
Если у Вас есть рабочие конфиги, то достаточно их скопировать в соответствующие директории:
- для nginx /etc/nginx/sites-enabled/
- для gunicorn /etc/gunicorn.d/
C nginx ничего сложного нет. Я бы хотел обратить внимание на настройки для gunicorn.
CONFIG = {
'mode': 'wsgi',
'working_dir': '/home/pi/project',
#'working_dir': '/home/pi/project/project',
'user': 'www-data',
'group': 'www-data',
'python': '/usr/bin/python',
'args': (
'--bind=127.0.0.1:8081',
'--workers=5', # 5 достаточно для малинки
'--graceful-timeout=60',
'--timeout=60',
#'--debug',
#'wsgi:application',
'project.wsgi',
),
}
Если working_dir (путь к файлу wsgy.py) указать '/home/pi/project/project'
, а в args указать 'wsgi:application'
, то на малинке воркеры сначала стартуют, потом умирают без указания причины (под Ubuntu, например, gunicorn работает с обоими вариантами настроек).
Перенос MySQL
Дамп имеющейся БД можно сделать с помощью утилиты mysqldump.
mysqldump -u root -p dbname > dbname.sql
Полученный файл состоит из набора SQL-инструкций, которые восстанавливают структуру, а так же информацию, хранимую в базе данных.
На малинке создаем базу данных. Запускаем mysql shell.
mysql -u root -p
Добавляем новую базу данных.
mysql> create database dbname character set utf8 collate utf8_general_ci;
mysql> grant all privileges on dbname.* to someusr@localhost identified by 'somepassword';
Восстанавливаем данные с дампа. При размере дампа в 162 Мб время восстановления составило около 10 минут.
mysql -u root -p dbname < dbname.sql
Следует отметить, что базы данных лучше хранить на внешнем накопителе, иначе micro SD карта может быстро придти в негодность из-за частых операций записи. Как это сделать можно почитать здесь. Конфиг mysql расположен по пути /etc/mysql/my.cnf
Проверка
Перезапускаем nginx и gunicorn. Если frontend и backend настроены верно, можно открыть наше web приложение.
Переходим к нагрузочному тестированию. Установим apache benchmark.
sudo apt-get install apache2-utils
Протестируем в 4 потока 1000 запросами Raspberry PI модель B+.
ab -c 4 -n 1000 http://192.168.1.100/
vladislav@vladislav-N53SV:~$ ab -c 4 -n 1000 http://192.168.1.100/
This is ApacheBench, Version 2.3 <$Revision: 1528965 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.1.100 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: nginx/1.8.0
Server Hostname: 192.168.1.100
Server Port: 80
Document Path: /
Document Length: 24839 bytes
Concurrency Level: 4
Time taken for tests: 1309.607 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 25018000 bytes
HTML transferred: 24839000 bytes
Requests per second: 0.76 [#/sec] (mean)
Time per request: 5238.429 [ms] (mean)
Time per request: 1309.607 [ms] (mean, across all concurrent requests)
Transfer rate: 18.66 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 0.1 1 1
Processing: 4924 5237 91.4 5227 6419
Waiting: 4919 5227 91.3 5217 6403
Total: 4925 5238 91.4 5228 6420
Percentage of the requests served within a certain time (ms)
50% 5228
66% 5245
75% 5255
80% 5265
90% 5296
95% 5335
98% 5382
99% 5667
100% 6420 (longest request)
Запросы идут медленно, поскольку большую часть времени запроса занимает работа с БД. Ко мне недавно пришла Raspberry PI 2 модель B. Посмотрим на что она способна c теми же настройками и данными.
vladislav@vladislav-N53SV:~$ ab -c 4 -n 1000 http://192.168.1.14/
This is ApacheBench, Version 2.3 <$Revision: 1528965 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.1.14 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: nginx/1.8.0
Server Hostname: 192.168.1.14
Server Port: 80
Document Path: /
Document Length: 24838 bytes
Concurrency Level: 4
Time taken for tests: 170.083 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 25017000 bytes
HTML transferred: 24838000 bytes
Requests per second: 5.88 [#/sec] (mean)
Time per request: 680.330 [ms] (mean)
Time per request: 170.083 [ms] (mean, across all concurrent requests)
Transfer rate: 143.64 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 0.1 1 1
Processing: 569 678 104.6 650 1338
Waiting: 567 676 104.1 647 1334
Total: 569 679 104.6 651 1338
Percentage of the requests served within a certain time (ms)
50% 651
66% 682
75% 708
80% 727
90% 796
95% 890
98% 1045
99% 1138
100% 1338 (longest request)
Raspberry PI 2 обрабатывает запросы в среднем в 6,16 раз быстрее. Разработчики малинки не обманули.
Настройка DDNS
Настроить DDNS можно на роутере или на самой малинке. Я выбираю No IP, поскольку пользуюсь им несколько лет. Рассмотрим бесплатное использование.
Кликаем AddHost и заполняем форму.
Внизу кликаем кнопку AddHost
Хост добавлен. Справа от имени хоста отображается внешний IP адрес Вашей сети.
Настраиваем DDNS на роутере
Для примера я настрою DDNS на ASUS RT-N56U с прошивкой от padavan версии 3.4.3.9-091. Открываем в страницу меню роутера
(например 192.168.1.1). WAN->DDNS.
Выбираем сервис no-ip.com, указываем регистрационные данные, а так же наш добавленный хост (technopark-test.ddns.net).
Остальные параметры выставляем по собственному желанию.
Теперь при смене внешнего IP адреса наше приложение остается доступным в сети.
Настройка переадресации портов
Нам нужно, чтобы при обращении к хосту малинка отдавала веб приложение. Роутер занимается перенаправлением входящих пакетов, пришедших из вне с порта X на внутренный порт Y. В меню роутера переходим WAN->Переадресация портов. Необходимо перенаправлять внешний 80 порт на 80 порт малинки. Добавим новое правило и применим изменения.
Теперь малинка обрабатывает все приходящие пакеты на 80 порту. Проверим, введя в адресной строке браузера хост, полученный в No IP.
Теперь наше веб приложение доступно для пользователей сети Интернет.
Настраиваем DDNS на малинке
Этот вариант не подходит, если малинка имеет частный IP, поскольку она будет оправлять свой локальный IP адрес на на сервис No IP. Это еще один способ узнать IP адрес малинки локальной сети. Установим DDNS клиент.
sudo apt-get install ddclient
Во время установки необходимо выбрать сервис. Выбираем other и вводим dynupdate.no-ip.com, протокол dyndns2, имя пользователя, пароль, интерфейс — eth0, имя хоста.
Для проверки я выставил интервал обновления IP в 60 секунд. В файле /etc/default/ddclient необходимо выставить значение daemon_interval=«60».
Десерт
Моя малинка давно лежала на столе и пылилась, вместе с tm1638 и DHT11, выводя показания температуры и влажности в помещении и прочей информации.
Все же мне было интересно попробовать управлять GPIO Raspberry PI из django. Я разработал простое web приложение, которое объединило мои ранние наработки. Оно позволяет посмотреть температуру и влажность, измеренные с помощью DHT11, некоторую полезную информацию, управляет 8-ми релейным модулем (который может быть использован для управления электроприборами) и отправляет текст на tm1638.
Для управления GPIO необходимо запускать сервер с правами root. Это потенциальная уязвимость.
Полноценное использования web приложения предполагает работу сервера без прав суперпользователя, настройку https, добавление возможности администрирования учетных записей, ведение логов, разделение доступа к управляемым устройствам, работу электроприборов по расписанию и многое другое.
Впрочем это уже совсем другая история статья.
Заключение
Имея Raspberry PI моделей B, B+ или Raspberry PI 2, power bank, а так же «open» Ethernet jack получаем компактный сервер, который можно использовать для демонстрации своих наработок. Настройка сервера для Django приложений на Raspberry PI под управлением Raspbian мало чем отличится от любой другой сборки Linux. Пакеты в репозиториях могут быть устаревшими. Для работы с новыми версиями можно вручную собирать программы из исходников.
Исходный код демо приложения.
P.S. Хочу поблагодарить коллег по Технопарку за помощь при подготовке материала.
P.S.S. Я готов выслушать дельные советы и комментарии, а затем поправить материал.
Статья создана в рамках конкурса статей Технопарка@Mail.Ru (park.mail.ru).
Автор: bagrusss