Jak już wiemy GitLab posiada spore możliwości, jeżeli chodzi o obsługę sporej ilości użytkowników. W poprzednim wpisie wspomniałem, że po zwiększeniu vCPU czy pamięci operacyjnej RAM, możemy osiągnąć duży przeskok w postaci obsługiwanych użytkowników jednocześnie. Przy zastosowaniu już 4 rdzeni i 8GB RAM GitLab jest w stanie obsłużyć 2000 użytkowników. Idąc dalej 16 rdzeni i 32 GB RAM to już około 8000 użytkowników. Należy jednak pamiętać o dyskach na jakich leży GitLab. Przy większej ilości użytkowników warto się zastanowić czy nie zainwestować w dyski SSD. Jeżeli podane wielkości są dla nas wystarczające, sprawa wygląda na załatwioną.
W przypadku gdy chcemy zadbać o wysoką dostępność podczas awarii maszyny czy też serwerowni, możemy wykorzystać wbudowaną w GitLaba geo replikacje. Replika GitLab’a może być wykorzystywana do klonowania i pobierania projektów. Takie rozwiązanie przyspiesza pracę z dużymi repozytoriami na duże odległości. Gdy geo replikacja jest włączona, oryginalna instancja działa jako primary node, a zreplikowana jest w trybie read-only i działa jako secondary node.
Zasada wydaje się być prosta. Niestety są pewne ograniczenia i rzeczy, które musimy wykonać ręcznie, ale o tym za chwilę.
Jak wspomniałem wcześniej, cała architektura bazuje na primary i secondary node. Zapisy mogą być wykonywane tylko w pierwszym node. W drugim nodzie baza danych jest replikowana za pomocą tzw. Streaming replication (SR). Jeżeli wykorzystujemy serwer LDAP, również powinien być on replikowany na potrzeby Disaster Recovery. Do synchronizacji z pierwszym nodem wykorzystywana jest autoryzacja zabezpieczona przez JWT (JSON Web Token). Repozytoria są klonowane/aktualizowane przez Git za pomocą protokołu HTTPS. Załączniki, obiekty LFS (Lagre File Storage) i inne pliki są pobierane również za pomocą HTTPS, ale w tym przypadku wykorzystywane jest do tego interfejs API.
W przypadku najnowszej wersji GitLab’a istnieje kilka ograniczeń, o których należy pamiętać przy wybieraniu tego typu architektury. Oczywiście jeżeli używacie starszych wersji te ograniczenia mogą się różnić. Pierwszym ograniczeniem jest przekierowanie dla HTTP lub proxy (SSH) zapytań z drugiego do pierwszego noda podczas wykonywania git push. Drugie ograniczenie jest takie, że pierwszy nod musi być online, aby logowanie OAuth działało. Ograniczenia dotyczą również samej replikacji. Replikacji nie podlegają m.in. strony GitLab’a oraz sam GitLab nie dba o replikację treści w pamięciach obiektowych. W przypadku korzystania z Amazon S3 możemy wykorzystać do tego CRR (Cross-Region Replication), a w przypadku Google Cloud Storage możemy wykorzystać Multi-Region Storage. W innych przypadkach musimy korzystać z harmonogramu zadań i skryptów synchronizujących zawartość.
Zalecanym sposobem instalacji i konfiguracji georeplikacji jest użycie paczek Omnibus. Wszystkich, którzy uwielbiają instalacje ze źródeł muszę zmartwić. Korzystanie z Geo w instalacjach źródłowych było przestarzała i zostanie usunięte w przyszłej wersji. Dlatego warto rozważyć migrację do instalacji z pakietów Omnibus. Aby uruchomić geo replikacje musimy spełnić kilka warunków. Jedną z najbardziej istotnych jest posiadanie licencji. Wymagana jest licencja w wersji Premium lub wyższa. Na pierwszym serwerze musimy posiadać już zainstalowanego i skonfigurowanego GitLaba. Na drugim serwerze przeprowadzamy tylko „czystą” instalacje. Oznacza to, że po samej instalacji nie zmieniamy nawet hasła root’a. Oczywiście między serwerami musi działać komunikacja oznacza to, że porty 80, 443, 22 oraz 5432 muszą zostać dodane do wyjątków w naszych zaporach sieciowych. Gdy to wszystko posiadamy, przechodzimy do konfiguracji replikacji bazy danych.
Zaczynamy od pierwszego serwera. Logujemy się do niego za pomocą SSH.
sudo -i
gitlab-ctl set-geo-primary-node
gitlab-ctl pg-password-md5 gitlab
sudo -u gitlab-psql /opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -d gitlabhq_production password gitlab select usename,passwd from pg_shadow where usename='gitlab';
postgresql['sql_user_password'] = 'fca0b89a972d69f00eb3ec98a5838484' gitlab_rails['db_password'] = 'mypassword'
gitlab-ctl set-replication-password
roles ['geo_primary_role'] postgresql['listen_address'] = '10.0.0.3' postgresql['md5_auth_cidr_addresses'] = ['10.0.0.3/32','10.0.0.4/32'] postgresql['max_replication_slots'] = 1 gitlab_rails['auto_migrate'] = false
gitlab-ctl reconfigure gitlab-ctl restart postgresql
gitlab_rails['auto_migrate'] = true
W tym momencie mamy skonfigurowany pierwszy serwer na potrzeby replikacji. Po przejściu tych kroków warto sprawdzić, czy aby na pewno serwer PostgreSQL nasłuchuje na odpowiednim interfejsie i porcie. Jeżeli wszystko jest ok, należy skopiować plik z certyfikatem z pierwszego na drugi serwer. Certyfikat ten został automatycznie wygenerowany podczas konfiguracji i będzie wykorzystywany do zabezpieczenia połączenia z bazą danych.
gitlab-ctl stop unicorn gitlab-ctl stop sidekiq
gitlab-rake gitlab:tcp_check[10.0.0.3,5432]
Jeżeli połączenie się nie powiedzie musimy sprawdzić adresy IP na jakich działają usługi oraz czy połączenie nie jest blokowane przez zaporę sieciową.
install -D -o gitlab-psql -g gitlab-psql -m 0400 -T server.crt ~gitlab-psql/.postgresql/root.crt
sudo -u gitlab-psql /opt/gitlab/embedded/bin/psql --list -U gitlab_replicator -d "dbname=gitlabhq_production sslmode=verify-ca" -W -h 10.0.03
W tym kroku podajemy hasło użytkownika gitlab_replicator Jeżeli jako wynik polecenia pojawi się lista baz danych z pierwszego serwera oznacza to, że połączenie jest nawiązane bez problemu.
roles ['geo_secondary_role'] postgresql['listen_address'] = 10.0.0.4 postgresql['md5_auth_cidr_addresses'] = ['10.0.0.4/32'] postgresql['sql_user_password'] = 'fca0b89a972d69f00eb3ec98a5838484' gitlab_rails['db_password'] = 'mypassword' geo_secondary['db_fdw'] = true
gitlab-ctl reconfigure gitlab-ctl restart postgresql gitlab-ctl reconfigure
gitlab-ctl replicate-geo-database --slot-name=nazwa_replikacji --host=10.0.0.3
Przechodzimy do kolejnego etapu jakim jest autoryzacja do naszych serwerów. Standardowo demon SSH wyszukuje klucze do autoryzacji przez wyszukiwanie liniowe. Oznacza to, że przy dużej ilości użytkowników operacja ta może zająć sporo czasu. Jeżeli użytkownik często dodaje lub usuwa klucze, system operacyjny może nie mieć możliwości buforowania pliku authorized_keys, co powoduje wielokrotny odczyt z dysku. GitLab Shell rozwiązuje ten problem, zapewniając sposób autoryzacji użytkowników SSH poprzez szybkie indeksowane wyszukanie w bazie danych GitLab. Domyślnie GitLab zarządza plikiem authorized_keys, gdzie zapisane są wszystkie klucze publiczne użytkowników mających dostęp do GitLab’a. W przypadku geo replikacji wymagana jest konfiguracja opierająca się na wyszukiwaniu odcisku palca w bazie danych. W ramach konfiguracji poniższe kroki należy wykonać na obu serwerach, ale pole Write to „authorized keys” file musi być odznaczone tylko na pierwszym serwerze. Jeżeli działa replikacja bazy danych, wszystko zostaje zreplikowane na drugi serwer.
Po zalogowaniu na serwer czy to pierwszy czy to drugi edytujemy plik sshd_configi znajdujący się w /etc/ssh/ i dodajemy do niego zawartość
AuthorizedKeysCommand /opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell-authorized-keys-check git %u %k AuthorizedKeysCommandUser git
GitLab przechowuje w pliku /etc/gitlab/gitlab-secrets.json kilka wartości, które muszą być takie same na wszystkich węzłach. Dlatego też należy ten plik skopiować z pierwszego na drugi serwer. Wcześniej należy wykonać sobie kopię zapasową pliku na drugim serwerze. Na drugim serwerze wykonujemy kolejno plecenia:
mv /etc/gitlab/gitlab-secrets.json /etc/gitlab/gitlab-secrets.json.`date +%F`
Kopiujemy w dowolny sposób plik z pierwszego serwera (możemy to zrobić za pomocą scp, rsync lub jakiegokolwiek innego narzędzia, które umożliwi nam przeniesienie pliku z jednego serwera na drugi. Gdy już mamy plik w docelowym miejscu nadajemy mu odpowiednie uprawnienia oraz uruchamiamy rekonfiguracje GitLab’a oraz restartujemy wszystkie usługi z nim związane.
chown root:root /etc/gitlab/gitlab-secrets.json chmod 0600 /etc/gitlab/gitlab-secrets.json gitlab-ctl reconfigure gitlab-ctl restart
W przypadku wykonania przełączenia awaryjnego administrator systemu może wypromować drugi serwer, aby stał się podstawowym. W tym przypadku DNS musi zostać zaktualizowany, dodatkowo wszystkie żądania SSH do nowo promowanego węzła zostaną odrzucone z powodu niezgodności klucza hosta SSH. Aby temu zapobiec, klucze z pierwszego serwera muszą zostać zreplikowane do serwera zapasowego.
find /etc/ssh -iname ssh_host_* -exec cp {} {}.backup.`date +%F` ;
scp root@primary-node-fqdn:/etc/ssh/ssh_host_*_key* /etc/ssh chown root:root /etc/ssh/ssh_host_*_key* chmod 0600 /etc/ssh/ssh_host_*_key*
for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done for file in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf $file; done
sudo service ssh reload
Teraz przechodzimy do długo wyczekiwanego momentu, czyli dodania drugiego serwera jako replika. Logujemy się na pierwszy serwer i już z graficznego interfejsu dodajemy zapasowy serwer.
Na koniec jeszcze uruchamiamy dostęp do Git’a za pomocą http/HTTPS. Znajdziemy ją w Admin Area > Settings
Teraz na pierwszym serwerze, możemy zobaczyć, czy wszystko działa poprawnie.
Te małe pomarańczowe ostrzeżenia to informacje o tym, że korzystam z http, a nie https, który jest zalecany. A co się dzieje na naszym drugim serwerze?
Samo uruchomienie replikacji między serwerami nie jest specjalnie trudne, ale czasem może przysporzyć bólu głowy. Możemy w ramach georeplikacji uruchomić kilka replik, co wydaje się być dobrym zabezpieczeniem. Po zakończeniu konfiguracji samo działanie serwerów jakby nieznacznie zwolniło. Z moich obserwacji widać, że podczas uruchamiania obu serwerów bardzo mocno zostaje obciążony CPU. Podobnie dzieje się w trakcie replikacji, ale w tym wypadku obciążenie jest mniejsze. Rozwiązanie jest bardzo ciekawe, jeżeli mówimy o rozproszeniu serwerów GitLab’a po cały świecie.
Na szczęście tego typu skalowanie nie jest jedyną możliwością GitLab’a. Kolejne możliwości skalowania w kolejnym wpisie!