Deployment kilku instancji/wersji jednej aplikacji - Capistrano?

Najpierw kontekst: używam Rails do rozwoju aplikacji webowej, ale nie jako witryny WWW, tylko narzędzia dla mojej firmy. Czyli piszę aplikację, a nie serwis. Pojawiła się potrzeba użycia mojej aplikacji także w drugiej firmie, ale - oczywiście, jak to w życiu bywa - z drobnymi modyfikacjami w stosunku do wersji pierwotnej. Zastanawiam się - zanim te dwie wersje mi się rozjadą - jak elegancko obsłużyć problem tych drobnych różnic.
Generalnie chodzi o to, że dwie wersje różnią się nieco templatem (inne logo firmy, itd.), a także configiem (obydwie instancje chodzą na tym samym serwerze na różnych portach, oczywiście inna baza danych/user/pass). Okazuje się oczywiście, że zaczynają się pojawiać także inne różnice, więc pewne parametry/dane zakodowane na twardo w modelach będę rozdzielał do jakiegoś modelu Konfiguracja lub po prostu wczytywał z bazy. I tak dalej, na pewno to znacie.

I teraz pytanie, droga wycieczko: jak to sprawnie rozwiązać z punktu widzenia ciągłego uaktualniania aplikacji i deploymentu. Dotychczas poznając Rails olewałem tematy takie jak Capistrano, bo nie było mi to potrzebne. Owszem, stosuję Subversion do trzymania kodu, ale ta druga wersja aplikacji nie istnieje tam (jeszcze?) jako jakiś fork czy coś. Jak dotąd na serwerze produkcyjnym mam dwie “working copies”, jedna oryginalna, druga z niewielkimi modyfikacjami opisanymi powyżej (template, lighttpd.conf, database.yml i zmieniony nieco jeden model). Kiedy na tej zmienionej WC robię “update to newest” to Subversion elegancko dba o uaktualnienie aplikacji z zachowaniem modyfikacji specyficznych dla drugiej instancji aplikacji. Ale oczywiście nie jest to docelowo dobre rozwiązanie, bo np. te wszystkie zmiany nie są zapisane nigdzie w repozytorium, więc jak kiedyś szlag trafi working copy na serwerze produkcyjnym to będę musiał te zmiany odtworzyć z notatek, backupu - czujemy wewnętrzne fuj.
Przeczytałem sobie ogólnie opis działania Capistrano i jak na razie nie widzę, żeby w tej sprawie mógł mi pomóc - ale może się mylę? Mam jeden serwerek na obydwie instancje, na nim MySQL z dwoma bazami produkcyjnymi itd - więc nie mam skomplikowanych potrzeb w zakresie deploymentu, dlatego sądzę, że Capistrano mi nie pomoże.

Być może wystarczającym rozwiązaniem jest dla mnie skrypt deploymentowy z użyciem ‘patch’, który na oryginalny kod z repozytorium nakłada niewielkie zmiany? Oczywiście przy założeniu, że pozostałe różnice w zachowaniu aplikacji wyrzucę do jakiejś konfiguracji. Może powinienem także zrobić jednak jakiś fork w repozytorium? Ale jak, w końcu różnice są drobne, więc nie chciałbym spędzać ciągle czasu na merge’owaniu zmian z trunku do jakiegoś brancha.

Co sądzicie?

Propozycja.

Jesli mozesz rozdzielic aplikacje na glowna i poszczegolne czesci to moze byc dla ciebie rozwiazanie problemu.

  1. Aplikacja root
  2. Poszczegolne katalogi: config/firma1, config/firma2, db/firma1, db/firma2 , app/views/firma1, app/views/firma2

Zrob patcha dla rails aby czytal katalogi dla firmy1 i dla firmy2.

Jak to rozwiazac?
Sprawa jest b. prosta. Zdecyduj tylko jak bedziesz rozroznial wywolania gdy jedna firma lub druga korzysta z aplikacji.

Nastepnie patch, uzylem podobnego rozwiazania dla develpowania aplikacji rownolegle przez kilka osob (developer, webmaster, tester i oczywiscie production)

Podam dla rozdzielenia views, (dla db i config pozukam w kodzie railsa jak bede mial czas i oczywiscie zadowoli cie to proste i skuteczne rozwiazanie):

[code]module ActionView

class Base
alias_method :__render_file, :render_file

def render_file(template_path, use_full_path = true, local_assigns = {})
  if use_full_path
    if firma1 # przyklad
        template_path = 'firma1/' + template_path
    elsif firma2 # przyklad
        template_path = 'firma2/' + template_path
    end
  end
  return __render_file(template_path, use_full_path, local_assigns)
