Terraform

Terraform w służbie konteneryzacji, czyli zarządzanie Kubernetesem w podejściu IaC

2025-03-10
Podziel się

W dzisiejszym świecie IT konteneryzacja stała się fundamentem nowoczesnego podejścia do wdrażania i zarządzania aplikacjami. Narzędzia do ich orkiestracji, takie jak Kubernetes, umożliwiają skuteczne zarządzanie infrastrukturą w większości rozwiązań firmowych i korporacyjnych. Często mamy do czynienia z infrastrukturą hybrydową, która niejednokrotnie ma bardzo szerokie znaczenie. Łączy ona rozwiązania on-premises, oparte na popularnych wirtualizatorach, z chmurami publicznymi. Działają one w oparciu o popularne modele zarządzania, takie jak IaaS (Infrastructure as a Service), PaaS (Platform as a Service), SaaS (Software as a Service) oraz coraz popularniejszy CaaS (Containers as a Service).

Kubernetes to najpopularniejsza platforma orkiestracji kontenerów. Umożliwia automatyczne wdrażanie, skalowanie i zarządzanie aplikacjami kontenerowymi. Jednak sama konfiguracja klastra czy definiowanie zasobów mogą być skomplikowane i podatne na błędy, szczególnie gdy liczba środowisk i zasobów rośnie. Platformy takie jak Rancher czy OpenShift, które opierają się na Kubernetesie, oferują narzędzia ułatwiające administrację. Są to na przykład graficzny interfejs użytkownika oraz zintegrowane narzędzia typu GitOps. Mimo to tworzenie kompletnych środowisk i szybkie wdrażanie aplikacji pozostaje wyzwaniem. W takich sytuacjach można sięgnąć po narzędzia, np. Helm czy Kustomize. Dzięki nim proces wdrażania aplikacji staje się znacznie prostszy. Zwłaszcza jeżeli mówimy o dużych konstrukcjach wykorzystujących Kubernetesa w sposób kompletny.

Narzędzia, takie jak Ansible czy Pulumi, również mogą poradzić sobie z tematyką konteneryzacji, jednak nie zostały do tego stworzone. Ansible służy głównie do automatyzacji powtarzalnych procesów, a nie do zarządzania nimi. Z kolei Pulumi pozwala na użycie pełnych języków programowania, takich jak Python czy JavaScript, co umożliwia tworzenie dynamicznych i złożonych rozwiązań. Wymaga jednak znajomości programowania.

Co zatem wybrać? Z pomocą przychodzi HashiCorp Terraform — jedno z najpopularniejszych narzędzi IaC (Infrastructure as Code). Terraform umożliwia deklaratywne definiowanie i zarządzanie infrastrukturą w sposób spójny, powtarzalny i łatwy do wersjonowania. Pozwala także na automatyzację konfiguracji zarówno samego Kubernetesa, jak i jego zaplecza w chmurze lub środowisku on-premises. Dodatkowo wspiera integrację z narzędziami do zarządzania klastrami, takimi jak Rancher czy OpenShift.

W tym artykule przeanalizujemy, jak Terraform upraszcza zarządzanie Kubernetesem oraz jakie korzyści wynikają z jego zastosowania. Omówimy różne aspekty pracy z Terraformem w kontekście Kubernetesa — od tworzenia klastrów, przez zarządzania zasobami aplikacyjnymi, po współpracę z innymi narzędziami oraz integrację z popularnymi platformami konteneryzacyjnymi. Przyjrzymy się także najlepszym praktykom, takim jak wykorzystanie modułów Terraform oraz automatyzacja za pomocą narzędzi CI/CD.

Podejście IaC umożliwia większą przewidywalność infrastruktury oraz łatwiejsze zarządzanie konfiguracją. Pozwala także na szybkie odtwarzanie środowisk. Niezależnie od tego, czy wdrażamy Kubernetesa on-premises, czy korzystamy z dostawców chmury publicznej, Terraform umożliwia unifikację zarządzania i zwiększa efektywność operacyjną.

Czym jest IaC i dlaczego warto go stosować w kontekście Kubernetesa?

IaC (Infrastructure as Code) umożliwia definiowanie kompletnych środowisk wirtualnych przy użyciu podejścia deklaratywnego. W przeciwieństwie do wspomnianych wcześniej narzędzi do zarządzania infrastrukturą, które łączą podejście deklaratywne i imperatywne, Terraform korzysta wyłącznie z modelu deklaratywnego. Oznacza to, że musimy jedynie określić cel, a Terraform sam ustali kroki potrzebne do jego osiągnięcia. Warto podkreślić, że Kubernetes stanowi kompletną infrastrukturę wirtualną, w której mamy odpowiedniki połączonych ze sobą w jedną całość serwerów, urządzeń sieciowych i aplikacji. Już samo to wystarcza, aby sięgnąć po takie narzędzia jak Terraform.

Załóżmy, że naszym celem jest zainstalowanie Deploymentu w istniejącym klastrze Kubernetes. Deployment ten jest definicją aplikacji korzystającej z różnych obiektów Kubernetesa, jak PersistentVolumes, Secrets, ConfigMaps, Services i inne. Aplikacja musi być zainstalowana w osobnej przestrzeni nazw oraz być wystawiona na zewnątrz poprzez Ingress. Dodatkowo musimy umożliwić sterowanie liczbą podów lub wdrożyć autoscaling. Terraform pozwoli nam osiągnąć ten cel w sposób deklaratywny, automatyzując tworzenie zasobów i zarządzanie nimi.

Wymagania, które opisaliśmy, są standardem dla większości aplikacji wdrażanych w środowisku kontenerowym. Zazwyczaj realizujemy je ręcznie, tworząc i edytując manifesty poszczególnych obiektów. Alternatywą jest wykorzystanie zaawansowanych narzędzi, takich jak Helm Chart, które pozwalają połączyć wszystkie elementy składowe w jeden projekt i uruchomić go za pomocą jednego polecenia.

