Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Infrastructure as Code z Terraform

Serwer produkcyjny postawiono rok temu, klikając w panelu dostawcy. Działa. Ale nikt nie pamięta, jaki dokładnie wybrano rozmiar maszyny, które porty otwarto i czy dysk ma 50 czy 100 gigabajtów. Postawienie identycznego środowiska testowego to teraz kilka godzin zgadywania - i tak wyjdzie inaczej.

Rzymianie nie budowali akweduktów z pamięci. Każdy zaczynał się od planu architektonicznego: rysunku, z którego dowolna ekipa mogła odtworzyć tę samą konstrukcję w innej prowincji. Infrastructure as Code to ten sam pomysł: infrastruktura definiowana w kodzie, a nie klikaniem.

Nie myl tego z narzędziami, które brzmią podobnie, a robią co innego: to nie framework do testowania infrastruktury, nie system monitorowania serwerów i nie narzędzie do kompresji obrazów Dockera. To sposób opisania tego, co ma istnieć.

Plan w pliku

Terraform czyta pliki z rozszerzeniem

.tf
. Opis składa się z kilku rodzajów bloków:

1provider "aws" {
2  region = "eu-central-1"
3}
4
5variable "app_name" {
6  type    = string
7  default = "legion-api"
8}
9
10variable "app_port" {
11  type    = number
12  default = 3000
13}
14
15resource "aws_instance" "legion_server" {
16  ami           = "ami-0abcdef1234567890"
17  instance_type = "t3.micro"
18
19  tags = {
20    Name = var.app_name
21  }
22}
23
24output "server_ip" {
25  value = aws_instance.legion_server.public_ip
26}

provider
mówi, u kogo budujemy - tutaj AWS w regionie
eu-central-1
.
variable
to parametr planu; dzięki niemu ten sam opis postawi środowisko testowe i produkcyjne, różniące się tylko wartościami.
resource
opisuje rzecz, która ma istnieć - maszynę, sieć, bazę.
output
wskazuje, co Terraform ma pokazać po zakończeniu; adres IP zwykle poznajesz dopiero po utworzeniu serwera.

Zwróć uwagę na sposób odwoływania się:

var.app_name
sięga po zmienną, a
aws_instance.legion_server.public_ip
- po pole utworzonego zasobu. Z tych odwołań Terraform sam wyprowadza kolejność tworzenia: skoro output potrzebuje adresu maszyny, maszyna musi powstać wcześniej.

Cztery komendy

Praca z Terraformem to zawsze ta sama sekwencja:

  1. terraform init
    - inicjalizacja projektu; pobiera providery wymienione w plikach.
  2. terraform plan
    - podgląd zmian bez ich stosowania.
  3. terraform apply
    - zastosowanie zmian.
  4. terraform output
    - sprawdzenie wyników.

Drugi krok jest sercem całego narzędzia, więc nazwijmy go wprost:

terraform plan
to DRY RUN. Porównuje Twój opis ze stanem faktycznym i wypisuje, co zamierza utworzyć, zmienić i usunąć - nie ruszając niczego. Nie tworzy zasobów, nie usuwa infrastruktury i nie pobiera providerów; od pobierania jest
init
.

Ten podgląd jest jedyną chwilą, w której zobaczysz zamiar narzędzia, zanim stanie się faktem. Czytaj go, @name - zwłaszcza linie zaczynające się od minusa, bo Terraform potrafi uznać, że pewnej zmiany nie da się wykonać w miejscu, i usunąć zasób, żeby utworzyć go na nowo. Przy maszynie testowej to niedogodność; przy bazie z danymi - katastrofa.

Plan zapisany do pliku

W zespole i w CI stosuje się wariant dwuetapowy, żeby mieć pewność, że wdrażasz dokładnie to, co przejrzałeś:

1terraform init
2terraform plan -out=tfplan
3terraform apply tfplan
4terraform output

-out=tfplan
zapisuje wyliczony plan do pliku.
apply tfplan
stosuje dokładnie ten plan, zamiast wyliczać go na nowo.

Różnica ma znaczenie, gdy między przeglądem a zatwierdzeniem minie kilka minut, a ktoś w tym czasie zmieni infrastrukturę. Zwykłe

apply
policzyłoby wtedy plan od nowa i zrobiło coś innego, niż przeczytałeś na ekranie.

Stan, którego nie wolno commitować

Terraform musi pamiętać, co już utworzył - inaczej przy każdym uruchomieniu stawiałby wszystko od zera. Zapisuje to w pliku

terraform.tfstate
.

Ten plik nie należy do repozytorium Git, i to z dwóch powodów naraz. Po pierwsze zawiera wrażliwe dane - hasła do baz, klucze, adresy - zapisane jawnym tekstem, bo Terraform musi je pamiętać między uruchomieniami. Po drugie Git nie zapewnia blokady przy pracy zespołowej: gdy dwie osoby uruchomią

apply
jednocześnie, powstaną dwie wersje stanu i konflikt, którego nie da się rozstrzygnąć scaleniem, bo to nie jest plik do czytania przez człowieka.

Powody, które czasem się słyszy - że plik jest za duży dla Gita albo że Terraform sam go usuwa po

apply
- są nieprawdziwe.

Rozwiązaniem jest backend zdalny: wspólne miejsce, które trzyma stan i blokuje go na czas operacji.

1terraform {
2  backend "s3" {
3    bucket         = "imperium-terraform-state"
4    key            = "legion-api/terraform.tfstate"
5    region         = "eu-central-1"
6    dynamodb_table = "terraform-locks"
7  }
8}

Tabela wskazana w

dynamodb_table
służy właśnie do blokady - druga osoba uruchamiająca
apply
zobaczy komunikat, że stan jest zajęty, zamiast zepsuć wspólną infrastrukturę.

Podsumowanie

Plan architektoniczny gotowy, prowincje odtwarzalne:

  • Infrastructure as Code to podejście, w którym infrastruktura jest definiowana w kodzie - nie framework testowy, nie monitoring, nie kompresja obrazów,
  • pliki
    .tf
    zawierają bloki:
    provider
    (u kogo),
    variable
    (parametry),
    resource
    (co ma istnieć),
    output
    (co pokazać po zakończeniu),
  • kolejność tworzenia Terraform wyprowadza sam, z odwołań między zasobami,
  • cztery kroki:
    terraform init
    terraform plan
    terraform apply
    terraform output
    ,
  • terraform plan
    to DRY RUN - pokazuje podgląd zmian bez ich stosowania
    ; nie tworzy, nie usuwa i nie pobiera providerów,
  • czytaj plan, zwłaszcza usunięcia - Terraform potrafi odtworzyć zasób zamiast zmienić go w miejscu,
  • w zespole:
    plan -out=tfplan
    , potem
    apply tfplan
    - wdrażasz dokładnie to, co przejrzałeś,
  • terraform.tfstate
    nie trafia do Gita: zawiera wrażliwe dane i nie ma blokady dla pracy zespołowej
    ,
  • rozwiązaniem jest backend zdalny z blokadą stanu na czas operacji.

W następnej lekcji zbierzesz cały ten moduł w jeden projekt - konteneryzację, pipeline i wdrożenie. A na razie zapamiętaj: klikanie w panelu tworzy serwer, którego nikt nie umie odtworzyć; plan w pliku tworzy taki, który odtworzy każdy.

Przejdź do CodeWorlds