Wersojonowanie konfiguracji systemu

Systemy kontroli wersji towarzyszą nam już od bardzo dawna. W dzisiejszych czasach każdy projekt, który jest tworzony w zespole jest skazany na porażkę, jeśli nie jest wdrożona procedura wersjonowania kodu. Programy takie jak Git, Subversion (powszechnie nazywany SVN), czy też Bazaar na dobre zadomowiły się w warsztacie narzędzi wielu programistów.

Systemy wersjonowania nie są jednak używane tylko przez programistów, ponieważ administratorzy też czerpią całymi garściami z dobrodziejstw jakie dają nam te systemy. Administratorzy bardzo często wykorzystują tego typu rozwiązania do wersjonowania plików konfiguracyjnych na utrzymywanych przez siebie serwerach. Temu właśnie zagadnieniu poświęcony będzie ten artykuł, a więc do dzieła!

Na początku zacznijmy od …. początku, czyli:

Po co wersjonować pliki konfiguracyjne?

Odpowiedź jest prosta – ponieważ chcemy mieć historię wszystkich zmian, jakie zostały wprowadzone w konfiguracji danego systemu. Dzięki temu pozbywamy się takich problemów jak przywracanie starej konfiguracji, kontrola zmian (wiemy co i kiedy zostało zmienione), wiemy kto to zmieniał.

Czasem zdarza się taka sytuacja, że nasz kolega zmieni coś w jednym pliku i nic nikomu nie powie. Po kilku godzinach serwer zacznie wariować, będzie sypał dziwnymi błędami, a Tobie zostanie dane zadanie usunięcia awarii. I szukaj igły w stogu siana. Jeśli mamy ewidencje rewizji zmian to bardzo łatwo sprawdzimy co było ostatnio zmieniane w konfiguracji, a ta wiedza często pozwala rozwiązać problem z serwerem, ponieważ wiemy co ostatnio było zmieniane. Dzięki tym informacją zawężamy nasz obszar poszukiwań do minimum, ponieważ wiemy, że kiedyś wszystko działało bez zarzutu, a po ostatnich zmianach coś zaczęło się sypać.

Fajną rzeczą jest też to, że np. taki svn może nam wysłać maila, jeśli ktoś coś zmieni. Nie musimy pisać żadnych głupich maili do wszystkich w stylu “Słuchajcie upgradnąłem apache do najnowszej wersji”, tylko wystarczy, że to zrobimy i wyślemy nasze zmiany (commitniemy) do serwera. Po chwili wszyscy dostaną maila z naszym komentarzem i dokładną listą zmian jakie zostały przez nas wprowadzone.

Jest tylko jedno ale! Z doświadczenia wiem, że ludzie logują się na maszynę, zmieniają konfiguracją, testują, jeśli działa to zapisują i wychodzą. Niestety każdy zapomina o zatwierdzeniu (commicie). Później takie niecommitnięte zmiany potrafią leżeć miesiącami, aż jakiś dobry człowiek tego nie zauważy i nie commitnie. Problem tylko taki, że jeśli coś takiego się dzieje, to idea wersjonowania konfiguracji traci swój sens, ponieważ na serwerze nie ma nigdy aktualnej wersji.

Dlatego też ważną rzeczą jest codzienne powiadomienie (np. w postaci maila) o wszystkich niezatwierdzonych zmianach. Poniżej dwa skrypty, które pomogą nam łatwo i szybko stworzyć takie powiadomienia. Pierwszy skrypt, służy do wyświetlenia na standardowe wyjście (STDOUT) wszystkich niezatwierdzonych zmian w katalogu przekazanym jako argument do skryptu ($1):

#!/bin/bash

# Skrypt wyswietla na STDOUT
DIRECTORY=$1
SUBJECT="[uncommited] "`hostname`
BODY=""
FILE_COUNT=$( svn st $DIRECTORY | awk '{print $2}' | wc -l )

# jesli wszystkie pliki zostaly commitniete to nie mamy co robic i wychodzimy
if [ $FILE_COUNT == 0 ]; then
  exit 0
fi

echo "================== UNCOMMITED FILES ======================="
echo
svn st $DIRECTORY
echo
echo "==========================================================="
echo
echo

for file in $( svn st $DIRECTORY | awk '{print $2}' ); do
  # standardowe bledy przekazujemy do nulla (zazwyczaj blad bedzie wtedy,
  # gdy plik nie jest w svn, a chcemy zrobic diff)
  svn diff $file 2> /dev/null 

  # jesli byl error (zazwyczaj po prostu pliku nie ma w repozytorium
  # svn: status ?) to wyswietlamy ten plik na STDOUT
  if [ $? != 0 ]; then
    echo "Index: $file"
    echo "========================================================"
    cat $file
  fi

  echo
  echo
done

Jak działa ten skrypt? Może najpierw przykład wywołania:

root@www01:/# /usr/local/bin/show_uncommited.sh /etc/
================== UNCOMMITED FILES =======================

M      /etc/apache2/apache2.conf

===========================================================

