Wyślij zapytanie Dołącz do Sii

Całkiem niedawno na naszym blogu pojawił się artykuł dot. koncepcji „infrastruktury jako kodu”(infrastructure as code, IaC). Znając już zalety takiego podejścia do zarządzania infrastrukturą, chciałbym trochę ten temat rozwinąć i przedstawić jedno z narzędzi, które możemy w tym celu wykorzystać — terraform.

Zanim jednak przejdę do przedstawiania terraformu, chciałbym wspomnieć o różnych kategoriach narzędzi IaC:

  • narzędzia do zarządzania konfiguracją (configuration management),
  • narzędzia instrumentacji (orchestration),
  • narzędzia do tworzenia zasobów/infrastruktury chmurowej (provisioning).

Zarządzanie konfiguracją (configuration management)

Do najpopularniejszych narzędzi zarządzania konfiguracją należą:

  • Ansible,
  • Puppet,
  • Chef, SaltStack.

Są to narzędzia, które najczęściej służą do instalowania oprogramowania, zarządzania usługami i ogólnej konfiguracji systemu. Ich cechą charakterystyczną (jednocześnie wielką zaletą) jest powtarzalność, tzn. to, że kod raz stworzony możemy uruchamiać wielokrotnie i za każdym razem otrzymamy ten sam rezultat (tę samą zadeklarowaną konfigurację). Jeżeli chcielibyśmy napisać skrypt w bashu, który tworzyłby nam nowego użytkownika, użylibyśmy:

#!/bin/bash
useradd newuser

Przy pierwszym uruchomieniu zostanie stworzony użytkownik ”newuser”. Przy kolejnym uruchomieniu skryptu zostanie zwrócony błąd:

useradd: user 'newuser' already exists

Aby naprawić nasz skrypt, musielibyśmy dodać logikę, która sprawdzałaby, czy użytkownik już istnieje, czy nie.

Narzędzia do zarządzania konfiguracją mają tę przewagę, że nie oczekują od nas podawania kroków, które mają być wykonane (dla przykładu: sprawdź, czy folder istnieje, stwórz folder, sprawdź, czy użytkownik istnieje, stwórz użytkownika), a oczekują od nas jedynie konfiguracji, którą chcemy osiągnąć.

Poniżej podaję przykładowy kod ansible na stworzenie użytkownika:

- name: Dodawanie nowego użytkownika "newuser"
  user:
    name: newuser
    shell: /bin/bash
    groups: admins,developers
    append: yes

Przy pierwszym uruchomieniu Ansible zorientuje się, że taki użytkownik nie istnieje i go stworzy. Przy kolejnym uruchomieniu Ansible sprawdzi, że taki użytkownik już został stworzony i nie ma potrzeby na wykonanie kroku dodania nowego użytkownika. To jest właśnie przewaga narzędzi configuration management, które nie oczekują od nas dokładnego podawania kroków, które mają nas zaprowadzić do celu. Wystarczy, że zdefiniujemy nasz cel, a narzędzia te postarają się ten cel osiągnąć.

Różnice w narzędziach do zarządzania konfiguracją

Jeśli chodzi o różnice pomiędzy różnymi narzędziami, to poza formą deklarowania zmian w konfiguracji (Ansible — YAML; Puppet — własny język), różnią się też tym, czy ich działanie opiera się na pracy z agentami instalowanymi na docelowej maszynie.

Wygodny pod tym względem wydaje się Ansible, który nie wymaga od nas instalowania żadnego agenta. Zaletami podejścia wykorzystującego agenta jest to, że taki agent jest w stanie nieustannie kontrolować stan naszego serwera i go poprawiać w przypadku ręcznych modyfikacji, które odbiegają od tych zadeklarowanych. Jeżeli agent monitoruje nasz serwer, a jeden z adminów ręcznie wyłączył usługę, która wcześniej została zadeklarowana jako włączona, to taki agent automatycznie tę usługę włączy.

Instrumentacja (orchestration)

Do tej grupy możemy zaliczyć narzędzia, które wspierają pracę z kontenerami, takie jak Kubernetes, Amazon ECS/Fargate, Docker Swarm. Do zadań tych narzędzi należy m.in.:

  • Nadzorowanie aktualnego stanu naszej aplikacji, a w przypadku wykrycia zmian, doprowadzenia stanu, który zdefiniowaliśmy i którego oczekujemy (desired state).
  • Monitorowanie prawidłowego działania naszych kontenerów i zastępowanie ich w przypadku wykrycia nieprawidłowości.
  • Zapewnianie komunikacji pomiędzy naszymi kontenerami / maszynami.

Tworzenie zasobów (provisioning)

