\chapter{Развёртывание}

Сейчас я покажу как разворачивать сервер на примере конфигурации с сайта
\url{http://mongrel2.org}. Вы узнаете обо всех инструментах, необходимых для
автоматизации этого процесса. Пример небольшой, но получив нужные знания вы
можете легко их применить для более сложной инфраструктуры.

\section{Требования}

Может показаться очевидным, но я всё же пробегусь по всем необходимым
реквизитам:

\begin{description}
\item [Mongrel2] Невероятно, но для всего этого нужен установленный Mongrel2 :-)
\item [m2sh] Не понимаю, почему многие думают, что эта утилита не нужна. Если у
    вас нет другой аналогичной, то без неё не обойтись.
\item [Питон] На некоторых системах (таких как Debian) Питон не полностью
    установлен. Если это так, то нужно доставить.
\item [root] Нужен рутовый доступ. Либо через \shell{sudo}, либо иным способом.
\item [Базовые знания Питона] К этому моменту понадобятся базовые навыки в
Питоне.
\end{description}

Для начала этого достаточно. По мере необходимости мы будем вносить изменения в
систему.

\begin{aside}{Изучаем Питон}
Зачем изучать программирование? Тенденция такова, что, если вы системный
администратор, который не умеет кодить, то вы рискуете остаться не у дел. Рано
или поздно вам придётся автоматизировать системы, а не управлять ими вручную.
Если не верите мне, то посмотрите на компании, которые строят бизнес только на
том, что автоматизируют системы. Итак, вам нужно научиться писать код. Проблема
в том, чтоб большинствой книг по этой теме --- полный отстой.

Вот почему я начал писать свою книгу
\href{http://learnpythonthehardway.org}{Learn Python The Hard Way} (к сожалению
пока только на английском). Она предназначена для тех, кто мало знает о
программировании, но хочет научиться. Эта книга обучает Питону, но помимо этого,
она учит всем тем вещам, которые программисты осваивают прежде чем начинают
программировать. Когда вы осилите эту книгу, у вас будет ``коричневый пояс по
программированию''. Это значит, что ваши шансы освоить другие более серьезные
книги значительно увеличиваются.

Только \emph{не читайте} ``Dive Into Python'' --- это ужасное введение в язык.
\end{aside}

\subsection{Введение в procer}

Одна из целей этого небольшого мануала --- научить читателя создавать
инфраструктуру для автоматизации работы сервера. С помощью \shell{m2sh} можно
управлять сервером, но этой утилиты недостаточно. Mongrel2 общается с различными
компонентами, которые запущены в отдельных процессах. И попытка управлять этими
процессами без специального инструмента зачастую оборачивается большой головной
болью: приходится писать скрипты, встривать их в процесс загрузки и т.п.; и всё
это лишь для того, чтобу запустить простую демку типа "Hello world".

Мне нужен был некий менеджер процессов в пользовательском пространстве. Это
пргорамма, которая запускает другие программы, но, что более важно, поддерживает
их в запущенном состоянии. Когда вам нужно развернуть кучу процессов, такой
менеджер просто незаменим. Сценарий работы стандартен --- менеджер считывает
конфигурационный файл с описанием процессов и их зависимостей, стартует все эти
процессы и наблюдает за ними. Если какой-то из них рушится, он его
перезапускает. Всё просто.