Index: /etc/apache2/apache2.conf
===================================================================
--- /etc/apache2/apache2.conf	(revision 21)
+++ /etc/apache2/apache2.conf	(working copy)
@@ -198,7 +198,7 @@
 # If you are behind a reverse proxy, you might want to change %h into %{X-Forwarded-For}i
 #
 LogFormat "%v:%p %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
-LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" in %T sec" combined
 LogFormat "%h %l %u %t \"%r\" %>s %b" common
 LogFormat "%{Referer}i -> %U" referer
 LogFormat "%{User-agent}i" agent

Na początku sprawdzamy, czy są jakieś zmiany w konfiguracji w katalogu wskazanym jako argument wywołania skryptu. Jeśli są jakieś niecommitnięte rzeczy to wyświetlamy ich listę a następnie diff każdego z tych plików.

Ok mamy listę zmian, więc teraz przydało by się wysłać do nas tą listę mailem. Poniżej skrypt, który służy do tego celu:

#!/bin/bash

COMMAND="/usr/local/bin/show_uncommited.sh $1"
COUNT=$( $COMMAND | wc -l )
EMAIL="automail@plix.pl"
FROM="Uncommited files "
SYSTEM=$( uname )
SUBJECT="[uncommited] "`hostname`

# jesli wszystko jest commitniete to wychodzimy
if [ $COUNT == 0 ]; then
  exit 0
fi

if [ $SYSTEM == "FreeBSD" ]; then
  $COMMAND | mail -s "$SUBJECT" $EMAIL
else
  $COMMAND | mail -s "$SUBJECT" -a "From: $FROM" $EMAIL
fi

Wyjaśniać za dużo chyba nie trzeba. Jeśli mamy jakieś niezatwierdzone zmiany to wysyłamy standardowe wyjście (STDOUT) mailem na podany w skrypcie adres email. Skrypt przyjmuje jeden obowiązkowy argument – ścieżka do katalog z naszą konfiguracją. Przykładowe wywołanie:

/usr/local/bin/mail_uncommited.sh /etc/

Teraz wystarczy dodać do crona, aby codziennie o północy wysyłana była do nas taka lista zmian:

00 00 * * * root /bin/bash /usr/local/bin/mail_uncommited.sh /etc/ > /dev/null 2> /dev/null

Należy oczywiście pamiętać, aby ustawić prawidłowo zmienną środowiskową PATH tj. żeby znane były ścieżki do svn itp:

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

Teraz kilka uwag jak ulepszyć ten prosty system. Po pierwsze lepiej jest korzystać z git, niż z svn. Git jest rozproszony (możemy np. commitować lokalnie), więc możemy zrobić tak, że tworzymy sobie nową gałąź i testujemy konfigurację. Jeśli wszystko jest ok, to mergujemy, jeśli nie to wracamy do starej konfiguracji. Ja nie korzystam tutaj z gita, ponieważ u nas svn jest lepiej znany przez ludzi. Poza tym svn też daje radę, więc po co kombinować i kazać się wszystkim uczyć czegoś nowego.

Kolejna rzecz to użytkownicy. Co bardziej uważni czytelnicy powinni zauważyć, że w przykładzie, gdzie kolega coś zmienia, a ja muszę poprawić nigdzie nie użyłem słowa konto, czy użytkownik. Zmiany konfiguracji zazwyczaj wprowadzamy z roota, więc wystarczy nam jedno konto (co nie znaczy, że jest to jakoś bezpieczne!). Ja nie lubię strzelać do muchy z armaty – większej funkcjonalności nie potrzebuję, więc wystarczy mi to rozwiązanie.

Hmm warto jeszcze wszystko przetestować lokalnie tzn. odpalić wszystko “z palca” zanim dodamy to do crona. Może się zdarzyć, że nie mamy zainstalowanego svn lub mailx i coś będzie się nam wywalać. Na pierwszy raz cronem też warto potestować.

PS. Dziękuję wszystkim za maile z pochwałami oraz pytaniami czy dalej będę coś pisać. Ostatnio miałem trochę przygód w życiu osobistym (jak to się mówi, można było spieprzyć sobie niechcący życie), więc uporanie się z tymi problemami było dla mnie priorytetem. Teraz wychodzę na prostą, więc będę mieć czas na bloga.

You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

