[{"content":"","date":"12 sierpnia 2025","externalUrl":null,"permalink":"/tags/elasticsearch/","section":"Tags","summary":"","title":"Elasticsearch","type":"tags"},{"content":"","date":"12 sierpnia 2025","externalUrl":null,"permalink":"/","section":"Michał Kuzdzal","summary":"","title":"Michał Kuzdzal","type":"page"},{"content":"","date":"12 sierpnia 2025","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"Czasem trzeba zrobić rolling restart w klastrze Elasticsearch - wymienić sprzęt, zaktualizować wersję lub przenieść shardy na nowy węzeł. Bez odpowiedniego przygotowania proces może trwać długo i generować dużo niepotrzebnego ruchu.\nPoniżej opisuję, co robię, żeby przyspieszyć restart i ograniczyć ruch shardów.\nWyłączanie alokacji shardów podczas restartu # Żeby uniknąć niekontrolowanego przemieszczania shardów w trakcie restartu węzła, wyłączam alokację replik. Klaster wtedy nie zaczyna od razu przesuwać danych, co pozwala na kontrolowany proces restartu.\nPUT _cluster/settings { \u0026quot;persistent\u0026quot;: { \u0026quot;cluster.routing.allocation.enable\u0026quot;: \u0026quot;primaries\u0026quot; } } Po zakończeniu restartu przywracam domyślne ustawienie:\nPUT _cluster/settings { \u0026quot;persistent\u0026quot;: { \u0026quot;cluster.routing.allocation.enable\u0026quot;: null } } Opóźnienie reakcji klastra (delayed timeout) # Domyślnie Elasticsearch od razu po utracie węzła zaczyna rebalansować shardy, co generuje zbędny ruch, jeśli węzeł szybko wróci. Zwiększam timeout, żeby dać czas na ewentualny powrót węzła.\nPUT _all/_settings { \u0026quot;index.unassigned.node_left.delayed_timeout\u0026quot;: \u0026quot;5m\u0026quot;}\nFlush przed restartem # Wykonuję flush, żeby zapisać segmenty na dysk i przyspieszyć późniejsze odzyskiwanie shardów.\nPOST /_flush\nRestart node po node # Restart wykonuję pojedynczo dla każdego węzła:\nWyłączam alokację shardów (patrz wyżej) Robię flush Restartuję węzeł Przywracam alokację shardów (null) Czekam na status klastra green Powtarzam dla kolejnego węzła Tuning recovery shardów # Jeśli infrastruktura pozwala, zwiększam liczbę równoczesnych recovery i limit przepustowości, żeby skrócić czas odtwarzania shardów.\nPUT _cluster/settings { \u0026quot;persistent\u0026quot;: { \u0026quot;cluster.routing.allocation.node_concurrent_recoveries\u0026quot;: 15, \u0026quot;indices.recovery.max_bytes_per_sec\u0026quot;: \u0026quot;2000mb\u0026quot; } } ","date":"12 sierpnia 2025","externalUrl":null,"permalink":"/elasticsearch-recovery-speedup/","section":"Posts","summary":"Czasem trzeba zrobić rolling restart w klastrze Elasticsearch - wymienić sprzęt, zaktualizować wersję lub przenieść shardy na nowy węzeł. Bez odpowiedniego przygotowania proces może trwać długo i generować dużo niepotrzebnego ruchu.\nPoniżej opisuję, co robię, żeby przyspieszyć restart i ograniczyć ruch shardów.\n","title":"Przyśpieszenie rolling restart i recovery shardów w Elasticsearch","type":"posts"},{"content":"","date":"12 sierpnia 2025","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"Puppet przez lata był jednym z filarów automatyzacji i konfiguracji w dużych środowiskach IT. W 2022 roku projekt został przejęty przez firmę Perforce, a pod koniec 2024 roku ogłoszono poważne zmiany w sposobie dystrybucji i licencjonowania.\nNajważniejsze z nich to:\nod 2025 roku oficjalne binarki Puppet są dostępne wyłącznie w prywatnym repozytorium Perforce, aby z nich korzystać, trzeba zaakceptować nową licencję, darmowa wersja pozwala na zarządzanie maksymalnie 25 węzłami (agentami) - powyżej tego progu konieczna jest komercyjna umowa, kod źródłowy pozostaje otwarty (Apache 2.0), ale tempo publicznych aktualizacji jest wolniejsze niż dotychczas.\nLimit 25 węzłów może brzmieć jak coś akceptowalnego dla małych środowisk, ale w praktyce nie wystarczy niemal nikomu - nawet niewielkie firmy łatwo przekraczają tę liczbę, licząc serwery produkcyjne, stagingowe, bazy danych czy load balancery.\nOpenVox - społecznościowa odpowiedź na zmiany # W odpowiedzi na nowe zasady licencjonowania powstał fork o nazwie OpenVox, prowadzony przez społeczność Vox Pupuli. Projekt ma na celu utrzymanie otwartej, dostępnej dla wszystkich wersji Puppet, wraz z gotowymi binarkami i bez ograniczeń liczby węzłów.\nTrzeba jednak pamiętać, że korzystanie z forka wiąże się z pewnym ryzykiem:\nprojekt może zostać porzucony w dowolnym momencie, tempo rozwoju i wydawania poprawek może być wolniejsze, nie ma gwarancji takiej stabilności i testów, jak w produkcie wspieranym przez firmę, mogą pojawić się problemy z kompatybilnością w przyszłości, liczba dostępnych modułów i integracji może być mniejsza niż w oryginale. Dla niektórych organizacji OpenVox może być atrakcyjną opcją, ale w większych, krytycznych środowiskach trzeba dokładnie ocenić, czy ryzyko jest akceptowalne.\nJakie są inne alternatywy dla Puppet? # Jeżeli Puppet w nowym modelu licencyjnym nie spełnia Twoich wymagań, na rynku wciąż jest kilka dojrzałych narzędzi do automatyzacji konfiguracji:\nAnsible - w pełni open source, bez ograniczeń liczby hostów. Bardzo popularny w DevOpsach i CI/CD, konfiguracje pisane w YAML. Jest on agentless, przez co nie jest do konca alternatywą dla puppeta, Chef - projekt open source w teorii, ale darmowy tylko w określonych przypadkach: użytek osobisty, non-profit w określonych ramach, lub organizacje kontrybuujące do Chef OSS. W każdej innej sytuacji wymagana jest komercyjna licencja, SaltStack (Salt) - otwarte narzędzie przejęte przez VMware, działające w trybie master/minion lub agentless. Wersja OSS nie ma limitów liczby węzłów, wersja komercyjna dodaje GUI i integracje klasy enterprise. Co to oznacza dla nas # Zmiany w Puppet to jasny sygnał, że nawet długoletnie projekty open source mogą w pewnym momencie zmienić swój model biznesowy. Dla większości firm limit 25 węzłów to realna przeszkoda, wymuszająca dodatkowe koszty lub migrację na inne rozwiązanie.\nWarto więc już teraz przyjrzeć się alternatywom - czy to w formie forka OpenVox, czy przejścia na inne narzędzia takie jak Ansible, SaltStack czy Chef - i ocenić, które z nich najlepiej odpowiadają na potrzeby naszej infrastruktury.\n","date":"8 sierpnia 2025","externalUrl":null,"permalink":"/puppet-przejety-przez-perforce-co-sie-zmienilo-i-jakie-sa-inne-alternatywy-dla-puppet/","section":"Posts","summary":"Puppet przez lata był jednym z filarów automatyzacji i konfiguracji w dużych środowiskach IT. W 2022 roku projekt został przejęty przez firmę Perforce, a pod koniec 2024 roku ogłoszono poważne zmiany w sposobie dystrybucji i licencjonowania.\n","title":"Puppet przejęty przez Perforce - co się zmieniło i jakie są inne alternatywy dla Puppet?","type":"posts"},{"content":"","date":"1 sierpnia 2025","externalUrl":null,"permalink":"/tags/argocd/","section":"Tags","summary":"","title":"Argocd","type":"tags"},{"content":"W świecie Kubernetes, zarządzanie rosnącą liczbą aplikacji i ich konfiguracjami staje się wyzwaniem. Tradycyjne podejścia często prowadzą do powielania konfiguracji i trudności w utrzymaniu spójności w różnych środowiskach (staging i production). Właśnie tutaj z pomocą przychodzi wzorzec App-of-Apps (aplikacja aplikacji) w ArgoCD, który pozwala na skalowalne zarządzanie całym ekosystemem aplikacji z jednego, centralnego miejsca.\nWzorzec ArgoCD App-of-Apps polega na tym, że jedna, główna aplikacja (parent application) zarządza cyklem życia wielu innych aplikacji (child applications). Zamiast konfigurować każdą aplikację z osobna, definiujemy je wszystkie w jednej, nadrzędnej aplikacji, która następnie synchronizuje i monitoruje ich stan. To kluczowy element podejścia GitOps z ArgoCD.\nArchitektura i struktura katalogów dla GitOps z ArgoCD # Aby w pełni wykorzystać wzorzec App-of-Apps, kluczowa jest przemyślana struktura katalogów w repozytorium Git. Umożliwia ona spójne definiowanie konfiguracji dla różnych środowisk.\n. ├── app-of-apps │ ├── values-production.yaml # Globalne wartości dla produkcji │ └── values-staging.yaml # Globalne wartości dla stagingu ├── apps │ ├── cert-manager │ │ ├── Chart.yaml # Definicja Helm chart dla cert-manager │ │ ├── values-production.yaml # Wartości dla produkcji │ │ └── values-staging.yaml # Wartości dla stagingu │ └── fluent-bit │ ├── Chart.yaml # Definicja Helm chart dla fluent-bit │ ├── values-production.yaml # Wartości dla produkcji │ └── values-staging.yaml # Wartości dla stagingu W tej strukturze:\napp-of-apps: Katalog zawiera główne pliki values.yaml dla każdego środowiska. Te pliki kontrolują, które aplikacje i z jakimi parametrami mają zostać wdrożone w danym środowisku. apps: Katalog, w którym znajdują się definicje (w moim przypadku Helm Charts) każdej z aplikacji (child applications). Każda aplikacja ma swój własny podkatalog z plikiem Chart.yaml i specyficznymi plikami values.yaml dla różnych środowisk. Konfiguracja Helm Chart jako zależności # W naszym przykładzie, cert-manager jest wdrażany jako Helm Chart, ale zamiast kopiować cały kod, definiujemy go jako zależność (dependencies) w pliku Chart.yaml:\napiVersion: v2 name: cert-manager description: Helm chart for cert-manager type: application version: 0.1.0 appVersion: 1.0.0 dependencies: - name: cert-manager alias: certmanager version: 1.16.2 repository: https://charts.jetstack.io Dzięki temu podejściu, nasza główna aplikacja ArgoCD instaluje cert-managera z oficjalnego repozytorium Jetstack. My natomiast, w pliku values-production.yaml, możemy łatwo dostosować jego konfigurację za pomocą aliasu certmanager:\ncertmanager: namespace: cert-manager crds: enabled: true replicaCount: 2 podDisruptionBudget: enabled: true To bardzo elastyczne zarządzanie aplikacjami, ponieważ pozwala na dostosowanie konfiguracji zewnętrznego charta bez modyfikowania go bezpośrednio, a jednocześnie utrzymanie wszystkich specyficznych dla środowiska parametrów w jednym miejscu.\nPodsumowanie i korzyści # Używanie wzorca App-of-Apps w ArgoCD, w połączeniu z dobrze zorganizowaną strukturą katalogów, przynosi liczne korzyści dla Twojego zarządzania infrastrukturą:\nStandaryzacja: Konfiguracje dla różnych środowisk są spójne i łatwe do zarządzania. Łatwość zarządzania: Zmiany wprowadzane są w jednym miejscu, co minimalizuje błędy. Skalowalność: Dodawanie nowych aplikacji jest proste. Automatyzacja: ArgoCD automatycznie wykrywa i wdraża zmiany, zapewniając spójność stanu klastra. ","date":"1 sierpnia 2025","externalUrl":null,"permalink":"/argocd-app-of-apps-jak-zarzadzac-gitops-w-k8s/","section":"Posts","summary":"W świecie Kubernetes, zarządzanie rosnącą liczbą aplikacji i ich konfiguracjami staje się wyzwaniem. Tradycyjne podejścia często prowadzą do powielania konfiguracji i trudności w utrzymaniu spójności w różnych środowiskach (staging i production). Właśnie tutaj z pomocą przychodzi wzorzec App-of-Apps (aplikacja aplikacji) w ArgoCD, który pozwala na skalowalne zarządzanie całym ekosystemem aplikacji z jednego, centralnego miejsca.\n","title":"ArgoCD App-of-Apps: Jak efektywnie zarządzać aplikacjami w Kubernetes?","type":"posts"},{"content":"","date":"1 sierpnia 2025","externalUrl":null,"permalink":"/tags/devops/","section":"Tags","summary":"","title":"Devops","type":"tags"},{"content":"","date":"1 sierpnia 2025","externalUrl":null,"permalink":"/tags/git/","section":"Tags","summary":"","title":"Git","type":"tags"},{"content":"","date":"1 sierpnia 2025","externalUrl":null,"permalink":"/tags/gitops/","section":"Tags","summary":"","title":"Gitops","type":"tags"},{"content":"","date":"1 sierpnia 2025","externalUrl":null,"permalink":"/tags/k8s/","section":"Tags","summary":"","title":"K8s","type":"tags"},{"content":" TL;DR # Kubernetes 1.33 to kamień milowy, który znacząco podnosi elastyczność i bezpieczeństwo platformy. Kluczowe nowości to stabilne, natywne kontenery sidecar, które upraszczają złożone architektury, oraz funkcja in-place Pod resize, umożliwiająca zmianę alokacji zasobów (CPU i pamięci) w działających kontenerach bez konieczności ich restartu. Dodatkowo, domyślnie włączone przestrzenie nazw użytkowników podnoszą poziom izolacji, czyniąc Kubernetes jeszcze potężniejszym narzędziem dla każdego dewelopera i administratora.\n1. Kubernetes 1.33 – Ewolucja, a nie rewolucja # Kubernetes nie przestaje się rozwijać, a każda nowa wersja to krok w stronę doskonalszej orkiestracji kontenerów. Wersja 1.33, najnowsze wydanie, skupia się na ewolucji platformy, dostarczając funkcji, na które społeczność czekała od dawna. W artykule przybliżamy dwie najważniejsze nowości, które mogą zmienić sposób projektowania i zarządzania aplikacjami w chmurze.\n2. Natywne kontenery sidecar: Prostsze zarządzanie złożonymi architekturami # Wzorzec sidecar, polegający na umieszczaniu dodatkowych kontenerów pomocniczych (np. do logowania czy monitorowania) obok głównej aplikacji w tym samym Podzie, zawsze był popularny. Jednak jego implementacja w starszych wersjach Kubernetes bywała problematyczna.\nJak to działało wcześniej? Wcześniej, gdy startował Pod, nie było gwarancji kolejności uruchamiania kontenerów. Często zdarzało się, że główny kontener startował przed sidecarem. Prowadziło to do nieprzewidywalnych zachowań i błędów, szczególnie podczas rolowania wdrożeń, ponieważ aplikacja mogła próbować komunikować się z sidecarem, który jeszcze nie był gotowy. Wymagało to stosowania skomplikowanych mechanizmów i skryptów, aby wymusić poprawną kolejność.\nJak to działa teraz w Kubernetes 1.33? Dzięki natywnemu wsparciu dla sidecarów, proces został całkowicie zmieniony. Kubernetes implementuje sidecary jako specjalną klasę init containers z restartPolicy: Always. To gwarantuje, że:\nNajpierw startują sidecary i muszą być gotowe. Dopiero później startuje główny kontener aplikacji. Sidecary działają przez cały cykl życia Podu i kończą działanie dopiero po głównym kontenerze. Ta fundamentalna zmiana w cyklu życia Podu eliminuje wcześniejsze problemy i sprawia, że złożone architektury z sidecarami są o wiele bardziej niezawodne i łatwiejsze w utrzymaniu.\n3. Zmiana rozmiaru Podów w miejscu (in-place Pod resize): Elastyczność bez przestojów # Dotychczas, zmiana zasobów (CPU lub pamięci RAM) w działającym kontenerze wymagała jego restartu/rolloutu. Było to szczególnie uciążliwe dla aplikacji stanowych (sts), gdzie przerwa w działaniu jest niepożądana, lub problematyczna.\nW Kubernetes 1.33 ten problem zostaje rozwiązany dzięki funkcji in-place Pod resize.\nJak to działa? # Zamiast restartować Pod, możesz teraz dynamicznie zmienić alokację zasobów dla działającego kontenera. Nowa funkcja pozwala na modyfikację pola spec.containers[*].resources w specyfikacji Podu, które teraz reprezentuje pożądane zasoby.\nAby dokonać takiej zmiany, możesz użyć nowego sub-zasobu resize za pomocą kubectl:\nkubectl edit pod \u0026lt;pod-name\u0026gt; --subresource resize\nKubelet na węźle hostującym Pod próbuje dostosować zasoby w locie. Status operacji jest widoczny w status.containerStatuses[*].resources, co daje pełny wgląd w postępy.\nDlaczego in-place Pod resize to game-changer? # Ta funkcja ma kluczowe znaczenie, zwłaszcza dla aplikacji stanowych (StatefulSets), gdzie zachowanie ciągłości działania i stanu jest priorytetem. Zmiana zasobów nie wymaga restartu, co jest kluczowe dla aplikacji wrażliwych na przerwy. Oprócz tego:\nZwiększona wydajność: Możesz dostosowywać zasoby do rzeczywistego obciążenia, co prowadzi do oszczędności i lepszego wykorzystania zasobów klastra. Szybsze skalowanie: Możliwość szybkiego zwiększenia zasobów na start, a następnie ich zmniejszenia (tzw. vertical autoscaling), to ogromna korzyść dla aplikacji o zmiennym profilu obciążenia. 4. Inne istotne zmiany: Domyślne User Namespaces # Kubernetes 1.33 domyślnie włącza przestrzenie nazw użytkowników (User Namespaces). To kolejny ważny krok w kierunku poprawy bezpieczeństwa. Funkcja ta pozwala na uruchamianie procesów wewnątrz kontenera z niższymi uprawnieniami niż te na poziomie systemu hosta. Dzięki temu, nawet w przypadku luki w zabezpieczeniach kontenera, ryzyko eskalacji uprawnień na poziomie systemu jest mniejsz.\n5. Podsumowanie # Kubernetes 1.33 dostarcza kluczowych usprawnień, które podnoszą jakość i efektywność pracy z kontenerami. Stabilne sidecary upraszczają zarządzanie złożonymi aplikacjami, a dynamiczna zmiana rozmiaru Podów daje niezrównaną elastyczność, szczególnie w przypadku aplikacji stanowych (sts).\n","date":"28 lipca 2025","externalUrl":null,"permalink":"/kubernetes-133/","section":"Posts","summary":"TL;DR # Kubernetes 1.33 to kamień milowy, który znacząco podnosi elastyczność i bezpieczeństwo platformy. Kluczowe nowości to stabilne, natywne kontenery sidecar, które upraszczają złożone architektury, oraz funkcja in-place Pod resize, umożliwiająca zmianę alokacji zasobów (CPU i pamięci) w działających kontenerach bez konieczności ich restartu. Dodatkowo, domyślnie włączone przestrzenie nazw użytkowników podnoszą poziom izolacji, czyniąc Kubernetes jeszcze potężniejszym narzędziem dla każdego dewelopera i administratora.\n","title":"In-place Pod Resize i Sidecary w Kubernetes 1.33 – Co to zmienia?","type":"posts"},{"content":"","date":"28 lipca 2025","externalUrl":null,"permalink":"/tags/kubernetes/","section":"Tags","summary":"","title":"Kubernetes","type":"tags"},{"content":"","date":"22 lipca 2025","externalUrl":null,"permalink":"/tags/ddos/","section":"Tags","summary":"","title":"Ddos","type":"tags"},{"content":"","date":"22 lipca 2025","externalUrl":null,"permalink":"/tags/haproxy/","section":"Tags","summary":"","title":"Haproxy","type":"tags"},{"content":" Wstęp # W świecie rosnącego natężenia ruchu automatycznego (botów) i ataków DDoS staje się niezbędne wprowadzenie inteligentnych filtrów już na warstwie L7. W tym wpisie opiszę, jak dzięki prostemu skryptowi w Lua oraz mechanizmom HAProxy zbudowałem jedną z wielu warstw ochrony backendów przed nieporządanym ruchem.\nKoncepcja rozwiązania # Wykrywanie „sesji” per IP w oparciu o cookie\\ Każda unikalna wartość ciasteczka (__Secure-app_session) to jedna sesja,\\ każde żądanie bez ciasteczka to tzw. „no-cookie” request. Limit 150 sesji/IP w oknie 120 s\\ Po przekroczeniu tej wartości IP zostaje oznaczone jako podejrzane. Akcja po przekroczeniu\\ Przekierowanie do backendu z kolejką (queue), lub drop requestu. Skrypt Lua: szczegóły działania # Poniżej pełny kod skryptu, wraz z opisem:\n-- Globalna tabela do przechowywania stanu per IP local ip_unique_sessions = {} local last_cleanup = os.time() -- Funkcja czyszcząca – resetuje całą strukturę co 120 sekund local function cleanup() local now = os.time() if now - last_cleanup \u0026gt;= 120 then ip_unique_sessions = {} last_cleanup = now end end -- Escapowanie znaków specjalnych w nazwie ciasteczka local function escape_pattern(text) return text:gsub(\u0026quot;([^%w])\u0026quot;, \u0026quot;%%%1\u0026quot;) end -- Wyciąganie wartości cookie z nagłówka local function get_cookie_value(cookie_header, cookie_name) if not cookie_header then return nil end local pattern = escape_pattern(cookie_name) .. \u0026quot;=([^;]+)\u0026quot; return cookie_header:match(pattern) end -- Główna funkcja sprawdzająca limit function check_rate_limit(txn) -- 1) Czyszczenie przestarzałych danych cleanup() -- 2) Pobranie IP i nagłówka Cookie local client_ip = txn.f:src() or \u0026quot;unknown\u0026quot; local cookie_hdr = txn.f:hdr(\u0026quot;Cookie\u0026quot;) -- 3) Wyciągnięcie wartości ciasteczka local cookie_val = get_cookie_value(cookie_hdr, \u0026quot;__Secure-app_session\u0026quot;) -- 4) Inicjalizacja struktury, jeśli nowe IP if not ip_unique_sessions[client_ip] then ip_unique_sessions[client_ip] = { cookie = {}, -- set dla unikalnych wartości cookies no_cookie = 0 -- licznik requestów bez ciasteczka } end -- 5) Aktualizacja stanu: cookie vs no_cookie if cookie_val then ip_unique_sessions[client_ip].cookie[cookie_val] = true else ip_unique_sessions[client_ip].no_cookie = ip_unique_sessions[client_ip].no_cookie + 1 end -- 6) Zliczanie „sesji” local count = 0 for _ in pairs(ip_unique_sessions[client_ip].cookie) do count = count + 1 end count = count + ip_unique_sessions[client_ip].no_cookie -- 7) Decyzja o przekroczeniu limitu if count \u0026gt; 150 then return \u0026quot;true\u0026quot; else return \u0026quot;false\u0026quot; end end -- Rejestracja funkcji jako sample-fetch „rate_limit” core.register_fetches(\u0026quot;rate_limit\u0026quot;, check_rate_limit) Omówienie krok po kroku # Zmienne globalne\\ ip_unique_sessions: pusty słownik, kluczem jest IP, wartością tabela z podkluczami cookie (set) i no_cookie (licznik).\\ last_cleanup: znacznik czasu ostatniego pełnego resetu. cleanup()\\ Wywoływane przy każdym sprawdzeniu – czyści cały stan, jeśli od ostatniego resetu minęło ≥120 s.\\ Zapobiega niekontrolowanemu wzrostowi zużycia pamięci. escape_pattern(text)\\ Zamienia znaki specjalne w nazwie ciasteczka na escaped (%), by string.match traktował je dosłownie. Dzięki temu nazwy z podkreśleniami, myślnikami czy kropkami są bezpieczne. get_cookie_value(cookie_header, cookie_name)\\ Przy braku nagłówka Cookie od razu zwraca nil.\\ Buduje wzorzec: \u0026lt;nazwa\u0026gt;=([^;]+) i zwraca pierwszy dopasowany fragment (wartość ciasteczka). Inicjalizacja struktury\\ Dla każdego nowego IP tworzymy tabelę z pustym setem ciasteczek i licznikiem 0. Aktualizacja stanu\\ Jeśli ciasteczko istnieje: dodajemy jego wartość do setu (unikalność gwarantowana),\\ jeśli nie: inkrementujemy no_cookie. Zliczanie i próg\\ Sumujemy liczbę kluczy w cookie + wartość no_cookie.\\ Porównujemy z progiem (150); w razie przekroczenia zwracamy \u0026quot;true\u0026quot;. Konfiguracja HAProxy # Konfiguracja haproxy może wyglądać następująco:\n# Zaladowanie skryptu lua-load /opt/implix/haproxy/ddos_rate_limit.lua # Sprawdzenie rate_limit, z pominięciem whitelisty http-request set-var(req.rate_limit_exceeded) lua.rate_limit if !{ src -f /etc/haproxy/whitelist.txt } # Ustawienie ddos_rate_exceeded na true jeżeli ip przekroczyło limit acl ddos_rate_exceeded var(req.rate_limit_exceeded) -m str true # Kierowanie do kolejkującego backendu use_backend fpm-queue-backend if ddos_rate_exceeded # Można też zdropować takie połączenie # http-request deny if ddos_rate_exceeded W moim przypadku podejrzany ruch trafia na backend z kolejką, gdzie takie żądania czekają na obsłużenie.\nJakie mogą być inne podejścia do obsługi takich połączeń?\ndeny - bezpośredni zakończenie połączenia z dowolnym kodem http, silent-drop - zamyka połączenie po stronie HAProxy bez żadnej odpowiedzi ani komunikatu do klienta, tarpid - podobne do silent dropa, z tą różnicą że połączenie jest przetrzymywane przez socket haproxy. Podsumowanie # HAProxy dzięki skryptom Lua otwiera przed nami niemal nieograniczone możliwości zaawansowanej konfiguracji i zarządzania ruchem. Pokazany wyżej przykład to jedynie wierzchołek góry lodowej – za pomocą Lua możesz zbudować własny, w pełni programowalny load balancer, implementować niestandardowe algorytmy routingu, walidować czy modyfikować nagłówki w locie, a nawet integrować się z zewnętrznymi systemami. To elastyczne podejście pozwala dostosować HAProxy dokładnie do potrzeb Twojej infrastruktury i łatwo rozwijać go o kolejne mechanizmy ochrony czy optymalizacji.\n","date":"22 lipca 2025","externalUrl":null,"permalink":"/haproxy-lua-ddos-protection/","section":"Posts","summary":"Wstęp # W świecie rosnącego natężenia ruchu automatycznego (botów) i ataków DDoS staje się niezbędne wprowadzenie inteligentnych filtrów już na warstwie L7. W tym wpisie opiszę, jak dzięki prostemu skryptowi w Lua oraz mechanizmom HAProxy zbudowałem jedną z wielu warstw ochrony backendów przed nieporządanym ruchem.\n","title":"HAProxy + Lua: Ochrona przed botami i atakami DDoS","type":"posts"},{"content":"","date":"22 lipca 2025","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"","date":"22 lipca 2025","externalUrl":null,"permalink":"/tags/lua/","section":"Tags","summary":"","title":"Lua","type":"tags"},{"content":"","date":"10 lipca 2025","externalUrl":null,"permalink":"/tags/gitlab/","section":"Tags","summary":"","title":"Gitlab","type":"tags"},{"content":"","date":"10 lipca 2025","externalUrl":null,"permalink":"/tags/terraform/","section":"Tags","summary":"","title":"Terraform","type":"tags"},{"content":"Dziś opiszę, jak zintegrować Terraform z GitLab CI/CD, aby stworzyć wydajny i niezawodny proces GitOps.\nPo co Terraform i GitOps? # Terraform pozwala opisywać infrastrukturę jako kod (IaC). Dzięki temu możesz ją wersjonować, łatwo powielać i audytować. GitOps dodaje do tego proces CI/CD, w którym każda zmiana w kodzie jest automatycznie wdrażana, eliminując ręczne modyfikacje i minimalizując ryzyko błędów. Trzymanie stanu w gitlabi pomoże też uniknąć potencjalnych problemów i konfliktów.\nStruktura GitLab CI/CD # Nasze CI/CD podzielimy na trzy główne etapy: init, plan i apply. Dodatkowo, stan Terraform (tzw. State) przechowamy bezpiecznie w GitLab, co uprości zarządzanie i wyeliminuje potencjalne problemy z przechowywaniem stanu w różnych miejscach.\nPoniżej przedstawiam, jak powinien wyglądać plik .gitlab-ci.yml:\nstages: - validate - plan - apply variables: TF_ADDRESS: \u0026quot;${CI_API_V4_URL}/projects/${CI_PROJECT_ID}\u0026quot; STATES: \u0026quot;terraform/state/${TF_STATE_NAME}\u0026quot; TERRAFORM_INIT: \u0026quot;terraform init \\ -backend-config=address=${TF_ADDRESS}/${STATES} \\ -backend-config=lock_address=${TF_ADDRESS}/${STATES}/lock \\ -backend-config=unlock_address=${TF_ADDRESS}/${STATES}/lock \\ -backend-config=username=${TF_USERNAME} \\ -backend-config=password=${TF_PASSWORD} \\ -backend-config=lock_method=POST \\ -backend-config=unlock_method=DELETE \\ -backend-config=retry_wait_min=5\u0026quot; TF_STATE_NAME: \u0026quot;nazwa-projektu\u0026quot; .terraform-base: image: name: \u0026quot;registry.gitlab.com/gitlab-org/terraform-images/stable:latest\u0026quot; before_script: - eval $TERRAFORM_INIT validate: stage: validate extends: - .terraform-base script: - terraform validate plan: stage: plan extends: - .terraform-base script: - terraform plan -out=plan.tf artifacts: paths: - plan.tf apply: stage: apply extends: - .terraform-base script: - terraform apply -input=false plan.tf rules: - if: '$CI_COMMIT_BRANCH == \u0026quot;main\u0026quot;' when: manual Sam pipline prezentuje się następująco:\nSkąd wziąć zmienne? # CI_API_V4_URL i CI_PROJECT_ID: Te zmienne zawierają adres URL do API oraz unikalny identyfikator projektu (np. CI_API_V4_URL=https://git.example.com/api/v4/\nCI_PROJECT_ID=210), TF_STATE_NAME: dowolna nazwa stanu, która będzie widoczna w gitalabie, TF_USERNAME i TF_PASSWORD: Te zmienne są kluczowe do uwierzytelniania w API GitLab, aby potok mógł bezpiecznie zarządzać stanem Terraform. Najbezpieczniej jest stworzyć Project Access Token lub Personal Access Token z odpowiednimi uprawnieniami (zakres api), a następnie zapisać go jako zmienną środowiskową w ustawieniach CI/CD projektu w GitLab. Podsumowanie # Integracja Terraform z GitLab CI/CD daje nam potężne narzędzie do zarządzania infrastrukturą w sposób w pełni zautomatyzowany, bezpieczny i zgodny z najlepszymi praktykami GitOps. Taki proces pozwala na szybsze i bardziej niezawodne wdrażanie, minimalizując błędy i zapewniając pełną transparentność zmian.\n","date":"10 lipca 2025","externalUrl":null,"permalink":"/terraform-with-gitops/","section":"Posts","summary":"Dziś opiszę, jak zintegrować Terraform z GitLab CI/CD, aby stworzyć wydajny i niezawodny proces GitOps.\nPo co Terraform i GitOps? # Terraform pozwala opisywać infrastrukturę jako kod (IaC). Dzięki temu możesz ją wersjonować, łatwo powielać i audytować. GitOps dodaje do tego proces CI/CD, w którym każda zmiana w kodzie jest automatycznie wdrażana, eliminując ręczne modyfikacje i minimalizując ryzyko błędów. Trzymanie stanu w gitlabi pomoże też uniknąć potencjalnych problemów i konfliktów.\n","title":"Terraform i GitOps w GitLab CI/CD","type":"posts"},{"content":"","date":"8 lipca 2025","externalUrl":null,"permalink":"/tags/kali/","section":"Tags","summary":"","title":"Kali","type":"tags"},{"content":"Dzięki nowej konteneryzacji Apple (ogłoszonej podczas WWDC 2025) możesz teraz bezproblemowo uruchomić Kali Linux bezpośrednio na swoim Macu z Apple Silicon. To idealne rozwiązanie dla tych, którzy chcą szybko testować narzędzia bezpieczeństwa bez konieczności stawiania pełnej maszyny wirtualnej.\n1. Co to jest Apple Container? # Apple Container to nowy framework wprowadzony w macOS Sequoia, umożliwiający izolowane uruchamianie dystrybucji Linuksa na sprzęcie Apple Silicon. Działa to podobnie do WSL2 na Windows, ale w pełni zintegrowane z ekosystemem Apple.\nKluczowe zalety:\nLekka wirtualizacja z natywnym wsparciem dla Apple Silicon Integracja z narzędziem Homebrew Obsługa standardowego formatu kontenerów Docker 2. Przygotowanie środowiska # Wymagania # macOS Sequoia (15.x) z Apple Silicon (M1/M2/M3) Zainstalowany Homebrew Instalacja kontenerów Apple # Otwórz Terminal\nZainstaluj CLI kontenerów:\nbrew install --cask container\nUruchom usługę systemową kontenera:\ncontainer system start\n3. Uruchomienie Kali Linux w kontenerze # Po przygotowaniu frameworka możesz od razu odpalić obraz Kali Linux z DockerHub:\ncontainer run --rm -it kalilinux/kali-rolling\nWyjaśnienie parametrów:\n--rm – usuwa kontener po zamknięciu -it – interaktywna sesja terminalowa kalilinux/kali-rolling – oficjalny obraz Kali Linux Montowanie woluminów # Aby uzyskać dostęp do plików z macOS wewnątrz kontenera:\ncontainer run --rm -it \\ --volume $(pwd):/mnt \\ --workdir /mnt \\ docker.io/kalilinux/kali-rolling:latest --volume $(pwd):/mnt – montuje aktualny katalog do /mnt --workdir /mnt – ustawia katalog roboczy w kontenerze 4. Ograniczenia i znane problemy # Chociaż uruchamianie Kali Linux w kontenerze to duży krok naprzód, warto pamiętać o kilku ograniczeniach:\nTylko Apple Silicon – kontenery działają wyłącznie na procesorach M1/M2/M3. Brak przejścia sprzętowego – niektóre narzędzia pentestingowe wymagające bezpośredniego dostępu do urządzeń USB czy GPU mogą nie działać. Wczesna faza rozwoju – framework może mieć błędy, które będą eliminowane w kolejnych aktualizacjach macOS Sequoia. 5. Dlaczego warto? # 🚀 Szybkie wdrożenie: kilka poleceń wystarczy, by mieć działający Kali Linux. 🔒 Bezpieczeństwo: izolacja kontenera minimalizuje ryzyko wpływu na system hosta. 💻 Wydajność: lekka wirtualizacja daje niemal natywne osiągi. 🔄 Aktualność: korzystasz z najnowszego obrazu kali-rolling. 6. Podsumowanie # Uruchomienie Kali Linux w kontenerze na macOS to prosty sposób na rozszerzenie swojego środowiska pentestowego bez konieczności instalowania pełnej maszyny wirtualnej. Dzięki nowemu frameworkowi Apple Container na Sequoia, użytkownicy Apple Silicon zyskują dostęp do pełnej gamy narzędzi Kali w zaledwie kilka minut.\n","date":"8 lipca 2025","externalUrl":null,"permalink":"/uruchamianie-kali-linux-na-macos-w-kontenerze-apple/","section":"Posts","summary":"Dzięki nowej konteneryzacji Apple (ogłoszonej podczas WWDC 2025) możesz teraz bezproblemowo uruchomić Kali Linux bezpośrednio na swoim Macu z Apple Silicon. To idealne rozwiązanie dla tych, którzy chcą szybko testować narzędzia bezpieczeństwa bez konieczności stawiania pełnej maszyny wirtualnej.\n","title":"Uruchamianie Kali Linux na macOS w kontenerze Apple","type":"posts"},{"content":"Jeśli zależy Ci na wykorzystaniu pełni możliwości HAProxy, w tym najnowszych funkcji takich jak obsługa protokołu QUIC, często konieczna jest kompilacja z kodu źródłowego. Domyślne pakiety HAProxy dostępne w oficjalnych repozytoriach systemów (np. przez apt install haproxy) zazwyczaj nie zawierają wsparcia dla QUIC, ponieważ wymaga to użycia niestandardowej biblioteki OpenSSL. Co więcej, obsługa QUIC jest często dostępna w wersjach komercyjnych (HAProxy Enterprise), dlatego ręczna kompilacja jest najlepszym sposobem, aby uzyskać tę funkcjonalność w wersji darmowej.\nW tym poradniku pokażę, jak skompilować HAProxy w wersji 3.2.3 na systemie Debian 12, używając OpenSSL z obsługą QUIC. Cały proces podzielimy na dwa główne etapy: kompilację OpenSSL, a następnie kompilację HAProxy.\nEtap 1: Kompilacja i instalacja OpenSSL z QUIC # Zaczynamy od przygotowania OpenSSL z obsługą protokołu QUIC. Domyślna wersja OpenSSL w systemie Debian nie obsługuje tej funkcji, dlatego musimy skompilować ją ręcznie.\nInstalacja niezbędnych narzędzi\nZanim zaczniemy, upewnij się, że masz zainstalowane podstawowe narzędzia do kompilacji oraz biblioteki deweloperskie, które będą nam potrzebne do skompilowania HAProxy (Lua, PCRE2).Bash\nsudo apt install make build-essential liblua5.4-dev libpcre2-dev Pobranie i dekompresja OpenSSL\nPobierzemy wersję OpenSSL z gałęzi quictls, która została zmodyfikowana, aby wspierać QUIC.Bash\nwget https://github.com/quictls/openssl/archive/refs/tags/opernssl-3.1.5-quic1.tar.gz tar zxvf opernssl-3.1.5-quic1.tar.gz cd opernssl-3.1.5-quic1 Konfiguracja i kompilacja OpenSSL\nTeraz skonfigurujemy i skompilujemy OpenSSL. Użyjemy wielu opcji, aby zapewnić optymalizację, bezpieczeństwo oraz obsługę QUIC (enable-tls1_3). Instalacja docelowo znajdzie się w katalogu /opt/quictls, aby nie kolidowała z systemową wersją OpenSSL.Bash\nOPENSSL_OPTS=\u0026quot;enable-tls1_3 \\ -g -O3 -fstack-protector-strong -Wformat -Werror=format-security \\ -DOPENSSL_TLS_SECURITY_LEVEL=2 -DOPENSSL_USE_NODELETE -DL_ENDIAN \\ -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 \\ -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m \\ -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DMD5_ASM \\ -DAESNI_ASM -DVPAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM \\ -DX448_ASM -DPOLY1305_ASM -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2 \\ \u0026quot; ./config --libdir=lib --prefix=/opt/quictls $OPENSSL_OPTS make -j $(nproc) make install -j $(nproc) Weryfikacja instalacji OpenSSL\nSprawdźmy, czy nowa wersja OpenSSL została poprawnie zainstalowana i obsługuje QUIC.Bash\n/opt/quictls/bin/openssl version Oczekiwana odpowiedź powinna wyglądać tak: OpenSSL 3.1.5+quic 30 Jan 2024 (Library: OpenSSL 3.1.5+quic 30 Jan 2024)\nEtap 2: Kompilacja HAProxy 3.2.3 # Teraz, gdy mamy gotowy OpenSSL z QUIC, możemy przejść do kompilacji HAProxy, która go wykorzysta.\nPobranie i dekompresja HAProxy\nPobierz najnowszą stabilną wersję HAProxy 3.2.3 ze strony projektu.Bash\nwget http://www.haproxy.org/download/3.2/src/haproxy-3.2.3.tar.gz tar zxf haproxy-3.2.3.tar.gz cd haproxy-3.2.3 Konfiguracja i kompilacja HAProxy\nW tej sekcji skompilujemy HAProxy, wskazując mu ścieżki do naszego niestandardowego OpenSSL. Musimy również włączyć wsparcie dla QUIC, Lua, PCRE2 oraz innych przydatnych funkcji.Bash\nHAPROXY_CFLAGS=\u0026quot;-O3 -g -Wall -Wextra -Wundef -Wdeclaration-after-statement -Wfatal-errors -Wtype-limits -Wshift-negative-value -Wshift-overflow=2 -Wduplicated-cond -Wnull-dereference -fwrapv -Wno-address-of-packed-member -Wno-unused-label -Wno-sign-compare -Wno-unused-parameter -Wno-clobbered -Wno-missing-field-initializers -Wno-cast-function-type -Wno-string-plus-int -Wno-atomic-alignment\u0026quot; HAPROXY_OPTS=\u0026quot;TARGET=linux-glibc \\ USE_PCRE2=1 USE_PCRE2_JIT=1 \\ USE_PCRE= USE_PCRE_JIT= \\ USE_GETADDRINFO=1 \\ USE_OPENSSL=1 USE_LIBCRYPT=1 \\ USE_LUA=1 \\ USE_PROMEX=1 \\ USE_QUIC=1 \\ USE_EPOLL=1 \\ USE_THREAD=1 \\ USE_NS=1 \\ USE_SLZ=1 USE_ZLIB= \\ LUA_LIB_NAME=lua5.4 \\ \u0026quot; echo \u0026quot;/opt/quictls/lib\u0026quot; \u0026gt; /etc/ld.so.conf.d/quictls.conf \u0026amp;\u0026amp; ldconfig make -j $(nproc) $HAPROXY_OPTS CFLAGS=\u0026quot;$HAPROXY_CFLAGS\u0026quot; LDFLAGS=\u0026quot;$HAPROXY_LDFLAGS\u0026quot; SSL_INC=/opt/quictls/include SSL_LIB=/opt/quictls/lib all admin/halog/halog Ważna uwaga: Komenda echo \u0026quot;/opt/quictls/lib\u0026quot; \u0026gt; /etc/ld.so.conf.d/quictls.conf \u0026amp;\u0026amp; ldconfig dodaje ścieżkę do naszych nowo skompilowanych bibliotek OpenSSL do globalnej konfiguracji systemu. To kluczowy krok, który pozwala HAProxy (i innym programom) znaleźć biblioteki SSL/TLS.\nInstalacja HAProxy\nPo udanej kompilacji, zainstaluj binarkę HAProxy w domyślnej lokalizacji.Bash\nsudo make -j $(nproc) install-bin Gratulacje! Właśnie skompilowałeś HAProxy w wersji 3.2.3 z pełnym wsparciem dla protokołu QUIC na Debianie 12. Teraz możesz skonfigurować HAProxy, aby wykorzystać jego nowe możliwości w Twoim środowisku.\n","date":"1 czerwca 2025","externalUrl":null,"permalink":"/untitled/","section":"Posts","summary":"Jeśli zależy Ci na wykorzystaniu pełni możliwości HAProxy, w tym najnowszych funkcji takich jak obsługa protokołu QUIC, często konieczna jest kompilacja z kodu źródłowego. Domyślne pakiety HAProxy dostępne w oficjalnych repozytoriach systemów (np. przez apt install haproxy) zazwyczaj nie zawierają wsparcia dla QUIC, ponieważ wymaga to użycia niestandardowej biblioteki OpenSSL. Co więcej, obsługa QUIC jest często dostępna w wersjach komercyjnych (HAProxy Enterprise), dlatego ręczna kompilacja jest najlepszym sposobem, aby uzyskać tę funkcjonalność w wersji darmowej.\n","title":"Kompilacja HAProxy 3.2.3 z obsługą QUIC (OpenSSL 3.1.5) na Debianie 12","type":"posts"},{"content":"Jeżeli chcemy użyć ingressa z ArgoCD zetkniemy się z problemem pętli redirectów\ncurl -I https://argo.michal.kuzdzal.pl HTTP/2 307 date: Sat, 06 Aug 2022 20:25:02 GMT content-type: text/html; charset=utf-8 location: https://argo.michal.kuzdzal.pl/ Dzieje się tak ponieważ backend ArgoCD oczekuje, że sam nawiąże połączenie TLS, w innym przypadku zawsze przekierowuje połączenie na HTTPS.\nNajprostszym sposobem jest wyłączenie przekierowań:\nkubectl edit deployments.apps argocd-server -n argocd W polu command dodajemy opcję insecure:\n- command: - argocd-server - --insecure Tworzymy na nowo poda:\nkubectl scale -n argocd deployment/argocd-server --replicas=0 \u0026amp;\u0026amp; kubectl scale -n argocd deployment/argocd-server --replicas=1 Po tym zabiegu wszystko powinno już działać:\ncurl -I https://argo.michal.kuzdzal.pl HTTP/2 200 date: Sat, 06 Aug 2022 20:50:51 GMT content-type: text/html; charset=utf-8 content-length: 788 accept-ranges: bytes content-security-policy: frame-ancestors 'self'; x-frame-options: sameorigin x-xss-protection: 1 strict-transport-security: max-age=15724800; includeSubDomains ","date":"6 sierpnia 2022","externalUrl":null,"permalink":"/argocd/","section":"Posts","summary":"Jeżeli chcemy użyć ingressa z ArgoCD zetkniemy się z problemem pętli redirectów\ncurl -I https://argo.michal.kuzdzal.pl HTTP/2 307 date: Sat, 06 Aug 2022 20:25:02 GMT content-type: text/html; charset=utf-8 location: https://argo.michal.kuzdzal.pl/ Dzieje się tak ponieważ backend ArgoCD oczekuje, że sam nawiąże połączenie TLS, w innym przypadku zawsze przekierowuje połączenie na HTTPS.\n","title":"ArgoCD - ingress ssl too many redirects","type":"posts"},{"content":"","date":"29 marca 2022","externalUrl":null,"permalink":"/tags/python/","section":"Tags","summary":"","title":"Python","type":"tags"},{"content":"Czasem jest taka potrzeba uruchomienia jakiegoś lokalnego skryptu/programu na zdalnym hoście. Jeżeli nie chcemy kopiować i umieszczać na hoście tego skryptu możemy użyć ssh:\nssh user@host python3 \u0026lt; script.py Natomiast jeżeli chcemy uruchomić skrypt z dodatkowymi parametrami:\nssh user@host python3 -u - --parametr arg1 \u0026lt; script.py Oczywiście nic nie stoi na przeszkodzie aby odpalić w ten sposób każdy inny skrypt bashowy, pearlowy itp.\n","date":"29 marca 2022","externalUrl":null,"permalink":"/python-lokalny-skrypt-na-zdalnej-maszynie-ssh/","section":"Posts","summary":"Czasem jest taka potrzeba uruchomienia jakiegoś lokalnego skryptu/programu na zdalnym hoście. Jeżeli nie chcemy kopiować i umieszczać na hoście tego skryptu możemy użyć ssh:\nssh user@host python3 \u003c script.py Natomiast jeżeli chcemy uruchomić skrypt z dodatkowymi parametrami:\n","title":"Python - lokalny skrypt na zdalnej maszynie (ssh)","type":"posts"},{"content":"","date":"29 marca 2022","externalUrl":null,"permalink":"/tags/ssh/","section":"Tags","summary":"","title":"Ssh","type":"tags"},{"content":"","date":"6 marca 2022","externalUrl":null,"permalink":"/tags/ci/cd/","section":"Tags","summary":"","title":"CI/CD","type":"tags"},{"content":"Czasami jest potrzeba przekazania zmiennej env pomiędzy różnymi stagami pipelina. Od wersji 13 gitlaba możemy do tego użyć wbudowanego mechanizmu inherit environment variables. Zapisujemy naszą wartość w pliku .env i przekazujemy ją za pomocą mechanizmu artifacts:\nbuild: stage: build script: - echo \u0026quot;COMMIT=true\u0026quot; \u0026gt;\u0026gt; build.env artifacts: reports: dotenv: build.env deploy: stage: test script: - echo \u0026quot;$COMMIT\u0026quot; Linki # Inherit environment variables.\n","date":"6 marca 2022","externalUrl":null,"permalink":"/gitlab-ci-cd-environment-variable/","section":"Posts","summary":"Czasami jest potrzeba przekazania zmiennej env pomiędzy różnymi stagami pipelina. Od wersji 13 gitlaba możemy do tego użyć wbudowanego mechanizmu inherit environment variables. Zapisujemy naszą wartość w pliku .env i przekazujemy ją za pomocą mechanizmu artifacts:\n","title":"Gitlab CI/CD - environment variable","type":"posts"},{"content":"","date":"6 marca 2022","externalUrl":null,"permalink":"/tags/pipeline/","section":"Tags","summary":"","title":"Pipeline","type":"tags"},{"content":"Terraform, numer jeden jeżeli chodzi o IaC (Infrastructure as Code). W bardzo przyjemny sposób można zarządzać infrastrukturą cloudową jak i on-premise.\nW tym przypadku opiszę pokrótce jak deployować virtualną maszynę w LXD.\nKonfiguracja # Mamy mało kodu, więc tworzymy wszystko w jednym pliku main.tf:\nterraform { required_providers { lxd = { source = \u0026quot;terraform-lxd/lxd\u0026quot; } } } provider \u0026quot;lxd\u0026quot; { generate_client_certificates = true accept_remote_certificate = true lxd_remote { name = \u0026quot;lxd-1\u0026quot; scheme = \u0026quot;https\u0026quot; address = \u0026quot;lxd.kuzdzal.pl\u0026quot; port = \u0026quot;8443\u0026quot; default = true } } resource \u0026quot;lxd_container\u0026quot; \u0026quot;worker\u0026quot; { count = 3 remote = \u0026quot;lxd-1\u0026quot; name = \u0026quot;k8s-${count.index}\u0026quot; image = \u0026quot;ubuntu:20.04\u0026quot; ephemeral = false type = \u0026quot;virtual-machine\u0026quot; config = { \u0026quot;user.access_interface\u0026quot; = \u0026quot;enp5s0\u0026quot; } limits = { \u0026quot;memory\u0026quot; = \u0026quot;8GB\u0026quot; \u0026quot;cpu\u0026quot; = 4 } profiles = [\u0026quot;default\u0026quot;] device { name = \u0026quot;root\u0026quot; properties = { \u0026quot;path\u0026quot; = \u0026quot;/\u0026quot; \u0026quot;pool\u0026quot; = \u0026quot;pool_nvme\u0026quot; \u0026quot;size\u0026quot; = \u0026quot;25GB\u0026quot; } type = \u0026quot;disk\u0026quot; } } output \u0026quot;droplet_ip_addresses\u0026quot; { value = { for droplet in lxd_container.worker: droplet.name =\u0026gt; droplet.ipv4_address } } Uruchomienie # Inicjalizacja, czyli pobranie wszystkich wymaganych pluginów (w tym przypadku tylko lxd), zsetupowanie i na końcu zniszczenie zasobów:\n~ terraform init ~ terraform apply -auto-approve ~ terraform destroy -auto-approve Linki # Terraform lxd.\n","date":"23 lutego 2022","externalUrl":null,"permalink":"/terraform/","section":"Posts","summary":"Terraform, numer jeden jeżeli chodzi o IaC (Infrastructure as Code). W bardzo przyjemny sposób można zarządzać infrastrukturą cloudową jak i on-premise.\nW tym przypadku opiszę pokrótce jak deployować virtualną maszynę w LXD.\n","title":"Terraform - deploy LXD container","type":"posts"},{"content":"","date":"1 lutego 2022","externalUrl":null,"permalink":"/tags/varnish/","section":"Tags","summary":"","title":"Varnish","type":"tags"},{"content":"Varnish, świetny serwer cache\u0026rsquo;u umożliwiający bardzo zaawansowaną konfigurację. Większość serwerów cdn dostępnych w internecie wykorzystuje właśnie varnisha na backendzie do serwowania statycznych danych. Osobiście użyłem go jako front przed ghostem, o którego de facto oparty jest ten blog.\nPliki konfiguracyjne # Konfiguracja samego varnisha default.vcl:\nvcl 4.0; backend default { .host = \u0026quot;blog-mk:2368\u0026quot;; } sub vcl_recv { if (req.url ~ \u0026quot;/(admin|p|ghost)/\u0026quot;) { return (pass); } unset req.http.cookie; } sub vcl_backend_response { if (beresp.http.content-type ~ \u0026quot;text/plain|text/css|application/json|application/x-javascript|text/xml|application/xml|application/xml+rss|text/javascript\u0026quot;) { set beresp.do_gzip = true; set beresp.http.cache-control = \u0026quot;public, max-age=1209600\u0026quot;; } set beresp.ttl = 1w; } Deployment varnish-dep.yaml:\n--- apiVersion: apps/v1 kind: Deployment metadata: name: blog-varnish-dep labels: app: blog-varnish spec: replicas: 1 selector: matchLabels: app: blog-varnish template: metadata: labels: app: blog-varnish spec: containers: - name: varnish image: varnish:6.4 imagePullPolicy: Always ports: - containerPort: 80 volumeMounts: - mountPath: /etc/varnish/default.vcl name: varnish-config subPath: default.vcl readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 3 periodSeconds: 3 livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 5 volumes: - name: varnish-config configMap: name: varnish-config items: - key: default.vcl path: default.vcl Service varnish-svc.yaml:\n--- kind: Service apiVersion: v1 metadata: name: varnish-svc spec: selector: app: blog-varnish ports: - protocol: TCP port: 80 targetPort: 80 Ingress varnish-ing.yaml:\n--- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: public name: blog-stage spec: rules: - host: michal.kuzdzal.pl http: paths: - path: / pathType: Prefix backend: service: name: varnish-svc port: number: 80 Deploy # kubectl create configmap varnish-config --from-file=default.vcl -n blog-stage kubectl apply -f varnish-ing.yaml -f varnish-svc.yaml -f varnish-dep.yaml Podsumowanie # W moim przypadku zastosowanie varnisha zwiększyło możliwości przetwarzania req/s mojego clustra prawie dziesięciokrotnie. Wszystko oparte jest tutaj o dosyć słabe wydajnościowo free-tier z oracle-cloud\u0026rsquo;a. Natomiast jeżeli połączymy całość z cloudflarem, to można uzyskać więcej niż zadawalające rezultaty.\nLinki # Varnish,\nOracle free-tier.\n","date":"1 lutego 2022","externalUrl":null,"permalink":"/varnish-k8s/","section":"Posts","summary":"Varnish, świetny serwer cache’u umożliwiający bardzo zaawansowaną konfigurację. Większość serwerów cdn dostępnych w internecie wykorzystuje właśnie varnisha na backendzie do serwowania statycznych danych. Osobiście użyłem go jako front przed ghostem, o którego de facto oparty jest ten blog.\n","title":"Varnish - cache serwer w k8s","type":"posts"},{"content":"","date":"5 stycznia 2022","externalUrl":null,"permalink":"/tags/ingress/","section":"Tags","summary":"","title":"Ingress","type":"tags"},{"content":"","date":"5 stycznia 2022","externalUrl":null,"permalink":"/tags/k3s/","section":"Tags","summary":"","title":"K3s","type":"tags"},{"content":"Domyślnym ingressem w k3s jest traefik. Osobiście wolne korzystać z nginx\u0026rsquo;a więc opiszę pokrótce jak zdeploywać go w clustrze k3s\u0026rsquo;a.\nInstalacja k3s # Zaczniemy od instalacji samego k3s z wyłączonym traefikiem:\ncurl -sfL https://get.k3s.io | sh -s - --disable traefik Deploy nginx ingress # Z zainstalowanym \u0026lsquo;clustrem\u0026rsquo; jesteśmy gotowi do instalacji nginx ingress:\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/deploy.yaml Zmieniamy network na lokalny aby wystawić ingress na \u0026lsquo;zewnątrz\u0026rsquo;:\ncat \u0026gt; ingress.yaml \u0026lt;\u0026lt;EOF spec: template: spec: hostNetwork: true EOF kubectl patch deployment ingress-nginx-controller -n ingress-nginx --patch \u0026quot;$(cat ingress.yaml)\u0026quot; Testy deploy\u0026rsquo;u # W tym momencie na localhoscie powinniśmy mieć już wystawiony porty http/s. Możemy to sprawdzić curlem:\n➜ ~ curl https://localhost -k \u0026lt;html\u0026gt; \u0026lt;head\u0026gt;\u0026lt;title\u0026gt;404 Not Found\u0026lt;/title\u0026gt;\u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;center\u0026gt;\u0026lt;h1\u0026gt;404 Not Found\u0026lt;/h1\u0026gt;\u0026lt;/center\u0026gt; \u0026lt;hr\u0026gt;\u0026lt;center\u0026gt;nginx\u0026lt;/center\u0026gt; \u0026lt;/body\u0026gt; Deploy przykładowego nginxa # Utwórzmy zatem przykładowy deployment i wystawmy go za pomocą ingressu:\ncat \u0026gt; deploy.yaml \u0026lt;\u0026lt;EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 1 selector: matchLabels: # manage pods with the label app: nginx app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-ingress annotations: kubernetes.io/ingress.class: nginx spec: rules: - http: paths: - path: / pathType: Prefix backend: service: name: nginx-svc port: number: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-svc spec: ports: - name: http port: 80 selector: app: nginx EOF kubectl apply -f deploy.yaml Ważne tutaj jest dodanie w ingress\u0026rsquo;ie kubernetes.io/ingress.class: nginx. Inaczej nasz ingress nie wystawi naszego servicu.\nJeżeli nie chcemy tego robić musimy wyedytować naszą ingressclass i ustawić go jako default:\nkubectl edit ingressclass nginx annotations: ingressclass.kubernetes.io/is-default-class: \u0026quot;true\u0026quot; Linki # Nginx ingress\n","date":"5 stycznia 2022","externalUrl":null,"permalink":"/k3s-nginx-ingress/","section":"Posts","summary":"Domyślnym ingressem w k3s jest traefik. Osobiście wolne korzystać z nginx’a więc opiszę pokrótce jak zdeploywać go w clustrze k3s’a.\nInstalacja k3s # Zaczniemy od instalacji samego k3s z wyłączonym traefikiem:\n","title":"k3s - nginx ingress","type":"posts"},{"content":"","date":"5 stycznia 2022","externalUrl":null,"permalink":"/tags/nginx/","section":"Tags","summary":"","title":"Nginx","type":"tags"},{"content":"Drone jest fajnym i lekkim toolem do Continuous Integration i Continuous Delivery/Deployment. Jak przy jego po mocy zdeployować coś do clustra k8s?\nZ pomocą przychodzi projekt dostępny na GitHub\u0026rsquo;ie.\nPrzygotowanie # Stwórzmy pipeline, który utworzy nam testowy deployment gotowy do dalszej pracy:\n# drone 1.0 syntax kind: pipeline name: deploy steps: - name: deploy image: sinlead/drone-kubectl settings: kubernetes_server: from_secret: k8s_server kubernetes_cert: from_secret: k8s_cert kubernetes_token: from_secret: k8s_token commands: - kubectl create namespace deploy-test Kiedy mamy już przygotowany pipeline, to musimy dodać dla danego projektu w Drone odpowiednie secrets\u0026rsquo;y:\nSecret\u0026rsquo;y możną wyciągnąć z clustra za pomocą komend:\nkubectl get secret NAME TYPE DATA AGE default-token-lcknp kubernetes.io/service-account-token 3 10d ... kubectl config view -o jsonpath='{range .clusters[*]}{.name}{\u0026quot;\\t\u0026quot;}{.cluster.server}{\u0026quot;\\n\u0026quot;}{end}' kubectl get secret default-token-lcknp -o jsonpath='{.data.token}' | base64 --decode \u0026amp;\u0026amp; echo kubectl get secret default-token-lcknp -o jsonpath='{.data.ca\\.crt}' \u0026amp;\u0026amp; echo Jeżeli wszystko poszło dobrze po odpaleniu pipelina w logach consoli powinniśmy zobaczyć nowo utworzony namespace, który jest gotowy do dalszych prac:\nDziałamy tutaj na uprawnieniach cluster-admin i oczywiście w celach labowych nie ma w tym nic złego. Do nadawani odpowiednich uprawnień w clustrze polecam zapoznać się z rozwiązaniem permission-manager.\nLinki # Drone,\nPermission-manager.\n","date":"14 grudnia 2021","externalUrl":null,"permalink":"/cd-cd-drone-k8s-deploy/","section":"Posts","summary":"Drone jest fajnym i lekkim toolem do Continuous Integration i Continuous Delivery/Deployment. Jak przy jego po mocy zdeployować coś do clustra k8s?\nZ pomocą przychodzi projekt dostępny na GitHub’ie.\nPrzygotowanie # Stwórzmy pipeline, który utworzy nam testowy deployment gotowy do dalszej pracy:\n","title":"CI/CD - drone k8s deploy","type":"posts"},{"content":"Do domowego laba k8s bardzo fajnie sprawdza się microk8s. Jest instalowany przez snapa, jego konfiguracja jest banalna i co najważniejsze posiada masę addonów, które ułatwiają odpalenie wiele rzeczy w sekundę. Jednym z takich addonów jest \u0026ldquo;storage\u0026rdquo;, który utworzy nam storage class w naszym clustrze alokując storage jako host directory.\nPrzydatne jednak może być podpięcie zewnętrznego storygu jak np. NFS.\nPrzygotowanie # Na każdym z nodów clustra musimy zainstalować klienta nfs:\napt install nfs-common -y Deploy NFS jako PV # helm install stable/nfs-client-provisioner --set nfs.server=x.x.x.x --set nfs.path=/example/path Ustawienie domyślnej storage class # kubectl patch storageclass nfs-client -p \u0026#39;{\u0026#34;metadata\u0026#34;: {\u0026#34;annotations\u0026#34;:{\u0026#34;storageclass.kubernetes.io/is-default-class\u0026#34;:\u0026#34;true\u0026#34;}}}\u0026#39; Linki # Helm chart.\n","date":"28 lutego 2021","externalUrl":null,"permalink":"/kubernetes-nfs-storage/","section":"Posts","summary":"Do domowego laba k8s bardzo fajnie sprawdza się microk8s. Jest instalowany przez snapa, jego konfiguracja jest banalna i co najważniejsze posiada masę addonów, które ułatwiają odpalenie wiele rzeczy w sekundę. Jednym z takich addonów jest “storage”, który utworzy nam storage class w naszym clustrze alokując storage jako host directory.\nPrzydatne jednak może być podpięcie zewnętrznego storygu jak np. NFS.\n","title":"Kubernetes - nfs storage","type":"posts"},{"content":"","date":"25 grudnia 2020","externalUrl":null,"permalink":"/tags/lxd/","section":"Tags","summary":"","title":"Lxd","type":"tags"},{"content":"Podczas deployu microk8s w kontenerze LXD może pojawić się problem z daemon-proxy. Wówczas w statusie microk8s zobaczymy:\nFAIL: Service snap.microk8s.daemon-proxy is not running\nW logach samego procesu (journalctl -u snap.microk8s.daemon-proxy) widzimy:\nI1130 18:53:44.150679 1 conntrack.go:52] Setting nf_conntrack_max to 1048576\nI1130 18:53:44.152679 1 conntrack.go:83] Setting conntrack hashsize to 262144\nerror: write /sys/module/nf_conntrack/parameters/hashsize: operation not supported\nProblem ten jest związany z ilością połączeń conntrack i jest zależny od ilości rdzeni/wątków procesora. W przypadku małej liczby rdzeni CPU problem może w ogóle nie występować.\nRozwiązaniem jest oczywiście zwiększenie parametru conntrack hashsize na wskazaną w logu powyżej (lub większą) na serwerze nadrzędnym (hoscie):\necho 262144 \u0026gt; /sys/module/nf_conntrack/parameters/hashsize Linki # Microk8s LXD\n","date":"25 grudnia 2020","externalUrl":null,"permalink":"/microk8s-fail-snap-microk8s-daemon-proxy-is-not-running/","section":"Posts","summary":"Podczas deployu microk8s w kontenerze LXD może pojawić się problem z daemon-proxy. Wówczas w statusie microk8s zobaczymy:\nFAIL: Service snap.microk8s.daemon-proxy is not running\nW logach samego procesu (journalctl -u snap.microk8s.daemon-proxy) widzimy:\n","title":"Microk8s - FAIL: snap.microk8s.daemon-proxy","type":"posts"},{"content":"","date":"8 grudnia 2020","externalUrl":null,"permalink":"/tags/docker/","section":"Tags","summary":"","title":"Docker","type":"tags"},{"content":"Przy pomocy beatów od elasticka i opcji autodiscovery mamy możliwość monitorowania kontenerów z poziomu hosta bez niepotrzebnej ingerencji do środka samych kontenerów. Autodoscoverer podczas startu beat\u0026rsquo;a skanuje odpalone kontenery i przypisuje im odpowiedni config.\nKonfiguracja filebeata # Do głównej konfiguracji filebeat.yml dodajemy wpis (w tym przypadku dla nginx\u0026rsquo;a):\nfilebeat.autodiscover: providers: - type: docker templates: - condition.contains: docker.container.image: nginx config: - module: nginx access: input: type: container paths: - \u0026quot;/var/lib/docker/containers/${data.docker.container.id}/*.log\u0026quot; error: input: type: container paths: - \u0026quot;/var/lib/docker/containers/${data.docker.container.id}/*.log\u0026quot; Filebeat będzie wyszukiwał logów do każdego kontenera zbudowanego z obrazu nginxa i podpinał do niego moduł \u0026ldquo;nginx\u0026rdquo;.\nParametry, po których możemy wyszukiwać konkretne kontenery, jest oczywiście więcej, oto kilka przykładowych:\nhost port docker.container.id docker.container.name docker.container.labels Jeżeli używamy docker-compose musimy dodać jeszcze wpis o logging\u0026rsquo;u do configu:\nnginx: image: nginx:alpine ports: - 80:80 . .some config . logging: driver: \u0026quot;json-file\u0026quot; options: max-size: 10m max-file: \u0026quot;3\u0026quot; labels: \u0026quot;production_status\u0026quot; env: \u0026quot;os\u0026quot; Linki # Autodiscoveredit,\nDocker-compose logging.\n","date":"8 grudnia 2020","externalUrl":null,"permalink":"/filebeat-autodiscovery/","section":"Posts","summary":"Przy pomocy beatów od elasticka i opcji autodiscovery mamy możliwość monitorowania kontenerów z poziomu hosta bez niepotrzebnej ingerencji do środka samych kontenerów. Autodoscoverer podczas startu beat’a skanuje odpalone kontenery i przypisuje im odpowiedni config.\n","title":"Docker - filebeat autodiscovery","type":"posts"},{"content":"","date":"8 grudnia 2020","externalUrl":null,"permalink":"/tags/elk/","section":"Tags","summary":"","title":"Elk","type":"tags"},{"content":"","date":"8 grudnia 2020","externalUrl":null,"permalink":"/tags/filebeat/","section":"Tags","summary":"","title":"Filebeat","type":"tags"},{"content":"W przypadku puppeta sprawa jest bardzo prosta. Najpierw deklarujemy naszą usługę:\nservice { \u0026#34;stunnel4\u0026#34; : ensure =\u0026gt; \u0026#34;running\u0026#34;, enable =\u0026gt; \u0026#34;true\u0026#34;, require =\u0026gt; Package[\u0026#34;stunnel4\u0026#34;], } Następnie w pliku, którym chcemy striggerować nasz serwis dodajemy parametr \u0026rsquo;notify':\nfile { \u0026#39;/etc/stunnel/stunnel.pem\u0026#39;: ## {{{ source =\u0026gt; \u0026#39;puppet:///modules/lb-hq-cm-ha/stunnel-mysql.pem\u0026#39;, owner =\u0026gt; root, group =\u0026gt; root, mode =\u0026gt; \u0026#39;0644\u0026#39;, notify =\u0026gt; Service[\u0026#39;stunnel4\u0026#39;], } ## }}} Linki # Puppet service.\n","date":"5 października 2020","externalUrl":null,"permalink":"/puppet-restart-uslugi-po-zmianie/","section":"Posts","summary":"W przypadku puppeta sprawa jest bardzo prosta. Najpierw deklarujemy naszą usługę:\nservice { \"stunnel4\" : ensure =\u003e \"running\", enable =\u003e \"true\", require =\u003e Package[\"stunnel4\"], } Następnie w pliku, którym chcemy striggerować nasz serwis dodajemy parametr ’notify':\nfile { '/etc/stunnel/stunnel.pem': ## {{{ source =\u003e 'puppet:///modules/lb-hq-cm-ha/stunnel-mysql.pem', owner =\u003e root, group =\u003e root, mode =\u003e '0644', notify =\u003e Service['stunnel4'], } ## }}} Linki # Puppet service.\n","title":"Puppet - restart usługi po zmianie pliku","type":"posts"},{"content":"Przy pracy z gitem nie raz spotkamy się z sytuacją kiedy będziemy musieli wycofać ostatnio dodany commit. Z pomocą przychodzi reset z oderwaniem \u0026ldquo;głowy\u0026rdquo; o jeden commit do góry:\ngit reset --soft HEAD~1 Flaga \u0026ndash;soft pozwala nam na zachowanie zmian w plikach.\ngit reset --hard HEAD~1 Flaga \u0026ndash;hard usuwa wszelkie zmiany w plikach.\nJeżeli chcemy wycofać się o kilka commitów podajemy id danego commita\ngit reset --hard 0a15a3b9 ","date":"1 października 2020","externalUrl":null,"permalink":"/git-cofniecie-ostatniego-commitu/","section":"Posts","summary":"Przy pracy z gitem nie raz spotkamy się z sytuacją kiedy będziemy musieli wycofać ostatnio dodany commit. Z pomocą przychodzi reset z oderwaniem “głowy” o jeden commit do góry:\ngit reset --soft HEAD~1 Flaga –soft pozwala nam na zachowanie zmian w plikach.\n","title":"Git - cofnięcie ostatniego commitu","type":"posts"},{"content":"","date":"30 września 2020","externalUrl":null,"permalink":"/tags/ansible/","section":"Tags","summary":"","title":"Ansible","type":"tags"},{"content":"Przy budowaniu playbooków często musimy dodać jakąś ścieżkę globalnie do zmiennej PATH. Możemy tego dokonać np. przy użyciu modułu copy:\n- name: Add new $PATH. copy: dest: /etc/profile.d/my-path.sh content: \u0026#39;PATH=$PATH:{{ /opt/my/path/ }}\u0026#39; Linki # Ansible copy.\n","date":"30 września 2020","externalUrl":null,"permalink":"/ansible-dodanie-sciezki-path/","section":"Posts","summary":"Przy budowaniu playbooków często musimy dodać jakąś ścieżkę globalnie do zmiennej PATH. Możemy tego dokonać np. przy użyciu modułu copy:\n- name: Add new $PATH. copy: dest: /etc/profile.d/my-path.sh content: 'PATH=$PATH:{{ /opt/my/path/ }}' Linki # Ansible copy.\n","title":"Ansible - dodanie ścieżki $PATH","type":"posts"},{"content":"Exit code przydać nam się mogą w ansiblu do sprawdzania prostych warunków. W tym przypadku do zweryfikowania czy mamy zainstalowany pakiet repozytoriów puppetlabs.\n- name: \u0026quot;Check if puppet is installed\u0026quot; shell: dpkg-query -W puppet5-release register: is_puppet_installed failed_when: no changed_when: no - name: \u0026quot;Download puppetlabs package\u0026quot; get_url: url: https://apt.puppetlabs.com/puppet5-release-{{ ansible_distribution_release }}.deb dest: /tmp/puppet5-release-{{ ansible_distribution_release }}.deb when: is_puppet_installed.rc == 1 - name: \u0026quot;Install puppet repository\u0026quot; apt: deb=\u0026quot;/tmp/puppet5-release-{{ ansible_distribution_release }}.deb\u0026quot; when: is_puppet_installed.rc == 1 Linki # Ansible error handling\n","date":"29 września 2020","externalUrl":null,"permalink":"/ansible/","section":"Posts","summary":"Exit code przydać nam się mogą w ansiblu do sprawdzania prostych warunków. W tym przypadku do zweryfikowania czy mamy zainstalowany pakiet repozytoriów puppetlabs.\n- name: \"Check if puppet is installed\" shell: dpkg-query -W puppet5-release register: is_puppet_installed failed_when: no changed_when: no - name: \"Download puppetlabs package\" get_url: url: https://apt.puppetlabs.com/puppet5-release-{{ ansible_distribution_release }}.deb dest: /tmp/puppet5-release-{{ ansible_distribution_release }}.deb when: is_puppet_installed.rc == 1 - name: \"Install puppet repository\" apt: deb=\"/tmp/puppet5-release-{{ ansible_distribution_release }}.deb\" when: is_puppet_installed.rc == 1 Linki # Ansible error handling\n","title":"Ansible - instalacja pakietu jeśli nie istnieje","type":"posts"},{"content":"","date":"22 września 2020","externalUrl":null,"permalink":"/tags/backup/","section":"Tags","summary":"","title":"Backup","type":"tags"},{"content":"LXD to tak naprawdę nakładka (api) na kontenery LXC.\nBackup kontenerów możemy robić na kilka sposobów.\nSnapshot # Snapshot to tak naprawdę nic innego, jak rsync file systemu danego kontenera. Snapshot nie zapisuje konfiguracji kontenera!\\\nlxc snapshot nazwaKontenera nazwaSnapshotu lxc restore nazwaKontenera nazwaSnapshotu Export # Eksport kontenera zapisuje do pliku tarball cały file system kontenera, wraz ze wszystkimi snapshotami, oraz jego konfiguracją.\nlxc export nazwaKontenera /sciezka/do/pliku.tar lxc import /sciezka/do/pliku.tar Copy # Można również skopiować dany kontener obok lokalnie lub na inny host LXD\nlxd copy nazwaKontenera nowyKontener Rsync # Możemy po prostu użyć starego dobrego rsynca do backupu kontenerów/snapshotów.\nrsync -arhvP /var/lib/lxc /sciezka/do/backupu Skrypt # Prosty skrypt backupujący wszystkie kontenery na danym hoscie\n#!/bin/bash for x in $(lxc list -c n --format csv); do lxc export \u0026#34;${x}\u0026#34; \u0026#34;/opt/backups/lxd/${i}-backup-$(date +\u0026#39;%d-%m-%Y\u0026#39;).tar\u0026#34; done Linki # Projekt LXD,\nBackup lxd by redhat.\n","date":"22 września 2020","externalUrl":null,"permalink":"/backup-kontenerow-lxd/","section":"Posts","summary":"LXD to tak naprawdę nakładka (api) na kontenery LXC.\nBackup kontenerów możemy robić na kilka sposobów.\nSnapshot # Snapshot to tak naprawdę nic innego, jak rsync file systemu danego kontenera. Snapshot nie zapisuje konfiguracji kontenera!\\\n","title":"Backup kontenerów LXD","type":"posts"},{"content":"","date":"22 września 2020","externalUrl":null,"permalink":"/tags/lxc/","section":"Tags","summary":"","title":"Lxc","type":"tags"},{"content":"Haproxy nie umożliwia nam zapisywania logów bezpośrednio do pliku i trzeba w tym celu użyć np. rsysloga. Logi można wysyłać na zdalny serwer logów, lub odpalić taki serwer lokalnie.\nKonfiguracja # Dodajmy konfigurację do rsysloga /etc/rsyslog.d/49-haproxy.conf\n$ModLoad imudp $UDPServerAddress 127.0.0.1 $UDPServerRun 514 local0.panic,local0.alert,local0.crit -/var/log/haproxy-critical.log \u0026amp; ~ local0.error -/var/log/haproxy-error.log \u0026amp; ~ :msg, contains, \u0026quot;SSL handshake\u0026quot; /var/log/haproxy-ssl.log \u0026amp; ~ :msg, contains, \u0026quot;\u0026lt;BADREQ\u0026gt;\u0026quot; /var/log/haproxy-badreq.log \u0026amp; ~ local0.* -/var/log/haproxy.log \u0026amp; ~ Konfiguracja haproxy.conf\nglobal log 127.0.0.1 local0 log 127.0.0.1 local0 info log 127.0.0.1 local0 crit log 127.0.0.1 local0 alert defaults log global log-format %ci:%cp\\ [%t]\\ %ft\\ %b/%s\\ %Tq/%Tw/%Tc/%Tr/%Tt\\ %ST\\ %B\\ %CC\\ %CS\\ %tsc\\ %ac/%fc/%bc/%sc/%rc\\ %sq/%bq\\ %hr\\ %hs\\ %{+Q}r\\ %{+X}o\\ %ci:%cp_%fi:%fp_%Ts_%rt:%pid\\ %sslv\\ %sslc Dodanie reguł logrotat\u0026rsquo;a /etc/logrotate.d/haproxy\n/var/log/haproxy*.log { daily rotate 14 missingok notifempty compress delaycompress postrotate invoke-rc.d rsyslog rotate \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 || true endscript } Na koniec reload haproxy i rsyslog\u0026rsquo;a\nsystemctl reload rsyslog systemctl reload haproxy Linki # Blog HAProxy.\n","date":"20 lipca 2020","externalUrl":null,"permalink":"/haproxy-logowanie-do-pliku/","section":"Posts","summary":"Haproxy nie umożliwia nam zapisywania logów bezpośrednio do pliku i trzeba w tym celu użyć np. rsysloga. Logi można wysyłać na zdalny serwer logów, lub odpalić taki serwer lokalnie.\nKonfiguracja # Dodajmy konfigurację do rsysloga /etc/rsyslog.d/49-haproxy.conf\n","title":"HAProxy - logowanie do pliku","type":"posts"},{"content":"Od marca 2018 r. let\u0026rsquo;s encrypt wprowadził opcję generowania certyfikatów typu wildcard.\nGenerowanie certyfikatu # certbot certonly --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory --manual-public-ip-logging-ok -d '*.kuzdzal.pl' -d kuzdzal.pl W trakcje operacji zostaniemy poproszeni o dodanie rekordu TXT dla wskazanej domeny.\nSaving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator manual, Installer None Obtaining a new certificate Performing the following challenges: dns-01 challenge for kuzdzal.pl - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please deploy a DNS TXT record under the name _acme-challenge.kuzdzal.pl with the following value: x4MrZ6y-JqFJQRmq_lGi9ReRQHPa1aTC9J2O7wDKzq8 Before continuing, verify the record is deployed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Press Enter to Continue Linki # Let\u0026rsquo;s encrypt wildcard,\nCertbot.\n","date":"12 lipca 2020","externalUrl":null,"permalink":"/letsencrypt-wildcard/","section":"Posts","summary":"Od marca 2018 r. let’s encrypt wprowadził opcję generowania certyfikatów typu wildcard.\nGenerowanie certyfikatu # certbot certonly --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory --manual-public-ip-logging-ok -d '*.kuzdzal.pl' -d kuzdzal.pl W trakcje operacji zostaniemy poproszeni o dodanie rekordu TXT dla wskazanej domeny.\n","title":"Let's encrypt - certyfikat wildcard","type":"posts"},{"content":"","date":"12 lipca 2020","externalUrl":null,"permalink":"/tags/lets-encrypt/","section":"Tags","summary":"","title":"Lets Encrypt","type":"tags"},{"content":"","date":"11 lipca 2020","externalUrl":null,"permalink":"/tags/zabbix/","section":"Tags","summary":"","title":"Zabbix","type":"tags"},{"content":"Dzięki agentowi zabbixa możemy uruchamiać zewnętrzne programy/skrypty i przekazywać ich outputu bezpośrednio do serwera zabbixa. Umożliwia to opcja UserParameter.\nProblem może pojawić się, jeżeli skrypt zwraca output po jakimś dłuższym czasie, wtedy zabbix server może nas przywitać błędem:\nTimeout while executing a shell script.\nProblem rozwiązuje zwiększenie parametru Timeout. Opcję musimy zmienić zarówno po stronie agenta monitorowanego serwera, jak i po stronie samego zabbix-server\u0026rsquo;a. W plikach zabbix-agent.conf i zabbix-server.conf ustawiamy parametr timeout na maksymalną wartość 30 sekund:\nTimeout 30\nPo edycji plików konfiguracyjnych robimy reload agenta i servera.\nLinki # UserParameter\\\n","date":"11 lipca 2020","externalUrl":null,"permalink":"/zabbix-timeout/","section":"Posts","summary":"Dzięki agentowi zabbixa możemy uruchamiać zewnętrzne programy/skrypty i przekazywać ich outputu bezpośrednio do serwera zabbixa. Umożliwia to opcja UserParameter.\nProblem może pojawić się, jeżeli skrypt zwraca output po jakimś dłuższym czasie, wtedy zabbix server może nas przywitać błędem:\n","title":"Zabbix - timeout executing script","type":"posts"},{"content":" ","date":"10 lipca 2020","externalUrl":null,"permalink":"/devops-roadmap-2022/","section":"Posts","summary":"","title":"DevOps roadmap 2022","type":"posts"},{"content":"","date":"3 lipca 2020","externalUrl":null,"permalink":"/tags/keepalived/","section":"Tags","summary":"","title":"Keepalived","type":"tags"},{"content":"","date":"3 lipca 2020","externalUrl":null,"permalink":"/tags/ovh/","section":"Tags","summary":"","title":"Ovh","type":"tags"},{"content":"Keepalived, narzędzie do zapewnienia loadbalancingu i wysokiej dostępności (HA).\nWstęp # Jak wiadomo w OVH, aby przypisać adresację publiczną, trzeba wygenerować w panelu adres mac, który następnie musimy przypisać serwerowi. Powstaje więc problem, jeżeli chcemy połączyć serwery keepalive\u0026rsquo;m musimy przypisać obu serwerom te same mac addressy, co może prowadzić do różnych problemów z warstwą L2.\nDodatkowo, jeżeli chcemy przypisać kilka publiczny adresów ip, niezbędne będzie zastosowanie VRF\u0026rsquo;ów (virtual routing and forwarding).\nTablice routingu # Konfiguracja z systemd, edytujemy plik /etc/iproute2/rt_tables i dodajemy nowe tablice:\n100 net-bgp0 101 net-bgp1 102 net-bgp2 103 net-bgp3 104 net-bgp4 Konfiguracja keepalived # Plik konfiguracyjny /etc/keepalived/keepalived.conf:\nvrrp_instance lb-cm { state BACKUP interface eth0 virtual_router_id 53 priority 101 advert_int 1 nopreempt # zapobiega flappowaniu adresacji virtual_routes { # dodanie tablic routingu (default GW) default via 5.6.187.1 dev eth1 } virtual_ipaddress { # przypisanie adresacji 5.6.187.16/24 dev eth1 5.6.187.17/24 dev eth2 5.6.187.18/24 dev eth3 5.6.187.20/24 dev eth4 5.6.187.21/24 dev eth5 } notify /etc/keepalived/keepalivednotify.sh } Podmiana maców # W skrypcie notify, oprócz powiadomienia na slacu o zmianie stanów adresacji, możemy umieścić podmianę mac adresów /etc/keepalived/keepalivednotify.sh:\n#!/bin/bash state=$3 echo $3 \u0026gt; /var/run/keepalive.state case $3 in MASTER) echo \u0026#34;Keepalive\u0026#39;s bringing up - state $3\u0026#34; |/usr/bin/logger -i -t \u0026#34;Tunnel:\u0026#34; ip link set eth1 address 02:01:02:83:6a:6c ip link set eth2 address 02:01:02:40:a6:f1 ip link set eth3 address 02:01:02:7e:fd:eb ip link set eth4 address 02:01:02:c5:e2:9b ip link set eth5 address 02:01:02:4d:7f:49 ip r a default via 5.6.187.16 dev eth1 table net-bgp0 ip r a default via 5.6.187.17 dev eth2 table net-bgp1 ip r a default via 5.6.187.18 dev eth3 table net-bgp2 ip r a default via 5.6.187.20 dev eth4 table net-bgp3 ip r a default via 5.6.187.21 dev eth5 table net-bgp4 ip rule add from 5.6.187.16/32 table net-bgp0 ip rule add from 5.6.187.17/32 table net-bgp1 ip rule add from 5.6.187.18/32 table net-bgp2 ip rule add from 5.6.187.20/32 table net-bgp3 ip rule add from 5.6.187.21/32 table net-bgp4 ip -s -s neigh flush all ;; BACKUP) echo \u0026#34;Tunnel down - state $3\u0026#34; |/usr/bin/logger -i -t \u0026#34;Tunnel:\u0026#34; ip rule del from 5.6.187.16/32 table net-bgp0 ip rule del from 5.6.187.17/32 table net-bgp1 ip rule del from 5.6.187.18/32 table net-bgp2 ip rule del from 5.6.187.20/32 table net-bgp3 ip rule del from 5.6.187.21/32 table net-bgp4 ip link set eth1 address 02:01:02:03:04:01 ip link set eth2 address 02:01:02:03:04:02 ip link set eth3 address 02:01:02:03:04:03 ip link set eth4 address 02:01:02:03:04:04 ip link set eth5 address 02:01:02:03:04:05 ip -s -s neigh flush all ;; *) echo \u0026#34;Error, unknown state. Tunnel down - state $3\u0026#34; | /usr/bin/logger -i -t \u0026#34;Tunnel:\u0026#34; ip rule del from 5.6.187.16/32 table net-bgp0 ip rule del from 5.6.187.17/32 table net-bgp1 ip rule del from 5.6.187.18/32 table net-bgp2 ip rule del from 5.6.187.20/32 table net-bgp3 ip rule del from 5.6.187.21/32 table net-bgp4 ip link set eth1 address 02:01:02:03:04:01 ip link set eth2 address 02:01:02:03:04:02 ip link set eth3 address 02:01:02:03:04:03 ip link set eth4 address 02:01:02:03:04:04 ip link set eth5 address 02:01:02:03:04:05 esac Linki # Virtual routing and forwarding,\nKeepalived.\n","date":"3 lipca 2020","externalUrl":null,"permalink":"/ovh-keepalived-i-publiczne-ip/","section":"Posts","summary":"Keepalived, narzędzie do zapewnienia loadbalancingu i wysokiej dostępności (HA).\nWstęp # Jak wiadomo w OVH, aby przypisać adresację publiczną, trzeba wygenerować w panelu adres mac, który następnie musimy przypisać serwerowi. Powstaje więc problem, jeżeli chcemy połączyć serwery keepalive’m musimy przypisać obu serwerom te same mac addressy, co może prowadzić do różnych problemów z warstwą L2.\nDodatkowo, jeżeli chcemy przypisać kilka publiczny adresów ip, niezbędne będzie zastosowanie VRF’ów (virtual routing and forwarding).\n","title":"OVH - keepalived i publiczne ip (VRF)","type":"posts"},{"content":"Wykonanie dumpa bazy danych kontenera mysql z poziomu hosta:\ndocker exec NAZWA_KONTENERA /usr/bin/mysqldump -u root --password=root DATABASE \u0026gt; backup.sql Odtworzenie dumpa:\ncat backup.sql | docker exec -i NAZWA_KONTENERA /usr/bin/mysql -u root --password=root DATABASE Linki # Docker exec,\nMysqldump.\n","date":"2 lipca 2020","externalUrl":null,"permalink":"/docker-backup-bazy-mysql/","section":"Posts","summary":"Wykonanie dumpa bazy danych kontenera mysql z poziomu hosta:\ndocker exec NAZWA_KONTENERA /usr/bin/mysqldump -u root --password=root DATABASE \u003e backup.sql Odtworzenie dumpa:\ncat backup.sql | docker exec -i NAZWA_KONTENERA /usr/bin/mysql -u root --password=root DATABASE Linki # Docker exec,\nMysqldump.\n","title":"Docker - backup Bazy MySQL","type":"posts"},{"content":"","date":"2 lipca 2020","externalUrl":null,"permalink":"/tags/mysql/","section":"Tags","summary":"","title":"Mysql","type":"tags"},{"content":"Żeby zapewnić HA cluster powinien składać się, z nieparzystej liczby nodów (3, 5, 7\u0026hellip;). Samo XtraDB jest forkiem MySQL Galera.\nWstęp # Poniżej przykładowa konfiguracja dla dwóch nodów (niezalecana):\nxtradb-1 - 10.1.100.101\nxtradb-2 - 10.1.100.102\nKonfiguracja zakłada komunikację po adresach IP (samo resolvowanie dnsów przy bazach danych, jest niezalecane ze względu na performance).\nDodanie kolejnych nodów przebiega analogicznie.\nInstalacja (deb/ubuntu) # apt-get update \u0026amp;\u0026amp; apt-get install lsb-release gnupg wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb apt-get update \u0026amp;\u0026amp; apt-get install percona-xtradb-cluster-57 -y Konfiguracja # Przed dalszym etapem wymagane jest zatrzymanie baz na wszystkich nodach:\nsystemctl stop mysql.service Podnoszenie clustra zawsze wygląda tak samo. Przygotowujemy jeden z nodów, którego będziemy bootstrapować, następnie podłączać do niego pozostałe nody.\nNa każdym z nodów edytujemy plik: /etc/mysql/percona-xtradb-cluster.conf.d/wsrep.cnf\n\\[mysqld\\]\nwsrep_provider=/usr/lib/galera3/libgalera_smm.so\nwsrep_cluster_address=gcomm://10.1.100.101,10.1.100.102\nbinlog_format=ROW\ndefault_storage_engine=InnoDB\nwsrep_slave_threads= 8\nwsrep_log_conflicts\ninnodb_autoinc_lock_mode=2\nwsrep_node_address=10.1.100.101\nwsrep_cluster_name=XtraDB_Cluster\nwsrep_node_name=node-1\npxc_strict_mode=ENFORCING\nwsrep_sst_method=xtrabackup-v2\nwsrep_sst_auth=”sstuser:YourPassword”\nNa pozostałych nodach zmieniamy tylko wsrep_node_name i wsrep_node_address\nInicjalizacja clustra # /etc/init.d/mysql bootstrap-pxc Dodanie użytkownika API wsrep:\nmysql -p -e \u0026#34;CREATE USER \u0026#39;sstuser\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY \u0026#39;YourPassword\u0026#39;;GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO \u0026#39;sstuser\u0026#39;@\u0026#39;localhost\u0026#39;;FLUSH PRIVILEGES;\u0026#34; Dodanie kolejnego noda # Po edycji pliku konfiguracyjnego i podmianie node_name i node_address, podłączamy host poprzez wystartowanie bazy\nsystemctl start mysql.service Status XtraDB Cluster # Status można sprawdzić z poziomu mysql\u0026rsquo;a:\nmysql -p -e \u0026#34;show status like \u0026#39;wsrep%’;\u0026#34; Linki # Dokumentacja percony,\nBootstrap noda,\nAPI wsrep,\nMySQL Galera.\\\n","date":"29 czerwca 2020","externalUrl":null,"permalink":"/xtradb-cluster/","section":"Posts","summary":"Żeby zapewnić HA cluster powinien składać się, z nieparzystej liczby nodów (3, 5, 7…). Samo XtraDB jest forkiem MySQL Galera.\nWstęp # Poniżej przykładowa konfiguracja dla dwóch nodów (niezalecana):\nxtradb-1 - 10.1.100.101\nxtradb-2 - 10.1.100.102\nKonfiguracja zakłada komunikację po adresach IP (samo resolvowanie dnsów przy bazach danych, jest niezalecane ze względu na performance).\nDodanie kolejnych nodów przebiega analogicznie.\n","title":"XtraDB Cluster","type":"posts"},{"content":"Ansible kurs od redhat\u0026rsquo;a,\nGra do nauki git\u0026rsquo;a,\nGra do nauki SQL\u0026rsquo;a,\nPlugin do nauki VIM\u0026rsquo;a,\nWlasny serwer s3,\nDarmowa książka Automate the Boring Stuff with Python,\n","date":"19 czerwca 2020","externalUrl":null,"permalink":"/link/","section":"Posts","summary":"Ansible kurs od redhat’a,\nGra do nauki git’a,\nGra do nauki SQL’a,\nPlugin do nauki VIM’a,\nWlasny serwer s3,\nDarmowa książka Automate the Boring Stuff with Python,\n","title":"Zbiór ciekawych linków","type":"posts"},{"content":"Cześć, jestem Michał 👋\nSRE/DevOps. Na co dzień pilnuję, żeby infra stała prosto, stawiała się sama i krzyczała, zanim coś padnie. Ten blog to mój dziennik pracy — krótkie notatki, potknięcia i rozwiązania, które chcę zapamiętać.\nLubię rzeczy proste, powtarzalne i opisane w gicie. Mniej klikania, więcej kodu.\nCzym się bawię # Orkiestracja \u0026amp; deploy — Kubernetes, ArgoCD, GitLab CI/CD, Harbor, LXD Infrastruktura jako kod — Terraform, Ansible, Puppet Observability — Prometheus, VictoriaMetrics, Grafana, Icinga, ELK (Elasticsearch, Logstash, Kibana), Kafka (Queueing / Log-aggregation) Bazy danych — TiDB, TiKV, MySQL, Percona XtraDB Cluster, MongoDB Storage — JuiceFS, ZFS Ruch — HAProxy, Nginx, Traefik, ProxySQL Sekrety — Vault A pod spodem cała „nudna\u0026quot; podstawa — Linux, Docker, Git, Bash, Python — bez której to nie ruszy.\nGdzie mnie złapać # GitHub LinkedIn Email ","date":"19 czerwca 2020","externalUrl":null,"permalink":"/about/","section":"Michał Kuzdzal","summary":"Cześć, jestem Michał 👋\nSRE/DevOps. Na co dzień pilnuję, żeby infra stała prosto, stawiała się sama i krzyczała, zanim coś padnie. Ten blog to mój dziennik pracy — krótkie notatki, potknięcia i rozwiązania, które chcę zapamiętać.\n","title":"O mnie","type":"page"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"}]