Но есть один момент: все из них --- полный отстой. Есть
\href{http://cr.yp.to/daemontools.html}{daemontools}, который компилируется со
скрипом, а потом предполагает, что процесс не может плодить потомков с помощью
fork. Тупо. Есть \href{http://www.fefe.de/minit}{minit}, который вообще не
компилируется без библиотеки dietlibc, а потом предполагает, что он единственный
init-процесс во всей системе (не подходит для пользовательского пространства).
Есть \href{http://www.nico.schottelius.org/software/cinit}{cinit}, который
компилируется, но создаёт кучу скриптов и, опять же, полгает, что он ---
единственный init-скрипт. Ну и, наконец, есть
\href{http://smarden.org/runit}{runit}. Внутри самый ужасный Си код, который я
когда-либо видел. Более того, у него такой же странный дизайн как и у
daemontools.

После многократных попыток я сдался. Программа либо не компилировалась, либо
была слишком сложной, либо плохо задокументирована, либо не поддерживалась.
Одним словом --- не подходила. Единственным выбором было написать свою. Что я и
сделал.

В результате --- \shell{procer}. Вы можете найти эту утилиту в
\file{tools/procer}. Она делает всё что нам нужно и работает подобно
daemontools или minit, но гораздо проще по своему дизайну. Вот список отличий от
всех приведённых выше аналогов:

\begin{enumerate}
\item Гораздо проще и компилируется в один выполняемый файл.
\item Компилируется везде, где компилируется Mongrel2, потому что использует
    библиотеку \file{libm2.a}.
\item Не пытается стать единственным системным init-процессом и не настаивает на
    том, чтобы быть всегда запущенной. Её можно запускать и останавливать и она в
    свою очередь будет стартовать те процессы, которые ещё не запущены.
\item Предполагает, что процессы всегда создают PID файл, что очень удобно
    для управления. Это отличает её от daemontools и я сильно удивлён, что
    daemontools работает так, как он работает.
\item Управляет зависимостями, т.е. может запускать процессы в определённой
    последовательности.
\item Использует довольно простой формат конфигурационных файлов, которые
    расположены в разных директориях (у каждого процесса она своя).
\item Может быть запущена под рутом. Как и Mongrel2 назначет владельцем процесса
    того пользователя, который владеет директорией профайлов.
\item Она очень маленькая; написана так, что код легко понять, несмотря на то,
    что это Си.
\item И самое лучшее --- я могу использовать её в этом руководстве и у вас не
    пойдёт голова кругом, когда вы будете устанавливать или использовать.
\end{enumerate}

Конечно же, если у вас есть другая утилита и вы с ней знакомы --- используйте
её. Подойдёт всё, что может управлять процессами. В этом мануале я буду
использовать \shell{procer}.

\begin{aside}{Альтернативы для утилиты procer}
Я написал procer исключительно для этой книги, но я также использую его для
развёртывания сервера. Утилита работает для меня, но вы можете попробовать
другие решения. Mongrel2 поддерживает любой режим запуска: под обычным
пользователем (как работает daemontools/runit), либо под рутом (как init.d
скрипты). 

Возможно, вы захотите проверить ещё одну альтернативу --
\href{http://github.com/peterkeen/proclaunch}{proclaunch}. Это скрипт на Перле,
который взял procer за основу и добавил некоторые фичи.

Так или иначе, Mongrel2 практичен --- выполняет то, что нужно теми инструментами,
которые есть в наличии. Нравится daemontools? Отлично, запустите \verb|mongrel2 config.sqlite server_uuid|
и всё будет в порядке. Хотите стартовать сервер с
помощью init.d или использовать другой альтернативный скрипт? Без проблем,
запускайте под рутом.
\end{aside}


\subsection{Устанавливаем procer}

Установка очень простая. На выходе --- один бинарный файл. Исходники лежат в
\file{tools/procer}. Чтобы установить с нуля, выполните все команды по
списку:

\begin{code}{Install procer}
\begin{lstlisting}
> cd projects/mongrel2
> make clean all && sudo make install
> cd tools/procer
> make clean all && sudo make install
\end{lstlisting}
\end{code}

После завершения процесса, файл procer будет лежать в папке
\file{/usr/local/bin}. Используйте и наслаждайтесь! Остаток главы посвящён
детальному рассмотрению процесса развёртывания веб-сервера Mongrel2.

\section{План}

Любое хорошее дело начинается с плана. Давайте распланируем действия по
развёртыванию сервера:

\begin{enumerate}
\item Создать рабочее пространство --- иерархию директорий и файлов необходимых
    для нашей задачи.
\item Создать файл настроек config.sqlite, который будет работать с демками в
    \shell{examples}
\item Настроить procer для запуска сервера и трёх примеров на Питоне: chat,
    handlertest, и mp3stream, а также бэкенда на web.py, чтобы показать пример
    проксирования.
\item Настроить статический контент.
\item Убедиться, что procer поддерживает все подсистемы в запущенном состоянии.
\end{enumerate}

Как только эта инфраструктура заработает, вы сможете создавать более сложные
конфигурации для своих приложений. Запомните, цель --- добиться максимальной
\emph{автоматизации}.

\section{Шаг 1: Готовим рабочее пространство}

Нужно создать директорию, которую Mongrel2 во время запуска сделает рутовой.
Затем в этой директории создать все необходимые профайлы.

\begin{code}{Создаём рутовую директорию и профайлы}
\begin{lstlisting}
# go home first
> cd ~/

# create the deployment dir
> mkdir deployment
> cd deployment/

# fill it with the directories we need
deployment > mkdir run tmp logs static profiles

# create the procer profile dirs for each thing
deployment > cd profiles/
deployment/profiles > mkdir chat mp3stream handlertest web mongrel2
deployment/profiles > cd ..

# copy the mongrel2_conf.py sample from the source to here
deployment > cp ~/mongrel2/examples/python/tests/mongrel2.conf mongrel2.conf

# load the default mongrel2.conf into the config.sqlite
deployment > m2sh load

# see our end results
deployment > ls
mongrel2.conf  config.sqlite  logs  profiles  run  static tmp

\end{lstlisting}
\end{code}

Надеюсь, вы уже видите возможность автоматизировать даже этот процесс. Я же
делаю это вручную, чтобы показать, где зарыта собака. Вполне возможно, что со
временем m2sh будет поддерживать команды для создания профайлов.

Мы только что сделали следующее:

\begin{enumerate}
  \item Создали директорию \file{\~{}/deployment} где будут лежать все файлы.
  \item Создали поддиректории \file{run}, \file{tmp}, \file{logs}, и
    \file{profiles}, которые Mongrel2 и procer будут использовать во время работы.
  \item Для каждого проекта создали профайл (изначально просто директория). Итого
    пять профайлов: \file{chat}, \file{mp3stream}, \file{handlertest}, \file{web},
    \file{mongrel2}.
  \item Скопировали пример конфигурационного файла mongrel2.conf из примеров.
  \item Инициализировали базу настроек \file{config.sqlite} из этого конфигурационного файла.
\end{enumerate}


\section{Шаг 2: Конфигурация mongrel2.org}

Теперь мы готовы внести изменения в настройки. Но вы должны попробовать это
сделать самостоятельно. Ведь я уже дал вам готовый файл \file{mongrel2.conf};
нужно только слегка его подкорректировать. Вот что нужно сделать:

\begin{enumerate}
\item Избавьтесь от обработчика \ident{test\_directory} --- нам он не нужен.
\item Смените \ident{base} в маршруте \ident{chat\_demo\_dir} на
    \file{static/chatdemo}. Мы настроим этот маршрут в конце.
\item Измените рутовую директорию \ident{chroot} в сервере на
    \file{/home/YOU/deployment/}
\item Измените один или несколько UUID: вы можете воспользоваться командой
    \shell{m2sh uuid}, чтобы сгенерировать идентификаторы. Этот шаг
    опционален; я хочу, чтобы вы знали, что есть такая команда.
\item Измените \ident{port} у \ident{web\_app\_proxy} --- 8080 вместо 80.
\item Наконец, замените ``mongrel2.org'' на ``localhost'', чтобы запускать сервер локально.
\end{enumerate}

После внесения всех правок команда \shell{m2sh load -db config.sqlite -config
mongrel2.conf} считает конфигурационный файл и внесет все изменения в базу
настроек. Поиграйтесь с ней с помощью команд \shell{m2sh servers} и \shell{m2sh
hosts}.

Можно протестировать сервер на данном этапе, запустив серию команд:

\begin{code}{Тестируем первоначальную конфигурацию}
\begin{lstlisting}
> m2sh start -db config.sqlite -host localhost
^C
> m2sh start -db config.sqlite -host localhost -sudo
> less logs/error.log
> m2sh stop -db config.sqlite -host localhost -murder
\end{lstlisting}
\end{code}

Этого достаточно, чтобы убедиться, что сервер запускается. Но он не
функционален, поскольку другие компоненты ещё не запущены.


\section{Шаг 3: Настраиваем procer}

Нам нужно, чтобы \shell{procer} запускал всё, что нам нужно, и поддерживал в
запущенном состояни. Для этого нужно положить определённые файлы в директорию
\file{profiles}. Для каждой подсистемы должна быть своя директория, например
\file{chat} для демо-чата. Когда \shell{procer} стартует, он пытается загрузить
профайлы из папки; в нашем случае это \file{profiles}. Мы будем делать всё
вручную, но такую инфраструктуру очень и очень легко автоматизировать.

Итак, для начала накидаем скелет, а потом будем наполнять его, параллельно
запуская \shell{procer} и анализируя результат:

\begin{code}{Скелет конфигурации}
\begin{lstlisting}
deployment > cd profiles/
deployment/profiles > ls
chat  handlertest  mongrel2  mp3stream  web

# make all the restart settings
deployment/profiles > for i in *; do touch $i/restart; done

# make all the empty dependencies
deployment/profiles > for i in *; do touch $i/depends; done

# setup the pid_files to some sort of default
deployment/profiles > for i in *; do echo $PWD/$i/$i.pid > $i/pid_file; done
deployment/profiles > cat chat/pid_file

# get the run script setup to do nothing
deployment/profiles > for i in *; do echo '#!/bin/sh' > $i/run; done
deployment/profiles > for i in *; do chmod u+x $i/run; done

# check out what we did
deployment/profiles > ls -lR
\end{lstlisting}
\end{code}

Теперь можно запустить \shell{procer} --- он попытается активировать профайлы,
но не сможет, поскольку система не до конца настроена. Тем не менее, посмотрим,
что он нам говорит: 

\begin{lstlisting}
> sudo procer $PWD $PWD/../run/procer.pid
> less error.log
\end{lstlisting}

Предполагается, что вы находитесь в директории \file{profiles}. Там должен
появиться файл \file{error.log}. Взгляните на него --- туда пишутся не только
ошибки, но и попытки запустить процессы. 

\begin{code}{Первый запуск}
\begin{lstlisting}
DEBUG procer.c:232: Loading 5 actions.
DEBUG procer.c:83: STARTED chat
ERROR Failed to open PID file /home/zedshaw/deployment/profiles/chat/chat.pid for reading.
ERROR Failed to open PID file /home/zedshaw/deployment/profiles/chat/chat.pid for reading.
INFO  No previous Mongrel2 running, continuing on.
DEBUG procer.c:37: ACTION: command=/home/zedshaw/deployment/profiles/chat/run, pid_file=/home/zedshaw/deployment/profiles/chat/chat.pid, restart=1, depends=(null)
DEBUG procer.c:56: WAITING FOR CHILD.
INFO  Now running as UID:1000, GID:1000
DEBUG procer.c:60: Command ran and exited successfully, now looking for the PID file.
ERROR chat didn't make pidfile /home/zedshaw/deployment/profiles/chat/chat.pid.
\end{lstlisting}
\end{code}

Эти строки говорят нам о следующем:

\begin{enumerate}
\item \shell{procer} стартует и обнаруживает 5 профайлов.
\item Запускает чат, сообщает, что PID файл не найден, так что можно продолжать.
\item Уведомляет какое действие он выполняет (посредством ACTION).
\item Запускает скрипт \file{run}, меняет привелегии и ждёт (WAITING), пока
    скрипт завершит работу.
\item После запуска, скрипт ищет PID-файл, но не находит его и завершает работу.
\item \shell{procer} повторяет эти действия для всех профайлов. Поскольку ни один из них не
работает, он завершает работу.
\end{enumerate}

Теперь давайте автоматизируем запуск Mongrel2:

\begin{code}{procer и Mongrel2}
\begin{lstlisting}
> cd ~/deployment
# make mongrel2 run as root
deployment > sudo chown root.root profiles/mongrel2

# tell procer where mongrel2 puts its pid_file
# notice the > not >> on this
deployment > echo "$PWD/run/mongrel2.pid" > profiles/mongrel2/pid_file

# make the run script start mongrel2 (notice the >> on this)
deployment > echo "cd $PWD" >> profiles/mongrel2/run
deployment > echo "m2sh start -db config.sqlite -host localhost" >> profiles/mongrel2/run

# check out the results
deployment > cat profiles/mongrel2/run
#!/bin/sh
cd /home/YOU/deployment
m2sh start -db config.sqlite -host localhost
\end{lstlisting}
\end{code}

Очевидно, вам не надо добавлять команды с помощью \shell{echo} --- можно просто
отредактировать файлы. Я так сделал, чтобы вам было удобнее изучать пример.

Теперь... убедитесь, что Mongrel2 не запущен и снова запустите procer.

\begin{code}{Запускаем Mongrel2}
\begin{lstlisting}
> cd ~/deployment
# clear out the error.log for testing
deployment > rm profiles/error.log

# start procer
deployment > sudo procer $PWD/profiles $PWD/procer.pid

# see if procer is running
deployment > ps ax | grep procer
17934 ?        Ss     0:00 procer /home/zedshaw/deployment/profiles /home/zedshaw/deployment/procer.pid

# see if mongrel2 is running
deployment > ps ax | grep mongrel2
17944 ?        Ssl    0:00 mongrel2 config.sqlite ba0019c0-9140-4f82-80ca-0f4f2e81def7

\end{lstlisting}
\end{code}

Чтобы увидеть \shell{procer} в действии, остановите сервер (\shell{m2sh stop -db
config.sqlite -host localhost -murder}) и взгляните на \file{profiles/error.log}
--- вы увидте, что Mongrel2 снова запущен.

\subsection{Примеры на Питоне}

Мы смогли добиться того, что procer запускает Mongrel2 и следит за ним. Теперь
давайте проделаем то же самое для наших небольших демо-скриптов на Питоне. Для
этого нам надо выполнить немного больше работы --- запустить скрипты в фоновом
режиме и создать PID-файлы. Начнём с демо-чата. Предполагая, что исходники
веб-сервера лежат в \file{\~{}/projects/mongrel2}, меняем файл
\file{profiles/chat/run} следующим образом:

\begin{code}{run-скрипт для демо-чата}
\begin{lstlisting}[language=sh]
#!/bin/sh
set -e

DEPLOY=/home/YOU/deployment
SOURCE=/home/YOU/projects/mongrel2

cd $SOURCE/examples/chat
nohup python -u chat.py 2>&1 > chat.log &
echo $! > $DEPLOY/profiles/chat/chat.pid
\end{lstlisting}
\end{code}

Этот скрипт использует некоторые фишечки, о которых вы, может быть, не знаете,
но они очень удобны:

\begin{enumerate}
\item Первый трюк --- это \shell{set -e} --- указывает системе немедленно
    прекратить выполнение скрипта, если какая-либо команда вернула ошибку. Любой
    шелл-скрипт должен начинаться с этой команды.
\item Далее записываются пути, где лежат все необходимые файлы. Незабывайте,
    вместо YOU вы подставляете фактическое имя пользователя.
\item После этого запускается \file{chat.py} с помощью \shell{nohup}. В этой
    строчке скрипт переводится в фоновый режим с перенаправлением вывода.
\item В конце --- вывод магической переменной \verb|$!| (PID последнего
    запущенного процесса) в файл \file{chat.pid}.
\end{enumerate}

Если запустить этот скрипт вручную, то должно получиться что-то вроде этого:

\begin{lstlisting}
deployment > ./profiles/chat/run
nohup: redirecting stderr to stdout

deployment > ps ax | grep chat
19305 pts/1    Sl     0:00 python chat.py

deployment > kill -TERM 19305
\end{lstlisting}

Теперь можно перезапустить \shell{procer}, чтобы убедиться, что демо-чат также
автоматически запускается наряду с веб-сервером.

\begin{code}{Запуск демо-чата}
\begin{lstlisting}
# run procer to get stuff started
deployment > sudo procer $PWD/profiles $PWD/run/procer.pid

# see if it's all running
deployment > ps ax | grep procer
19607 ?        Ss     0:00 procer /home/zedshaw/deployment/profiles /home/zedshaw/deployment/run/procer.pid

deployment > ps ax | grep mongrel2
19621 ?        Ssl    0:00 mongrel2 config.sqlite ba0019c0-9140-4f82-80ca-0f4f2e81def7

deployment > ps ax | grep chat
19609 ?        Sl     0:00 python chat.py

# try killing chat to see if it comes back
deployment > kill -TERM `cat profiles/chat/chat.pid`

deployment > ps ax | grep chat
19669 ?        Sl     0:00 python chat.py
\end{lstlisting}
\end{code}

Если вы посмотрите на \file{profiles/error.log}, то увидите, что \shell{procer}
запускает каждый процесс под нужным пользователем: чат --- под текущим
пользователем, веб-сервер --- под рутом.

Остальные скрипты очень сильно похожи на первый, поэтому лишь приведу их
содержимое:

\begin{code}{Остальные скрипты}
  \file{profiles/handlertest/run}
\hrule

\begin{lstlisting}[language=sh]
#!/bin/sh
set -e

DEPLOY=/home/YOU/deployment
SOURCE=/home/YOU/projects/mongrel2

cd $SOURCE/examples/http_0mq
nohup python -u http.py 2>&1 > http.log &
echo $! > $DEPLOY/profiles/handlertest/handlertest.pid
\end{lstlisting}

\file{profiles/mp3stream/run}
\hrule

\begin{lstlisting}[language=sh]
#!/bin/sh
set -e

DEPLOY=/home/YOU/deployment
SOURCE=/home/YOU/projects/mongrel2

cd $SOURCE/examples/mp3stream
nohup python -u handler.py 2>&1 > mp3stream.log &
echo $! > $DEPLOY/profiles/mp3stream/mp3stream.pid
\end{lstlisting}


\file{profiles/web/run}
\hrule
\begin{lstlisting}[language=sh]
#!/bin/sh
set -e

DEPLOY=/home/YOU/deployment
SOURCE=/home/YOU/projects/mongrel2

cd $SOURCE/examples/chat
nohup python -u www.py 2>&1 > www.log &
echo $! > $DEPLOY/profiles/web/web.pid

\end{lstlisting}
\end{code}


\subsection{Тестируем}

Как только все скрипты готовы, запускаем \shell{procer} и тестируем с помощью curl.

\begin{code}{Тестируем с помощью curl}
\begin{lstlisting}
> curl http://localhost:6767/
Hello, World!
> curl http://localhost:6767/handlertest
...
\end{lstlisting}
\end{code}


\subsection{Procer и его плоды}

В результате использования \shell{procer} вы получаете следующее:

\begin{description}
\item [Быстрая разработка] Как только вы настроили скрипты, ваш цикл
    разработка-перезапуск-отладка сильно сокращается, потому что \shell{procer}
    наблюдает за вашими процессами и рестартует их \emph{надлежащим образом} в случае
    необходимости: вы вносите изменения в свой код, убиваете процесс и
    \shell{procer} автоматически перезапускает процесс.
\item [Простая автоматизация] Как вы заметили, для автоматизации процесса нужно
    добавить профайл, который представляет собой несколько директорий и несколько
    файлов.
\item [\file{profiles/run.log}] Все команды посылают диагностический вывод в
    этот файл и вы можете видеть, если что-то пойдет не так.
\item [Устойчивость] Procer отслеживает PID-файлы и процессы и даже если вы
    убьёте его, конца света не настанет. Всё будет по-прежнему работать. Когда вы
    снова запускаете procer, он просто сверяет файлы с процессами и запускает что
    нужно. Т.е. вы можете смело конфигурировать procer на лету, убивать,
    перезапускать его, а ваша система будет работать как часы.
\end{description}

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

\section{Шаг 4: Статический контент}

Вот мы и добрались до статического контента. Как только мы настроим выдачу
файлов, можно пробовать демо-чат.

Итак:

\begin{code}{Настраиваем статический контент}
\begin{lstlisting}
> cp -r ~/projects/mongrel2/examples/chat/static static/chatdemo
> m2sh stop -db config.sqlite -host localhost -murder
> curl -I http://localhost:6767/chatdemo/
\end{lstlisting}
\end{code}

Если curl возвращает то что нужно, то можно в браузере открыть
\url{http://localhost:6767/chatdemo/} и чат должен работать. Обратите внимание
--- вы только что остановили Mongrel2, но он снова запустился: \shell{procer} не
дремлет.

\section{Шаг 5: Тестируем}

По ходу выполнения предыдущих шагов вы уже, наверное, тестировали и я отмечу
основные моменты, на которые стоит обратить внимание:

\begin{enumerate}
\item /chatdemo/ работает и вы можете посылать сообщения. Попробуйте в разных
    браузерах.
\item /handlertest/ открывается и выводит небольшое сообщение.
\item Убедитесь, что mp3streamer выдаёт потоковое аудио. Положите несколько mp3
    файлов в его рабочую директорию, потом убейте обработчик, чтобы \shell{procer}
    его перезапустил. Затем откройте \shell{mplayer} и укажите на
    \url{http://localhost:6767/mp3stream} --- должно заработать.
\item Проверьте, что прокси перенаправляет запросы на web.py приложение.
\item Остановите те или иные процессы из профайлов и посмотрите, перезапускает
    ли их \shell{procer}.
\item Остановите и запустите \shell{procer} --- убедитесь, что всё по-прежнему
    работает.
\end{enumerate}

Если возникнут проблемы, попробуйте пробежаться по каждому профайлу по
отдельности --- проверьте содержимое профайлов, вручную запустите и т.п. В таких
случаях лучший инструмент --- \shell{diff}.

\section{Улучшения}

Мы подходим к концу этой главы. К этому моменты вы уже знаете практически всё,
на что способен Mongrel2; а также --- подойдёт ли \shell{procer} к вашим нуждам
или нет и то как использую его я в своей работе.

Самое \emph{большое} улучшение, которое мы может быть реализуем в ближайшем
будущем --- автоматизация создания профайлов и управление ими с помощью
\shell{m2sh}. Если вы чувствуете в себе силы, можете попробовать сделать это
сами и поделиться с сообществом.

А в целом: автоматизируйте, автоматизируйте, автоматизируйте.

\section{Советы}

Когда вы запускаете Mongrel2 под рутом, он ведёт себя как и подобает нормальному
серверу: назначает привилегии текущего пользователя и делает заданную директорию
рутовой. Это повышает безопасность и упрощает развёртывание. Кроме того,
поскольку всё находится в одной папке, очень легко синхронизировать настройки
между машинами --- достаточно положить их в репозиторий git или hg. Вы буквально
обречены делать портируемые конфигурации.

В текущей версии мы не приложили много усилий для автоматизации процесса
развёртывания \shell{пользовательских приложений}. Так что пока с этим могут
возникнуть некоторые неудобства. Но, однозначно, в версии 2.0 будут улучшения в
эту сторону.

Ниже приведены основные выводы, к которым мы пришли в процессе работы над первой
версией сервера:

\begin{enumerate}

\item Не запускайте ничего под рутом --- это очень плохая привычка. Mongrel2
спроектирован таким образом, чтобы корректно работать под обычным пользователем.
Суперпользователь нужен только один раз --- чтобы запустить Mongrel2 с помощью
m2sh и ключа -sudo.

\item Храните всё в одной директории. Это упрощает процесс развёртывания.  Я,
например, делаю всё локально, а потом с помощью \shell{rsync} загружаю на
удалённый сервер.

\item Если вы пишите на Питоне, используйте virtualenv или аналогичный софт для
создания изолированной виртуальной среды. Многие системы, такие как OSX,
используют устаревшие пакеты и обновляют их на своё усмотрение. Из-за этого
могут возникнуть проблемы совместимости. Лучший способ гарантировать
работоспособность приложения в любой системной конфигурации --- использовать
virtualenv.

\item Создайте пользователя для своего приложения и всегда используйте только
его. Я никогда не работаю под рутом. \emph{Абсолютно всё} работает под обычным
пользователем и хранится в домашней папке /home/USER. Я захожу под ним и
управляю сервером. Если мне надо перегрузить сервер (что может делать только
суперпользователь), я делаю это в отдельной сессии (открытой с помощью screen).

\item Используйте \href{http://www.gnu.org/software/screen/}{GNU screen}.

\item Храните config.sqlite и .conf файл в chroot-директории, как и весь
остальной контент. Также убедитесь, что конфигурационные файлы недоступны из
контент-директорий. Mongrel2 помогает в этом отношении, запрещая создавать
Dir-обработчики, которые могут открыть доступ к этим файлам из браузера.

\end{enumerate}

И ещё немного советов для тех, кто хочет воспользоваться альтернативным
менеджером процессов, таким как daemontools, runit, или init.d-скриптом.
Неважно, что вы выберите, следующие практики помогут предотвратить некоторые
проблемы:

\begin{enumerate}

\item Что бы вы ни выбрали, убедитесь, что ваша программа может запускать
процессы под \emph{обычным} пользователем и выполнять chroot в заданную
директорию.  Если вы запускаете Mongrel2 под суперпользователем --- это неверно.
На самом деле, если вы запускаете любой сервис под рутом, когда сервис этого не
требует, то это в корне неверно.

\item Mongrel2 комфортно себя чувствует, если запущен под обычным пользователем.
Более того, в этом случае он полагает, что запущен из-под менеджера процессов и
не записывает логи в stdout/stderr.

\item Если вы хотите, чтобы веб-сервер слушал 80-й порт и запускался из-под
daemontools и под обычным пользователем --- используйте
\href{http://manpages.ubuntu.com/manpages/lucid/man1/privbind.1.html}{privbind}.
Эта утилита запускает любую команду, такую как \file{mongrel2}, и позволяет ей
связываться с любым портом ниже 1024.

\item Убедитесь, что менеджер процессов не является самым слабым звеном в
системе. Иными словами, если вы убьёте его, убедитесь, что он не тянет
за собой все процессы, которые мониторит. Не слушайте, если автор говорит вам,
что менеджер "неубиваем и всегда будет в запущенном состоянии". В любой
программе есть баги и люди иногда останавливают процессы по незнанию. Так что
если такая ситуация имеет место быть --- это очень плохой дизайн и с этим надо
что-то делать.

\end{enumerate}

По мере развития проекта мы будем улучшать эту область --- автоматизацию и
р
