Niestandardowe logi i Kubernetes
Artykuł ukazał się pierwotnie na blogu Chmurowiska.
Wszyscy lubimy logi. Przydają się na przykład, gdy musimy wyśledzić jakiś błąd w naszych aplikacjach. W przypadku gdy uruchamiamy aplikację za pomocą Dockera i Kubernetesa, najlepiej jeżeli nasze logi zrzucane są na standardowe wyjścia stdout i stderr. Platforma potrafi takie logi zagregować i udostępnić je dla nas za pomocą standardowego polecenia kubectl logs
Uruchommy sobie prostego poda, który co sekundę napisze nam coś na konsoli:
apiVersion: v1
kind: Pod
metadata:
name: simple-logger
spec:
containers:
- name: logger
image: busybox
args:
- sh
- -c
- 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done'
Możemy teraz łatwo zobaczyć, co też Pod ma nam do powiedzenia:
Niestandardowe logi
Na pewno część z Was spotkała się jednak z aplikacjami, które zapisują logi i informacje o błędach w sobie tylko znanym miejscu, bez możliwości jego zmiany. Ktoś, kiedyś zakodował np. ścieżkę do pliku z logiem i nie mamy jak tego zmienić. Ciężko będzie się np. dostać go danych przechowywanych w takim miejscu jak /var/log/mojaaplikacja/plik.log.
Mamy więc taką definicję Poda:
apiVersion: v1
kind: Pod
metadata:
name: dirty-logger
spec:
containers:
- name: logger
image: busybox
args:
- sh
- -c
- 'mkdir /var/log/ && mkdir /var/log/mojaaplikacja && i=0; while true; do echo "$i: $(date)" >> /var/log/mojaaplikacja/plik.log; i=$((i+1)); sleep 1; done'
I aby pobrać logi z takiej aplikacji musimy dostać się do środka kontenera i te logi odczytać.
Da się. Jest to jednak mało wygodne. No i w przypadku usunięcia Poda tracimy dostęp do tych logów.
Pokażę jak sobie z takim problemem poradzić.
Kubernetes to dość elastyczna platforma. A Pod to niekoniecznie tylko uruchomiony kontener. W Podzie możemy uruchomić kilka kontenerów, dołączyć do niego jakiś wolumin jako storage. I te cechy Poda pozwolą na wybrnięcie z kłopotu i “eksport” logów na stdout.
Poza kontenerem, w którym pracuje nasza krnąbrna aplikacja, do Poda dodamy wolumin, na którym będą zapisywane logi. Dodatkowo dojdzie także pomocniczy kontener, który będzie nasze logi odczytywał z tego samego woluminu i wypisywał na standardowe wyjście.
Mamy więc:
- Aplikację pracująca w głównym kontenerze
- Aplikacja pomocnicza, pracująca w dodatkowym kontenerze, odczytująca na bieżąco logi i “wyświetlająca” je na konsoli.
- Wolumin wewnątrz poda. Podmontowany zarówno do głównego kontenera, jak i aplikacji pomocniczej.
Manifest dla takiego rozwiązania mo©w wyglądać na przykład tak:
apiVersion: v1
kind: Pod
metadata:
name: appliaction-logger
spec:
volumes:
- name: logsvolume
emptyDir: {}
containers:
- name: application
image: busybox
args:
- sh
- -c
- 'mkdir /var/log/ && mkdir /var/log/mojaaplikacja && i=0; while true; do echo "$i: $(date)" >> /var/log/mojaaplikacja/plik.log; i=$((i+1)); sleep 1; done'
volumeMounts:
- name: logsvolume
mountPath: /var/log/mojaaplikacja/
- name: loghelper
image: busybox
args:
- sh
- -c
- 'tail -f /var/log/mojaaplikacja/plik.log'
volumeMounts:
- name: logsvolume
mountPath: /var/log/mojaaplikacja/
Teraz nic nie stoi już na przeszkodzie, abyśmy dostali się do logów naszej aplikacji za pomocą standardowego polecenia kubectl logs
. Musimy sięgnąć tylko oczywiście do kontenera, który nasze logi udostępnia.
Przyjrzyjmy się jeszcze po kolei poszczególnym elementom zawartym w naszym rozwiązaniu.
Fragment zaznaczony jako 3 to wolumin wewnątrz Poda. Miejsce w którym główna aplikacja, zaznaczona jako 1 będzie zapisywała logi. 2 to aplikacja pomocnicza, odczytująca logi. 4 i 5 to punkty montowania woluminu 1 do poszczególnych kontenerów wewnątrz poda.
Podsumowanie
Uruchamianie dwóch lub więcej kontenerów w jednym Podzie nie jest podejściem, które powinniśmy zawsze stosować. Umieszczanie na przykład razem WordPressa i MySQL nie jest dobrym pomysłem. Więcej, jest złym pomysłem.
Są jednak przypadki, gdzie taki dodatkowy kontener może nas wspomóc w realizacji zadań. I wtedy warto go zastosować.