Podejście, jakie oferuje Terraform, jest nieco inne. Zamiast żmudnego tworzenia plików YAML z definicją danego obiektu, deklarujemy parametry w sposób typowy dla Terraforma, przypominający budowanie infrastruktury wirtualnej. Provider, czyli rodzaj sterownika tłumaczącego parametry określone w Terraformie na instrukcje zrozumiałe dla Kubernetesa, wykonuje resztę czynności. To on, niejako w tle, tworzy manifest obiektu i wdraża go w klastrze.

Pamiętajmy o kluczowej funkcjonalności Terraforma, czyli o zależnościach. Tworząc aplikacje ręcznie, musimy pamiętać o kolejności tworzenia obiektów. W wielu przypadkach obiekty, które początkowo nie mogą osiągnąć żądanego stanu z powodu niespełnionych zależności, jak np. brak sekretu uniemożliwiający uruchomienie poda, ostatecznie ten stan osiągną. Jednak czasami wymaga to od nas szczególnej uwagi oraz poświęcenia czasu na odpowiednie zaplanowanie wdrożenia, a także poszukiwanie błędów.

Do pewnego stopnia z opresji ratuje nas Helm, który po odpowiednim skonfigurowaniu wykonuje całą pracę za nas i uruchamia kompletną oraz działającą aplikację. Pamiętajmy jednak, że Helm jest narzędziem skupionym wyłącznie na aplikacjach i zarządzaniu chartami w Kubernetesie. Helm umożliwia łatwe instalowanie, aktualizowanie i usuwanie aplikacji w klastrze, ale nie służy do zarządzania infrastrukturą poza nim. Dodatkowo Helm nie posiada wbudowanego mechanizmu planowania w takim sensie jak Terraform. Istnieją wprawdzie dodatkowe wtyczki, takie jak Helm Diff, które ułatwiają to zadanie, jednak nie zapewniają pełnej wizualizacji stanu przed jego wykonaniem. To właśnie ta funkcjonalność jest kluczową cechą Terraforma.

Chciałbym podkreślić różnice między tymi narzędziami i jasno zaznaczyć, że nie stanowią one dla siebie konkurencji. Nie musimy rezygnować z Helm Chartów, które często otrzymujemy od deweloperów już przygotowane do wdrożenia. Mogą one stanowić integralną i bardzo pomocną część konfiguracji zdefiniowanej w Terraformie, o czym opowiemy sobie w dalszej części artykułu. Powiedzmy to wprost: w IT bardzo rzadko mamy do czynienia z jednym uniwersalnym narzędziem, które potrafi zastąpić wszystkie inne. Tak samo jest w tym przypadku. Mam nadzieję, że przechodząc przez kolejne rozdziały artykułu, uda mi się udowodnić tę tezę.

Zaczynamy pracę z Kubernetesem

Początki nie różnią się zbytnio od klasycznej sytuacji, gdy tworzymy infrastrukturę. Także tutaj musimy użyć właściwego providera. Jak wspomniałem, provider to pewnego rodzaju sterownik, który zawiera definicje obiektów kubernetesowych oraz instrukcje ich tworzenia. Dzięki temu Terraform może samodzielnie wykonać zadania, które dotychczas definiowaliśmy w plikach YAML. Kubernetes Provider, o którym mowa, jest jednym z oficjalnie dostępnych na stronie HashiCorp. Dzięki temu już na starcie mamy gwarancję, że zadziała prawidłowo zarówno z naszą instancją Terraforma, jak i z naszym klastrem — pod warunkiem, że spełnimy wymagania co do jego minimalnej wersji.

Dokumentacja Providera Kubernetes

Rys. Dokumentacja Providera Kubernetes

Kolejnym krokiem, jaki musimy wykonać, jest naturalnie uwierzytelnienie w naszym klastrze kubernetesowym. Aby Terraform mógł wykonywać jakiekolwiek działania, musi istnieć plik określony w zmiennej systemowej KUBECONFIG, podanie jego konkretnej lokalizacji, bądź też domyślna konfiguracja dla użytkownika, z którego będziemy uruchamiać skrypty. Mamy tutaj dużą dowolność, włączając w to również pluginy dostawców usług chmurowych, jeśli tylko będziemy korzystać z tego typu rozwiązań.

Pozostaje jeszcze kwestia uprawnień po stronie samego Kubernetesa. Najlepszym rozwiązaniem jest utworzenie w klastrze dedykowanego konta serwisowego z koniecznym zestawem uprawnień niezbędnym do wykonania wszystkich czynności określonych w skrypcie Przypomnijmy, że RBAC został wprowadzony do Kubernetesa w wersji 1.6. Natomiast w wersji 1.8 został oznaczony jako stabilny.

Oczywiście w zależności od środowiska, na którym pracujemy i czynności, jakie mamy do wykonania, można też Terraformowi przydzielić pełne prawa administratora klastra. Wówczas ułatwimy sobie nieco zadanie. Nie natrafimy bowiem na problemy z brakiem uprawnień, które trzeba będzie rozwiązywać na bieżąco. Jednocześnie narazimy się jednak na niebezpieczeństwo wykonania pewnych niepożądanych czynności. Przypomnijmy, że w Terraformie nie określamy plików z definicjami, jakie mają być wykorzystane w projekcie. Dzieje się to automatycznie. Prawdopodobieństwo popełnienia błędu rośnie też wraz z liczbą współpracujących ze sobą osób. Warto o tym pamiętać i stosować dobre praktyki już na samym początku.

Tworzymy podstawowe zasoby Kubernetesa

HashiCorp przyzwyczaił nas do dosyć jasnego i klarownego nazewnictwa. W związku z tym budowanie deploymentu zaczynamy od użycia trzech funkcji: `kubernetes_namespace`, `kubernetes_deployment` oraz `kubernetes_service`.

O ile w pierwszym przypadku podajemy jedynie nazwę przestrzeni nazw, o tyle w przypadku deploymentu musimy określić wszystkie parametry, które normalnie zawarlibyśmy w manifeście YAML. Możemy zauważyć liczne podobieństwa między tymi dwoma podejściami. Mimo że konstrukcja i składnia użytych języków programowania są różne, to jednak parametry potrzebne do stworzenia naszego wdrożenia musimy podać w sposób jawny.

Przykładowy deployment

Rys. Przykładowy deployment