11 Comments »

 
  • hyc says:

    Niegłupi pomysł, ale raczej do mniejszych, niż dużych firm. W tych dużych administrator jest bardziej telefonistką do dostawcy/supportu, a każda zmiana jest potwierdzona kilkusetstronową dokumentacją od dostawcy. Czyż nie jest to chore ? ;) Jak dobrze, że nie jestem administratorem u siebie ;)

  • [...] wiadomości z tego serwisu Follow us on Twitter 43 śledzących RSS Feed 301 czytelników Wersjonowanie konfiguracji systemu 1 głosuj! Systemy kontroli wersji towarzyszą nam już od bardzo dawna. W dzisiejszych [...]

  • kombain says:

    a nie lepiej byłoby stworzyć skrypt, który na koniec dnia będzie commitował wszystkie zmiany? Automatycznie.

  • y3ti says:

    Na początku było takie założenie, aby samo się commitowało. Stwierdziliśmy jednak, aby tego nie robić ponieważ bardzo często klikamy o różnych porach dnia (rano, w ciągu dnia, wieczorem czy wręcz nad ranem). Taki automatyczny commit mógłby wpaść właśnie w momencie, w którym administrator dokonywał by zmian w pliku konfiguracyjnym.

    Kolejna rzecz to, że chcemy mieć “świadome” commity, tylko przetestowanych rozwiązań. Wszelkie niecommitnięte rzeczy powinny zostać przejrzane – a nóż widelec coś się zmodyfikuje samo (update systemu, jakieś backdoory, źle napisane skrypty powłoki itp.)

  • zdzichu says:

    Swego czasu próbowałem trzymać konfiguracje w svn, ale po różnych dziwnych objawach spowodowanych istnieniem wszędzie katalogów .svn dałem sobie spokój. Teraz korzystamy z rcsvers.vim (dodatkowo zmodyfikowanego) który znakomicie zastępuje te wszystkie cuda z svn.

    @hyc – a może jakis przykład w jakich to dużych firmach spotkaleś się z czymś takim?

  • y3ti says:

    @zdzichu: jeśli przeszkadza Ci w każdym katalogu .svn to skorzystaj z innego systemu kontroli wersji np. git. Git tworzy tylko jeden katalog .git w katalogu “root” projektu. Dla przykładu z naszym /etc będziemy mieć tylko /etc/.git/ i nigdzie indziej żadnych zbędnych katalogów. Tak jak pisałem git, czy bzr jest dużo fajniejszy od svn i ma dużo większe możliwości, jednak nam starcza svn. Kolejna rzecz, że trzeba nauczyć ludzi korzystać z innego systemu, jeśli chcemy rezygnować z svn.

  • Scottie says:

    OK, fajny artykuł, ale może jakieś HOW-TO dla zupełnie początkujących?? Takie od podstaw, włączając w to instalację i konfigurację takiego systemu?! Byłbym wdzięczny… :)
    Powiedzmy, że jest taka sytuacja. Jest dziesięciu DBA, którzy zajmują się 100 bazami danych. Na każdej z tych baz są pewne pliki konfiguracyjne (np. pfile.ora, listener.ora, sqlnet.ora), które należałoby wersjonować. Pytanie: jak to zrobić??

  • y3ti says:

    @Scottie: mogę spróbować napisać coś więcej, tylko nie wiem czy jest sens tworzyć takie HOWTO krok po kroku. W sieci jest dużo materiałów na ten temat. Wiedza, którą trzeba mieć, aby odpalić coś takiego:

    1. Obsługa svn z punktu widzenia użytkownika (commit, checkout, add, rm, mv etc.)
    2. Administracja serwerem svn (w moim przypadku apache + mod_dav + svn)
    3. Znajomość środowiska UNIX-owego (cron, bash, etc.)

    Trochę długi by był artykuł, choć nie jest powiedziane, że nie możliwy do zrobienia. Pogoogluj trochę. Jeśli masz jakieś pytania to możesz łapać mnie na priv. Łatwiej mi będzie pomóc Tobie, niż pisać całe howto – chyba, że więcej osób jest zainteresowanych.

    Co do Twojego pytania o to jak trzymać konfigurację dla tych baz danych to też powstaje problem, czy mają one być wszystkie takie same na każdym z serwerów. Moje rozwiązanie dotyczyło N serwerów, przy czym każdy z nich pełnił inną funkcję (loadbalancer, firewall, db, app, cache, monitoring itp. itd.). Opisz dokładniej problem, to wtedy będę mógł Ci w stanie pomóc.

  • Scottie says:

    Dobra, dałem radę – Google jest b. pomocne, o ile wie czego się szuka. Wpisałem frazę, dosłownie: “apache + mod_dav + svn” i to wystarczyło. Thx!! :-)

    Co do mojego przypadku… Uprośćmy sytuację i powiedzmy, że jest 2 DBA, którzy mają wydzielony serwer Linux z Apache i zainstalowanym SVN-em. Administrują sobie dwoma RDBMS Oracle na dwóch różnych serwerach Unix. Oczywiście konfiguracja baz danych jest inna (i przeważnie jest inna; zwykle inne są nazwy, ścieżki, ale przede wszystkim inne są parametry pamięciowe, które wymagają tuningu). Jeden z DBA idzie na urlop, a drugi pod jego nieobecność zmuszony był dokonać zmian w pliku konfiguracyjnym. Koleś wraca z wakacji, co prawda opalony, ale stopy odmrożone, bo był nad Bałtykiem ;-) i tu SVN wysłał do niego maila (?), że się coś zmieniło. Tak przynajmniej ja to widzę i jakoś to sobie tak wyobrażam…

  • y3ti says:

    Dokładnie tak :)

  • Mariusz says:

    fajny artykulik. Podchwyciłem Twój pomysł i przepisując go do ePN podłączyłem do nagiosa. Teraz odpowiedzialny admin dostaje sms lub wiadomość na jabberka o ewentualnych zmianach. Dzięki :)

 

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>