end

end
end[/code]
template_path - teraz bedzie wygladac views/firma1 lub views/firma2

Dzieki temu bedziesz mogl w prosty sposob miec 3 subwersje.
1na dla aplikacji root (wykluczysz wybrane katalogi)
2ga i 3cia tylko dla aplikacji firm (tylko wybrane katalogi)

Taka jest moja propozycja, abys nie rozjechal sie z aplikacja.

Pozdrawiam

Nie wiem na ile Ci sie to przyda, ale sa takie rozwiazania jak zdecentralizowany system kontroli wersji. Byc moze SVK bylby odpowiedni lub inne Arch, Darcs …

W Subversion i CVS istnieje idea tzw. ‘Vendor branches’ http://svnbook.red-bean.com/en/1.1/ch07s05.html
http://sean.treadway.info/articles/2005/04/12/keeping-in-sync-with-typo

Oczywiscie jest z tym zabawa :slight_smile:

[quote=tczubinski]1. Aplikacja root
2. Poszczegolne katalogi: config/firma1, config/firma2, db/firma1, db/firma2 , app/views/firma1, app/views/firma2[/quote]
To na pewno dobry pomysł, jeśli poszczególne wersje rozjadą się znacznie w wyglądzie. Dzięki. Ale może na razie spróbuję jednak wyciągnąć pewne zachowania, które są nieporządane przez drugą firmę (a które są obecnie zakodowane na sztywno) do jakiejś konfiguracji, którą umieszczę np. /config/ albo po prostu jako model Configuration (nazwa Config jest już używana przez Rails).
Do “ręcznego” pamiętania pozostaną więc tylko pliki specyficzne dla konkretnego deploymentu (cóż za piękne polskie słowo), jest ich tylko kilka i nie będą się (raczej) zmieniać w toku rozwoju aplikacji.

Co prawda wieczór, podczas którego poznałem podstawy Subversion, uważam za jeden z najlepiej zainwestowanych wieczorów przy komputerze :slight_smile: ale wolałbym uniknąć zmieniania systemu kontroli wersji, z wielu powodów. Pomyślę nad “verdor branches”, choć z lektury Red-bean wynika, że to spore armaty jak na potrzeby jednoosobowej orkiestry, którą stanowię :slight_smile:

Ja wiem, ja wiem !:slight_smile:

Subversion, zrobic branch i polaczyc to z SVNmerge.

troche o svnmerge masz tutaj
http://blog.temp.rsc.pl/2007/01/01/jak-sobie-ulatwic-pisanie-aplikacji/

samo capistrano nie pomoze.

Ten patch moze Ci rosnac w nieskonczonosc jezeli beda coraz to dalej idace zmiany.

Jak użyjesz SVNmerge i będziesz sie stosowal do zasady - jedna funkcja, jeden commit to merge bedzie sie sprowadzal do:

svnmerge merge -r 237 svn commit -m "MFC - r237 from trunk"
i wiola.

Sam mialem teraz taki projekt. Wyszliśmy od jednego site’u, a teraz jest ich piec. Ogolnie podobne, ale zbudowane na jednej podstawie. Dopoki nie uruchomilem SVNmerge to rzeczywiscie reczne sledzenie zmian i ich nanoszenie było trudne. Zwłaszcza ze wersje rozjechaly sie dosc wczesnie i pozniej bylo duzo bugfixow.

PS. Ktos zaproponowal Vendor Branches - to jest mechanizm przeznaczony do innych zastosowan. To czego Ty potrzebujesz to:
http://svnbook.red-bean.com/en/1.1/ch04s02.html

PS2. Jakbys sie zdecydowal na svnmerge i bedziesz mial z tym problemy, daj znac. Napisze i opublikuje tutorial do tego.

[quote=ruthrsc]Ja wiem, ja wiem !:slight_smile:

Subversion, zrobic branch i polaczyc to z SVNmerge.[/quote]
Dzięki. Twój wpis w blogu na temat SVNmerge, dev-Todo przeczytałem już wcześniej. Chyba mnie zaraz ukamieniujecie, bo odrzucam wszelkie propozycje :smiley: ale nadal uważam, że bedę starał się uniknąć branchowania, przynajmniej dopóki różnice między dwoma wersjami są niewielkie, a praca nad aplikacją nie będzie moją główną pracą dzienną. Póki co będę wszystkie różnice wrzucał do konfiguracji. Muszę tylko zdecydować jak tę konfigurację zapisać: czy po prostu do /app/controllers/application.rb, czy do osobnego modelu (ale konfiguracja może być zaprogramowana w kodzie, a nie ładowana z bazy!) czy po prostu walnąć jakiś ‘require’ gdzieś w application.rb, ładujący plik z konfiguracją zapisaną jako stała tablica czy hash. Co jest najbardziej Rails-way?

