Terraformi lõkse

Terraformi lõkse
Toome esile mõned lõksud, sealhulgas need, mis on seotud silmustega, kui avalduste ja juurutustehnikatega, samuti üldisemad probleemid, mis Terraformi üldiselt mõjutavad:

  • count ja for_each parameetritel on piirangud;
  • piirata nulli seisakuid;
  • isegi hea plaan võib ebaõnnestuda;
  • refaktoreerimisel võib olla oma lõkse;
  • edasilükatud sidusus on kooskõlas... edasilükkamisega.

Parameetritel count ja for_each on piirangud

Selle peatüki näidetes kasutatakse laialdaselt loendusparameetrit ja for_each avaldist tsüklites ja tingimusloogikas. Need toimivad hästi, kuid neil on kaks olulist piirangut, millest peate teadma.

  • Count ja for_each ei saa viidata ühelegi ressursi väljundmuutujale.
  • count ja for_each ei saa mooduli konfiguratsioonis kasutada.

count ja for_each ei saa viidata ühelegi ressursi väljundmuutujale

Kujutage ette, et peate juurutama mitu EC2 serverit ja te ei soovi mingil põhjusel ASG-d kasutada. Teie kood võib olla selline:

resource "aws_instance" "example_1" {
   count             = 3
   ami                = "ami-0c55b159cbfafe1f0"
   instance_type = "t2.micro"
}

Vaatame neid ükshaaval.

Kuna loendusparameeter on seatud staatilisele väärtusele, töötab see kood probleemideta: kui käivitate rakenduse käsu, loob see kolm EC2 serverit. Aga mis siis, kui soovite oma praeguse AWS-i piirkonna igas saadavuse tsoonis (AZ) juurutada ühe serveri? Saate lasta oma koodil laadida aws_availability_zones andmeallikast tsoonide loend, seejärel igaüks neist läbi vaadata ja luua selles loendusparameetri ja massiiviindeksi juurdepääsu abil EC2 serveri:

resource "aws_instance" "example_2" {
   count                   = length(data.aws_availability_zones.all.names)
   availability_zone   = data.aws_availability_zones.all.names[count.index]
   ami                     = "ami-0c55b159cbfafe1f0"
   instance_type       = "t2.micro"
}

data "aws_availability_zones" "all" {}

See kood töötab ka hästi, kuna loendusparameeter võib andmeallikatele ilma probleemideta viidata. Aga mis juhtub siis, kui loodavate serverite arv sõltub mõne ressursi väljundist? Selle demonstreerimiseks on lihtsaim viis kasutada ressurssi random_integer, mis, nagu nimigi ütleb, tagastab juhusliku täisarvu:

resource "random_integer" "num_instances" {
  min = 1
  max = 3
}

See kood genereerib juhusliku arvu vahemikus 1 kuni 3. Vaatame, mis juhtub, kui proovime kasutada selle ressursi väljundit aws_instance ressursi loendusparameetris:

resource "aws_instance" "example_3" {
   count             = random_integer.num_instances.result
   ami                = "ami-0c55b159cbfafe1f0"
   instance_type = "t2.micro"
}

Kui käivitate selle koodiga terraformiplaani, kuvatakse järgmine tõrketeade:

Error: Invalid count argument

   on main.tf line 30, in resource "aws_instance" "example_3":
   30: count = random_integer.num_instances.result

The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the -target argument to first apply only the resources that the count depends on.

Terraform nõuab, et loendur ja for_each arvutataks planeerimisetapis, enne ressursside loomist või muutmist. See tähendab, et count ja for_each võivad viidata literaalidele, muutujatele, andmeallikatele ja isegi ressursside loenditele (nii kaua, kui nende pikkust saab määrata ajakava koostamise ajal), kuid mitte arvutatud ressursi väljundmuutujatele.

count ja for_each ei saa mooduli konfiguratsioonis kasutada

Ühel päeval võib teil tekkida kiusatus lisada oma mooduli konfiguratsioonile loendusparameeter:

module "count_example" {
     source = "../../../../modules/services/webserver-cluster"

     count = 3

     cluster_name = "terraform-up-and-running-example"
     server_port = 8080
     instance_type = "t2.micro"
}

