W Czelabińsku odbywają się meetupy administratorów systemów Sysadminka, a na ostatnim z nich wygłaszałem referat na temat naszego rozwiązania dla aplikacji na 1C-Bitrix w Kubernetes.
Bitrix, Kubernetes, Ceph — świetna mieszanka?
Opowiem, jak z tego wszystkiego zbudowaliśmy działające rozwiązanie.
Zaczynamy!

Meetup odbył się 18 kwietnia w Czelabińsku. O naszych meetupach można poczytać w i zobaczyć na .
Jeśli chcesz do nas przyjść z referatem lub jako słuchacz — zapraszam, pisz na vadim.isakanov@gmail.com i w Telegramie t.me/vadimisakanov.
Mój referat
Rozwiązanie „Bitrix w Kubernetes, wersja Southbridge 1.0”
Opowiem o naszym rozwiązaniu w formacie „dla tych, którzy zaczynają z Kubernetes”, jak to było przedstawione na meetupie. Ale zakładam, że słowa Bitrix, Docker, Kubernetes, Ceph są wam znane przynajmniej na poziomie artykułów w Wikipedii.
Co tak naprawdę jest już gotowe o Bitrix w Kubernetes?
W całym Internecie jest bardzo mało informacji o aplikacjach działających na Bitrix w Kubernetes.
Znalazłem tylko takie materiały:
Referat Aleksandra Serbuli, 1C-Bitrix, oraz Antona Tuzlukowa z Qsoft:

Zalecałem go wysłuchać.
Opracowanie własnego rozwiązania od użytkownika .
Znalazłem jeszcze .
Iiiii… w zasadzie to wszystko.
Ostrzegam, że jakość pracy rozwiązań zgodnie z powyższymi linkami nie była przez nas sprawdzana 🙂
Przygotowując nasze rozwiązanie, rozmawiałem z Aleksandrem Serbulą, wtedy jego referat jeszcze nie istniał, dlatego w moich slajdach jest punkt „Bitrix nie korzysta z Kubernetes”.
Ale za to jest już wiele gotowych obrazów Docker do pracy z Bitrix w Docker:
Czy to wystarczy do stworzenia pełnoprawnego rozwiązania dla Bitrix w Kubernetes?
Nie. Jest wiele problemów, które trzeba rozwiązać.
Jakie są problemy z Bitrix w Kubernetes?
Pierwszy — gotowe obrazy z Dockerhub nie nadają się do Kubernetes
Jeśli chcemy zbudować architekturę mikroserwisową (a w Kubernetes zazwyczaj tego chcemy), aplikację w Kubernetes należy dzielić na kontenery i dążyć do tego, aby każdy kontener realizował jedną małą funkcję (i robił to dobrze). Dlaczego tylko jedną? Krótko mówiąc — im prostsze, tym bardziej niezawodne.
Jeśli dłużej — proszę zobaczyć ten artykuł i wideo:
Obrazy Docker w Dockerhub są głównie budowane na zasadzie „wszystko w jednym”, dlatego musieliśmy jednak stworzyć własną wersję i nawet obrazy robić od podstaw.
Po drugie — kod strony jest edytowany z panelu administracyjnego
Utworzono nową sekcję na stronie — zaktualizowano kod (dodano katalog o nazwie nowej sekcji).
Zmieniono właściwości komponentu z panelu administracyjnego — kod się zmienił.
Kubernetes „domyślnie” nie potrafi tego obsługiwać, kontenery muszą być niemutowalne (Stateless).
Przyczyna: każdy kontener (pod) w klastrze obsługuje tylko część ruchu. Jeśli zmienisz kod tylko w jednym kontenerze (podzie), to w różnych podach kod będzie różny, strona będzie działać w sposób zróżnicowany, różnym użytkownikom będą pokazywane różne wersje strony. Tak żyć nie można.
Po trzecie — trzeba rozwiązać kwestię z wdrożeniem.
Jeśli mamy monolit i jeden „klasyczny” serwer, wszystko jest całkiem proste: wdrażamy nową bazę kodu, przeprowadzamy migrację BD, przekierowujemy ruch na nową wersję kodu. Przełączenie następuje natychmiastowo.
Jeśli mamy stronę na Kubernetes, podzieloną na mikrousługi, kontenerów z kodem jest dużo — oj. Trzeba zbudować kontenery z nową wersją kodu, wdrożyć je zamiast starych, prawidłowo wykonać migrację BD i w idealnym przypadku zrobić to niezauważalnie dla odwiedzających. Na szczęście Kubernetes wspiera nas w tym, zapewniając wiele różnych rodzajów wdrożenia.
Po czwarte — trzeba rozwiązać kwestię przechowywania statyki.
Jeśli Twoja strona waży „zaledwie” 10 gigabajtów i wdrożysz ją w całości w kontenerach, otrzymasz kontenery ważące 10 gigabajtów, które będą wdrażane w nieskończoność.
Najcięższe części strony trzeba przechowywać poza kontenerami, i pojawia się pytanie, jak to właściwie robić.
Czego nie ma w naszym rozwiązaniu.
Cały kod Bitrix nie jest podzielony na mikrofunkcje/mikrousługi (tak, aby rejestracja była osobno, moduł sklepu internetowego osobno itd.). Całą bazę kodu przechowujemy w każdym kontenerze w całości.
Bazy w Kubernetes również nie przechowujemy (realizowałem rozwiązania z bazą w Kubernetes dla środowisk deweloperów, ale nie dla produkcji).
Administratorzy strony zauważą, że strona działa w Kubernetes. Funkcja „sprawdzenie systemu” działa nieprawidłowo, aby edytować kod strony z panelu administracyjnego, najpierw trzeba nacisnąć przycisk „chcę edytować kod.”
Z problemami się uporaliśmy, ustaliliśmy konieczność wdrożenia mikroserwisowości, cel jest jasny – stworzyć działający system do pracy aplikacji na Bitrixie w Kubernetes, zachowując zarówno możliwości Bitrixa, jak i zalety Kubernetes. Zaczynamy wdrożenie.
Architektura
Wiele «roboczych» podów z serwerem WWW (worker'y).
Jeden pod z zadaniami cron (może być tylko jeden).
Jeden upgrade pod do edytowania kodu strony z panelu administracyjnego (też musi być tylko jeden).

Rozwiązujemy kwestie:
- Gdzie przechowywać sesje?
- Gdzie przechowywać cache?
- Gdzie przechowywać statykę, nie można trzymać gigabajtów statyki w masie kontenerów?
- Jak będzie działać baza danych?
Obraz Docker
Zaczynamy od budowy obrazu Docker.
Idealna opcja – mamy jeden uniwersalny obraz, na jego podstawie uzyskujemy zarówno worker pody, jak i pody z zadaniami cron oraz upgrade pody.
.
Zawiera nginx, apache/php-fpm (można wybrać podczas budowy), msmtp do wysyłania poczty oraz cron.
Podczas budowy obrazu do katalogu /app kopiowana jest pełna baza kodu strony (z wyjątkiem tych części, które przeniesiemy do oddzielnego wspólnego storage).
Mikroserwisowość, usługi
worker pody:
- Kontener z nginx + kontener apache/php-fpm + msmtp
- msmtp nie udało się przenieść do oddzielnego mikroserwisu, Bitrix zaczyna protestować, że nie może bezpośrednio wysłać poczty
- W każdym kontenerze jest pełna baza kodu.
- Zakaz zmiany kodu w kontenerach.
cron pod:
- kontener z apache, php, cron
- w komplecie pełna baza kodu
- zakaz zmiany kodu w kontenerach
upgrade pod:
- kontener z nginx + kontener apache/php-fpm + msmtp
- brak zakazu zmiany kodu w kontenerach
przechowywanie sesji
przechowywanie cache Bitrix
Jeszcze ważne: hasła do wszystkiego, od bazy danych do poczty, przechowujemy w tajemnicach Kubernetes. Zyskujemy bonus, hasła są widoczne tylko dla tych, którym dajemy dostęp do tajemnic, a nie dla wszystkich, którzy mają dostęp do bazy kodu projektu.
Przechowywanie statyki
Można użyć czegokolwiek: ceph, nfs (ale nfs nie polecamy do produkcji), przechowywanie sieciowe od „chmurowych” dostawców itp.
Przechowywanie należy podłączyć w kontenerach do katalogu /upload/ strony oraz innych katalogów ze statyką.
Baza danych.
Dla uproszczenia zalecamy przenieść bazę poza Kubernetes. Baza w Kubernetes – to oddzielne, skomplikowane zadanie, znacznie skomplikuje schemat.
Przechowywanie sesji
Używamy memcached 🙂
Dobrze radzi sobie z przechowywaniem sesji, jest sklastrowany, „natywnie” wspierany jako session.save_path w php. Taki system był wielokrotnie wykorzystywany jeszcze w klasycznej architekturze monolitycznej, kiedy budowaliśmy klastry z dużą liczbą serwerów www. Do wdrożeń używamy helm.
$ helm install stable/memcached --name sessionphp.ini — tutaj w obrazie ustawione są konfiguracje dla przechowywania sesji w memcached
Użyliśmy zmiennych środowiskowych do przesyłania danych o hostach z memcached .
To pozwala na użycie tego samego kodu w środowiskach dev, stage, test, prod (nazwy hostów memcached w nich będą się różnić, dlatego do każdego środowiska musimy przesłać unikalne nazwy hostów dla sesji).
Magazyn cache Bitrix
Potrzebujemy odpornego na awarie magazynu, do którego wszystkie pody mogłyby pisać i z którego mogłyby czytać.
Również używamy memcached.
To rozwiązanie jest zalecane przez samego Bitrixa.
$ helm install stable/memcached --name cachebitrix/.settings_extra.php — tutaj w Bitrixie ustalamy, gdzie przechowujemy cache
Również używamy zmiennych środowiskowych.
Cron tasks
Istnieją różne podejścia do wykonywania zadań cron w Kubernetes.
- oddzielne wdrożenie z podami do wykonywania zadań cron
- cronjob do wykonywania zadań cron (jeśli to aplikacja webowa — z wget , lub kubectl exec do wnętrza jednego z worker podów, itp.)
- etc.
Można dyskutować o najodpowiedniejszym, ale w tym przypadku wybraliśmy opcję „oddzielne wdrożenie z podami do zadań cron”
Jak to zrobiono:
- zabieramy zadania cron przez ConfigMap lub przez plik config/addcron
- uruchamiamy kontener, identyczny do worker-podu, w jednej instancji + zezwalamy na wykonywanie zadań cron w nim
- używana jest ta sama baza kodu, dzięki ujednoliceniu budowa kontenera jest prosta
Co dobrego uzyskujemy:
- mamy działające zadania cron w środowisku identycznym do środowiska deweloperów (docker)
- zadania cron nie muszą być „przepisywane” na Kubernetes, one działają w tej samej formie i w tej samej bazie kodu, co wcześniej
- do zadań cron mogą dodawać wszyscy członkowie zespołu z prawami commit do gałęzi produkcyjnej, a nie tylko administratorzy
Moduł Southbridge K8SDeploy i edytowanie kodu z panelu administracyjnego
Mówiliśmy o upgrade podów?
A jak kierować tam ruch?
Hurra, napisaliśmy do tego moduł w php 🙂 To mały klasyczny moduł dla Bitrixa. Jeszcze nie jest dostępny publicznie, ale planujemy go udostępnić.
Moduł instalowany jest jak zwykły moduł w Bitrixie:

I wygląda to tak:

Umożliwia ustawienie cookie, które identyfikuje administratora strony i pozwala Kubernetesowi kierować ruch do podu aktualizacyjnego.
Po zakończeniu zmian należy nacisnąć git push, zmiany w kodzie zostaną wysłane do git, a następnie system zbuduje obraz z nową wersją kodu i „rozpowszechni” go w klastrze, zastępując stare pody.
Tak, trochę na siłę, ale przy tym zachowujemy architekturę mikroserwisów i nie odbieramy użytkownikom Bitrixa ulubionej możliwości poprawienia kodu z panelu administracyjnego. W końcu to opcja, problem z poprawą kodu można rozwiązać inaczej.
Helm chart
Do budowy aplikacji w Kubernetes zazwyczaj używamy menedżera pakietów Helm.
Dla naszego rozwiązania Bitrix w Kubernetes, nasz główny administrator systemów, Sergey Bondarev, napisał specjalny chart Helm.
Wykonuje budowę workerów, ugrade, podów cron, konfiguruje ingressy, usługi, przekazuje zmienne z tajemnic Kubernetes do podów.
Kod przechowujemy w Gitlabie, a budowę Helmu również uruchamiamy z Gitlaba.
Krótko mówiąc, wygląda to tak
$ helm upgrade --install project .helm --set image=registrygitlab.local/k8s/bitrix -f .helm/values.yaml --wait --timeout 300 --debug --tiller-namespace=productionHelm umożliwia również „bezszwowy” rollback, jeśli coś pójdzie nie tak podczas wdrożenia. Miło, że to nie ty w panice „naprawiasz kod przez ftp, bo produkcja padła”, tylko Kubernetes robi to automatycznie, bez przestojów.
Wdrożenie
Tak, jesteśmy fanami Gitlab i Gitlab CI, używamy go 🙂
Przy commicie w Gitlabie w repozytorium projektu Gitlab uruchamia pipeline, który wykonuje wdrożenie nowej wersji środowiska.
Etapy:
- build (budujemy nowy obraz Dockera)
- test (testujemy)
- clean up (usuwamy środowisko testowe)
- push (wysyłamy go do rejestru Dockera)
- deploy (wdrażamy aplikację w Kubernetes za pomocą Helmu).

Hurra, gotowe, wdrażamy!
Albo zadawajmy pytania, jeśli są.
Więc, co zrobiliśmy
Z technicznego punktu widzenia:
- zdockerowaliśmy Bitrix;
- „przecięliśmy” Bitrix na kontenery, z których każdy wykonuje minimum funkcji;
- osiągnęliśmy stan stateless kontenerów;
- rozwiązaliśmy problem aktualizacji Bitrixa w Kubernetes;
- wszystkie funkcje Bitrixa działały dalej (prawie wszystkie);
- opracowaliśmy wdrożenie w Kubernetes i rollback między wersjami.
Z punktu widzenia biznesowego:
- odporność na awarie;
- narzędzia Kubernetes (prosta integracja z Gitlab CI, bezszwowe wdrożenie itd.);
- hasła w tajemnicach (widoczne tylko dla tych, którzy mają bezpośredni dostęp do haseł);
- łatwo jest tworzyć dodatkowe środowiska (do rozwoju, testów itp.) w ramach jednolitych zasobów.
Źródło: habr.com
