W życiu każdego admina przychodzi moment w którym trzeba umieścić cholernie niedorobiona niezbyt dobrze napisaną aplikację na serwerze i okazuje się że ta aplikacja po jakimś czasie zaczyna wariować. Czy to zwiecha czy wpada w pętlę i żre procesor jak szalona czy po prostu cieknie i po jakimś czasie zżera cały RAM i OOMkiller mówi “that’s a good day for you to die”, trzeba znaleźć sposób żeby dalej chodziła (bo nie ma alternatywy/nie da się naprawić/whatever).

Standardowym podejściem jest albo napisanie skryptu-niańki sprawdzającego czy działa poprawnie i zajmującego się resetem (w przypadku gdy app wpada w deadlock czy cieknie) lub prosty restart po padzie, czy używając while sleep 1 ;do /some/where/app ; done czy supervisora typu np. daemontools.

Gdy potrzebny jest prosty restart to nie jest problemem, schody zaczynają się gdy trzeba napisać więcej warunków.  Z czasem dochodzi potrzeba dodania więcej ficzerów np. alerty na maila w wypadku restartu, sprawdzanie danego URLa czy app działa, więcej testów itd. Potem pojawia się inna aplikacja, copy-paste starego skryptu, parę zmian, znowu dopisywanie nowych rzeczy (bo np. chcemy powiadamiać programistę o padzie ale tylko tej aplikacji, albo chcemy żeby dostawał maila tylko jeżeli restart się nie powiedzie). Jeżeli tego będzie wystarczająco dużo to pewnie nasz skrypcik spotka rewrite żeby obsługiwał pliki konfiguracyjne, stronę statusu, więcej testów itd.

Guess what ? Ktoś już to zrobił ;]

Enter Monit

Jest to dość stary soft (-V pokazuje że powstał 2000) o którego istnieniu dowiedziałem się dopiero trochę ponad pół roku temu. Ideą jego jest że ustawiamy danej usłudze parę warunków i akcję do wykonania gdy dane warunki zostaną/nie zostaną spełnione. Przykład:

check process lighttpd
      with pidfile "/var/run/lighttpd.pid"
      alert some@email.pl with reminder on 3 cycles
      start program = "/etc/init.d/lighttpd start"
      stop program = "/etc/init.d/lighttpd stop"
      if memory usage > 1% then alert
      if memory usage > 15% then restart
      if cpu usage > 95% for 2 cycles then alert
      if failed host 127.0.0.1 port 80  protocol http
            and request '/server-status' hostheader 'some.where.pl'
        with timeout 20 seconds for 2 cycles
      then alert
      if failed host 127.0.0.1 port 80  protocol http
            and request '/server-status' hostheader 'some.where.pl'
        with timeout 20 seconds for 5 cycles
      then restart

check file lighttpd-config
      with path "/etc/lighttpd/lighttpd.conf"
      if changed checksum
         then exec "/etc/init.d/lighttpd restart"

Lighttpd to może niezbyt dobry przykład (nie zdycha w nieokreślonych okoliczonościach) ale pozwala to pokazać parę rzeczy. Na początku ustawiamy co sprawdzać i jaki ma PID (najnowszy monit potrafi matchować nazwę procesu po regexpie, ale jeżeli da się po pidzie lepiej robić to po pidzie;]) oraz gdzie wysyłać alerty (można też ofc ustawić “globalny” mail) oraz w wypadku gdy usługa jest down permanentnie co ile “przypominać się” (UWAGA: Domyślnie monit alertuje jak nagios tzn. wysyła maila tylko przy zmianie stanu usługi) . Dalej jak startować/zatrzymywać usługę czyli w sumie tyle ile każdy typowy supervisor robi.

Interesujące nas ficzery są dalej, tutaj ustawiłem że gdy app zeżre więcej niż 1% total RAMu to wysyła alert (normalnie lighttpd mi żre 0.1% [~2MB], bo phpa mam przez FastCGI), przydatne jak chcemy podebugować zanim OOMkiller zabawi się z procesem/monit restartnie. Jeżeli przekroczy nam 15% znaczy że coś jest nie tak i robimy restart (w przypadku np. aplikacji javowych sensowne wartości byłyby np odpowiednio 75% i 85%).

Potem sprawdzamy CPU, tutaj jest tylko alert ponieważ to mówi tam “jest obciążenie, trzeba więcej serwerów”. Można używać tego do restartu aplikacji, ale lepiej jest sprawdzać czy ona pracuje poprawnie bo CPU load może być po prostu spowodowany ruchem a nie popsutą aplikacją.

Dalej mamy właściwe checki sprawdzające poprawność dzialania usługi. 2 identyczne checki tylko z inną ilością cykli. Pierwszy ma za zadanie alertować gdy aplikacja długo nie odpowiada, druga to restart gdy jest kompletnie “down”

Monit nie ogranicza się do uruchomionych procesów, można monitorować pliki, sockety czy ogólne parametry systemu, ostatni blok to przykład monitorowania pliku, sprawdzamy czy suma kontrolna się zgadza i jak plik zostanie zmieniony to restartujemy lighttpd. Przydatne przy testowaniu ale do takich rzeczy lepiej użyć Puppeta ;).

Dodatkowo w configu można włączyć proste webowe UI z podglądem co działa/nie działa oraz opcją stop/start/restart usług. Reszta w manualu;]

Z wad to cóż, format configa jest trochę nietypowy, -t (check config file) nie jest zbyt słowne oraz status “not monitored” oznacza zarówno “nie jest monitorowany” jak i “jest monitorowany i zaraz usługa będzie zrestartowana” co jest dosyć mylące, ale jak najbardziej do przejścia.

Szkoda tylko że o tym sofcie dowiedziałem się dopiero niedawno, jeden z tych tooli “czemu nikt mi nie powiedział że coś takiego istnieje”… chyba pora na napisanie kolejnego “admin toolboxa”