W przykładzie widzimy podany namespace, który, podobnie jak w klasycznej definicji, jest opcjonalny. Jeśli go nie podamy, zostanie wykorzystany aktualnie używany namespace zdefiniowany w pliku kubeconfig. Działa to dokładnie tak samo jak w tradycyjnym podejściu.

Tutaj jednak mamy możliwość odwołania się do utworzonego w pierwszym kroku zasobu typu `kubernetes_namespace`, o którym wspomnieliśmy wcześniej. Kolejnym krokiem będzie utworzenie zasobu typu `service`. Również tutaj możemy wykorzystać funkcjonalności, jakie oferuje nam terraform. Oprócz przestrzeni nazw mamy pełną dowolność używania zmiennych, które możemy wykorzystać chociażby do określenia selektora aplikacji, użytych portów czy typu klastra.

Przedstawiłem jedynie prosty przykład, stanowiący trzon większości aplikacji kontenerowych. Jednak, jak wspomnieliśmy wcześniej, Terraform, a szczególnie używany przez nas provider, oferuje znacznie więcej niż tylko budowanie standardowej aplikacji składającej się jedynie z definicji deploymentu i serwisu. Z wyjątkiem kilku przypadków, umożliwia on wykonanie praktycznie każdej czynności związanej z przygotowaniem środowiska i wdrożeniem aplikacji. Wystarczy wspomnieć o konfiguracji sieci, zarządzaniu limitami, autoskalowaniu i wielu innych. Takie wdrożenie bardziej przypomina konfigurację infrastruktury serwerowej. Stanowi również doskonałe uzupełnienie tego, co oferuje Helm.

Wykorzystanie Helm Chartów we wdrożeniu

Temat Helm Chartów przewija się praktycznie od początku artykułu, co nie dziwi, ponieważ stanowią one znakomitą alternatywę dla klasycznego wdrożenia. Co więcej, doskonale integrują się z Terraformem, co może być zaskakujące na pierwszy rzut oka.

Dzięki providerowi Helm dla Terraform, który – podobnie jak Kubernetes – jest dostępny jako oficjalna dystrybucja, można zautomatyzować wdrażanie aplikacji i zarządzać ich cyklem życia w sposób deklaratywny. Jest to szczególnie przydatne w środowiskach, gdzie konfiguracja aplikacji musi być powtarzalna, łatwa do odtworzenia oraz wersjonowana.

W efekcie otrzymujemy spójność konfiguracji, ponieważ cała infrastruktura i aplikacje mogą być zarządzane jednym zestawem plików Terraform. Zyskujemy także automatyzację wdrożeń, ponieważ Helm Charty mogą być wdrażane w ramach tego samego planu Terraform co infrastruktura klastra.

Dodatkowo mamy możliwość wersjonowania, co jest immanentną cechą Terraforma. Pozwala to na precyzyjne określanie wersji Helm Chartów, co znacznie ułatwia zarządzanie aktualizacjami. Ważną zaletą jest też idempotencja – Terraform sprawdza stan wdrożonych zasobów i dokonuje tylko niezbędnych zmian.

Użycie Helm Chartów w Terraform

Rys. Użycie Helm Chartów w Terraform

W powyższym przykładzie Terraform wykorzystuje Helm Chart do wdrożenia NGINX w Kubernetesie. Można w prosty sposób zdefiniować wartości konfiguracyjne (plik values.yaml) oraz kontrolować wersję wdrożonego oprogramowania.

Dzięki tej integracji Terraform staje się potężnym narzędziem do kompleksowego zarządzania zarówno infrastrukturą Kubernetes, jak i aplikacjami – w sposób w pełni zautomatyzowany i kontrolowany. Otrzymujemy przy tym jeszcze jeden „bonus” – nie musimy rezygnować z posiadanych już Helm Chartów na rzecz Terraforma.

Powiedzmy sobie wprost: robienie rewolucji polegającej na całkowitej zmianie podejścia do wdrażania aplikacji rzadko kiedy jest realne – i najczęściej zwyczajnie tego nie chcemy. Dodatkowo zazwyczaj znaczna część aplikacji, które posiadamy, jest tworzona i utrzymywana przez zewnętrzne podmioty. Dostarczają one gotowy do wdrożenia produkt. Nawet gdybyśmy chcieli zrezygnować z tego i całkowicie zmienić system przygotowania oraz parametryzowania aplikacji, to najczęściej nie będziemy w stanie tego zrobić z przyczyn czysto formalnych.

Terraform, posiadając w swojej gamie providerów takie produkty jak Helm, nie zmusza nas praktycznie do niczego. Pozwala za to skonstruować pewne procesy w sposób łatwy i szybki, bez konieczności rezygnacji z istniejących już procedur. Co najważniejsze, robi to w sposób spójny i zgodny z tym, co znamy z klasycznego wykorzystania Terraforma – czyli w procesie zarządzania infrastrukturą wirtualną.

Wykonywanie typowych czynności administracyjnych

Terraform nie został co prawda stworzony do zarządzania cyklicznymi zadaniami operacyjnymi. Można go jednak wykorzystać do automatycznego tworzenia mechanizmów, które te zadania wykonują.

Co rozumiem przez cykliczne zadania? Istnieją czynności, o których łatwo zapomnieć w natłoku obowiązków związanych z zarządzaniem środowiskami konteneryzacyjnymi. Przykładem może być usuwanie niepotrzebnych obrazów na workerach czy starych i niewykorzystywanych obiektów, takich jak ConfigMap, Secrets czy PersistentVolumes.

Oczywiście są to zadania, które powinno się wykonywać regularnie. Terraform co prawda nie wyręczy nas całkowicie, ale może ułatwić ich realizację – na przykład poprzez tworzenie i uruchamianie CronJobs lub aplikacji, które zajmą się czyszczeniem tych zasobów.

Czyszczenie PVC przy pomocy CronJoba

Rys. Czyszczenie PVC przy pomocy CronJoba

Zarządzanie klastrami Kubernetes przez Terraform