Zapewne każdy na początku swojej przygody z którąkolwiek chmurą, zaczynał od tworzenia zasobów, wykorzystując do tego interfejs webowy — dobry na początek, przejrzysty, łatwy. Z czasem pojawia się jednak konieczność zautomatyzowania wielu czynności i ułatwienia sobie pracy. Czas na kolejny krok, którym jest wykorzystanie gotowych narzędzi CLI.

Szybko dochodzimy jednak do wniosku, że takie zarządzanie infrastrukturą za pomocą, czy to AWS CLI czy Azure CLI, zaczyna przypominać zarządzanie konfiguracją serwera za pomocą basha. Nadchodzi czas na wykorzystanie dedykowanego narzędzia, które zostało stworzone właśnie w tym celu. W przypadku pracy z AWS mamy do dyspozycji CloudFormation, w przypadku Azure będą to ARM Templates.

Jeśli jednak chcielibyśmy, aby nasz zainwestowany czas nie ograniczał nas tylko do jednego dostawcy, powinniśmy zdecydować się na terraform.

Terraform

Terraform pobieramy ze strony terraform.io. Dzięki temu, że jest napisany w języku Go, mamy do czynienia z pojedynczym plikiem binarnym, który umieszczamy w dowolnym miejscu w naszej ścieżce systemowej PATH.

Wskazówka: jeśli pracujemy z chmurą Azure, możemy korzystać z terraform, wykorzystując do tego ”cloud shell”, czyli terminal uruchamiany w przeglądarce dla naszego konta.

Konfigurację naszej infrastruktury definiujemy w języku HCL, Hashicorp Configuration Language, w plikach z rozszerzeniem *.tf, które w wielkim uproszczeniu mają następującą składnię:

resource "rodzaj_zasobu" "nazwa_dla_naszego_zasobu_w_terraform" {
    name     = "nazwa_zasobu_w_chmurze"
    location = "westeurope" # atrybut
  }

Przykład dla tworzenia „Grupy zasobów” (Resource group) w chmurze Azure:

resource "azurerm_resource_group" "moja_grupa" {
    name     = "ResourceGroup"
    location = "West Europe"
  }

Przykład dla wirtualnej maszyny w AWS:

  resource "aws_instance" "vm1" {
    ami           = "ami-830c94e3"
    instance_type = "t2.micro"
  }

Jedną z wielu zalet terraform jest fakt, że za jego pomocą możemy tworzyć zasoby po stronie różnych dostawców usług chmurowych i to nie tylko tych największych jak AWS, Azure, GCP, ale również tych mniejszych (np. DigitalOcean). Terraform komunikuje się bezpośrednio z API danego dostawcy usług, tworząc zasoby, które zdefiniowaliśmy w plikach *.tf.

Aby terraform wiedział, czy ma do czynienia z AWS, Azure czy GCP, definiujemy dostawcę (provider) dla naszego kodu:

Przykład dla Azure:

  terraform {
    required_providers {
      azurerm = {
        source  = "hashicorp/azurerm"
        version = "~> 2.39"
      }
    }
  }

  provider "azurerm" {
    subscription_id = "id_naszej_subskrypcji"
    features {}
  }

i dla AWS:

  terraform {
    required_providers {
      aws = {
        source  = "hashicorp/aws"
        version = "~> 3.0"
      }
    }
  }

  provider "aws" {
    region = "region"
    features {}
  }

Jak można zauważyć, w żadnym miejscu dotychczas nie podaliśmy informacji uwierzytelniających.
Jeżeli pracujemy z chmurą Azure, mamy lokalnie zainstalowany „azure cli” i chcemy z naszej lokalnej maszyny wykonać kod terraform, to nie potrzebujemy podawać żadnych dodatkowych informacji. Terraform automatycznie wykorzysta azure cli, żeby się uwierzytelnić. W przypadku serwerów CI (lub braku azure cli) możemy stworzyć w chmurze „Jednostkę Usługi” (ang. Service Principal) i ustawić na danym hoście zmienne środowiskowe:

ARM_CLIENT_ID="00000000-0000-0000-0000-000000000000"
ARM_CLIENT_SECRET="00000000-0000-0000-0000-000000000000"
ARM_SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000"
ARM_TENANT_ID="00000000-0000-0000-0000-000000000000"

W przypadku AWS, jednym ze sposobów uwierzytelnienia będzie zdefiniowanie zmiennych środowiskowych:

AWS_ACCESS_KEY_ID="xxx"
AWS_SECRET_ACCESS_KEY="zzz"

Terraform – przykład

Mając już skonfigurowanego terraforma, przedstawię poniżej przykład dla Azure’a który tworzy:

  • Grupę Zasobów
  • App Service Plan
  • App Service

Nasza konfiguracja dla Azure:

terraform {
    required_providers {
      azurerm = {
        source  = "hashicorp/azurerm"
        version = "~> 2.39"
      }
    }
  }

  provider "azurerm" {
    subscription_id = "id_naszej_subskrypcji"
    features {}
  }

Definiujemy nowy zasób typu azurerm_resource_group (Grupa Zasobów), przypisujemy mu nazwę „example”, której będziemy mogli użyć, aby odwołać się do tego zasobu

resource "azurerm_resource_group" "example" {
    name     = "example-resources" // Nazwa pod jaką dany zasób zostanie stworzony w chmurze
    location = "West Europe"       // Region, w którym dany zasób zostanie stworzony
  }

Definiujemy kolejny zasób typu azurerm_app_service_plan (App Service Plan)

resource "azurerm_app_service_plan" "example" {
    name = "example-appserviceplan"
    location = azurerm_resource_group.example.location

Jako że każdy zasób musi być umieszczony w grupie zasobów, a w naszym przypadku grupa zasobów jest tworzona wyżej w kodzie, odwołujemy się do nazwy tej nowo tworzonej grupy i „pobieramy” wartość atrybutu „name”

resource_group_name = azurerm_resource_group.example.name

Definiujemy parametry dla App Service Planu

    sku {
      tier = "Standard"
      size = "S1"
    }
  }

Definiujemy nowy zasób typu azurerm_app_service (App Service)

resource "azurerm_app_service" "example" {
    name = "example-app-service"

Poniżej odwołujemy się do grupy zasobów, pobieramy wartość dla regionu i ustawiamy taką samą wartość dla naszego app service’u.

location = azurerm_resource_group.example.location
    resource_group_name = azurerm_resource_group.example.name

Definiujemy, w jakim planie powinien zostać stworzony nasz app service

app_service_plan_id = azurerm_app_service_plan.example.id

Definiujemy dodatkową konfigurację

    site_config {
      dotnet_framework_version = "v4.0"
    }

    app_settings = {
      "SOME_KEY" = "some-value"
    }

    connection_string {
      name  = "Database"
      type  = "SQLServer"
      value = "Server=some-server.mydomain.com;Integrated Security=SSPI"
    }
  }

Mając w jednym katalogu plik *.tf z powyższą treścią, wykonujemy kolejno:

  • terraform init (zainicjalozowanie terraforma; pobranie odpowiednich wtyczek pod odpowiedniego dostawcę — w naszym przypadku azure),
  • terraform plan (porównanie naszej zdefiniowanej konfiguracji w plikach *.tf ze stanem faktycznym zasobów w chmurze i przedstawienie zmian):
An execution plan has been generated and is shown below.
  Resource actions are indicated with the following symbols:
    + create

  Terraform will perform the following actions:

    # azurerm_app_service.example will be created
    + resource "azurerm_app_service" "example" {
        + app_service_plan_id               = (known after apply)
        + app_settings                      = {
            + "SOME_KEY" = "some-value"
          }
  ------------
  wycięte informacje na temat zasobów i zmian
  ------------

  Plan: 3 to add, 0 to change, 0 to destroy.
  • terraform apply (wprowadzenie zmian, które zostały nam przedstawione w wyniku komendy terraform plan).

Po wykonaniu ostatniej komendy powinniśmy widzieć nasze nowo zdefiniowane zasoby w chmurze.
Jeśli chcemy pozbyć się zasobów zarządzanych przez terraform, możemy użyć polecenia terraform destroy.

Terraform – co dalej

Niestety niemożliwe jest kompletne przedstawienie narzędzia terraform w jednym wpisie. Nie został poruszony temat plików stanu (*.tfstate), bezpieczeństwa konfiguracji i integracji terraform z systemami CI/CD.

Jeśli na co dzień jesteś odpowiedzialny za zarządzanie zasobami w chmurze lub po prostu zaciekawiło cię to narzędzie, to zachęcam do udania się na oficjalną stronę terraform.io po więcej informacji i przykładów.

5/5 ( głosy: 8)
Ocena:
5/5 ( głosy: 8)
Autor

Zostaw komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Może Cię również zainteresować

Pokaż więcej artykułów

Bądź na bieżąco

Zasubskrybuj naszego bloga i otrzymuj informacje o najnowszych wpisach.

Otrzymaj ofertę

Jeśli chcesz dowiedzieć się więcej na temat oferty Sii, skontaktuj się z nami.

Wyślij zapytanie Wyślij zapytanie

Natalia Competency Center Director

Get an offer

Dołącz do Sii

Znajdź idealną pracę – zapoznaj się z naszą ofertą rekrutacyjną i aplikuj.

Aplikuj Aplikuj

Paweł Process Owner

Join Sii

ZATWIERDŹ

This content is available only in one language version.
You will be redirected to home page.

Are you sure you want to leave this page?