File: deploying.tex

package info (click to toggle)
mongrel2 1.12.0-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 5,976 kB
  • sloc: ansic: 39,083; python: 2,833; sql: 1,555; sh: 467; makefile: 360; asm: 189; yacc: 145; php: 73; awk: 28; sed: 5
file content (709 lines) | stat: -rw-r--r-- 43,269 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
\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}

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