Wykorzystanie Terraforma w Kubernetesie nie ogranicza się jedynie do wdrażania aplikacji czy obiektów. Możemy go użyć także, a może nawet przede wszystkim, do zarządzania infrastrukturą, na której będzie uruchomiony klaster Kubernetes. Może to obejmować na przykład provisionowanie maszyn wirtualnych z wykorzystaniem odpowiednich providerów – w zależności od tego, czy korzystamy z chmury publicznej, czy prywatnej.

Możemy zautomatyzować w zasadzie każdą czynność – od utworzenia maszyny wirtualnej aż po podłączenie jej do klastra w roli mastera czy workera. Terraform jest narzędziem, które potrafi kontrolować cały proces automatyzacji tworzenia klastra Kubernetes. Obejmuje to infrastrukturę, węzły, konfigurację sieci oraz aplikacje. Dzięki temu znacząco zmniejsza się ryzyko błędów ludzkich oraz czas potrzebny na ręczne konfigurowanie. Stosowanie podejścia IaC pozwala traktować całą infrastrukturę jako kod. Umożliwia to wersjonowanie, audytowanie oraz łatwe zarządzanie konfiguracjami klastra Kubernetes w sposób powtarzalny.

Elastyczność, jaką oferuje to rozwiązanie, jest nie do przecenienia. Z poziomu Terraforma można zarządzać całą infrastrukturą klastra zarówno w środowisku on-premises – np. VMware czy OpenStack – jak i w chmurze publicznej. Terraform umożliwia więc wdrażanie klastrów w różnych środowiskach. Dzięki temu otrzymujemy możliwość centralnego zarządzania zarówno infrastrukturą, jak i aplikacjami uruchamianymi w Kubernetesie. Wszystkie zasoby – w tym maszyny wirtualne, węzły, pody oraz aplikacje – mogą być opisane w jednym pliku konfiguracyjnym.

Zatrzymajmy się na chwilę przy tym zagadnieniu. Co właściwie możemy uzyskać, definiując kompletne środowisko kontenerowe w jednym projekcie Terraforma? Przede wszystkim otrzymujemy kompletny skrypt, który umożliwia wdrożenie i uruchomienie całego, skonfigurowanego oraz sparametryzowanego klastra kubernetesowego wraz z działającymi aplikacjami. Pierwsza myśl, jaka przychodzi mi do głowy, to stawianie środowisk deweloperskich – które często są klonami istniejących środowisk produkcyjnych czy przedprodukcyjnych.

Konfiguracja takich klastrów wymaga od nas sporego wysiłku – oprócz powołania maszyn wirtualnych i zainstalowania na nich Kubernetesa lub, w przypadku chmur publicznych, wykorzystania modelu CaaS, musimy także zadbać o ich odpowiednie sparametryzowanie. Dodatkowo konieczne jest uruchomienie wszystkich niezbędnych na tym środowisku aplikacji.

Oczywiście dużą część tych czynności możemy zautomatyzować – na przykład przy pomocy Ansible, wykorzystując pipeline’y CI/CD lub nawet korzystając ze skryptów bash. Jest to podejście jak najbardziej słuszne. Terraform jednak oferuje zdecydowanie więcej. Dodatkowo – jak już wielokrotnie wspominałem – nie stanowi konkurencji dla większości narzędzi automatyzujących, lecz raczej działa jako konsolidator. Dzięki Terraformowi możemy połączyć wszystkie te narzędzia w jedną spójną całość.

Uruchomienie polecenia ‘kubeadm’ na zdalnym serwerze

Rys. Uruchomienie polecenia ‘kubeadm’ na zdalnym serwerze

Współpraca Terraform z providerami zewnętrznymi

Baza providerów Terraforma wynosi na ten moment ponad 4800. W znacznej większości są to providery należące do kategorii community – czyli niewspierane oficjalnie przez HashiCorp i niebędące produktami partnerów tej firmy. Jednak przy tak dużej liczbie dostępnych providerów trudno znaleźć nowoczesne rozwiązanie, które byłoby w Terraformie całkowicie niedostępne.

Jednym z kluczowych zastosowań Terraforma jest integracja z platformami chmurowymi – takimi jak AWS, Azure, Google Cloud oraz wieloma innymi. Terraform wspiera wielu dostawców chmurowych poprzez dedykowane, najczęściej oficjalne providery dla każdej z tych platform. Dzięki temu możemy wykorzystać go do tworzenia, zarządzania i skalowania zasobów chmurowych, które są niezbędne dla działania Kubernetesa.

Dzięki dedykowanym providerom mamy możliwość automatycznego tworzenia zasobów – takich jak maszyny wirtualne, wirtualne sieci prywatne czy load balancery, a także zasoby do przechowywania danych oraz usługi monitorowania i bezpieczeństwa. Każdy dostawca chmury oferuje jednak nieco inne usługi. Napisanie jednego uniwersalnego skryptu, który pozwalałby na przenośność platformy konteneryzacyjnej między różnymi środowiskami, jest więc wyzwaniem dosyć karkołomnym – ale nie niemożliwym.

Musimy jednak wspomnieć o jednej ważnej rzeczy: dostawcy chmur publicznych, z których korzystamy, dostarczają nam kompletne środowisko konteneryzacyjne zgodne ze specyfikacją i możliwe do zarządzania w sposób klasyczny. Decydując się na skorzystanie z jednego z operatorów oferujących Kubernetesa w podejściu CaaS, otrzymujemy dokładnie takie same możliwości wdrażania aplikacji, jak gdybyśmy postawili go na własnych maszynach wirtualnych. Różnica polega jedynie na sposobie dostarczania orkiestratora i zarządzania nim. Opisane wcześniej metody zarządzania klastrami kubernetesowymi poprzez Terraform są jak najbardziej aktualne dla wszystkich dostawców chmur, dla których istnieje odpowiedni provider. Trzeba jednak pamiętać, że pewne czynności będą wykonywane zupełnie inaczej w różnych środowiskach.

Przykładem może być dodawanie nodów do Kubernetesa. Jest to co prawda czynność wykonywana może nie tak często, ale jednak kluczowa – zwłaszcza gdy w miarę rozwoju środowiska pojawia się potrzeba zwiększenia zasobów. Zazwyczaj dostawcy chmury działają jednak według swoich własnych zasad.

Dodanie węzła do Google Kubernetes Engine

Rys. Dodanie węzła do Google Kubernetes Engine

Moduły Terraform – strukturyzowanie kodu w kontekście Kubernetes

Wykorzystanie modułów Terraform to technika, która pozwala podzielić duże i złożone konfiguracje na mniejsze, łatwiejsze do zarządzania fragmenty. Moduły umożliwiają ponowne wykorzystanie kodu, poprawiają czytelność oraz ułatwiają utrzymanie i aktualizację zasobów.

W przypadku zarządzania Kubernetesem z użyciem Terraforma moduły są nieocenionym i często niedocenianym narzędziem. Ułatwiają organizowanie zasobów w sposób, który sprzyja integracji z różnymi środowiskami oraz zespołami. Jedną z podstawowych zalet i kluczową cechą stosowania modułów jest lepsza organizacja kodu. Pozwala ona podzielić infrastrukturę Kubernetes na logiczne komponenty – takie jak klastry, sieci, przestrzenie nazw czy konfiguracje węzłów. Zamiast pisać jedną dużą konfigurację o niskiej czytelności, tworzymy moduły odpowiadające za poszczególne elementy infrastruktury.

Na przykład możemy mieć osobny moduł do tworzenia klastra lub nawet zestaw modułów – oddzielnie dla każdego dostawcy chmurowego. Możemy także stworzyć osobny moduł do konfiguracji zasobów w przestrzeni nazw oraz moduł do zarządzania podłączeniem do zewnętrznych źródeł danych czy dodatkowych, współpracujących z klastrem, takich jak skanery kodu czy repozytoria. Jest to szczególnie ważne w kontekście współpracy Terraforma z Kubernetesem. Jak już wielokrotnie wspomnieliśmy, klaster Kubernetes to tak naprawdę kompletny ekosystem, zawierający zarówno komponenty infrastrukturalne, jak i aplikacyjne. Od nas zależy, czy zbudujemy środowisko przenośne na inne platformy. Terraform nam to umożliwia, dając szereg narzędzi, z których warto skorzystać.

Drugą cechą używania modułów jest reużywalność i skalowalność kodu. Moduły umożliwiają łatwe wykorzystanie tych samych konfiguracji w różnych środowiskach. Na przykład możemy stworzyć jeden moduł do konfigurowania węzłów Kubernetesa i używać go zarówno w środowisku testowym, jak i produkcyjnym – zmieniając jedynie parametry, takie jak liczba węzłów czy typ maszyny. Dzięki temu możemy tworzyć bardziej elastyczne i skalowalne środowiska, które łatwo dostosować do zmieniających się wymagań.

Czy to naprawdę jest takie ważne? Co nam daje reużywalność kodu w codziennej pracy? Weźmy pod uwagę, że środowiska kontenerowe w firmie rzadko kiedy ograniczają się jedynie do produkcji i testów. Najczęściej mamy cały szereg środowisk deweloperskich, które bardzo często różnią się znacznie konfiguracją od środowisk testowych, a zarządzane i utrzymywane są bezpośrednio przez zespoły programistów. Jest to wbrew pozorom podejście dosyć dobre, gdyż umożliwia deweloperom dostosowanie klastrów do wymagań, które często w procesie tworzenia aplikacji znacznie się różnią. Wykorzystywane są bowiem pewne elementy, które najczęściej w fazie testów czy na produkcji nie mają prawa bytu. Środowiska takie mają być szybkie i skonfigurowane tak, aby praca była prosta i komfortowa.

Jednak nawet środowiska deweloperskie powinny być skonfigurowane w taki sposób, aby przypominały testowe czy produkcyjne. Weźmy dla przykładu wersję Kubernetesa czy operatorów, które powinny być zgodne na wszystkich środowiskach. Planując upgrade naszych klastrów, musimy uwzględnić wszystkie środowiska, z jakimi mamy do czynienia – nie tylko ze względów bezpieczeństwa, ale także, a może przede wszystkim, z powodu zmian specyfikacji. Wykorzystując moduły, jesteśmy w stanie zaplanować i przeprowadzić takie modyfikacje sprawnie i szybko, zachowując jednocześnie indywidualność konfiguracji każdego klastra.

Ostatnią zaletą wykorzystywania modułów jest łatwiejsza współpraca w zespole. Jest to rzecz bardzo często pomijana w kontekście administracji systemami, gdyż kojarzy nam się przede wszystkim z zespołami deweloperskimi, dla których jest ona kluczowa. Jednak mając bardzo rozbudowane środowisko z licznymi klastrami, a jednocześnie zespół składający się z co najmniej kilku osób, relatywnie często będziemy mieli sytuacje, w których więcej niż jedna osoba będzie chciała coś zmienić w konfiguracji klastra, wdrożyć nową aplikację czy też dokonać zmian w istniejącym projekcie. Podzielenie kodu na moduły umożliwia zespołom lepszą współpracę, ponieważ różne osoby mogą pracować nad różnymi częściami infrastruktury w sposób niezależny. Zamiast edytować jeden wspólny plik, członkowie zespołu mogą tworzyć i aktualizować moduły, które następnie są używane w różnych częściach konfiguracji.

Przykład struktury modułów

Rys. Przykład struktury modułów

Praktyki CI/CD z Terraform i Kubernetes

Integracja Terraforma z procesami Continuous Integration/Continuous Deployment (CI/CD) pozwala na automatyczne zarządzanie infrastrukturą Kubernetes w sposób powtarzalny, przewidywalny i zgodny z podejściem Infrastructure as Code. W kontekście Kubernetes Terraform może być używany do tworzenia, aktualizacji i usuwania klastrów oraz powiązanych zasobów, podczas gdy narzędzia CI/CD obsługują automatyzację wdrożeń aplikacji. Jak może wyglądać przykładowy pipeline takiego wdrożenia i gdzie tutaj jest miejsce dla Terraforma? Developer lub administrator commituje zmianę w konfiguracji Terraforma w repozytorium Git. Następnie zdefiniowany w CI/CD webhook uruchamia testy, wykonując polecenia `terraform validate` oraz `terraform plan`. Jeżeli testy przejdą pomyślnie, dadzą zielone światło do wykonania zmian infrastruktury za pomocą `terraform apply`.

Po zakończeniu wdrażania infrastruktury – zakładając oczywiście, że taka zmiana musi nastąpić – aplikacja jest wdrażana do klastra, np. za pomocą Helm Charts, Kustomize czy ArgoCD. Co zyskujemy w ten sposób? Przede wszystkim widzimy, że zostały wykorzystane różne narzędzia zgodnie ze swoim przeznaczeniem. Dokładnie to, o czym wspominałem już wielokrotnie: używanie Terraforma nie powoduje konfliktów z innymi narzędziami. Można wręcz powiedzieć, że w procesie CI/CD wszystkie one się wzajemnie uzupełniają.

Przykładowy pipeline CI/CD

Rys. Przykładowy pipeline CI/CD

Które podejście jest lepsze? Mam na myśli definiowanie zarówno infrastruktury, jak i zarządzanie wdrożeniami całkowicie w Terraformie, czy też wykorzystywanie narzędzi zgodnie z ich przeznaczeniem. Zabrzmiało to trochę tak, jakbym chciał wręcz zniechęcić do używania Terraforma do wdrożeń – wbrew temu, o czym pisałem wcześniej. Nic podobnego. Podejście, które wybierzemy, zależy od kilku czynników. Powinniśmy wziąć pod uwagę wielkość i stopień rozbudowania naszego środowiska oraz to, czy tworzymy proces od zera, jak również to, jaką mamy swobodę wyboru narzędzi, z których możemy skorzystać.

Tworząc bardzo rozbudowane środowisko z możliwością przenoszenia na inne platformy chmurowe, a jednocześnie posiadające małą liczbę relatywnie rzadko zmieniających się aplikacji, możemy rozważyć wykorzystanie czystego Terraforma. W ten sposób otrzymujemy kod zawierający kompletną definicję platformy konteneryzacyjnej wraz z aplikacjami, które możemy wdrażać bez potrzeby ingerowania w samo środowisko. Bardzo często jednak mamy do dyspozycji określony zestaw narzędzi lub też wyspecyfikowane wymagania stawiane przez naszą firmę. Wówczas należy się zastanowić, w jaki sposób zintegrować wszystkie te narzędzia, wykorzystując ich pełne możliwości.

Przypadek Terraforma nie jest zresztą jedyny. Znamy wiele przykładów, gdy korzystanie z zewnętrznych narzędzi jest korzystniejsze, a często nawet zalecane przez producenta. Przykładem może być chociażby przechowywanie informacji niejawnych w Kubernetesie. Mamy do dyspozycji sekrety, ale dla większego bezpieczeństwa zaleca się stosowanie zewnętrznych systemów do ich przechowywania – takich jak HashiCorp Vault. Inne przykłady to chociażby routing w Kubernetesie czy monitoring środowisk kontenerowych.

Producenci zazwyczaj starają się wyposażyć swoje produkty w szereg opcji zwiększających ich wydajność i funkcjonalność. Jednak rzadko kiedy zamykają się na możliwość stosowania narzędzi zewnętrznych. Dzieje się tak między innymi dlatego, że dzisiejsze systemy komputerowe stają się coraz bardziej zaawansowane i rozległe. Integracja chmur publicznych i prywatnych oraz mnogość stosowanych w nich rozwiązań zmuszają nas do wykorzystywania bardzo specjalistycznych narzędzi.

Integracja Terraform z HashiCorp Vault

Wspomniany już wcześniej HashiCorp Vault to jedno z najpopularniejszych narzędzi do zarządzania tajnymi danymi, które doskonale współpracuje z Terraformem, zwłaszcza w kontekście zarządzania Kubernetesem i infrastrukturą chmurową. Wdrażając Kubernetes za pomocą Terraforma, często musimy przechowywać i udostępniać wrażliwe dane, takie jak klucze API, certyfikaty TLS, hasła do baz danych czy tokeny dostępu. Integracja z Vault pozwala na ich dynamiczne zarządzanie i zwiększa poziom bezpieczeństwa infrastruktury.

Zyskujemy dzięki temu możliwość bezpiecznego przechowywania danych niejawnych, co eliminuje konieczność ich zahardcodowania w skryptach. Mamy także możliwość dynamicznego generowania i rotacji danych, takich jak krótkoterminowe poświadczenia do baz danych lub chmur publicznych, co minimalizuje ryzyko ich wycieku. Dodatkowo możemy precyzyjnie kontrolować polityki dostępu i RBAC przy pomocy Vaulta. Uzyskujemy także większą zgodność z regulacjami, co pozwala spełnić wymagania norm, takich jak ISO 27001. Terraform integruje się z Vault za pomocą providera o tej samej nazwie, który umożliwia zarządzanie danymi przechowywanymi w Vault oraz pobieranie ich na potrzeby innych zasobów Terraform.

Przykład konfiguracji HashiCorp Vault w Terraform

Rys. Przykład konfiguracji HashiCorp Vault w Terraform

Jakie zaawansowane funkcje oferuje HCP Vault i co zyskujemy w kontekście Terraforma, integrując te dwa narzędzia? Przede wszystkim automatyczne uwierzytelnianie. Terraform może korzystać z Vault Agent lub tokenów dostępowych, aby automatycznie uwierzytelniać się w Vault – bez konieczności przechowywania poświadczeń w kodzie. Zyskujemy także możliwość dynamicznego generowania poświadczeń do baz danych, ponieważ Vault pozwala Terraformowi tworzyć tymczasowe konta użytkowników baz danych, które po zakończeniu działania infrastruktury zostaną usunięte. Możemy również wykorzystać Vault jako źródło certyfikatów TLS dla klastra Kubernetes – dynamicznie je odnawiając i dostarczając do kontrolera Ingress lub serwera API.

Funkcjonalności, które możemy wykorzystać, jest znacznie więcej i ogólnie można powiedzieć, że Terraform i Vault to potężne połączenie dla organizacji wdrażających Kubernetes w podejściu IaC. Integracja z Vault pozwala eliminować twarde kodowanie sekretów w konfiguracjach Terraform i Kubernetes, poprawia bezpieczeństwo i automatyzuje zarządzanie danymi uwierzytelniającymi. W większych środowiskach, gdzie zarządzanie wieloma klastrami i aplikacjami staje się wyzwaniem, wykorzystanie Vault jako centralnego źródła tajnych danych znacząco podnosi poziom automatyzacji i bezpieczeństwa.

Integracja Terraform z OpenShift, Rancher i wirtualizatorami

Kubernetes stanowi trzon praktycznie każdej konteneryzacji. Jednak poza klasycznym podejściem mamy do dyspozycji także takie rozwiązania jak OpenShift czy Rancher, które umożliwiają tworzenie kompletnych i zintegrowanych środowisk gotowych do pracy. Dodatkowo oferują one w standardzie funkcjonalności i narzędzia, których trudno szukać w klasycznym Kubernetesie, takie jak konsola GUI, routowalna sieć czy zintegrowany katalog aplikacji.

Najczęściej używanym providerem do tworzenia klastra OpenShift w chmurach publicznych jest, należący do kategorii community, `openshift` lub pochodzący z oficjalnego repozytorium `azurerm`. Jeżeli natomiast wdrażany jest on w środowisku on-premises, Terraform może korzystać z providerów dla `openstack` czy `vsphere`.

Przykład wdrożenia OpenShift w klastrze AWS

Rys. Przykład wdrożenia OpenShift w klastrze AWS

W przypadku wdrażania OpenShift w środowisku on-premises Terraform może współpracować z IPI (Installer Provisioned Infrastructure) lub UPI (User Provisioned Infrastructure), wykorzystując narzędzia takie jak OpenShift Installer oraz Terraform Provider for vSphere/OpenStack. Zarządzanie zasobami OpenShift przy pomocy Terraforma nie różni się praktycznie niczym od podejścia w klasycznym Kubernetesie. OpenShift sam w sobie jest praktycznie – z małymi wyjątkami, takimi jak używanie DeploymentConfigów (aktualnie oznaczonych jako „deprecated”) – zgodny z Kubernetesem. Wykonywanie większości operacji, takich jak wdrożenia czy zarządzanie obiektami, będzie identyczne i wymagać będzie skorzystania z providera Kubernetes.

W przypadku Ranchera mamy znacznie więcej możliwości, ponieważ możemy skorzystać z providerów przygotowanych przez partnera HashiCorp. Do dyspozycji mamy providera o nazwie rancher2, który służy do zarządzania instancją Ranchera, czyli samą platformą Rancher. Umożliwia on w szczególności zarządzanie oraz tworzenie i usuwanie klastrów, konfigurację Ranchera, zarządzanie użytkownikami i politykami RBAC, a także zarządzanie aplikacjami wdrażanymi w Rancherze.

Przykład definiowania klastra w Rancherze

Rys. Przykład definiowania klastra w Rancherze

Dodanie użytkownika do Ranchera

Rys. Dodanie użytkownika do Ranchera

Drugim providerem, z jakiego możemy skorzystać, jest rke. Służy on stricte do tworzenia i zarządzania klastrami Kubernetes w oparciu o RKE (Rancher Kubernetes Engine) – bez potrzeby instalowania i używania Ranchera. Umożliwia między innymi tworzenie klastra kubernetesowego w oparciu o RKE, zarządzanie kontrolerami i workerami oraz konfigurację sieci i komponentów klastra.

Przykład tworzenia klastra RKE

Rys. Przykład tworzenia klastra RKE

Zalety i ograniczenia Terraform w kontekście Kubernetes

O zaletach podejścia IaC powiedzieliśmy już dużo. Reasumując – główne korzyści to spójność i powtarzalność wdrożeń oraz przenośność klastrów pomiędzy różnymi platformami wirtualizacyjnymi. Dodatkowo podejście to umożliwia zarządzanie pełnym cyklem życia zasobów oraz klastrem Kubernetes i jego zasobami jednocześnie. Terraform pozwala zarządzać całą infrastrukturą Kubernetesa. Obejmuje to nie tylko same manifesty, takie jak Deployment, Service czy Ingress, ale także sam klaster oraz jego węzły.

Możemy używać providera `kubernetes` do tworzenia podów, serwisów czy ingresów. Z kolei `rke` możemy wykorzystać do zarządzania klastrem RKE, a `google` do zarządzania klastrami GKE. Dzięki temu Terraform może być centralnym narzędziem do zarządzania całą infrastrukturą Kubernetes – zarówno samym klastrem, jak i aplikacjami. Dodatkową zaletą jest to, że Terraform obsługuje wiele providerów. Oznacza to, że może zarządzać nie tylko Kubernetesem, ale także siecią, bazami danych oraz systemami do przechowywania informacji niejawnych.

Dodatkowo Terraform pozwala na hermetyzowanie i ponowne użycie kodu poprzez moduły, dzięki czemu możemy łatwo zarządzać różnymi środowiskami bez jego duplikacji. Podejście to ma jednak swoje ograniczenia. Jednym z nich jest brak pełnej zgodności z natywnym API Kubernetesa. Provider kubernetes nie obsługuje wszystkich zasobów dostępnych natywnie w Kubernetesie, ponieważ wersje API Kubernetesa zmieniają się zazwyczaj szybciej niż provider Terraform. Kolejnym ograniczeniem jest brak natywnego mechanizmu do zarządzania zmianami aplikacji. Terraform działa w trybie infrastrukturalnym, co oznacza, że nie zapewnia takich funkcji jak rolling updates czy canary deployments, które oferują popularne narzędzia CI/CD. W takim wypadku lepiej użyć np. Helm + ArgoCD do zarządzania aplikacjami, a Terraforma wykorzystać do zarządzania infrastrukturą. No i w końcu zarządzanie tajnymi danymi jest ograniczone, gdyż Terraform sam w sobie nie szyfruje sekretów i jeśli np. zapisujemy hasło do bazy danych w kubernetes_secret, to trafia ono do stanu Terraform jako czysty tekst. Oczywiście użycie zewnętrznych narzędzi, takich jak HashiCorp Vault lub AWS Secrets Manager, rozwiązuje ten problem.

Ostatnim problemem, jaki możemy napotkać, jest rozjazd pomiędzy rzeczywistością a zapisanym stanem. Plik stanu jest kluczowy dla Terraforma i problem ten może wystąpić zawsze, natomiast w przypadku Kubernetesa jest on szczególnie ważny i uciążliwy. Zarządzanie klastrem przy pomocy kubectl czy też narzędzi GUI oferowanych przez Ranchera czy OpenShift jest zupełnie naturalne i nie zawsze chcemy „odpalać” petardy w postaci Terraforma, zwłaszcza w sytuacjach awaryjnych i wymagających pośpiechu. Takie działania mogą doprowadzić do sporego rozjazdu pomiędzy tym, co mamy faktycznie, a stanem, jaki widzi Terraform.

Podsumowanie

W artykule omówiliśmy pokrótce, jak Terraform ułatwia zarządzanie zasobami Kubernetes – począwszy od prostych wdrożeń, poprzez Helm Charty, aż po zaawansowane operacje administracyjne. W dzisiejszym dynamicznym świecie konteneryzacji skuteczne zarządzanie infrastrukturą staje się kluczowe dla zapewnienia niezawodności, skalowalności i bezpieczeństwa systemów. Terraform, jako jedno z najpotężniejszych narzędzi w ekosystemie IaC, odgrywa kluczową rolę w zarządzaniu Kubernetesem – zarówno w chmurze, jak i lokalnie. Infrastructure as Code, czyli deklaratywne podejście do definiowania zasobów infrastrukturalnych, pozwala organizacjom automatyzować wdrażanie, zarządzanie i utrzymanie środowisk chmurowych oraz on-premises.

Przyjęcie tego podejścia w Kubernetesie niesie za sobą liczne korzyści. Zaczynając od spójności konfiguracji i automatyzacji operacji, a kończąc na ułatwieniu współpracy zespołowej oraz możliwości odtwarzania środowisk na żądanie. Terraform pozwala na tworzenie podstawowych zasobów Kubernetes, takich jak Deployments, ConfigMaps, Secrets czy PersistentVolumes, zapewniając jednocześnie pełną kontrolę nad ich wersjonowaniem i zarządzaniem cyklem życia.

Wykorzystanie Helm Chartów w Terraformie dodatkowo upraszcza wdrażanie skomplikowanych aplikacji, umożliwiając deklaratywne zarządzanie ich konfiguracją oraz dostosowywanie parametrów wdrożenia w sposób przewidywalny i zautomatyzowany. Terraform nie ogranicza się jedynie do definiowania zasobów aplikacyjnych i może być z powodzeniem wykorzystywany także do typowych czynności administracyjnych, takich jak czyszczenie nieużywanych obrazów, zarządzanie przestrzenią dyskową czy rotacja sekretów.

Dzięki wykorzystaniu odpowiednich providerów możliwe jest zarządzanie klastrami Kubernetes zarówno on-premises, jak i w chmurze – niezależnie od tego, czy używamy kubeadm, RKE2, czy OpenShift. Niezwykle istotnym aspektem Terraforma jest jego integracja z providerami zewnętrznymi. Pozwala to na rozszerzenie możliwości zarządzania klastrem Kubernetes o usługi oferowane przez dostawców chmurowych, takich jak AWS, GCP, Azure oraz na korzystanie z narzędzi, takich jak Vault czy Datadog. Dzięki wykorzystaniu modułów w Terraformie możliwe jest strukturyzowanie kodu w sposób przejrzysty, reużywalny i łatwy w utrzymaniu, co znacząco ułatwia zarządzanie zarówno małymi, jak i dużymi środowiskami Kubernetes.

Automatyzacja w kontekście Kubernetes nie kończy się na samym wdrażaniu zasobów. Terraform może być również elementem procesu CI/CD, zapewniając spójność wdrożeń oraz umożliwia automatyczne dostosowywanie infrastruktury do zmieniających się potrzeb aplikacji. Możliwość integracji Terraforma z HashiCorp Vault lub innymi narzędziami do przechowywania sekretów dodatkowo podnosi poziom bezpieczeństwa. Dzięki temu nie musimy przechowywać wrażliwych danych bezpośrednio w klastrze. Terraform znajduje także zastosowanie w OpenShift, Rancherze oraz innych systemach zarządzania Kubernetesem. Umożliwia zarówno provisioning klastrów, jak i zarządzanie użytkownikami, rolami oraz politykami dostępu. Co więcej, wsparcie Terraforma dla różnych platform wirtualizacyjnych sprawia, że jest on doskonałym narzędziem zarówno dla wdrożeń chmurowych, jak i on-premises.

Nie możemy jednak zapomnieć o ograniczeniach, jakie Terraform posiada w kontekście Kubernetesa. Jednym z nich jest brak pełnej zgodności z natywnym API Kubernetesa. Oznacza to, że nie wszystkimi zasobami można zarządzać bezpośrednio przy użyciu providera. W nielicznych przypadkach, zwłaszcza jeżeli nasze środowisko jest rozbudowane i korzystamy z zaawansowanych oraz często niestandardowych rozwiązań, może to mieć znaczenie. Czasami konieczne jest także uzupełnianie Terraforma o dodatkowe narzędzia. Niemniej jednak Terraform pozostaje jednym z najpotężniejszych narzędzi do zautomatyzowanego zarządzania infrastrukturą Kubernetesa, a jego elastyczność i szerokie możliwości integracji czynią go niezastąpionym w nowoczesnych środowiskach kontenerowych.

Podsumowując, Terraform to nie tylko narzędzie do deklaratywnego zarządzania zasobami Kubernetes. To także potężne i wszechstronne rozwiązanie do automatyzacji, integracji i zabezpieczania środowisk kontenerowych. Jego zastosowanie w praktyce umożliwia firmom spójne, efektywne i przewidywalne zarządzanie klastrami Kubernetes – niezależnie od tego, czy działają one w chmurze, on-premises czy w środowiskach hybrydowych. Adaptacja IaC w wykonaniu Terraforma otwiera drogę do pełnej automatyzacji i niezawodności w zarządzaniu Kubernetesem, minimalizując ryzyko błędów konfiguracyjnych oraz zapewniając większą kontrolę nad infrastrukturą.