See kood üritab kasutada moodulis olevat loendust, et luua veebiserveri klastri ressursist kolm koopiat. Või soovite muuta mooduli ühendamise mõnest Boole'i ​​tingimusest olenevalt valikuliseks, määrates selle loendusparameetri väärtuseks 0. See võib tunduda mõistliku koodina, kuid terraformiplaani täitmisel kuvatakse see viga:

Error: Reserved argument name in module block

   on main.tf line 13, in module "count_example":
   13: count = 3

The name "count" is reserved for use in a future version of Terraform.

Kahjuks ei toetata alates Terraformi versioonist 0.12.6 mooduli ressursis loendi või for_each kasutamist. Terraform 0.12 väljalaskemärkmete (http://bit.ly/3257bv4) kohaselt kavatseb HashiCorp selle võimaluse tulevikus lisada, nii et olenevalt sellest, millal seda raamatut loete, võib see juba saadaval olla. Et seda kindlalt teada saada, loe Terraformi muudatuste logi siit.

Null seisakuaja kasutuselevõtu piirangud

Ploki create_before_destroy kasutamine koos ASG-ga on suurepärane lahendus seisakuta juurutuste loomiseks, välja arvatud üks hoiatus: automaatse skaleerimise reegleid ei toetata. Täpsemalt lähtestab see ASG suuruse tagasi väärtusele min_size igal juurutamisel, mis võib olla probleem, kui kasutate töötavate serverite arvu suurendamiseks automaatse skaleerimise reegleid.

Näiteks veebiserveri-klastri moodul sisaldab paari aws_autoscaling_schedule ressursse, mis kell 9 hommikul suurendab klastris olevate serverite arvu kahelt kümnele. Kui võtate kasutusele näiteks kell 11, käivitub uus ASG kümne serveri asemel vaid kahe serveriga ja jääb selliseks järgmise päeva kella 9-ni.

Sellest piirangust saab mööda hiilida mitmel viisil.

  • Muutke kordumise parameeter jaotises aws_autoscaling_schedule väärtuselt 0 9 * * * ("käivita kell 9") väärtusele 0-59 9-17 * * * ("käivita iga minuti järel kell 9 kuni 5"). Kui ASG-l on juba kümme serverit, ei muuda selle automaatse skaleerimise reegli uuesti käivitamine midagi, mida me tahame. Kuid kui ASG on alles hiljuti kasutusele võetud, tagab see reegel, et maksimaalselt minutiga jõuab selle serverite arv kümneni. See ei ole läbinisti elegantne lähenemine ning suured hüpped kümnelt serverilt kahele ja tagasi võivad samuti kasutajatele probleeme tekitada.
  • Looge kohandatud skript, mis kasutab ASG-s olevate aktiivsete serverite arvu määramiseks AWS API-d, kutsuge see välise andmeallika abil (vt „Väline andmeallikas” lk 249) ja määrake ASG parameetri wish_capacity väärtuseks, mille tagastab stsenaarium. Nii töötab iga uus ASG eksemplar alati sama võimsusega kui olemasolev Terraformi kood ja muudab selle hooldamise keerulisemaks.

Muidugi oleks Terraformil ideaaljuhul sisseehitatud tugi seisakuta juurutustele, kuid 2019. aasta mai seisuga ei olnud HashiCorpi meeskonnal plaanis seda funktsiooni lisada (üksikasjad - siin).

Õige plaan võib ebaõnnestuda

Mõnikord loob käsk plaan täiesti õige juurutusplaani, kuid käsk rakendus tagastab vea. Proovige näiteks lisada ressurssi aws_iam_user sama nimega, mida kasutasite 2. peatükis varem loodud IAM-i kasutaja jaoks:

resource "aws_iam_user" "existing_user" {
   # Подставьте сюда имя уже существующего пользователя IAM,
   # чтобы попрактиковаться в использовании команды terraform import
   name = "yevgeniy.brikman"
}

Nüüd, kui käivitate plaani käsu, väljastab Terraform näiliselt mõistliku juurutusplaani:

Terraform will perform the following actions:

   # aws_iam_user.existing_user will be created
   + resource "aws_iam_user" "existing_user" {
         + arn                  = (known after apply)
         + force_destroy   = false
         + id                    = (known after apply)
         + name               = "yevgeniy.brikman"
         + path                 = "/"
         + unique_id         = (known after apply)
      }

Plan: 1 to add, 0 to change, 0 to destroy.

Kui käivitate käsu Rakenda, kuvatakse järgmine tõrketeade:

Error: Error creating IAM User yevgeniy.brikman: EntityAlreadyExists:
User with name yevgeniy.brikman already exists.

   on main.tf line 10, in resource "aws_iam_user" "existing_user":
   10: resource "aws_iam_user" "existing_user" {

Probleem on muidugi selles, et selle nimega IAM-i kasutaja on juba olemas. Ja see võib juhtuda mitte ainult IAM-i kasutajatega, vaid peaaegu kõigi ressurssidega. Võimalik, et keegi lõi selle ressursi käsitsi või käsurida kasutades, kuid mõlemal juhul põhjustab ID-de sobitamine konfliktideni. Sellel veal on palju variatsioone, mis tabavad Terraformi uustulnukaid sageli üllatusena.

Põhimõte on see, et terraformi plaani käsk võtab arvesse ainult neid ressursse, mis on määratud Terraformi olekufailis. Kui ressursse luuakse mõnel muul viisil (näiteks käsitsi AWS-i konsoolis klõpsates), ei satu need olekufaili ja seetõttu ei võta Terraform neid plaani käsu täitmisel arvesse. Seetõttu osutub esmapilgul õigena tunduv plaan ebaõnnestunuks.

Sellest on kaks õppetundi.

  • Kui olete juba Terraformiga tööd alustanud, ärge kasutage midagi muud. Kui osa teie infrastruktuurist hallatakse Terraformi abil, ei saa te seda enam käsitsi muuta. Vastasel juhul ei riski te mitte ainult veidrate Terraformi vigadega, vaid eirate ka paljusid IaC eeliseid, kuna kood ei kujuta enam teie infrastruktuuri täpselt ette.
  • Kui teil on juba mõni infrastruktuur, kasutage impordi käsku. Kui alustate Terraformi kasutamist olemasoleva infrastruktuuriga, saate selle lisada olekufaili kasutades terraformi importimise käsku. Nii teab Terraform, millist infrastruktuuri tuleb hallata. Impordikäsklusel on kaks argumenti. Esimene on ressursi aadress teie konfiguratsioonifailides. Süntaks on siin sama, mis ressursilinkide puhul: _. (nagu aws_iam_user.existing_user). Teine argument on imporditava ressursi ID. Oletame, et ressursi ID aws_iam_user on kasutajanimi (näiteks yevgeniy.brikman) ja ressursi ID aws_instance on EC2 serveri ID (nagu i-190e22e5). Ressursi importimine on tavaliselt näidatud selle lehe allosas olevas dokumentatsioonis.

    Allpool on impordikäsk, mis sünkroonib aws_iam_user ressursi, mille lisasite oma Terraformi konfiguratsioonile koos IAM-i kasutajaga 2. peatükis (muidugi, asendades teie nimega yevgeniy.brikman):

    $ terraform import aws_iam_user.existing_user yevgeniy.brikman

    Terraform helistab AWS API-le, et leida teie IAM-i kasutaja ja luua olekufailide seos selle ja teie Terraformi konfiguratsioonis oleva aws_iam_user.existing_user ressursi vahel. Edaspidi, kui käivitate plaani käsu, teab Terraform, et IAM-i kasutaja on juba olemas, ega proovi seda uuesti luua.

    Väärib märkimist, et kui teil on juba palju ressursse, mida soovite Terraformi importida, võib koodi käsitsi kirjutamine ja iga ühekaupa importimine olla tülikas. Seega tasub uurida sellist tööriista nagu Terraforming (http://terraforming.dtan4.net/), mis suudab teie AWS-i kontolt koodi ja oleku automaatselt importida.

    Refaktoreerimisel võib olla oma lõkse

    Refaktoreerimine on programmeerimisel levinud praktika, kus muudate koodi sisemist struktuuri, jättes samal ajal välise käitumise muutmata. Selle eesmärk on muuta kood selgemaks, korralikumaks ja hõlpsamini hooldatavaks. Refaktoreerimine on asendamatu tehnika, mida tuleks regulaarselt kasutada. Kuid kui rääkida Terraformist või mõnest muust IaC-tööriistast, peate olema äärmiselt ettevaatlik selle suhtes, mida te koodijupi "välise käitumise" all mõtlete, vastasel juhul tekivad ootamatud probleemid.

    Näiteks on levinud ümberkujundamise tüüp muutujate või funktsioonide nimede asendamine arusaadavamate nimedega. Paljudel IDE-del on sisseehitatud ümberkujundamise tugi ja need saavad muutujaid ja funktsioone kogu projekti jooksul automaatselt ümber nimetada. Üldotstarbelistes programmeerimiskeeltes on see triviaalne protseduur, millele ei pruugi mõeldagi, kuid Terraformis tuleb sellega olla ülimalt ettevaatlik, sest muidu võib tekkida katkestusi.

    Näiteks veebiserveri klastri moodulil on sisendmuutuja klastri_nimi:

    variable "cluster_name" {
       description = "The name to use for all the cluster resources"
       type          = string
    }

    Kujutage ette, et hakkasite seda moodulit kasutama mikroteenuse nimega foo juurutamiseks. Hiljem soovite oma teenuse ümber nimetada baariks. See muudatus võib tunduda triviaalne, kuid tegelikkuses võib see põhjustada teenuse katkestusi.

    Fakt on see, et veebiserveri klastri moodul kasutab muutujat cluster_name paljudes ressurssides, sealhulgas kahe turberühma nimeparameetris ja ALB-s:

    resource "aws_lb" "example" {
       name                    = var.cluster_name
       load_balancer_type = "application"
       subnets = data.aws_subnet_ids.default.ids
       security_groups      = [aws_security_group.alb.id]
    }

    Kui muudate ressursi nimeparameetrit, kustutab Terraform selle ressursi vana versiooni ja loob selle asemele uue. Kuid kui see ressurss on ALB, ei ole teil selle kustutamise ja uue versiooni allalaadimise vahel mehhanismi liikluse ümbersuunamiseks oma veebiserverisse. Samuti, kui turvagrupp kustutatakse, hakkavad teie serverid võrguliiklust tagasi lükkama kuni uue rühma loomiseni.

    Teine ümberkujundamise tüüp, millest võiksite huvitatud olla, on Terraformi ID muutmine. Võtame näiteks veebiserveri klastri mooduli ressursi aws_security_group:

    resource "aws_security_group" "instance" {
      # (...)
    }

    Selle ressursi identifikaatorit nimetatakse eksemplariks. Kujutage ette, et ümberkujundamise ajal otsustasite selle muuta arusaadavamaks (teie arvates) nimeks cluster_instance:

    resource "aws_security_group" "cluster_instance" {
       # (...)
    }

    Mis saab lõpuks? See on õige: häire.

    Terraform seostab iga ressursi ID pilveteenuse pakkuja ID-ga. Näiteks iam_user on seotud AWS IAM-i kasutaja ID-ga ja aws_instance on seotud AWS EC2 serveri ID-ga. Kui muudate ressursi ID-d (nt eksemplarilt cluster_instance'iks, nagu see on aws_security_group puhul), näib, nagu oleksite kustutanud vana ressursi ja lisanud uue. Kui rakendate need muudatused, kustutab Terraform vana turvarühma ja loob uue, samal ajal kui teie serverid hakkavad võrguliiklust tagasi lükkama.

    Siin on neli peamist õppetundi, mida peaksite sellest arutelust võtma.

    • Kasutage alati käsku plaan. See võib paljastada kõik need tõrked. Vaadake selle väljund hoolikalt üle ja pöörake tähelepanu olukordadele, kus Terraform kavatseb kustutada ressursse, mida tõenäoliselt ei tohiks kustutada.
    • Loo enne kustutamist. Kui soovite ressurssi asendada, mõelge enne originaali kustutamist hoolikalt läbi, kas teil on vaja luua asendus. Kui vastus on jaatav, aitab create_before_destroy. Sama tulemuse saab käsitsi, tehes kaks sammu: esmalt lisage konfiguratsioonile uus ressurss ja käivitage käsk rakendus ning seejärel eemaldage konfiguratsioonist vana ressurss ja kasutage rakenduskäsku uuesti.
    • Identifikaatorite muutmine nõuab oleku muutmist. Kui soovite muuta ressursiga seotud ID-d (näiteks nimetada aws_security_group eksemplarist ümber klastri_eksemplariks) ilma ressurssi kustutamata ja sellest uut versiooni loomata, peate Terraformi olekufaili vastavalt värskendama. Ärge kunagi tehke seda käsitsi – kasutage selle asemel käsku terraform state. Identifikaatorite ümbernimetamisel peaksite käivitama käsu terraform state mv, millel on järgmine süntaks:
      terraform state mv <ORIGINAL_REFERENCE> <NEW_REFERENCE>

      ORIGINAL_REFERENCE on avaldis, mis viitab ressursile selle praegusel kujul ja NEW_REFERENCE on koht, kuhu soovite selle teisaldada. Näiteks kui nimetate rühma aws_security_group eksemplarist ümber cluster_instanceiks, peate käivitama järgmise käsu:

      $ terraform state mv 
         aws_security_group.instance 
         aws_security_group.cluster_instance

      See annab Terraformile teada, et olek, mis oli varem seotud failiga aws_security_group.instance, peaks nüüd olema seotud olekuga aws_security_group.cluster_instance. Kui pärast selle käsu ümbernimetamist ja käivitamist terravormi plaan muudatusi ei näita, siis tegite kõik õigesti.

    • Mõnda seadet ei saa muuta. Paljude ressursside parameetrid on muutmatud. Kui proovite neid muuta, kustutab Terraform vana ressursi ja loob selle asemele uue. Igal ressursi lehel on tavaliselt märgitud, mis konkreetse sätte muutmisel juhtub, seega kontrollige kindlasti dokumentatsiooni. Kasutage alati käsku plan ja kaaluge strateegia create_before_destroy kasutamist.

    Edasilükatud järjepidevus on kooskõlas... edasilükkamisega

    Mõned pilveteenuse pakkujate API-d, nagu AWS, on asünkroonsed ja nende järjepidevus on viivitatud. Asünkroonsus tähendab, et liides saab kohe vastuse tagastada, ootamata nõutud toimingu lõpuleviimist. Viivitatud järjepidevus tähendab, et muudatuste levimine kogu süsteemis võib võtta aega; sel ajal võivad teie vastused olla ebajärjekindlad ja sõltuda sellest, millise andmeallika koopia vastab teie API kutsetele.

    Kujutage näiteks ette, et teete API-kutse AWS-ile, paludes tal luua EC2 server. API tagastab "eduka" vastuse (201 loodud) peaaegu koheselt, ootamata serveri enda loomist. Kui proovite sellega kohe ühendust luua, siis see peaaegu kindlasti ebaõnnestub, kuna sel hetkel AWS alles lähtestab ressursse või pole server veel käivitunud. Veelgi enam, kui helistate selle serveri kohta teabe saamiseks uuesti, võite saada veateate (404 Ei leitud). Asi on selles, et teavet selle EC2 serveri kohta võidakse siiski levitada kogu AWS-is, enne kui see kõikjal kättesaadavaks saab, peate mõne sekundi ootama.

    Kui kasutate laisa järjepidevusega asünkroonset API-d, peate perioodiliselt oma taotlust uuesti proovima, kuni toiming on lõpule viidud ja süsteemis levib. Kahjuks ei paku AWS SDK selleks häid tööriistu ja Terraformi projekt kannatas varem paljude vigade all, nagu 6813 (https://github.com/hashicorp/terraform/issues/6813):

    $ terraform apply
    aws_subnet.private-persistence.2: InvalidSubnetID.NotFound:
    The subnet ID 'subnet-xxxxxxx' does not exist

    Teisisõnu loote ressursi (nagu alamvõrgu) ja proovite seejärel hankida selle kohta teavet (nt vastloodud alamvõrgu ID) ja Terraform ei leia seda. Enamik neist vigadest (sh 6813) on parandatud, kuid aeg-ajalt tuleb neid ikka ette, eriti kui Terraform lisab uue ressursitüübi toe. See on tüütu, kuid enamikul juhtudel ei põhjusta see mingit kahju. Terraform application uuesti käivitamisel peaks kõik toimima, kuna selleks ajaks on teave juba kogu süsteemis levinud.

    See katkend on esitatud Jevgeni Brikmani raamatust "Terraform: infrastruktuur koodi tasemel".

Allikas: www.habr.com

Lisa kommentaar