No to sie stanie praca dzienna jak będziesz musiał bugfixy przerzucać miedzy wersjami :slight_smile:

[quote=komor]Póki co będę wszystkie różnice wrzucał do konfiguracji. Muszę tylko zdecydować jak tę
[…]
Co jest najbardziej Rails-way?[/quote]
No jak już musisz tak (Klientttt naśśśśś pańńńńńńń :slight_smile: to proponuje użyć pluginu (btw: naszego forumowego kolegi ) AppConfig.

http://svn.jarmark.org/rails/app_config

Kiedy właśnie chcę doprowadzić do tego, że wersja kodu będzie jedna, a zmienne zachowania będą zależne od konfiguracji, ustalanej w czasie deploymentu.

O, fajne, to chyba to co trzeba mi do szczęścia. :slight_smile: Dzięki!

Potwierdzam iz zastosowanie SVNmerge pomoze rozwiazac.

Z zasady podchodze do spraw, iz trzeba szukac jak najprostszych rozwiazac, jak wiadomo to chyba jest najtrudniejsze. :wink:

A jesli "… zachowania będą zależne od konfiguracji, ustalanej w czasie deploymentu. " to chyba faktycznie powinienes sie skupic glownie na rozwiazaniu konfiguracji, wystarczy nawet yaml czy serializowanie konfiguracji do bazy.

Potwierdzam iz zastosowanie SVNmerge pomoze rozwiazac.

Z zasady podchodze do spraw, iz trzeba szukac jak najprostszych rozwiazac, jak wiadomo to chyba jest najtrudniejsze. :wink:

A jesli "… zachowania będą zależne od konfiguracji, ustalanej w czasie deploymentu. " to chyba faktycznie powinienes sie skupic glownie na rozwiazaniu konfiguracji, wystarczy nawet yaml czy serializowanie konfiguracji do bazy.[/quote]
Dla mnie stwierdzenie “I teraz pytanie, droga wycieczko: jak to sprawnie rozwiązać z punktu widzenia ciągłego uaktualniania aplikacji i deploymentu.” oznacza developerke dwoch wersji aplikacji niezaleznie. Pozatym nie wiem czy jest sens wszystko opakowywac w konfiguracji. Teoretycznie można w każdym kontrolerze dorabiac case z odpowiednim zachowaniem, podobnie jak w modelu - tylko po co ?

No chyba że zmiany dotyczą adresów email i tego typu rzeczy.

[quote=ruthrsc]Dla mnie stwierdzenie “I teraz pytanie, droga wycieczko: jak to sprawnie rozwiązać z punktu widzenia ciągłego uaktualniania aplikacji i deploymentu.” oznacza developerke dwoch wersji aplikacji niezaleznie. Pozatym nie wiem czy jest sens wszystko opakowywac w konfiguracji. Teoretycznie można w każdym kontrolerze dorabiac case z odpowiednim zachowaniem, podobnie jak w modelu - tylko po co ?

No chyba że zmiany dotyczą adresów email i tego typu rzeczy.[/quote]
Nie trzeba w każdym kontrolerze żadnych case, chodzi o drobiazgi w jednym modelu i kilku widokach, póki co. Już tłumaczę dokładniej.

Bo widzisz w momencie stawiania pierwotnego pytania sprawa była otwarta - czy zrobić dwa branche czy jednak ograniczyć się do czegoś prostszego w ramach jednego branchu (konfiguracja lub zautomatyzowanie patchowanie drobnych różnic w kodzie). Dzięki waszym poradom, m.in. Twoim (dzięki!), podjąłem decyzję, że jednak nie będę robił branchy, gdyż pałowanie się z tym (mimo ułatwień SVNMerge) nie jest opłacalne przy tych niewielkich różnicach między dwoma wersjami, które planuję utrzymywać.
Kiedy/jeśli projekt się rozwinie, to wolałbym zainwestować czas w przerobienie aplikacji tak, żeby miała wymienne moduły, co zresztą w przypadku Railsów (model MVC) nie wydaje się takie trudne. Ale to wszystko wtedy, kiedy moja aplikacja będzie potrzebna komuś z zewnątrz, a nie tylko mojej firmie i wspólnikom. Póki co zachcianki użytkowników będą kanalizowane do konfiguracji, bo chodzi o naprawdę niewielkie modyfikacje.

Dziękuję wszystkim za pomoc :slight_smile: