Backupeer v0.01
Zaczęło się banalnie od rozbudowy parku maszynowego webankiety... kiedy już całość pracowała pełną parą przyszedł czas na backupy danych. Ponieważ taka zmiana to jedyna realna szansa na wypróbowanie nowych rozwiązań postanowiłem poszukać nowego narzędzia do tego zadania. Istotnym argumentem za zmianą było także to, że zmieniły mi się wymagania stawiane przed systemem backupów, a stare skrypty szelowe były mało elastyczne (i średnio czytelne) - nic więc prostszego, znaleźć zainstalować i voila...
Niestety, poległem już na pierwszym etapie, oprogramowania do robienia kopii bezpieczeństwa jest chyba tyle i frameworków webowych w Javie, przejrzałem ileś-tam-projektów, najbliżej podium znalazł się backup-gem. Przyjrzałem się mu dokładniej i trochę zapał mi minął. Okazało się, że realizacja moich założeń będzie wymagała napisania sporej ilości kodu rozszerzającego backup-gem. Zirytowany tym stanem rzeczy postąpiłem jak rasowy geek... postanowiłem stworzyć własne, najlepsze na świecie (a jakże! :)) 1e10+1 rozwiązanie do obsługi backupów - tak narodził się Backupeer.
Założenia
Oto kryteria których początkowo używałem poszukując gotowego rozwiązania, a które ostatecznie przekształciły się w założenia projektowe:
- Backupeer ma być prosty w konfiguracji, tylko niezbędne minimum parametrów.
- Backupeer ma służyć do robienia kopii zarówno bazy danych jak i plików z filesystemu.
- Backupeer ma obsługiwać zarówno kompresję danych jak i ich szyfrowanie.
- Backupeer ma umożliwiać obsługę wielu miejsc składowania kopii bezpieczeństwa.
- Backupeer ma być łatwy w rozbudowie.
- Backupeer ma obsługiwać rotację backupów.
- Backupeer nie musi przesadnie kontrolować ilości przesyłanych danych.
- Backupeer ma być prostym narzędziem.
Dodatkowo byłoby przyjemnie gdyby całość nie wymagała zapoznania się ze 100 stronicowym manualem (z prozaicznej przyczyny - któż miałby stworzyć ów manual??)
Leżąca klepsydra
Przepływ danych podczas działania większości narzędzi do robienia kopii bezpieczeństwa wygląda w sposób zbliżony do rysunku poniżej:
->------\ /======>=
pliki, ->-----\ \ /=======>= lokalna kopia
zrzuty z baz,->------+-+->- outgoing/ =>===+=======>= zdalne serwery
konfiguracje ->-----/ / \=======>=
->------/ \======>=
Dane źródłowe które mają być zabezpieczone trafiają do jednego miejsca (katalog outgoing/), poddawane są obróbce (pakowanie, szyfrowanie), a następnie są rozsyłane do wszystkich miejsc docelowych. Po zakończeniu rozsyłania danych zwartość outgoing/ jest usuwana.
Dlaczego leżąca klepsydra? Patrząc na ten rysunek z boku przypomina mi on przewróconą klepsydrę :)
Od źródła do celu
Prace rozpocząłem od rozmyślania jak najwygodniej, albo wręcz idealnie ;) byłoby definiować co ma byc backupowane i dokąd ma trafiać... i wpadłem na rozwiązanie genialne w swej prostocie. Do definiowania danych posłużyłem sie URI. Jak to wygląda w praktyce? Najważniejsza część recepty na backup wygląda tak:
-
SOURCES=[
-
'file:///path/to/files',
-
'postgresql://username@host/database'
-
]
-
TARGETS=[
-
'file:///home/daniel/storage',
-
's3://sxAWdas:azs2123as@bucket/backup_store',
-
'sftp://user:password@host/home/target/backup_store'
-
]
Definiuję więc źródło i cel tworząc URI w którym podaje protokół (postgresql://) oraz jego dodatkowe parametry (nazwa użytkownika, maszyna i nazwa bazy danych). Efektem ubocznym takiego podejścia przeogromna elastyczność. Stworzenie własnego protokołu obsługującego specyficzną potrzebę to dopisanie kilkunastu linii w Rubym. Oczywiście obsługa źródła i celu to dwie odrębne sprawy, tak też jest z ich obsługą, przykładowo protokół file:// obsługiwany jest przez dwie klasy FileSourceProtocol i FileTargetProtcol.
Moje potrzeby wymagały powstania następujących protokołów:
Dla źródeł:
- lokalny plik:
file://[/]path - zrzut danych z PostgreSQL:
postgresql://[username]@host[:port]/database
Dla celów:
- lokalny plik:
file://[/]path - SFTP:
sftp://username[:password]@host/path[?identity_file=/path/to/key] - Amazon S3:
s3://access_key_id:secret_access_key@dns-like-bucket[/path_like_bucket]
Akcja!
O ile obsługa protokołów dla celów sprowadza się właściwie do wysłania gotowych danych do miejsca gdzie mają być składowane, o tyle obsługa protokołów źródłowych odpowiada za trochę więcej zadań. Przypomnę, że jednym z wymagań jest szyfrowanie i kompresja danych, więc także te zadania muszą być realizowane przez kod obsługujący protokoły źródłowe. Wykorzystałem tu pomysł potoku (pipeline) rozbijając te zadania na akcje w których wyjście jednej stanowi wejście następnej. Tak więc rozpoczynamy od akcji :content - jej rola jest pobranie danych źródłowych (w zależności od protokołu może to być wykonanie dumpa z bazy, TARowanie katalogu itd itd). Następnie odpalana jest akcja :compress pakująca dane za pomocą bzip2, a na końcu akcja :encrypt szyfrująca całość za pomocą gpg.
Rotowanie danych
Do omówienia pozostała jeszcze kwestia rotowania danych. Chodzi tu o usuwanie starszych kopii bezpieczeństwa. Ludzkość dopracowała się kilku sposobów postępowania w tym przypadku. Najbardziej popularnym jest chyba algorytm nazywany dziadek-ojciec-syn (GFS). W skrócie chodzi o to, że dane składowane są w hierarchicznej strukturze rozpoczynając swój żywot jako synowie. Po spełnieniu określonego warunku stają się ojcami, a później dziadkami. Dane które nie zostały przeniesione wyżej w hierarchii są usuwane. Warunkami promocji mogą być kryteria czasowe (np. backup z każdego piątku staje się ojcem) albo kryteria związane z ilością (np. co 4 ojciec staje się dziadkiem).
Tyle teoria, jak zaimplementowałem tą strategię w Backupeer? Hierarchię tworzą trzy poziomy daily, weekly, monthly co oddaje przeznaczenie każdego z poziomów. Każdy tych poziomów w miejscu docelowym jest reprezentowany przez osobny katalog w którym znajduje się katalog z data zawierajacy kopię danych.
-- target_dir/
+--- daily/
| 2007-11-13/
| ...
| 2007-11-19/
+--- weekly/
| 2007-11-12/
| 2007-11-19/
+--- monthly/
2007-11-01/
2007-12-01/
Taka implementacja daje mi kilka dodatkowych plusów: dopuszczalne jest wykonywanie kilku backupów jednego dnia - wszystkie wylądują w tym samym katalogu z dniem, zawsze najświeższy backup jest w katalogu daily. Jest jeszcze pewien minus, otóż ponieważ zależy mi na tym aby najnowsza kopia zawsze była w daily, tworzenie kopii weekly i monthly wymaga ponowego wysłania danych na serwer docelowy. Najgorszym więc przypadkiem jest taki gdy jedna kopia dzienna jest promowana zarówno na kopię tygodniową jak i miesięczną - wówczas te same dane będą wysłane 3 razy;( Wada ta wynika to z faktu, że większość protkołów uzywanych do transmisji danych (np. sftp, ftp itd) nie obłsuguje tworzenia kopii na docelowym serwerze. Bardziej jednak zależy mi na tym aby daily zawierało zawsze ostatnią kopie niż na tym aby przesyłać minimalną ilość danych. Domyślne parametry rotacji tworzą kopie weekly w każdy poniedziałek, a kopie monthly każdego pierwszego dnia miesiąca. Rysunkowo działanie rotacji wygląda następująco:
outgoing/ ->-*---->-----*---> daily/ [][][][][][][] |-> delete
| | \____________/
| daily_to_weekly_on days_to_keep
| |
\|/ +---> weekly/ [][][][] |-> delete
| \______/
weekly_to_monthly_on weeks_to_keep
|
+--------------> monthly/ [][][][]...
Backupeer v0.01
Kod Backupeera powstał w nieco ponad dwa dni, dlatego postanowiłem nie nadawać mu zbyt wielkiego numeru wersji ;) Sam korzystam z niego 'na produkcji' od dnia trzeciego i do tej pory działa bardzo dobrze. Backupeer miał być początkowo projektem wewnętrznym dla webankiety uznałem jednak, że wyszedł mi na tyle fajnie, że może komuś z Was także się on przyda. Ponieważ jednak nie mam tej pewności udostępniam go na razie tylko jako archiwum. To czy Backupeer rozwinie się dalej stając się np. gemem zależy chyba głownie od Waszego zainteresowania (i mojego wolnego czasu).
Do pełnej obsługi wszystkich protokołów wymagana jest instalacja następujących gemów:
gem install -y net-ssh net-sftp aws-s3
Oprócz tego w systemie muszą oczywiście istnieć komendy cp, tar, bzip2, gpg. Po rozpakowaniu archiwum możemy uruchomić przykładową receptę
ruby example_receipt.rb
Jej efekt powinien być zbliżony do tego:
-
-- CONTENT action URI: file://test/fixtures/sub ----------------------------------------------
-
-- COMPRESS action URI: file://test/fixtures/sub -------------------------------------------
-
-- ENCRYPT action URI: file://test/fixtures/sub --------------------------------------------
-
-- CONTENT action URI: file://test/fixtures/compressed.bz2 -----------------------------------
-
-- COMPRESS action URI: file://test/fixtures/compressed.bz2 --------------------------------
-
-- ENCRYPT action URI: file://test/fixtures/compressed.bz2 ---------------------------------
-
-- CONTENT action URI: file://test/fixtures/file.txt -----------------------------------------
-
-- COMPRESS action URI: file://test/fixtures/file.txt --------------------------------------
-
-- ENCRYPT action URI: file://test/fixtures/file.txt ---------------------------------------
-
-- TRANSFER action URI: file://storage -------------------------------------------------------
-
CONNECT
-
MKDIR /home/daniel/backupeer/storage/daily
-
MKDIR /home/daniel/backupeer/storage/weekly
-
MKDIR /home/daniel/backupeer/storage/monthly
-
MKDIR /home/daniel/backupeer/storage/daily/2007-11-13
-
COPY /home/daniel/backupeer/outgoing to /home/daniel/backupeer/storage/daily/2007-11-13
-
LIST /home/daniel/backupeer/storage/daily
-
LIST /home/daniel/backupeer/storage/weekly
-
LIST /home/daniel/backupeer/storage/monthly
Udostępniam Backupeera nieodpłatnie na liberalnej licencji MIT. Pamiętaj proszę, że korzystasz z mojego oprogramowania na swoją własną odpowiedzialność.
[ruby server tool webankieta]








ciukes said,
listopad 14, 2007 @ 01:41
Nic tak nie dowartosciowuje jak wymyslenie okraglejszego kola.
Radarek said,
listopad 14, 2007 @ 02:20
Zdaje się niezły kawał roboty, nawet jeśli to jest wymyślanie koła na nowo :).
Dobrze by było jednak zbudować backupeera jako gem. M.in. zdefiniujesz wtedy zależności od innych gemów. Nie widzę także powodów by nie wrzucić biblioteki na rubyforge. Jeśli to zrobisz to istnieje szansa, że ktoś kiedyś sam coś do tego dopisze, a tak to raczej wątpliwe :).
identor said,
listopad 14, 2007 @ 05:14
ERROR: While executing gem … (Gem::GemNotFoundException)
Could not find net-sft (> 0) in any repository
literowka?ojakigemchodzilo?
identor said,
listopad 14, 2007 @ 05:26
sorry_ale_spacja_mi_nie_dziala:
co_z_restorem_z_takiego_backupu?_jak_go_zrobic?
pozdrawiam!
daniel said,
listopad 14, 2007 @ 14:25
@ Radarek
Moim zdaniem brakuje troche kody zeby zrobić gema - chodzi o prostotę korzystania. Głowną potrzebną rozbudową jest IMHO to aby recepta byl bardziej podobna do Rakefile\’a czy recepet capistrano i uruchamiana np tak:
$> backupeer recepta
W wolnej chwili postaram się to dodać - wówczas istotnie przed gemizacją nie będzie już przeszkód.
@identor
Dzieki za informacje, zabrakło \’p\’ w nazwie gema :) juz poparwione.
Odzyskanie informacji wymaga jej odszyfrowania i rozpakowania, przykladowa recepta korzysta z kluczy (*przykladowych*) które są w test/fixtures/keys, najprościej jest zaimprtować klucz prywatny
$> gpg —import test/fixtures/keys/private.key
a pozniej po prostu rozszyfrować:
$> gpg -r Backupeer -o OUTFILE.bz2 —decrypt INFILE.bz2.gpg
zawadaa said,
listopad 16, 2007 @ 16:09
A nie łatwiej wykorzystać bardzo sympatyczny system backupów jakim jest Bacula (bacula.org). Tym można dokonać kopii farmy serwerów (bardzo skalowalne ustrojstwo) na różne miejsca składowania kopii bezp. Szyfrować i kompresować w locie (przy składowaniu na nowe napędy LTO-4 już nie ma takiej potrzeby). Poprzez mechanizm run-before można zrobić dump bazy i zgrać tylko ten dump. konfiguracja jest naprawdę prosta. Jest też sympatyczne narzędzie okienkowe - BAT. IMHO świetna sprawa. Polecam.
daniel said,
listopad 16, 2007 @ 23:06
@zawadaa
Bacula była jednym z mocnych liderów, odpadła m.in dlatego, że:
*) system backupów mialbyć “self contained” - mial nie zalezec od zewnetrznych serwerow, zeby w wypadku awarii maszyny z “nadzorca” backup dalej byl wykonywany
*) Bacula jest mimo wszystko skomplikowana (director, storage daemon, file daemon, woluminy, urzadzenia, schedule - duzo tego);
*) nie bardzo można liczyć na proste odtworzenie - nie mozesz sobie po prostu skopiowac/sciagnac pliku z sieci i na nim dzialac; nawet uruchomienie GUI to duzo wieksza “zabawa”
*) szyfrowanie w wypadku Baculi jest natywnie wspierane pomiedzy klientem a demonem skladujacym dane; ten drugi (ktory tak naprawde trzyma calosc danych) jest uwazany za “zaufany” i w srodku nic nie jest zaszyfrowane; zeby zrobic kopie na zewnatrz trzeba woluminy oddzielnie zaszyfrowac i przeslac w zdalne miejsce
*) jednym z wymagań była prostota - nie potrzebne jest mi więc narzedzie ktore pozwala postawic z backupu setke maszyn w ciagu godziny
Aby oddać sprawiedliwośc powyższe argumenty są kompilacją moich uwag i uwag zgłoszonych przez Pawła (administratora webankiety)
zawadaa said,
listopad 17, 2007 @ 00:11
@daniel
ad1) oczywiście w przypadku baculi musisz postawić temp Directora
ad2) coś za coś ;-)
ad3) po prostu (czyli choćby tak jak robi to rdiff-backup - też ciekawy ale taki “malusi”) to nie (znaczy nie, że jest to trudne/zaawansowane dla admina)- ale odzyskać/znaleźć plik co to ktoś nie do końca wie jak się zwał to… miodzio :-)
ad4) oj - nie doczytałeś albo masz stare dane ;-) bacula od wersji 2.2.0 wspiera szyfrowanie (nie tylko szyfrowanie transmisji). Pomiędzy (transmisja) oczywiście też (na wypadek “zdalnych” backupów, ale też szyfrowanie wolumenów. Czyli: ktoś Ci ukradnie dysk z backupami i zyskał… dysk - na odszyfrowanie danych straci duuużo czasu ;-)
ad4) ten argument oczywiście nie podlega dyskusji - Bacula to _system_ backupów - nie zabawka. Każdy potrzebuje czegoś innego bo i potrzeby są różne. :-)
Paweł J. Sawicki said,
listopad 19, 2007 @ 14:13
// Stawia sie wezwany do tablicy :)
@zawadaa
ad. ad. 4)
OK, zwracam honor - wspiera natywnie… ale:
“The implementation does not encrypt file metadata such as file path names, permissions, and ownership.”
Lekki problem moze byc np. w momencie gdy zrobimy backup folderu z sesjami, ktos sie dobierze do kopii zapasowej i odczyta np. nazwe katalogu zawierajacego dane dla danego odwiedzajacego… tyle, ze to bardziej wydumka i szukanie dziury w calym chyba :) W sumie jak juz szyfruja, to mogliby wszystko. To, ze wtedy director musi trzymac wiecej informacji z mapowaniem wlacznie (bo kopie byly by pewnie przez jakis guid wtedy identyfikowane) to raczej maly problem IMO.
Jak sam napisales to nowa funkcjonalnosc… Skoro mam np. przerzucac dane na jakis niezaufany serwer to wole jednak powierzyc moje dane sprawdzonemu gpg :)
Zeby nie bylo :) Osobiscie uzywam baculi i bardzo dobrze mi sie sprawdza. Potrafi zrobic kopie nawet po jakims nedznym dsl-u, a dwa skrypty na krzyz i mamy przerzucanie woluminow na S3… jak dla mnie wiecej nie potrzeba. Zobacze jeszcze jak to dokladnie wyglada z tym szyfrowaniem, bo moze rzeczywiscie bedzie wystarczajace.
daniel said,
listopad 19, 2007 @ 15:11
@zawadaa && @Paweł
ej noo moglibyście choć powiedzieć, że ten Backupeer nie jest taki zły :)))))))))))))
Dzięki za ciekawą dyskusję w temacie - jak są jeszcze jakieś niuanse wrzucajcie :)
Paweł J. Sawicki said,
listopad 19, 2007 @ 17:27
@daniel
No jest dobry, nawet bardzo :)
kodz said,
listopad 24, 2007 @ 20:55
Daniel, wspanialy backuper!!!!?!?!
Jarmark.org » said,
luty 6, 2008 @ 15:55
[…] Amazon spiskuje? Od udostępnienia publicznie mojego narzędzia do backupów mineło już parę miesięcy. Backupeer w tym czasie dziarsko backupował dane z webankiety bez najmniejszych problemów, dzień w dzień rozsyłając backupy zgodnie z receptą do kilku różnych źródeł (w tym do S3 Amazona). Tak było do początku lutego… Począwszy do 1-go zaczęły występować problemy z przesyłaniem danych do S3. Zamiast więc danych na Amazonie otrzymywałem komunikat ‘connection reset by peer’ w logach. Co dziwniejsze szybkie śledztwo wykazało, że dotyczy to tylko większych plików. Od kilku więc dni Backupeer zapaczowany na tą okoliczność próbuje przepchnąć dane do Amazona aż do skutku - i się działa, ale czasem za 30 próbą. Przyczyn ten sytuacji przyznam nie rozumiem - z techcznicznego punktu widzenia wszystko powinno być ok. Przyszła mi do głowy nieco spiskowa teoria :) Amazon ma swoje Data Centers m.in w Europie i właśnie te położone w UE wyróżniają się wyższymi cenami. Zastanawiam się więc czy nie jest to delikatna sugestia ze strony Amazona abym się domyślił, że korzystając z Data Center w UE będzie wszystko po staremu…. Na szczęście jestem mało domyślny :) [] Spodobało się? Podziel się z innymi: These icons link to social bookmarking sites where readers can share and discover new web pages. […]