<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[michal.kuzdzal.pl]]></title><description><![CDATA[Sys/DevOps - Ku pamięci]]></description><link>http://michal.kuzdzal.pl/</link><image><url>http://michal.kuzdzal.pl/favicon.png</url><title>michal.kuzdzal.pl</title><link>http://michal.kuzdzal.pl/</link></image><generator>Ghost 5.7</generator><lastBuildDate>Fri, 27 Mar 2026 22:13:47 GMT</lastBuildDate><atom:link href="http://michal.kuzdzal.pl/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Przyśpieszenie rolling restart i recovery shardów w Elasticsearch]]></title><description><![CDATA[<p>Czasem trzeba zrobi&#x107; rolling restart w klastrze Elasticsearch - wymieni&#x107; sprz&#x119;t, zaktualizowa&#x107; wersj&#x119; lub przenie&#x15B;&#x107; shardy na nowy w&#x119;ze&#x142;. Bez odpowiedniego przygotowania proces mo&#x17C;e trwa&#x107; d&#x142;ugo i generowa&#x107; du&#x17C;o niepotrzebnego ruchu.</p>]]></description><link>http://michal.kuzdzal.pl/elasticsearch-recovery-speedup/</link><guid isPermaLink="false">689b3bf9c6823b00015c08f3</guid><category><![CDATA[elasticsearch]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Tue, 12 Aug 2025 13:19:19 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2025/08/elasticsearch-speedup-recovery.png" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2025/08/elasticsearch-speedup-recovery.png" alt="Przy&#x15B;pieszenie rolling restart i recovery shard&#xF3;w w Elasticsearch"><p>Czasem trzeba zrobi&#x107; rolling restart w klastrze Elasticsearch - wymieni&#x107; sprz&#x119;t, zaktualizowa&#x107; wersj&#x119; lub przenie&#x15B;&#x107; shardy na nowy w&#x119;ze&#x142;. Bez odpowiedniego przygotowania proces mo&#x17C;e trwa&#x107; d&#x142;ugo i generowa&#x107; du&#x17C;o niepotrzebnego ruchu.<br>Poni&#x17C;ej opisuj&#x119;, co robi&#x119;, &#x17C;eby przyspieszy&#x107; restart i ograniczy&#x107; ruch shard&#xF3;w.</p><hr><h3 id="wy%C5%82%C4%85czanie-alokacji-shard%C3%B3w-podczas-restartu">Wy&#x142;&#x105;czanie alokacji shard&#xF3;w podczas restartu</h3><p>&#x17B;eby unikn&#x105;&#x107; niekontrolowanego przemieszczania shard&#xF3;w w trakcie restartu w&#x119;z&#x142;a, wy&#x142;&#x105;czam alokacj&#x119; replik. Klaster wtedy nie zaczyna od razu przesuwa&#x107; danych, co pozwala na kontrolowany proces restartu.</p><pre><code>PUT _cluster/settings 
{
  &quot;persistent&quot;: {    &quot;cluster.routing.allocation.enable&quot;: &quot;primaries&quot;  }
}</code></pre><p>Po zako&#x144;czeniu restartu przywracam domy&#x15B;lne ustawienie:</p><pre><code>PUT _cluster/settings
{
  &quot;persistent&quot;: {    &quot;cluster.routing.allocation.enable&quot;: null  }
}</code></pre><hr><h3 id="op%C3%B3%C5%BAnienie-reakcji-klastra-delayed-timeout">Op&#xF3;&#x17A;nienie reakcji klastra (delayed timeout)</h3><p>Domy&#x15B;lnie Elasticsearch od razu po utracie w&#x119;z&#x142;a zaczyna rebalansowa&#x107; shardy, co generuje zb&#x119;dny ruch, je&#x15B;li w&#x119;ze&#x142; szybko wr&#xF3;ci. Zwi&#x119;kszam timeout, &#x17C;eby da&#x107; czas na ewentualny powr&#xF3;t w&#x119;z&#x142;a.</p><p><code>PUT _all/_settings { &#xA0;&quot;index.unassigned.node_left.delayed_timeout&quot;: &quot;5m&quot;}</code></p><hr><h3 id="flush-przed-restartem">Flush przed restartem</h3><p>Wykonuj&#x119; flush, &#x17C;eby zapisa&#x107; segmenty na dysk i przyspieszy&#x107; p&#xF3;&#x17A;niejsze odzyskiwanie shard&#xF3;w.</p><p><code>POST /_flush</code></p><hr><h3 id="restart-node-po-node">Restart node po node</h3><p>Restart wykonuj&#x119; pojedynczo dla ka&#x17C;dego w&#x119;z&#x142;a:</p><ol><li>Wy&#x142;&#x105;czam alokacj&#x119; shard&#xF3;w (patrz wy&#x17C;ej)</li><li>Robi&#x119; flush</li><li>Restartuj&#x119; w&#x119;ze&#x142;</li><li>Przywracam alokacj&#x119; shard&#xF3;w (<code>null</code>)</li><li>Czekam na status klastra <strong>green</strong></li><li>Powtarzam dla kolejnego w&#x119;z&#x142;a</li></ol><hr><h3 id="tuning-recovery-shard%C3%B3w">Tuning recovery shard&#xF3;w</h3><p>Je&#x15B;li infrastruktura pozwala, zwi&#x119;kszam liczb&#x119; r&#xF3;wnoczesnych recovery i limit przepustowo&#x15B;ci, &#x17C;eby skr&#xF3;ci&#x107; czas odtwarzania shard&#xF3;w.</p><pre><code>PUT _cluster/settings 
{  
  &quot;persistent&quot;: {
    &quot;cluster.routing.allocation.node_concurrent_recoveries&quot;: 15,
    &quot;indices.recovery.max_bytes_per_sec&quot;: &quot;2000mb&quot;  
  }
}</code></pre>]]></content:encoded></item><item><title><![CDATA[Puppet przejęty przez Perforce - co się zmieniło i jakie są inne alternatywy dla Puppet?]]></title><description><![CDATA[<p>Puppet przez lata by&#x142; jednym z filar&#xF3;w automatyzacji i konfiguracji w du&#x17C;ych &#x15B;rodowiskach IT. W 2022 roku projekt zosta&#x142; przej&#x119;ty przez firm&#x119; <strong>Perforce</strong>, a pod koniec 2024 roku og&#x142;oszono powa&#x17C;ne zmiany w sposobie dystrybucji i licencjonowania.</p>]]></description><link>http://michal.kuzdzal.pl/puppet-przejety-przez-perforce-co-sie-zmienilo-i-jakie-sa-inne-alternatywy-dla-puppet/</link><guid isPermaLink="false">68958103c6823b00015c08ac</guid><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Fri, 08 Aug 2025 05:01:41 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2025/08/puppet-vs-openvox.png" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2025/08/puppet-vs-openvox.png" alt="Puppet przej&#x119;ty przez Perforce - co si&#x119; zmieni&#x142;o i jakie s&#x105; inne alternatywy dla Puppet?"><p>Puppet przez lata by&#x142; jednym z filar&#xF3;w automatyzacji i konfiguracji w du&#x17C;ych &#x15B;rodowiskach IT. W 2022 roku projekt zosta&#x142; przej&#x119;ty przez firm&#x119; <strong>Perforce</strong>, a pod koniec 2024 roku og&#x142;oszono powa&#x17C;ne zmiany w sposobie dystrybucji i licencjonowania.</p><p>Najwa&#x17C;niejsze z nich to:</p><ul><li>od 2025 roku oficjalne <strong>binarki Puppet</strong> s&#x105; dost&#x119;pne wy&#x142;&#x105;cznie w prywatnym repozytorium Perforce,</li><li>aby z nich korzysta&#x107;, trzeba zaakceptowa&#x107; now&#x105; licencj&#x119;,</li><li>darmowa wersja pozwala na zarz&#x105;dzanie maksymalnie <strong>25 w&#x119;z&#x142;ami (agentami)</strong> - powy&#x17C;ej tego progu konieczna jest komercyjna umowa,</li></ul><p>kod &#x17A;r&#xF3;d&#x142;owy pozostaje otwarty (Apache 2.0), ale tempo publicznych aktualizacji jest wolniejsze ni&#x17C; dotychczas.</p><p>Limit 25 w&#x119;z&#x142;&#xF3;w mo&#x17C;e brzmie&#x107; jak co&#x15B; akceptowalnego dla ma&#x142;ych &#x15B;rodowisk, ale w praktyce nie wystarczy niemal nikomu - nawet niewielkie firmy &#x142;atwo przekraczaj&#x105; t&#x119; liczb&#x119;, licz&#x105;c serwery produkcyjne, stagingowe, bazy danych czy load balancery.</p><hr><h2 id="openvoxspo%C5%82eczno%C5%9Bciowa-odpowied%C5%BA-na-zmiany">OpenVox - spo&#x142;eczno&#x15B;ciowa odpowied&#x17A; na zmiany</h2><p>W odpowiedzi na nowe zasady licencjonowania powsta&#x142; fork o nazwie <strong>OpenVox</strong>, prowadzony przez spo&#x142;eczno&#x15B;&#x107; <strong>Vox Pupuli</strong>. Projekt ma na celu utrzymanie otwartej, dost&#x119;pnej dla wszystkich wersji Puppet, wraz z gotowymi binarkami i bez ogranicze&#x144; liczby w&#x119;z&#x142;&#xF3;w.</p><p>Trzeba jednak pami&#x119;ta&#x107;, &#x17C;e korzystanie z forka wi&#x105;&#x17C;e si&#x119; z pewnym ryzykiem:</p><ul><li>projekt mo&#x17C;e zosta&#x107; porzucony w dowolnym momencie,</li><li>tempo rozwoju i wydawania poprawek mo&#x17C;e by&#x107; wolniejsze,</li><li>nie ma gwarancji takiej stabilno&#x15B;ci i test&#xF3;w, jak w produkcie wspieranym przez firm&#x119;,</li><li>mog&#x105; pojawi&#x107; si&#x119; problemy z kompatybilno&#x15B;ci&#x105; w przysz&#x142;o&#x15B;ci,</li><li>liczba dost&#x119;pnych modu&#x142;&#xF3;w i integracji mo&#x17C;e by&#x107; mniejsza ni&#x17C; w oryginale.</li></ul><p>Dla niekt&#xF3;rych organizacji OpenVox mo&#x17C;e by&#x107; atrakcyjn&#x105; opcj&#x105;, ale w wi&#x119;kszych, krytycznych &#x15B;rodowiskach trzeba dok&#x142;adnie oceni&#x107;, czy ryzyko jest akceptowalne.</p><hr><h2 id="jakie-s%C4%85-inne-alternatywy-dla-puppet">Jakie s&#x105; inne alternatywy dla Puppet?</h2><p>Je&#x17C;eli Puppet w nowym modelu licencyjnym nie spe&#x142;nia Twoich wymaga&#x144;, na rynku wci&#x105;&#x17C; jest kilka dojrza&#x142;ych narz&#x119;dzi do automatyzacji konfiguracji:</p><ul><li><strong>Ansible -</strong> w pe&#x142;ni open source, bez ogranicze&#x144; liczby host&#xF3;w. Bardzo popularny w DevOpsach i CI/CD, konfiguracje pisane w YAML. Jest on agentless, przez co nie jest do konca alternatyw&#x105; dla puppeta,</li><li><strong>Chef</strong> - projekt open source w teorii, ale <strong>darmowy tylko w okre&#x15B;lonych przypadkach</strong>: u&#x17C;ytek osobisty, non-profit w okre&#x15B;lonych ramach, lub organizacje kontrybuuj&#x105;ce do Chef OSS. W ka&#x17C;dej innej sytuacji wymagana jest komercyjna licencja,</li><li><strong>SaltStack (Salt)</strong> - otwarte narz&#x119;dzie przej&#x119;te przez VMware, dzia&#x142;aj&#x105;ce w trybie master/minion lub agentless. Wersja OSS nie ma limit&#xF3;w liczby w&#x119;z&#x142;&#xF3;w, wersja komercyjna dodaje GUI i integracje klasy enterprise.</li></ul><hr><h2 id="co-to-oznacza-dla-nas">Co to oznacza dla nas</h2><p>Zmiany w Puppet to jasny sygna&#x142;, &#x17C;e nawet d&#x142;ugoletnie projekty open source mog&#x105; w pewnym momencie zmieni&#x107; sw&#xF3;j model biznesowy. Dla wi&#x119;kszo&#x15B;ci firm limit 25 w&#x119;z&#x142;&#xF3;w to realna przeszkoda, wymuszaj&#x105;ca dodatkowe koszty lub migracj&#x119; na inne rozwi&#x105;zanie.</p><p>Warto wi&#x119;c ju&#x17C; teraz przyjrze&#x107; si&#x119; alternatywom - czy to w formie forka OpenVox, czy przej&#x15B;cia na inne narz&#x119;dzia takie jak Ansible, SaltStack czy Chef - i oceni&#x107;, kt&#xF3;re z nich najlepiej odpowiadaj&#x105; na potrzeby naszej infrastruktury.</p>]]></content:encoded></item><item><title><![CDATA[ArgoCD App-of-Apps: Jak efektywnie zarządzać aplikacjami w Kubernetes?]]></title><description><![CDATA[Odkryj wzorzec ArgoCD App-of-Apps i skaluj zarządzanie aplikacjami w Kubernetes. Dowiedz się, jak stworzyć spójną architekturę GitOps ...]]></description><link>http://michal.kuzdzal.pl/argocd-app-of-apps-jak-zarzadzac-gitops-w-k8s/</link><guid isPermaLink="false">6890aecc92967a0001d3c884</guid><category><![CDATA[k8s]]></category><category><![CDATA[argocd]]></category><category><![CDATA[devops]]></category><category><![CDATA[git]]></category><category><![CDATA[gitops]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Fri, 01 Aug 2025 14:42:00 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2025/08/argocd-app-of-apps.png" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2025/08/argocd-app-of-apps.png" alt="ArgoCD App-of-Apps: Jak efektywnie zarz&#x105;dza&#x107; aplikacjami w Kubernetes?"><p>W &#x15B;wiecie <strong>Kubernetes</strong>, zarz&#x105;dzanie rosn&#x105;c&#x105; liczb&#x105; aplikacji i ich konfiguracjami staje si&#x119; wyzwaniem. Tradycyjne podej&#x15B;cia cz&#x119;sto prowadz&#x105; do powielania konfiguracji i trudno&#x15B;ci w utrzymaniu sp&#xF3;jno&#x15B;ci w r&#xF3;&#x17C;nych &#x15B;rodowiskach (<strong>staging</strong> i <strong>production</strong>). W&#x142;a&#x15B;nie tutaj z pomoc&#x105; przychodzi wzorzec <strong>App-of-Apps</strong> (aplikacja aplikacji) w <strong>ArgoCD</strong>, kt&#xF3;ry pozwala na <strong>skalowalne zarz&#x105;dzanie</strong> ca&#x142;ym ekosystemem aplikacji z jednego, centralnego miejsca.</p><p>Wzorzec <strong>ArgoCD App-of-Apps</strong> polega na tym, &#x17C;e jedna, g&#x142;&#xF3;wna aplikacja (<em>parent application</em>) zarz&#x105;dza cyklem &#x17C;ycia wielu innych aplikacji (<em>child applications</em>). Zamiast konfigurowa&#x107; ka&#x17C;d&#x105; aplikacj&#x119; z osobna, definiujemy je wszystkie w jednej, nadrz&#x119;dnej aplikacji, kt&#xF3;ra nast&#x119;pnie synchronizuje i monitoruje ich stan. To kluczowy element podej&#x15B;cia <strong>GitOps z ArgoCD</strong>.</p><hr><h2 id="architektura-i-struktura-katalog%C3%B3w-dla-gitops-z-argocd">Architektura i struktura katalog&#xF3;w dla <strong>GitOps z ArgoCD</strong></h2><p>Aby w pe&#x142;ni wykorzysta&#x107; wzorzec App-of-Apps, kluczowa jest przemy&#x15B;lana struktura katalog&#xF3;w w <strong>repozytorium Git</strong>. Umo&#x17C;liwia ona sp&#xF3;jne definiowanie konfiguracji dla r&#xF3;&#x17C;nych &#x15B;rodowisk.</p><pre><code>.
&#x251C;&#x2500;&#x2500; app-of-apps
&#x2502;&#xA0; &#xA0;&#x251C;&#x2500;&#x2500; values-production.yaml  # Globalne warto&#x15B;ci dla produkcji
&#x2502;&#xA0; &#xA0;&#x2514;&#x2500;&#x2500; values-staging.yaml     # Globalne warto&#x15B;ci dla stagingu
&#x251C;&#x2500;&#x2500; apps
&#x2502;&#xA0; &#xA0;&#x251C;&#x2500;&#x2500; cert-manager
&#x2502;&#xA0; &#xA0;&#x2502;&#xA0; &#xA0;&#x251C;&#x2500;&#x2500; Chart.yaml          # Definicja Helm chart dla cert-manager
&#x2502;&#xA0; &#xA0;&#x2502;&#xA0; &#xA0;&#x251C;&#x2500;&#x2500; values-production.yaml # Warto&#x15B;ci dla produkcji
&#x2502;&#xA0; &#xA0;&#x2502;&#xA0; &#xA0;&#x2514;&#x2500;&#x2500; values-staging.yaml    # Warto&#x15B;ci dla stagingu
&#x2502;&#xA0; &#xA0;&#x2514;&#x2500;&#x2500; fluent-bit
&#x2502;&#xA0; &#xA0; &#xA0; &#xA0;&#x251C;&#x2500;&#x2500; Chart.yaml          # Definicja Helm chart dla fluent-bit
&#x2502;&#xA0; &#xA0; &#xA0; &#xA0;&#x251C;&#x2500;&#x2500; values-production.yaml # Warto&#x15B;ci dla produkcji
&#x2502;&#xA0; &#xA0; &#xA0; &#xA0;&#x2514;&#x2500;&#x2500; values-staging.yaml    # Warto&#x15B;ci dla stagingu
</code></pre><p>W tej strukturze:</p><ul><li><strong><code>app-of-apps</code></strong>: Katalog zawiera g&#x142;&#xF3;wne pliki <code>values.yaml</code> dla ka&#x17C;dego &#x15B;rodowiska. Te pliki kontroluj&#x105;, kt&#xF3;re aplikacje i z jakimi parametrami maj&#x105; zosta&#x107; wdro&#x17C;one w danym &#x15B;rodowisku.</li><li><strong><code>apps</code></strong>: Katalog, w kt&#xF3;rym znajduj&#x105; si&#x119; definicje (w moim przypadku <strong><em>Helm Charts</em></strong>) ka&#x17C;dej z aplikacji (<em>child applications</em>). Ka&#x17C;da aplikacja ma sw&#xF3;j w&#x142;asny podkatalog z plikiem <code>Chart.yaml</code> i specyficznymi plikami <code>values.yaml</code> dla r&#xF3;&#x17C;nych &#x15B;rodowisk.</li></ul><hr><h2 id="konfiguracja-helm-chart-jako-zale%C5%BCno%C5%9Bci">Konfiguracja Helm Chart jako zale&#x17C;no&#x15B;ci</h2><p>W naszym przyk&#x142;adzie, <strong>cert-manager</strong> jest wdra&#x17C;any jako <strong>Helm Chart</strong>, ale zamiast kopiowa&#x107; ca&#x142;y kod, definiujemy go jako <strong>zale&#x17C;no&#x15B;&#x107;</strong> (dependencies) w pliku <code>Chart.yaml</code>:</p><pre><code>apiVersion: v2
name: cert-manager
description: Helm chart for cert-manager
type: application
version: 0.1.0
appVersion: 1.0.0
dependencies:
&#xA0; - name: cert-manager
&#xA0; &#xA0; alias: certmanager
&#xA0; &#xA0; version: 1.16.2
&#xA0; &#xA0; repository: https://charts.jetstack.io
</code></pre><p>Dzi&#x119;ki temu podej&#x15B;ciu, nasza g&#x142;&#xF3;wna aplikacja <strong>ArgoCD</strong> instaluje <code>cert-managera</code> z oficjalnego repozytorium Jetstack. My natomiast, w pliku <code>values-production.yaml</code>, mo&#x17C;emy &#x142;atwo dostosowa&#x107; jego konfiguracj&#x119; za pomoc&#x105; aliasu <code>certmanager</code>:</p><pre><code>certmanager:
&#xA0; namespace: cert-manager
&#xA0; crds:
&#xA0; &#xA0; enabled: true
&#xA0; replicaCount: 2
&#xA0; podDisruptionBudget:
&#xA0; &#xA0; enabled: true
</code></pre><p>To bardzo elastyczne <strong>zarz&#x105;dzanie aplikacjami</strong>, poniewa&#x17C; pozwala na dostosowanie konfiguracji zewn&#x119;trznego charta bez modyfikowania go bezpo&#x15B;rednio, a jednocze&#x15B;nie utrzymanie wszystkich specyficznych dla &#x15B;rodowiska parametr&#xF3;w w jednym miejscu.</p><hr><h2 id="podsumowanie-i-korzy%C5%9Bci">Podsumowanie i korzy&#x15B;ci</h2><p>U&#x17C;ywanie wzorca <strong>App-of-Apps</strong> w <strong>ArgoCD</strong>, w po&#x142;&#x105;czeniu z dobrze zorganizowan&#x105; struktur&#x105; katalog&#xF3;w, przynosi liczne korzy&#x15B;ci dla Twojego <strong>zarz&#x105;dzania infrastruktur&#x105;</strong>:</p><ul><li><strong>Standaryzacja</strong>: Konfiguracje dla r&#xF3;&#x17C;nych &#x15B;rodowisk s&#x105; sp&#xF3;jne i &#x142;atwe do zarz&#x105;dzania.</li><li><strong>&#x141;atwo&#x15B;&#x107; zarz&#x105;dzania</strong>: Zmiany wprowadzane s&#x105; w jednym miejscu, co minimalizuje b&#x142;&#x119;dy.</li><li><strong>Skalowalno&#x15B;&#x107;</strong>: Dodawanie nowych aplikacji jest proste.</li><li><strong>Automatyzacja</strong>: ArgoCD automatycznie wykrywa i wdra&#x17C;a zmiany, zapewniaj&#x105;c sp&#xF3;jno&#x15B;&#x107; stanu klastra.</li></ul>]]></content:encoded></item><item><title><![CDATA[In-place Pod Resize i Sidecary w Kubernetes 1.33 – Co to zmienia?]]></title><description><![CDATA[<h3 id="tldr">TL;DR</h3><p>Kubernetes 1.33 to kamie&#x144; milowy, kt&#xF3;ry znacz&#x105;co podnosi elastyczno&#x15B;&#x107; i bezpiecze&#x144;stwo platformy. Kluczowe nowo&#x15B;ci to stabilne, natywne <strong>kontenery sidecar</strong>, kt&#xF3;re upraszczaj&#x105; z&#x142;o&#x17C;one architektury, oraz funkcja <strong>in-place Pod resize</strong>, umo&</p>]]></description><link>http://michal.kuzdzal.pl/kubernetes-133/</link><guid isPermaLink="false">6890c9c092967a0001d3c89c</guid><category><![CDATA[kubernetes]]></category><category><![CDATA[k8s]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Mon, 28 Jul 2025 13:18:00 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2025/08/k8s-pod-resize-sidecar.png" medium="image"/><content:encoded><![CDATA[<h3 id="tldr">TL;DR</h3><img src="http://michal.kuzdzal.pl/content/images/2025/08/k8s-pod-resize-sidecar.png" alt="In-place Pod Resize i Sidecary w Kubernetes 1.33 &#x2013; Co to zmienia?"><p>Kubernetes 1.33 to kamie&#x144; milowy, kt&#xF3;ry znacz&#x105;co podnosi elastyczno&#x15B;&#x107; i bezpiecze&#x144;stwo platformy. Kluczowe nowo&#x15B;ci to stabilne, natywne <strong>kontenery sidecar</strong>, kt&#xF3;re upraszczaj&#x105; z&#x142;o&#x17C;one architektury, oraz funkcja <strong>in-place Pod resize</strong>, umo&#x17C;liwiaj&#x105;ca zmian&#x119; alokacji zasob&#xF3;w (CPU i pami&#x119;ci) w dzia&#x142;aj&#x105;cych kontenerach bez konieczno&#x15B;ci ich restartu. Dodatkowo, domy&#x15B;lnie w&#x142;&#x105;czone <strong>przestrzenie nazw u&#x17C;ytkownik&#xF3;w</strong> podnosz&#x105; poziom izolacji, czyni&#x105;c Kubernetes jeszcze pot&#x119;&#x17C;niejszym narz&#x119;dziem dla ka&#x17C;dego dewelopera i administratora.</p><hr><h2 id="1-kubernetes-133-%E2%80%93-ewolucja-a-nie-rewolucja">1. Kubernetes 1.33 &#x2013; Ewolucja, a nie rewolucja</h2><p>Kubernetes nie przestaje si&#x119; rozwija&#x107;, a ka&#x17C;da nowa wersja to krok w stron&#x119; doskonalszej orkiestracji kontener&#xF3;w. Wersja 1.33, najnowsze wydanie, skupia si&#x119; na <strong>ewolucji platformy</strong>, dostarczaj&#x105;c funkcji, na kt&#xF3;re spo&#x142;eczno&#x15B;&#x107; czeka&#x142;a od dawna. W artykule przybli&#x17C;amy dwie najwa&#x17C;niejsze nowo&#x15B;ci, kt&#xF3;re mog&#x105; zmieni&#x107; spos&#xF3;b projektowania i zarz&#x105;dzania aplikacjami w chmurze.</p><hr><h2 id="2-natywne-kontenery-sidecar-prostsze-zarz%C4%85dzanie-z%C5%82o%C5%BConymi-architekturami">2. Natywne kontenery sidecar: Prostsze zarz&#x105;dzanie z&#x142;o&#x17C;onymi architekturami</h2><p>Wzorzec <strong>sidecar</strong>, polegaj&#x105;cy na umieszczaniu dodatkowych kontener&#xF3;w pomocniczych (np. do logowania czy monitorowania) obok g&#x142;&#xF3;wnej aplikacji w tym samym Podzie, zawsze by&#x142; popularny. Jednak jego implementacja w starszych wersjach Kubernetes bywa&#x142;a problematyczna.</p><p><strong>Jak to dzia&#x142;a&#x142;o wcze&#x15B;niej?</strong> Wcze&#x15B;niej, gdy startowa&#x142; Pod, nie by&#x142;o gwarancji kolejno&#x15B;ci uruchamiania kontener&#xF3;w. Cz&#x119;sto zdarza&#x142;o si&#x119;, &#x17C;e g&#x142;&#xF3;wny kontener startowa&#x142; przed sidecarem. Prowadzi&#x142;o to do nieprzewidywalnych zachowa&#x144; i b&#x142;&#x119;d&#xF3;w, szczeg&#xF3;lnie podczas rolowania wdro&#x17C;e&#x144;, poniewa&#x17C; aplikacja mog&#x142;a pr&#xF3;bowa&#x107; komunikowa&#x107; si&#x119; z sidecarem, kt&#xF3;ry jeszcze nie by&#x142; gotowy. Wymaga&#x142;o to stosowania skomplikowanych mechanizm&#xF3;w i skrypt&#xF3;w, aby wymusi&#x107; poprawn&#x105; kolejno&#x15B;&#x107;.</p><p><strong>Jak to dzia&#x142;a teraz w Kubernetes 1.33?</strong> Dzi&#x119;ki natywnemu wsparciu dla sidecar&#xF3;w, proces zosta&#x142; ca&#x142;kowicie zmieniony. Kubernetes implementuje sidecary jako specjaln&#x105; klas&#x119; <strong><code>init containers</code> z <code>restartPolicy: Always</code></strong>. To gwarantuje, &#x17C;e:</p><ol><li>Najpierw startuj&#x105; sidecary i musz&#x105; by&#x107; gotowe.</li><li>Dopiero p&#xF3;&#x17A;niej startuje g&#x142;&#xF3;wny kontener aplikacji.</li><li>Sidecary dzia&#x142;aj&#x105; przez ca&#x142;y cykl &#x17C;ycia Podu i ko&#x144;cz&#x105; dzia&#x142;anie dopiero po g&#x142;&#xF3;wnym kontenerze.</li></ol><figure class="kg-card kg-image-card"><img src="http://michal.kuzdzal.pl/content/images/2025/08/sidecar_before_133.png" class="kg-image" alt="In-place Pod Resize i Sidecary w Kubernetes 1.33 &#x2013; Co to zmienia?" loading="lazy" width="1024" height="559" srcset="http://michal.kuzdzal.pl/content/images/size/w600/2025/08/sidecar_before_133.png 600w, http://michal.kuzdzal.pl/content/images/size/w1000/2025/08/sidecar_before_133.png 1000w, http://michal.kuzdzal.pl/content/images/2025/08/sidecar_before_133.png 1024w" sizes="(min-width: 720px) 720px"></figure><p>Ta fundamentalna zmiana w cyklu &#x17C;ycia Podu eliminuje wcze&#x15B;niejsze problemy i sprawia, &#x17C;e z&#x142;o&#x17C;one architektury z sidecarami s&#x105; o wiele bardziej niezawodne i &#x142;atwiejsze w utrzymaniu.</p><hr><h2 id="3-zmiana-rozmiaru-pod%C3%B3w-w-miejscu-in-place-pod-resize-elastyczno%C5%9B%C4%87-bez-przestoj%C3%B3w">3. Zmiana rozmiaru Pod&#xF3;w w miejscu (in-place Pod resize): Elastyczno&#x15B;&#x107; bez przestoj&#xF3;w</h2><p>Dotychczas, zmiana zasob&#xF3;w (CPU lub pami&#x119;ci RAM) w dzia&#x142;aj&#x105;cym kontenerze wymaga&#x142;a jego restartu/rolloutu. By&#x142;o to szczeg&#xF3;lnie uci&#x105;&#x17C;liwe dla <strong>aplikacji stanowych</strong> (sts), gdzie przerwa w dzia&#x142;aniu jest niepo&#x17C;&#x105;dana, lub problematyczna.</p><p>W Kubernetes 1.33 ten problem zostaje rozwi&#x105;zany dzi&#x119;ki funkcji <strong><code>in-place Pod resize</code></strong>.</p><h3 id="jak-to-dzia%C5%82a">Jak to dzia&#x142;a?</h3><p>Zamiast restartowa&#x107; Pod, mo&#x17C;esz teraz dynamicznie zmieni&#x107; alokacj&#x119; zasob&#xF3;w dla dzia&#x142;aj&#x105;cego kontenera. Nowa funkcja pozwala na modyfikacj&#x119; pola <code>spec.containers[*].resources</code> w specyfikacji Podu, kt&#xF3;re teraz reprezentuje <strong>po&#x17C;&#x105;dane zasoby</strong>.</p><p>Aby dokona&#x107; takiej zmiany, mo&#x17C;esz u&#x17C;y&#x107; nowego sub-zasobu <code>resize</code> za pomoc&#x105; <code>kubectl</code>:</p><p><code>kubectl edit pod &lt;pod-name&gt; --subresource resize</code></p><p>Kubelet na w&#x119;&#x17A;le hostuj&#x105;cym Pod pr&#xF3;buje dostosowa&#x107; zasoby w locie. Status operacji jest widoczny w <code>status.containerStatuses[*].resources</code>, co daje pe&#x142;ny wgl&#x105;d w post&#x119;py.</p><h3 id="dlaczego-in-place-pod-resize-to-game-changer">Dlaczego <code>in-place Pod resize</code> to game-changer?</h3><p>Ta funkcja ma kluczowe znaczenie, zw&#x142;aszcza dla <strong>aplikacji stanowych (StatefulSets)</strong>, gdzie zachowanie ci&#x105;g&#x142;o&#x15B;ci dzia&#x142;ania i stanu jest priorytetem. Zmiana zasob&#xF3;w nie wymaga restartu, co jest kluczowe dla aplikacji wra&#x17C;liwych na przerwy. Opr&#xF3;cz tego:</p><ul><li><strong>Zwi&#x119;kszona wydajno&#x15B;&#x107;:</strong> Mo&#x17C;esz dostosowywa&#x107; zasoby do rzeczywistego obci&#x105;&#x17C;enia, co prowadzi do oszcz&#x119;dno&#x15B;ci i lepszego wykorzystania zasob&#xF3;w klastra.</li><li><strong>Szybsze skalowanie:</strong> Mo&#x17C;liwo&#x15B;&#x107; szybkiego zwi&#x119;kszenia zasob&#xF3;w na start, a nast&#x119;pnie ich zmniejszenia (tzw. vertical autoscaling), to ogromna korzy&#x15B;&#x107; dla aplikacji o zmiennym profilu obci&#x105;&#x17C;enia.</li></ul><hr><h2 id="4-inne-istotne-zmiany-domy%C5%9Blne-user-namespaces">4. Inne istotne zmiany: Domy&#x15B;lne User Namespaces</h2><p>Kubernetes 1.33 domy&#x15B;lnie w&#x142;&#x105;cza <strong>przestrzenie nazw u&#x17C;ytkownik&#xF3;w (User Namespaces)</strong>. To kolejny wa&#x17C;ny krok w kierunku poprawy bezpiecze&#x144;stwa. Funkcja ta pozwala na uruchamianie proces&#xF3;w wewn&#x105;trz kontenera z ni&#x17C;szymi uprawnieniami ni&#x17C; te na poziomie systemu hosta. Dzi&#x119;ki temu, nawet w przypadku luki w zabezpieczeniach kontenera, ryzyko eskalacji uprawnie&#x144; na poziomie systemu jest mniejsz.</p><hr><h2 id="5-podsumowanie">5. Podsumowanie</h2><p>Kubernetes 1.33 dostarcza kluczowych usprawnie&#x144;, kt&#xF3;re podnosz&#x105; jako&#x15B;&#x107; i efektywno&#x15B;&#x107; pracy z kontenerami. <strong>Stabilne sidecary</strong> upraszczaj&#x105; zarz&#x105;dzanie z&#x142;o&#x17C;onymi aplikacjami, a <strong>dynamiczna zmiana rozmiaru Pod&#xF3;w</strong> daje niezr&#xF3;wnan&#x105; elastyczno&#x15B;&#x107;, szczeg&#xF3;lnie w przypadku aplikacji stanowych (sts).</p>]]></content:encoded></item><item><title><![CDATA[HAProxy + Lua: Ochrona przed botami i atakami DDoS]]></title><description><![CDATA[Zobacz, jak wykorzystać skrypty Lua w HAProxy do ograniczania ruchu botów i ataków DDoS – przykład gotowego kodu, konfiguracja i omówienie ...]]></description><link>http://michal.kuzdzal.pl/haproxy-lua-ddos-protection/</link><guid isPermaLink="false">689208d292967a0001d3c8d8</guid><category><![CDATA[haproxy]]></category><category><![CDATA[linux]]></category><category><![CDATA[lua]]></category><category><![CDATA[ddos]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Tue, 22 Jul 2025 14:33:00 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2025/08/rate-limit-HAProxy-Lua.png" medium="image"/><content:encoded><![CDATA[<h2 id="wst%C4%99p">Wst&#x119;p</h2><img src="http://michal.kuzdzal.pl/content/images/2025/08/rate-limit-HAProxy-Lua.png" alt="HAProxy + Lua: Ochrona przed botami i atakami DDoS"><p>W &#x15B;wiecie rosn&#x105;cego nat&#x119;&#x17C;enia ruchu automatycznego (bot&#xF3;w) i atak&#xF3;w DDoS staje si&#x119; niezb&#x119;dne wprowadzenie inteligentnych filtr&#xF3;w ju&#x17C; na warstwie L7. W tym wpisie opisz&#x119;, jak dzi&#x119;ki prostemu skryptowi w Lua oraz mechanizmom HAProxy zbudowa&#x142;em jedn&#x105; z wielu warstw ochrony backend&#xF3;w przed nieporz&#x105;danym ruchem.</p><hr><h2 id="koncepcja-rozwi%C4%85zania">Koncepcja rozwi&#x105;zania</h2><ol><li><strong>Wykrywanie &#x201E;sesji&#x201D; per IP w oparciu o cookie</strong><br>- Ka&#x17C;da unikalna warto&#x15B;&#x107; ciasteczka (<code>__Secure-app_session</code>) to jedna sesja,<br>- ka&#x17C;de &#x17C;&#x105;danie bez ciasteczka to tzw. &#x201E;no-cookie&#x201D; request.</li><li><strong>Limit 150 sesji/IP w oknie 120 s</strong><br>- Po przekroczeniu tej warto&#x15B;ci IP zostaje oznaczone jako podejrzane.</li><li><strong>Akcja po przekroczeniu</strong><br>- Przekierowanie do backendu z kolejk&#x105; (queue), lub drop requestu.</li></ol><hr><h2 id="skrypt-lua-szczeg%C3%B3%C5%82y-dzia%C5%82ania">Skrypt Lua: szczeg&#xF3;&#x142;y dzia&#x142;ania</h2><p>Poni&#x17C;ej pe&#x142;ny kod skryptu, wraz z opisem:</p><pre><code>-- Globalna tabela do przechowywania stanu per IP
local ip_unique_sessions = {}
local last_cleanup = os.time()

-- Funkcja czyszcz&#x105;ca &#x2013; resetuje ca&#x142;&#x105; struktur&#x119; co 120 sekund
local function cleanup()
    local now = os.time()
    if now - last_cleanup &gt;= 120 then
        ip_unique_sessions = {}
        last_cleanup = now
    end
end

-- Escapowanie znak&#xF3;w specjalnych w nazwie ciasteczka
local function escape_pattern(text)
    return text:gsub(&quot;([^%w])&quot;, &quot;%%%1&quot;)
end

-- Wyci&#x105;ganie warto&#x15B;ci cookie z nag&#x142;&#xF3;wka
local function get_cookie_value(cookie_header, cookie_name)
    if not cookie_header then
        return nil
    end
    local pattern = escape_pattern(cookie_name) .. &quot;=([^;]+)&quot;
    return cookie_header:match(pattern)
end

-- G&#x142;&#xF3;wna funkcja sprawdzaj&#x105;ca limit
function check_rate_limit(txn)
    -- 1) Czyszczenie przestarza&#x142;ych danych
    cleanup()

    -- 2) Pobranie IP i nag&#x142;&#xF3;wka Cookie
    local client_ip  = txn.f:src() or &quot;unknown&quot;
    local cookie_hdr = txn.f:hdr(&quot;Cookie&quot;)

    -- 3) Wyci&#x105;gni&#x119;cie warto&#x15B;ci ciasteczka
    local cookie_val = get_cookie_value(cookie_hdr, &quot;__Secure-app_session&quot;)

    -- 4) Inicjalizacja struktury, je&#x15B;li nowe IP
    if not ip_unique_sessions[client_ip] then
        ip_unique_sessions[client_ip] = {
            cookie    = {},   -- set dla unikalnych warto&#x15B;ci cookies
            no_cookie = 0     -- licznik request&#xF3;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 &#x201E;sesji&#x201D;
    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 &gt; 150 then
        return &quot;true&quot;
    else
        return &quot;false&quot;
    end
end

-- Rejestracja funkcji jako sample-fetch &#x201E;rate_limit&#x201D;
core.register_fetches(&quot;rate_limit&quot;, check_rate_limit)
</code></pre><h3 id="om%C3%B3wienie-krok-po-kroku">Om&#xF3;wienie krok po kroku</h3><ol><li><strong>Zmienne globalne</strong><br>- <code>ip_unique_sessions</code>: pusty s&#x142;ownik, kluczem jest IP, warto&#x15B;ci&#x105; tabela z podkluczami <code>cookie</code> (set) i <code>no_cookie</code> (licznik).<br>- <code>last_cleanup</code>: znacznik czasu ostatniego pe&#x142;nego resetu.</li><li><strong><code>cleanup()</code></strong><br>- Wywo&#x142;ywane przy ka&#x17C;dym sprawdzeniu &#x2013; czy&#x15B;ci ca&#x142;y stan, je&#x15B;li od ostatniego resetu min&#x119;&#x142;o &#x2265;120 s.<br>- Zapobiega niekontrolowanemu wzrostowi zu&#x17C;ycia pami&#x119;ci.</li><li><strong><code>escape_pattern(text)</code></strong><br>- Zamienia znaki specjalne w nazwie ciasteczka na escaped (<code>%</code>), by <code>string.match</code> traktowa&#x142; je dos&#x142;ownie. Dzi&#x119;ki temu nazwy z podkre&#x15B;leniami, my&#x15B;lnikami czy kropkami s&#x105; bezpieczne.</li><li><strong><code>get_cookie_value(cookie_header, cookie_name)</code></strong><br>- Przy braku nag&#x142;&#xF3;wka <code>Cookie</code> od razu zwraca <code>nil</code>.<br>- Buduje wzorzec: <code>&lt;nazwa&gt;=([^;]+)</code> i zwraca pierwszy dopasowany fragment (warto&#x15B;&#x107; ciasteczka).</li><li><strong>Inicjalizacja struktury</strong><br>- Dla ka&#x17C;dego nowego IP tworzymy tabel&#x119; z pustym setem ciasteczek i licznikiem 0.</li><li><strong>Aktualizacja stanu</strong><br>- Je&#x15B;li ciasteczko istnieje: dodajemy jego warto&#x15B;&#x107; do setu (unikalno&#x15B;&#x107; gwarantowana),<br>- je&#x15B;li nie: inkrementujemy <code>no_cookie</code>.</li><li><strong>Zliczanie i pr&#xF3;g</strong><br>- Sumujemy liczb&#x119; kluczy w <code>cookie</code> + warto&#x15B;&#x107; <code>no_cookie</code>.<br>- Por&#xF3;wnujemy z progiem (150); w razie przekroczenia zwracamy <code>&quot;true&quot;</code>.</li></ol><hr><h2 id="konfiguracja-haproxy">Konfiguracja HAProxy</h2><p>Konfiguracja haproxy mo&#x17C;e wygl&#x105;da&#x107; nast&#x119;puj&#x105;co:</p><pre><code># Zaladowanie skryptu
lua-load /opt/implix/haproxy/ddos_rate_limit.lua

# Sprawdzenie rate_limit, z pomini&#x119;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&#x17C;eli ip przekroczy&#x142;o limit
acl ddos_rate_exceeded var(req.rate_limit_exceeded) -m str true

# Kierowanie do kolejkuj&#x105;cego backendu
use_backend fpm-queue-backend if ddos_rate_exceeded

# Mo&#x17C;na te&#x17C; zdropowa&#x107; takie po&#x142;&#x105;czenie
# http-request deny if ddos_rate_exceeded</code></pre><p>W moim przypadku podejrzany ruch trafia na backend z kolejk&#x105;, gdzie takie &#x17C;&#x105;dania czekaj&#x105; na obs&#x142;u&#x17C;enie.</p><p>Jakie mog&#x105; by&#x107; inne podej&#x15B;cia do obs&#x142;ugi takich po&#x142;&#x105;cze&#x144;?</p><ul><li>deny - bezpo&#x15B;redni zako&#x144;czenie po&#x142;&#x105;czenia z dowolnym kodem http,</li><li>silent-drop - zamyka po&#x142;&#x105;czenie po stronie HAProxy bez &#x17C;adnej odpowiedzi ani komunikatu do klienta,</li><li>tarpid - podobne do silent dropa, z t&#x105; r&#xF3;&#x17C;nic&#x105; &#x17C;e po&#x142;&#x105;czenie jest przetrzymywane przez socket haproxy.</li></ul><hr><h2 id="podsumowanie">Podsumowanie</h2><p>HAProxy dzi&#x119;ki skryptom Lua otwiera przed nami niemal nieograniczone mo&#x17C;liwo&#x15B;ci zaawansowanej konfiguracji i zarz&#x105;dzania ruchem. Pokazany wy&#x17C;ej przyk&#x142;ad to jedynie wierzcho&#x142;ek g&#xF3;ry lodowej &#x2013; za pomoc&#x105; Lua mo&#x17C;esz zbudowa&#x107; w&#x142;asny, w pe&#x142;ni programowalny load balancer, implementowa&#x107; niestandardowe algorytmy routingu, walidowa&#x107; czy modyfikowa&#x107; nag&#x142;&#xF3;wki w locie, a nawet integrowa&#x107; si&#x119; z zewn&#x119;trznymi systemami. To elastyczne podej&#x15B;cie pozwala dostosowa&#x107; HAProxy dok&#x142;adnie do potrzeb Twojej infrastruktury i &#x142;atwo rozwija&#x107; go o kolejne mechanizmy ochrony czy optymalizacji.</p>]]></content:encoded></item><item><title><![CDATA[Terraform i GitOps w GitLab CI/CD]]></title><description><![CDATA[Zobacz, jak za pomocą Terraform i GitLab CI/CD zautomatyzować wdrożenia i przechowywać stan w repozytorium GitLab'a.]]></description><link>http://michal.kuzdzal.pl/terraform-with-gitops/</link><guid isPermaLink="false">6890a1b992967a0001d3c821</guid><category><![CDATA[terraform]]></category><category><![CDATA[git]]></category><category><![CDATA[gitlab]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Thu, 10 Jul 2025 12:31:00 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2025/08/Terraform_i_GitOps_w_GitLab_CI-CD.png" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2025/08/Terraform_i_GitOps_w_GitLab_CI-CD.png" alt="Terraform i GitOps w GitLab CI/CD"><p>Dzi&#x15B; opisz&#x119;, jak zintegrowa&#x107; <strong>Terraform</strong> z <strong>GitLab CI/CD</strong>, aby stworzy&#x107; wydajny i niezawodny proces GitOps.</p><h4 id="po-co-terraform-i-gitops"><strong>Po co Terraform i GitOps?</strong></h4><p><strong>Terraform</strong> pozwala opisywa&#x107; infrastruktur&#x119; jako kod (<strong>IaC</strong>). Dzi&#x119;ki temu mo&#x17C;esz j&#x105; wersjonowa&#x107;, &#x142;atwo powiela&#x107; i audytowa&#x107;. <strong>GitOps</strong> dodaje do tego proces CI/CD, w kt&#xF3;rym ka&#x17C;da zmiana w kodzie jest automatycznie wdra&#x17C;ana, eliminuj&#x105;c r&#x119;czne modyfikacje i minimalizuj&#x105;c ryzyko b&#x142;&#x119;d&#xF3;w. Trzymanie stanu w gitlabi pomo&#x17C;e te&#x17C; unikn&#x105;&#x107; potencjalnych problem&#xF3;w i konflikt&#xF3;w.</p><hr><h3 id="struktura-gitlab-cicd"><strong>Struktura GitLab CI/CD</strong></h3><p>Nasze CI/CD podzielimy na trzy g&#x142;&#xF3;wne etapy: <code>init</code>, <code>plan</code> i <code>apply</code>. Dodatkowo, stan Terraform (tzw. <strong>State</strong>) przechowamy bezpiecznie w GitLab, co upro&#x15B;ci zarz&#x105;dzanie i wyeliminuje potencjalne problemy z przechowywaniem stanu w r&#xF3;&#x17C;nych miejscach.</p><p>Poni&#x17C;ej przedstawiam, jak powinien wygl&#x105;da&#x107; plik <code>.gitlab-ci.yml</code>:</p><pre><code>stages:
  - validate
  - plan
  - apply

variables:
  TF_ADDRESS: &quot;${CI_API_V4_URL}/projects/${CI_PROJECT_ID}&quot;
  STATES: &quot;terraform/state/${TF_STATE_NAME}&quot;
  TERRAFORM_INIT: &quot;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&quot;
  TF_STATE_NAME: &quot;nazwa-projektu&quot;
  
.terraform-base:
  image:
    name: &quot;registry.gitlab.com/gitlab-org/terraform-images/stable:latest&quot;
  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: &apos;$CI_COMMIT_BRANCH == &quot;main&quot;&apos;
      when: manual
</code></pre><p>Sam pipline prezentuje si&#x119; nast&#x119;puj&#x105;co:</p><figure class="kg-card kg-image-card"><img src="http://michal.kuzdzal.pl/content/images/2025/08/image.png" class="kg-image" alt="Terraform i GitOps w GitLab CI/CD" loading="lazy" width="477" height="130"></figure><hr><h4 id="sk%C4%85d-wzi%C4%85%C4%87-zmienne"><strong>Sk&#x105;d wzi&#x105;&#x107; zmienne?</strong></h4><ul><li><strong><code>CI_API_V4_URL</code></strong> i <strong><code>CI_PROJECT_ID</code></strong>: Te zmienne zawieraj&#x105; adres URL do API oraz unikalny identyfikator projektu (np. CI_API_V4_URL=<a href="https://git.int.clickmeeting.com/api/v4/projects/246/terraform/state">https://git.example.com/api/v4/</a><br>CI_PROJECT_ID=210),</li><li><strong><code>TF_STATE_NAME</code></strong>: dowolna nazwa stanu, kt&#xF3;ra b&#x119;dzie widoczna w gitalabie,</li><li><strong><code>TF_USERNAME</code></strong> i <strong><code>TF_PASSWORD</code></strong>: Te zmienne s&#x105; kluczowe do uwierzytelniania w API GitLab, aby potok m&#xF3;g&#x142; bezpiecznie zarz&#x105;dza&#x107; stanem Terraform. Najbezpieczniej jest stworzy&#x107; <strong>Project Access Token</strong> lub <strong>Personal Access Token </strong>z odpowiednimi uprawnieniami (zakres <code>api</code>), a nast&#x119;pnie zapisa&#x107; go jako <strong>zmienn&#x105; &#x15B;rodowiskow&#x105;</strong> w ustawieniach CI/CD projektu w GitLab.</li></ul><hr><h4 id="podsumowanie"><strong>Podsumowanie</strong></h4><p>Integracja Terraform z GitLab CI/CD daje nam pot&#x119;&#x17C;ne narz&#x119;dzie do zarz&#x105;dzania infrastruktur&#x105; w spos&#xF3;b w pe&#x142;ni zautomatyzowany, bezpieczny i zgodny z najlepszymi praktykami GitOps. Taki proces pozwala na szybsze i bardziej niezawodne wdra&#x17C;anie, minimalizuj&#x105;c b&#x142;&#x119;dy i zapewniaj&#x105;c pe&#x142;n&#x105; transparentno&#x15B;&#x107; zmian.</p>]]></content:encoded></item><item><title><![CDATA[Uruchamianie Kali Linux na macOS w kontenerze Apple]]></title><description><![CDATA[Dowiedz się, jak zainstalować i skonfigurować Kali Linux w Apple Container na macOS Sequoia z Apple Silicon. Szybkie uruchomienie...]]></description><link>http://michal.kuzdzal.pl/uruchamianie-kali-linux-na-macos-w-kontenerze-apple/</link><guid isPermaLink="false">688e3c77c7dbb400017ff4b7</guid><category><![CDATA[kali]]></category><category><![CDATA[linux]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Tue, 08 Jul 2025 16:35:00 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2025/08/Kali.png" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2025/08/Kali.png" alt="Uruchamianie Kali Linux na macOS w kontenerze Apple"><p>Dzi&#x119;ki nowej<strong> konteneryzacji Apple</strong> (og&#x142;oszonej podczas WWDC 2025) mo&#x17C;esz teraz bezproblemowo uruchomi&#x107; <strong>Kali Linux</strong> bezpo&#x15B;rednio na swoim Macu z Apple Silicon. To idealne rozwi&#x105;zanie dla tych, kt&#xF3;rzy chc&#x105; szybko testowa&#x107; narz&#x119;dzia bezpiecze&#x144;stwa bez konieczno&#x15B;ci stawiania pe&#x142;nej maszyny wirtualnej.</p><hr><h2 id="1-co-to-jest-apple-container">1. Co to jest Apple Container?</h2><p>Apple Container to nowy framework wprowadzony w <strong>macOS Sequoia</strong>, umo&#x17C;liwiaj&#x105;cy izolowane uruchamianie dystrybucji Linuksa na sprz&#x119;cie Apple Silicon. Dzia&#x142;a to podobnie do WSL2 na Windows, ale w pe&#x142;ni zintegrowane z ekosystemem Apple.</p><p><strong>Kluczowe zalety:</strong></p><ul><li>Lekka wirtualizacja z natywnym wsparciem dla Apple Silicon</li><li>Integracja z narz&#x119;dziem Homebrew</li><li>Obs&#x142;uga standardowego formatu kontener&#xF3;w Docker</li></ul><hr><h2 id="2-przygotowanie-%C5%9Brodowiska">2. Przygotowanie &#x15B;rodowiska</h2><h3 id="wymagania">Wymagania</h3><ul><li><strong>macOS Sequoia</strong> (15.x) z Apple Silicon (M1/M2/M3)</li><li>Zainstalowany <strong>Homebrew</strong></li></ul><h3 id="instalacja-kontener%C3%B3w-apple">Instalacja kontener&#xF3;w Apple</h3><p>Otw&#xF3;rz Terminal</p><p>Zainstaluj CLI kontener&#xF3;w:<br><code>brew install --cask container</code></p><p>Uruchom us&#x142;ug&#x119; systemow&#x105; kontenera:<br><code>container system start</code></p><hr><h2 id="3-uruchomienie-kali-linux-w-kontenerze">3. Uruchomienie Kali Linux w kontenerze</h2><p>Po przygotowaniu frameworka mo&#x17C;esz od razu odpali&#x107; obraz Kali Linux z DockerHub:<br><code>container run --rm -it kalilinux/kali-rolling</code></p><p><strong>Wyja&#x15B;nienie parametr&#xF3;w:</strong></p><ul><li><code>--rm</code> &#x2013; usuwa kontener po zamkni&#x119;ciu</li><li><code>-it</code> &#x2013; interaktywna sesja terminalowa</li><li><code>kalilinux/kali-rolling</code> &#x2013; oficjalny obraz Kali Linux</li></ul><h3 id="montowanie-wolumin%C3%B3w">Montowanie wolumin&#xF3;w</h3><p>Aby uzyska&#x107; dost&#x119;p do plik&#xF3;w z macOS wewn&#x105;trz kontenera:</p><pre><code>container run --rm -it \
--volume $(pwd):/mnt \
--workdir /mnt \
docker.io/kalilinux/kali-rolling:latest</code></pre><ul><li><code>--volume $(pwd):/mnt</code> &#x2013; montuje aktualny katalog do <code>/mnt</code></li><li><code>--workdir /mnt</code> &#x2013; ustawia katalog roboczy w kontenerze</li></ul><hr><h2 id="4-ograniczenia-i-znane-problemy">4. Ograniczenia i znane problemy</h2><p>Chocia&#x17C; uruchamianie Kali Linux w kontenerze to du&#x17C;y krok naprz&#xF3;d, warto pami&#x119;ta&#x107; o kilku ograniczeniach:</p><ol><li><strong>Tylko Apple Silicon</strong> &#x2013; kontenery dzia&#x142;aj&#x105; wy&#x142;&#x105;cznie na procesorach M1/M2/M3.</li><li><strong>Brak przej&#x15B;cia sprz&#x119;towego</strong> &#x2013; niekt&#xF3;re narz&#x119;dzia pentestingowe wymagaj&#x105;ce bezpo&#x15B;redniego dost&#x119;pu do urz&#x105;dze&#x144; USB czy GPU mog&#x105; nie dzia&#x142;a&#x107;.</li><li><strong>Wczesna faza rozwoju</strong> &#x2013; framework mo&#x17C;e mie&#x107; b&#x142;&#x119;dy, kt&#xF3;re b&#x119;d&#x105; eliminowane w kolejnych aktualizacjach macOS Sequoia.</li></ol><hr><h2 id="5-dlaczego-warto">5. Dlaczego warto?</h2><ul><li>&#x1F680; <strong>Szybkie wdro&#x17C;enie</strong>: kilka polece&#x144; wystarczy, by mie&#x107; dzia&#x142;aj&#x105;cy Kali Linux.</li><li>&#x1F512; <strong>Bezpiecze&#x144;stwo</strong>: izolacja kontenera minimalizuje ryzyko wp&#x142;ywu na system hosta.</li><li>&#x1F4BB; <strong>Wydajno&#x15B;&#x107;</strong>: lekka wirtualizacja daje niemal natywne osi&#x105;gi.</li><li>&#x1F504; <strong>Aktualno&#x15B;&#x107;</strong>: korzystasz z najnowszego obrazu <code>kali-rolling</code>.</li></ul><hr><h2 id="6-podsumowanie">6. Podsumowanie</h2><p>Uruchomienie <strong>Kali Linux w kontenerze na macOS</strong> to prosty spos&#xF3;b na rozszerzenie swojego &#x15B;rodowiska pentestowego bez konieczno&#x15B;ci instalowania pe&#x142;nej maszyny wirtualnej. Dzi&#x119;ki nowemu frameworkowi Apple Container na Sequoia, u&#x17C;ytkownicy Apple Silicon zyskuj&#x105; dost&#x119;p do pe&#x142;nej gamy narz&#x119;dzi Kali w zaledwie kilka minut.</p>]]></content:encoded></item><item><title><![CDATA[Kompilacja HAProxy 3.2.3 z obsługą QUIC (OpenSSL 3.1.5) na Debianie 12]]></title><description><![CDATA[<p>Je&#x15B;li zale&#x17C;y Ci na wykorzystaniu pe&#x142;ni mo&#x17C;liwo&#x15B;ci HAProxy, w tym najnowszych funkcji takich jak obs&#x142;uga protoko&#x142;u <strong>QUIC</strong>, cz&#x119;sto konieczna jest kompilacja z kodu &#x17A;r&#xF3;d&#x142;owego. Domy&#x15B;lne pakiety HAProxy</p>]]></description><link>http://michal.kuzdzal.pl/untitled/</link><guid isPermaLink="false">688c886c5dfbf900015c7933</guid><category><![CDATA[haproxy]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Sun, 01 Jun 2025 09:31:00 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2025/08/Gemini_Generated_Image_xln6w1xln6w1xln6.png" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2025/08/Gemini_Generated_Image_xln6w1xln6w1xln6.png" alt="Kompilacja HAProxy 3.2.3 z obs&#x142;ug&#x105; QUIC (OpenSSL 3.1.5) na Debianie 12"><p>Je&#x15B;li zale&#x17C;y Ci na wykorzystaniu pe&#x142;ni mo&#x17C;liwo&#x15B;ci HAProxy, w tym najnowszych funkcji takich jak obs&#x142;uga protoko&#x142;u <strong>QUIC</strong>, cz&#x119;sto konieczna jest kompilacja z kodu &#x17A;r&#xF3;d&#x142;owego. Domy&#x15B;lne pakiety HAProxy dost&#x119;pne w oficjalnych repozytoriach system&#xF3;w (np. przez <code>apt install haproxy</code>) zazwyczaj nie zawieraj&#x105; wsparcia dla QUIC, poniewa&#x17C; wymaga to u&#x17C;ycia niestandardowej biblioteki OpenSSL. Co wi&#x119;cej, obs&#x142;uga QUIC jest cz&#x119;sto dost&#x119;pna w wersjach komercyjnych (HAProxy Enterprise), dlatego r&#x119;czna kompilacja jest najlepszym sposobem, aby uzyska&#x107; t&#x119; funkcjonalno&#x15B;&#x107; w wersji darmowej.</p><p>W tym poradniku poka&#x17C;&#x119;, jak skompilowa&#x107; HAProxy w wersji 3.2.3 na systemie Debian 12, u&#x17C;ywaj&#x105;c OpenSSL z obs&#x142;ug&#x105; QUIC. Ca&#x142;y proces podzielimy na dwa g&#x142;&#xF3;wne etapy: kompilacj&#x119; OpenSSL, a nast&#x119;pnie kompilacj&#x119; HAProxy.</p><h4 id="etap-1-kompilacja-i-instalacja-openssl-z-quic"><strong>Etap 1: Kompilacja i instalacja OpenSSL z QUIC</strong></h4><p>Zaczynamy od przygotowania OpenSSL z obs&#x142;ug&#x105; protoko&#x142;u QUIC. Domy&#x15B;lna wersja OpenSSL w systemie Debian nie obs&#x142;uguje tej funkcji, dlatego musimy skompilowa&#x107; j&#x105; r&#x119;cznie.</p><p><strong>Instalacja niezb&#x119;dnych narz&#x119;dzi</strong></p><p>Zanim zaczniemy, upewnij si&#x119;, &#x17C;e masz zainstalowane podstawowe narz&#x119;dzia do kompilacji oraz biblioteki deweloperskie, kt&#xF3;re b&#x119;d&#x105; nam potrzebne do skompilowania HAProxy (Lua, PCRE2).Bash</p><pre><code>sudo apt install make build-essential liblua5.4-dev libpcre2-dev
</code></pre><p><strong>Pobranie i dekompresja OpenSSL</strong></p><p>Pobierzemy wersj&#x119; OpenSSL z ga&#x142;&#x119;zi <code>quictls</code>, kt&#xF3;ra zosta&#x142;a zmodyfikowana, aby wspiera&#x107; QUIC.Bash</p><pre><code>wget 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
</code></pre><p><strong>Konfiguracja i kompilacja OpenSSL</strong></p><p>Teraz skonfigurujemy i skompilujemy OpenSSL. U&#x17C;yjemy wielu opcji, aby zapewni&#x107; optymalizacj&#x119;, bezpiecze&#x144;stwo oraz obs&#x142;ug&#x119; QUIC (<code>enable-tls1_3</code>). Instalacja docelowo znajdzie si&#x119; w katalogu <code>/opt/quictls</code>, aby nie kolidowa&#x142;a z systemow&#x105; wersj&#x105; OpenSSL.Bash</p><pre><code>OPENSSL_OPTS=&quot;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 \
&quot;
./config --libdir=lib --prefix=/opt/quictls $OPENSSL_OPTS
make -j $(nproc)
make install -j $(nproc)
</code></pre><p><strong>Weryfikacja instalacji OpenSSL</strong></p><p>Sprawd&#x17A;my, czy nowa wersja OpenSSL zosta&#x142;a poprawnie zainstalowana i obs&#x142;uguje QUIC.Bash</p><pre><code>/opt/quictls/bin/openssl version
</code></pre><p>Oczekiwana odpowied&#x17A; powinna wygl&#x105;da&#x107; tak: <code>OpenSSL 3.1.5+quic 30 Jan 2024 (Library: OpenSSL 3.1.5+quic 30 Jan 2024)</code></p><h4 id="etap-2-kompilacja-haproxy-323"><strong>Etap 2: Kompilacja HAProxy 3.2.3</strong></h4><p>Teraz, gdy mamy gotowy OpenSSL z QUIC, mo&#x17C;emy przej&#x15B;&#x107; do kompilacji HAProxy, kt&#xF3;ra go wykorzysta.</p><p><strong>Pobranie i dekompresja HAProxy</strong></p><p>Pobierz najnowsz&#x105; stabiln&#x105; wersj&#x119; HAProxy 3.2.3 ze strony projektu.Bash</p><pre><code>wget 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
</code></pre><p><strong>Konfiguracja i kompilacja HAProxy</strong></p><p>W tej sekcji skompilujemy HAProxy, wskazuj&#x105;c mu &#x15B;cie&#x17C;ki do naszego niestandardowego OpenSSL. Musimy r&#xF3;wnie&#x17C; w&#x142;&#x105;czy&#x107; wsparcie dla QUIC, Lua, PCRE2 oraz innych przydatnych funkcji.Bash</p><pre><code>HAPROXY_CFLAGS=&quot;-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&quot;
HAPROXY_OPTS=&quot;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 \
&quot;
echo &quot;/opt/quictls/lib&quot; &gt; /etc/ld.so.conf.d/quictls.conf &amp;&amp; ldconfig
make -j $(nproc) $HAPROXY_OPTS CFLAGS=&quot;$HAPROXY_CFLAGS&quot; LDFLAGS=&quot;$HAPROXY_LDFLAGS&quot; SSL_INC=/opt/quictls/include SSL_LIB=/opt/quictls/lib all admin/halog/halog
</code></pre><p><strong>Wa&#x17C;na uwaga:</strong> Komenda <code>echo &quot;/opt/quictls/lib&quot; &gt; /etc/ld.so.conf.d/quictls.conf &amp;&amp; ldconfig</code> dodaje &#x15B;cie&#x17C;k&#x119; do naszych nowo skompilowanych bibliotek OpenSSL do globalnej konfiguracji systemu. To kluczowy krok, kt&#xF3;ry pozwala HAProxy (i innym programom) znale&#x17A;&#x107; biblioteki SSL/TLS.</p><p><strong>Instalacja HAProxy</strong></p><p>Po udanej kompilacji, zainstaluj binark&#x119; HAProxy w domy&#x15B;lnej lokalizacji.Bash</p><pre><code>sudo make -j $(nproc) install-bin
</code></pre><p>Gratulacje! W&#x142;a&#x15B;nie skompilowa&#x142;e&#x15B; HAProxy w wersji 3.2.3 z pe&#x142;nym wsparciem dla protoko&#x142;u QUIC na Debianie 12. Teraz mo&#x17C;esz skonfigurowa&#x107; HAProxy, aby wykorzysta&#x107; jego nowe mo&#x17C;liwo&#x15B;ci w Twoim &#x15B;rodowisku.</p>]]></content:encoded></item><item><title><![CDATA[ArgoCD - ingress ssl too many redirects]]></title><description><![CDATA[<p>Je&#x17C;eli chcemy u&#x17C;y&#x107; ingressa z ArgoCD zetkniemy si&#x119; z problemem p&#x119;tli redirect&#xF3;w</p><pre><code>curl -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.</code></pre>]]></description><link>http://michal.kuzdzal.pl/argocd/</link><guid isPermaLink="false">62eed19046fbf400011a73d8</guid><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Sat, 06 Aug 2022 20:56:25 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2022/08/argocd-ingress-redirects-loop-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2022/08/argocd-ingress-redirects-loop-1.jpg" alt="ArgoCD - ingress ssl too many redirects"><p>Je&#x17C;eli chcemy u&#x17C;y&#x107; ingressa z ArgoCD zetkniemy si&#x119; z problemem p&#x119;tli redirect&#xF3;w</p><pre><code>curl -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/</code></pre><p>Dzieje si&#x119; tak poniewa&#x17C; backend ArgoCD oczekuje, &#x17C;e sam nawi&#x105;&#x17C;e po&#x142;&#x105;czenie TLS, w innym przypadku zawsze przekierowuje po&#x142;&#x105;czenie na HTTPS.</p><p>Najprostszym sposobem jest wy&#x142;&#x105;czenie przekierowa&#x144;:</p><pre><code>kubectl edit deployments.apps argocd-server -n argocd</code></pre><p>W polu <strong>command</strong> dodajemy opcj&#x119; <strong>insecure</strong>:</p><pre><code>      - command:
        - argocd-server
        - --insecure</code></pre><p>Tworzymy na nowo poda:</p><pre><code>kubectl scale -n argocd deployment/argocd-server --replicas=0 &amp;&amp; kubectl scale -n argocd deployment/argocd-server --replicas=1</code></pre><p>Po tym zabiegu wszystko powinno ju&#x17C; dzia&#x142;a&#x107;:</p><pre><code>curl -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 &apos;self&apos;;
x-frame-options: sameorigin
x-xss-protection: 1
strict-transport-security: max-age=15724800; includeSubDomains</code></pre>]]></content:encoded></item><item><title><![CDATA[Ansible - split variable]]></title><description><![CDATA[<p>Czasami w ansiblu mo&#x17C;e zaj&#x15B;&#x107; potrzeba &#x17C;eby &quot;poci&#x105;&#x107;&quot; jak&#x105;&#x15B; zmienn&#x105;.<br>Jako &#x17C;e ansible == python, to mo&#x17C;emy skorzysta&#x107; z formatowania jinja2.</p><p>Przyk&#x142;adowo aby oddzieli&#x107; sam&#x105; nazw&#x119; u&#x17C;ytkownika od</p>]]></description><link>http://michal.kuzdzal.pl/ansible-split-variable/</link><guid isPermaLink="false">62c57fd444430e0001ba5f79</guid><category><![CDATA[ansible]]></category><category><![CDATA[python]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Wed, 06 Jul 2022 12:51:07 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2022/07/ansible-jinja.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2022/07/ansible-jinja.jpg" alt="Ansible - split variable"><p>Czasami w ansiblu mo&#x17C;e zaj&#x15B;&#x107; potrzeba &#x17C;eby &quot;poci&#x105;&#x107;&quot; jak&#x105;&#x15B; zmienn&#x105;.<br>Jako &#x17C;e ansible == python, to mo&#x17C;emy skorzysta&#x107; z formatowania jinja2.</p><p>Przyk&#x142;adowo aby oddzieli&#x107; sam&#x105; nazw&#x119; u&#x17C;ytkownika od maila ze zmiennej AWX awx_user_name:</p><pre><code>{{ awx_user_name.split(&apos;@&apos;)[0] | lower }}</code></pre><h3 id="linki">Linki</h3><p><a href="https://jinja.palletsprojects.com/en/3.1.x/">Jinja</a>.</p>]]></content:encoded></item><item><title><![CDATA[Python - lokalny skrypt na zdalnej maszynie (ssh)]]></title><description><![CDATA[<p>Czasem jest taka potrzeba uruchomienia jakiego&#x15B; lokalnego skryptu/programu na zdalnym ho&#x15B;cie. Je&#x17C;eli nie chcemy kopiowa&#x107; i umieszcza&#x107; na ho&#x15B;cie tego skryptu mo&#x17C;emy u&#x17C;y&#x107; ssh:</p><pre><code>ssh user@host python3 &lt; script.py</code></pre><p>Natomiast je&#x17C;eli</p>]]></description><link>http://michal.kuzdzal.pl/python-lokalny-skrypt-na-zdalnej-maszynie-ssh/</link><guid isPermaLink="false">6242a546c098ae0001f99ca3</guid><category><![CDATA[python]]></category><category><![CDATA[ssh]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Tue, 29 Mar 2022 06:30:54 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1600333527715-cc7f665bc332?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDI1fHxzbmFrZXxlbnwwfHx8fDE2NDg1MzUzNTc&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1600333527715-cc7f665bc332?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDI1fHxzbmFrZXxlbnwwfHx8fDE2NDg1MzUzNTc&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Python - lokalny skrypt na zdalnej maszynie (ssh)"><p>Czasem jest taka potrzeba uruchomienia jakiego&#x15B; lokalnego skryptu/programu na zdalnym ho&#x15B;cie. Je&#x17C;eli nie chcemy kopiowa&#x107; i umieszcza&#x107; na ho&#x15B;cie tego skryptu mo&#x17C;emy u&#x17C;y&#x107; ssh:</p><pre><code>ssh user@host python3 &lt; script.py</code></pre><p>Natomiast je&#x17C;eli chcemy uruchomi&#x107; skrypt z dodatkowymi parametrami:</p><pre><code>ssh user@host python3 -u - --parametr arg1 &lt; script.py</code></pre><p>Oczywi&#x15B;cie nic nie stoi na przeszkodzie aby odpali&#x107; w ten spos&#xF3;b ka&#x17C;dy inny skrypt bashowy, pearlowy itp.</p>]]></content:encoded></item><item><title><![CDATA[Gitlab CI/CD - environment variable]]></title><description><![CDATA[<p>Czasami jest potrzeba przekazania zmiennej env pomi&#x119;dzy r&#xF3;&#x17C;nymi stagami pipelina. Od wersji 13 gitlaba mo&#x17C;emy do tego u&#x17C;y&#x107; wbudowanego mechanizmu inherit environment variables. Zapisujemy nasz&#x105; warto&#x15B;&#x107; w pliku <em>.env</em> i przekazujemy j&#x105; za pomoc&#x105; mechanizmu</p>]]></description><link>http://michal.kuzdzal.pl/gitlab-ci-cd-environment-variable/</link><guid isPermaLink="false">6225185f5e900500013767d9</guid><category><![CDATA[CI/CD]]></category><category><![CDATA[gitlab]]></category><category><![CDATA[pipeline]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Sun, 06 Mar 2022 20:33:04 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2022/03/gitlab-ci-environment-variable-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2022/03/gitlab-ci-environment-variable-1.jpg" alt="Gitlab CI/CD - environment variable"><p>Czasami jest potrzeba przekazania zmiennej env pomi&#x119;dzy r&#xF3;&#x17C;nymi stagami pipelina. Od wersji 13 gitlaba mo&#x17C;emy do tego u&#x17C;y&#x107; wbudowanego mechanizmu inherit environment variables. Zapisujemy nasz&#x105; warto&#x15B;&#x107; w pliku <em>.env</em> i przekazujemy j&#x105; za pomoc&#x105; mechanizmu <strong>artifacts</strong>:</p><pre><code>build:
  stage: build
  script:
    - echo &quot;COMMIT=true&quot; &gt;&gt; build.env
  artifacts:
    reports:
      dotenv: build.env

deploy:
  stage: test
  script:
    - echo &quot;$COMMIT&quot;</code></pre><h3 id="linki">Linki</h3><p><a href="https://docs.gitlab.com/ee/ci/variables/README.html#inherit-environment-variables">Inherit environment variables</a>.</p>]]></content:encoded></item><item><title><![CDATA[Terraform - deploy LXD container]]></title><description><![CDATA[<p>Terraform, numer jeden je&#x17C;eli chodzi o IaC (<em><strong>Infrastructure as Code</strong>). W bardzo przyjemny spos&#xF3;b mo&#x17C;na zarz&#x105;dza&#x107; infrastruktur&#x105; cloudow&#x105; jak i </em>on-premise. <br>W tym przypadku opisz&#x119; pokr&#xF3;tce jak deployowa&#x107; virtualn&#x105; maszyn&#x119; w LXD.</p><h3 id="konfiguracja">Konfiguracja</h3>]]></description><link>http://michal.kuzdzal.pl/terraform/</link><guid isPermaLink="false">6216754d23e2000001a0bd13</guid><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Wed, 23 Feb 2022 18:17:47 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2022/02/terraform-lxd-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2022/02/terraform-lxd-1.jpg" alt="Terraform - deploy LXD container"><p>Terraform, numer jeden je&#x17C;eli chodzi o IaC (<em><strong>Infrastructure as Code</strong>). W bardzo przyjemny spos&#xF3;b mo&#x17C;na zarz&#x105;dza&#x107; infrastruktur&#x105; cloudow&#x105; jak i </em>on-premise. <br>W tym przypadku opisz&#x119; pokr&#xF3;tce jak deployowa&#x107; virtualn&#x105; maszyn&#x119; w LXD.</p><h3 id="konfiguracja">Konfiguracja</h3><p>Mamy ma&#x142;o kodu, wi&#x119;c tworzymy wszystko w jednym pliku main.tf:</p><pre><code>terraform {
  required_providers {
    lxd = {
      source = &quot;terraform-lxd/lxd&quot;
    }
  }
}

provider &quot;lxd&quot; {
  generate_client_certificates = true
  accept_remote_certificate    = true

  lxd_remote {
    name     = &quot;lxd-1&quot;
    scheme   = &quot;https&quot;
    address  = &quot;lxd.kuzdzal.pl&quot;
    port     = &quot;8443&quot;
    default  = true
  }
}

resource &quot;lxd_container&quot; &quot;worker&quot; {
  count     = 3
  remote    = &quot;lxd-1&quot;
  name      = &quot;k8s-${count.index}&quot;
  image     = &quot;ubuntu:20.04&quot;
  ephemeral = false
  type      = &quot;virtual-machine&quot;
  config = {
    &quot;user.access_interface&quot; = &quot;enp5s0&quot;
  }
  limits    = {
    &quot;memory&quot; = &quot;8GB&quot;
    &quot;cpu&quot; = 4
  }
  profiles = [&quot;default&quot;]
  device {
      name       = &quot;root&quot;
      properties = {
          &quot;path&quot; = &quot;/&quot;
          &quot;pool&quot; = &quot;pool_nvme&quot;
          &quot;size&quot; = &quot;25GB&quot;
      }
      type       = &quot;disk&quot;
  }
}

output &quot;droplet_ip_addresses&quot; {
  value = {
    for droplet in lxd_container.worker:
    droplet.name =&gt; droplet.ipv4_address
  }
}</code></pre><h3 id="uruchomienie">Uruchomienie</h3><p>Inicjalizacja, czyli pobranie wszystkich wymaganych plugin&#xF3;w (w tym przypadku tylko lxd), zsetupowanie i na ko&#x144;cu zniszczenie zasob&#xF3;w:</p><pre><code>~ terraform init
~ terraform apply -auto-approve
~ terraform destroy -auto-approve</code></pre><h3 id="linki">Linki</h3><p><a href="https://registry.terraform.io/providers/terraform-lxd/lxd/latest/docs">Terraform lxd</a>.</p>]]></content:encoded></item><item><title><![CDATA[Varnish - cache serwer w k8s]]></title><description><![CDATA[<p>Varnish, &#x15B;wietny serwer cache&apos;u umo&#x17C;liwiaj&#x105;cy bardzo zaawansowan&#x105; konfiguracj&#x119;. Wi&#x119;kszo&#x15B;&#x107; serwer&#xF3;w cdn dost&#x119;pnych w internecie wykorzystuje w&#x142;a&#x15B;nie varnisha na backendzie do serwowania statycznych danych. Osobi&#x15B;cie u&#x17C;y&</p>]]></description><link>http://michal.kuzdzal.pl/varnish-k8s/</link><guid isPermaLink="false">6205894ed0808d0001cecc2f</guid><category><![CDATA[k8s]]></category><category><![CDATA[varnish]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Tue, 01 Feb 2022 22:15:00 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2022/02/k8s-varnish.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2022/02/k8s-varnish.jpg" alt="Varnish - cache serwer w k8s"><p>Varnish, &#x15B;wietny serwer cache&apos;u umo&#x17C;liwiaj&#x105;cy bardzo zaawansowan&#x105; konfiguracj&#x119;. Wi&#x119;kszo&#x15B;&#x107; serwer&#xF3;w cdn dost&#x119;pnych w internecie wykorzystuje w&#x142;a&#x15B;nie varnisha na backendzie do serwowania statycznych danych. Osobi&#x15B;cie u&#x17C;y&#x142;em go jako front przed ghostem, o kt&#xF3;rego de facto oparty jest ten blog.</p><h3 id="pliki-konfiguracyjne">Pliki konfiguracyjne</h3><p>Konfiguracja samego varnisha <em>default.vcl</em>:</p><pre><code>vcl 4.0;

backend default {
  .host = &quot;blog-mk:2368&quot;;
}

sub vcl_recv {
  if (req.url ~ &quot;/(admin|p|ghost)/&quot;) {
           return (pass);
  }
  unset req.http.cookie;
}

sub vcl_backend_response {
    if (beresp.http.content-type ~ &quot;text/plain|text/css|application/json|application/x-javascript|text/xml|application/xml|application/xml+rss|text/javascript&quot;) {
        set beresp.do_gzip = true;
        set beresp.http.cache-control = &quot;public, max-age=1209600&quot;;
    }
    set beresp.ttl = 1w;
}</code></pre><p>Deployment <em>varnish-dep.yaml:</em></p><pre><code>---
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</code></pre><p>Service <em>varnish-svc.yaml</em>:</p><pre><code>---
kind: Service
apiVersion: v1
metadata:
  name: varnish-svc
spec:
  selector:
    app: blog-varnish
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80</code></pre><p>Ingress <em>varnish-ing.yaml</em>:</p><pre><code>---
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</code></pre><h3 id="deploy">Deploy</h3><pre><code>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</code></pre><h3 id="podsumowanie">Podsumowanie</h3><p>W moim przypadku zastosowanie varnisha zwi&#x119;kszy&#x142;o mo&#x17C;liwo&#x15B;ci przetwarzania req/s mojego clustra prawie <strong>dziesi&#x119;ciokrotnie</strong>. Wszystko oparte jest tutaj o dosy&#x107; s&#x142;abe wydajno&#x15B;ciowo <em>free-tier</em> z <strong>oracle-cloud&apos;a</strong>. Natomiast je&#x17C;eli po&#x142;&#x105;czymy ca&#x142;o&#x15B;&#x107; z cloudflarem, to mo&#x17C;na uzyska&#x107; wi&#x119;cej ni&#x17C; zadawalaj&#x105;ce rezultaty.</p><h3 id="linki">Linki</h3><p><a href="https://varnish-cache.org">Varnish</a>,<br><a href="https://www.oracle.com/pl/cloud/free/">Oracle free-tier.</a></p>]]></content:encoded></item><item><title><![CDATA[k3s - nginx ingress]]></title><description><![CDATA[<p>Domy&#x15B;lnym ingressem w k3s jest traefik. Osobi&#x15B;cie wolne korzysta&#x107; z nginx&apos;a wi&#x119;c opisz&#x119; pokr&#xF3;tce jak zdeploywa&#x107; go w clustrze k3s&apos;a.</p><h3 id="instalacja-k3s">Instalacja k3s</h3><p>Zaczniemy od instalacji samego k3s z wy&#x142;&#x105;czonym traefikiem:</p><pre><code>curl -sfL</code></pre>]]></description><link>http://michal.kuzdzal.pl/k3s-nginx-ingress/</link><guid isPermaLink="false">6202d4d3ae62c600012aa142</guid><category><![CDATA[k8s]]></category><category><![CDATA[k3s]]></category><category><![CDATA[nginx]]></category><category><![CDATA[ingress]]></category><dc:creator><![CDATA[michal]]></dc:creator><pubDate>Wed, 05 Jan 2022 20:58:00 GMT</pubDate><media:content url="http://michal.kuzdzal.pl/content/images/2022/02/k3s-nginx-ingress.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://michal.kuzdzal.pl/content/images/2022/02/k3s-nginx-ingress.jpg" alt="k3s - nginx ingress"><p>Domy&#x15B;lnym ingressem w k3s jest traefik. Osobi&#x15B;cie wolne korzysta&#x107; z nginx&apos;a wi&#x119;c opisz&#x119; pokr&#xF3;tce jak zdeploywa&#x107; go w clustrze k3s&apos;a.</p><h3 id="instalacja-k3s">Instalacja k3s</h3><p>Zaczniemy od instalacji samego k3s z wy&#x142;&#x105;czonym traefikiem:</p><pre><code>curl -sfL https://get.k3s.io | sh -s - --disable traefik</code></pre><h3 id="deploy-nginx-ingress">Deploy nginx ingress</h3><p>Z zainstalowanym &apos;clustrem&apos; jeste&#x15B;my gotowi do instalacji nginx ingress:</p><pre><code>kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/deploy.yaml</code></pre><p>Zmieniamy network na lokalny aby wystawi&#x107; ingress na &apos;zewn&#x105;trz&apos;:</p><pre><code>cat &gt; ingress.yaml &lt;&lt;EOF 
spec:
  template:
    spec:
      hostNetwork: true
EOF

kubectl patch deployment ingress-nginx-controller -n ingress-nginx --patch &quot;$(cat ingress.yaml)&quot;</code></pre><h3 id="testy-deployu">Testy deploy&apos;u</h3><p>W tym momencie na localhoscie powinni&#x15B;my mie&#x107; ju&#x17C; wystawiony porty http/s. Mo&#x17C;emy to sprawdzi&#x107; curlem:</p><pre><code>&#x279C;  ~ curl https://localhost -k
&lt;html&gt;
&lt;head&gt;&lt;title&gt;404 Not Found&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
&lt;center&gt;&lt;h1&gt;404 Not Found&lt;/h1&gt;&lt;/center&gt;
&lt;hr&gt;&lt;center&gt;nginx&lt;/center&gt;
&lt;/body&gt;</code></pre><h3 id="deploy-przyk%C5%82adowego-nginxa">Deploy przyk&#x142;adowego nginxa</h3><p>Utw&#xF3;rzmy zatem przyk&#x142;adowy deployment i wystawmy go za pomoc&#x105; ingressu:</p><pre><code>cat &gt; deploy.yaml &lt;&lt;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</code></pre><p>Wa&#x17C;ne tutaj jest dodanie w ingress&apos;ie <strong><em>kubernetes.io/ingress.class: nginx</em></strong>. Inaczej nasz ingress nie wystawi naszego servicu. <br>Je&#x17C;eli nie chcemy tego robi&#x107; musimy wyedytowa&#x107; nasz&#x105; ingressclass i ustawi&#x107; go jako default:</p><pre><code>kubectl edit ingressclass nginx
  annotations:
    ingressclass.kubernetes.io/is-default-class: &quot;true&quot;</code></pre><h3 id="linki">Linki</h3><p><a href="https://kubernetes.github.io/ingress-nginx/">Nginx ingress</a></p>]]></content:encoded></item></channel></rss>