Vaatame üle mõned peidetud probleemid, sealhulgas need, mis on seotud tsüklite, if avalduste ja juurutamismeetoditega, samuti probleemid, mis puudutavad Terraformi laiemalt:
- count ja for_each parameetrites on piirangud;
- nullaegsetele juurutustele on piirangud;
- isegi hea plaan võib osutuda ebaõnnestunuks;
- refaktoreerimisel võivad olla omad varjatud probleemid;
- viivitav kooskõla kooskõlastub... viivitusega.
count ja for_each parameetrites on piirangud
Selle peatüki näidetes kasutatakse count parameetrit ja for_each avaldust aktiivselt tsüklites ja tingimuslikus loogikas. Need toimivad hästi, kuid neil on kaks olulist piirangut, millest tuleb teadlik olla.
- count ja for_each ei saa osutada ükski ressursi väljundmuutuja.
- count ja for_each ei saa kasutada mooduli konfiguratsioonis.
count ja for_each ei saa osutada ükski ressursi väljundmuutuja
Kujutage ette, et peate juurutama mitu EC2 serverit ja mingil põhjusel ei soovi kasutada ASG-d. Teie kood võib välja näha nii:
resource "aws_instance" "example_1" {
count = 3
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}
Vaadakem neid järjestikku.
Kuna parameetrile count on määratud staatiline väärtus, töötab see kood probleemideta: kui teete käsu apply, luuakse kolm EC2-serverit. Kuid kui soovite käivitada ühe serveri igas piirkonna kättesaadavuse tsoonis (Availability Zone või AZ) AWS praeguse regiooni raames? Saate seadistada oma koodi, et laadida tsoonide nimekiri andmeallikast aws_availability_zones ja seejärel "tsükliliselt" läbida igaüht neist ja luua seal EC2-server, kasutades parameetrit count ja juurdepääsu massiivi indeksi kaudu:
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 samuti suurepäraselt, kuna parameeter count saab probleemideta viidata andmeallikatele. Kuid mis juhtub, kui serverite arv, mida peate looma, sõltub mõne ressursi väljundist? Seda demonstreerida, on kõige lihtsam võtta ressursiks random_integer, mis, nagu nimest võib aru saada, tagastab juhusliku täisarvu:
resource "random_integer" "num_instances" {
min = 1
max = 3
}See kood genereerib juhusliku arvu vahemikus 1 kuni 3. Vaadakem, mis juhtub, kui proovime kasutada selle ressursi väljundit result aws_instance parameetris count:
resource "aws_instance" "example_3" {
count = random_integer.num_instances.result
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}Kui käitada selle koodi terraform plan, saame järgmise vea:
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 count ja for_each arvutatakse planeerimise etapis, enne kui mingit ressursi luuakse või muudetakse. See tähendab, et count ja for_each võivad viidata literaalidele, muutujatele, andmeallikatele ja isegi ressursiloenditele (tingimusel, et nende pikkus on planeerimise ajal määratletav), kuid mitte arvutatud väljundmuutujatele.
count ja for_each ei tohi kasutada mooduli konfiguratsioonis.
Kunagi võite tunda ahvatlust lisada count parameeter mooduli konfiguratsioonidesse:
moodul "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 count'i mooduli sees, et luua kolm koopia ressursist webserver-cluster. Võib-olla soovite teha mooduli ühendamise valikuliseks, andes count'i parameetrile väärtuse 0. Selline kood näeks välja üsna mõistlik, kuid terraform plan'i käivitamisel saate sellise vea:
Viga: Reserveeritud argumendi nimi mooduli plokis
faili main.tf rida 13, moodulis "count_example":
13: count = 3
Nimi "count" on reserveeritud tulevaste versioonide jaoks Terraformis.Kahjuks ei toetata Terraform 0.12.6 väljalaskmise ajal count'i või for_each'i kasutamist mooduli ressursis. Vastavalt Terraform 0.12 väljalasketeatele (http://bit.ly/3257bv4) plaanib HashiCorp tulevikus selle võimaluse lisada, seega, sõltuvalt sellest, millal te seda raamatut loete, võib see juba saadaval olla. Kuidas olla kindel, .
Nulli seisakuga juurutamise piirangud
create_before_destroy ploki kasutamine ASG-ga on suurepärane lahendus nullkauguse seisakute korraldamiseks, välja arvatud üks nüanss: automaatsed skaaleerimise reeglid ei ole sel juhul toetatud. Täpsemalt öeldes seadistab see ASG suuruse iga juurutamise järel tagasi min_size'ile, mis võib olla probleem, kui olete kasutanud automaatsete skaaleerimise reegleid käivitatud serverite arvu suurendamiseks.
Näiteks webserver-cluster moodul sisaldab paari aws_autoscaling_schedule ressurssi, mis kell 9 suurendavad klastris serverite arvu kahest kümneni. Kui juurutamine toimub näiteks kell 11, laadib uus ASG rühm üles mitte kümne, vaid vaid kahe serveriga ja jääb sellesse olekusse kuni järgmise päeva kell 9.
Seda piiri on võimalik ületada mitmete viiside kaudu.
- Muutke aws_autoscaling_schedule'i recurrence parameeter väärtusele 0 9 * * * ("käivita kell 9 hommikul") millegi nagu 0-59 9-17 * * * ("käivita iga minut kell 9 hommikul kuni 5 õhtul"). Kui ASG-s on juba kümme serverit, ei muuda selle automaatse skaleerimise reegli rakendamine midagi, ja seda me vajamegi. Kuid kui ASG grupp on just hiljuti juurutatud, tagab see reegel, et maksimaalselt minuti jooksul saavutab selle serverite arv kümme. See pole just elegantne lähenemine ning suured kõikumised kümne ja kahe serveri vahel võivad samuti kasutajatele probleeme tekitada.
- Looge kohandatud skript, mis kasutab AWS API-d aktiveeritud serverite arvu määramiseks ASG-s, kutsuge seda välja välise andmeallika kaudu (vt punkit „Väline andmeallikas” lk 249) ning määrake ASG grupi desired_capacity parameetrile väärtus, mille see skript tagastab. Nii alustab iga uus ASG eksemplar alati sama mahutavusega, nagu oli meil Terraformi koodis, mis muudab selle haldamise keerulisemaks.
Kindlasti, ideaalis peaks Terraform toetama nullis käivitamisi, kuid 2019. aasta mais ei kavatsenud HashiCorpi meeskond seda funktsionaalsust lisada ().
Korrektselt koostatud plaan võib osutuda ebaõnnestunuks
Mõnikord, kui käivitate käsu plan, saadakse täiesti korrektne juurutamisplaan, kuid käsk apply tagastab vea. Proovige näiteks lisada aws_iam_user ressursi sama nimega, mida kasutasite IAM kasutaja loomiseks, mille lõite varem peatükis 2:
resource "aws_iam_user" "existing_user" {
# Sisestage siia juba olemasoleva IAM kasutaja nimi,
# et harjutada terraform import käsu kasutamist
name = "yevgeniy.brikman"
}Nüüd, kui käivitate käsu plan, loob Terraform esmapilgul täiesti mõistliku juurutamisplaani:
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.Käsk apply käivitamisel ilmneb järgmine tõrketeade:
Error: IAM kasutaja yevgeniy.brikman loomisel ilmnes viga: EntityAlreadyExists:
Kasutaja nimega yevgeniy.brikman juba eksisteerib.
failis main.tf rida 10, ressurss "aws_iam_user" "existing_user":
10: ressurss "aws_iam_user" "existing_user" {Probleem on selles, et selle nimega IAM kasutaja on juba olemas. Ja see ei kehti ainult IAM kasutajate, vaid ka praktiliselt iga ressursi kohta. Võib olla, et keegi on selle ressursi loonud käsitsi või käsurealt, kuid igal juhul põhjustavad identifikaatorite ristumised konflikte. Sellel veal on palju varieeruvaid vorme, mis sageli üllatavad uusi kasutajaid Terraformi kasutamisel.
Oluline punkt on see, et terraform plan käsk arvestab ainult neid ressursse, mis on määratud Terraformi olekufailis. Kui ressursid on loodud muul viisil (näiteks käsitsi AWSi konsoolil nuppu klõpsates), siis need ei kuulu olekufaili ja seetõttu ei arvestata neid Terraformi poolt plaani käivitamisel. Tulemuseks on esialgu õige plaan, mis osutub nurjunuks.
Sellest saab välja tuua kaks õppetundi.
- Kui olete juba Terraformiga töötama hakanud, ärge kasutage midagi muud. Kui osa teie infrastruktuurist hallatakse Terraformi abil, ei saa te seda enam käsitsi muuta. Vastasel juhul mitte ainult ei riski te kummaliste Terraformi vigade saamisega, vaid ka kaotate paljusid IaC eeliseid, kuna kood ei ole enam teie infrastruktuuri täpne esitus.
- Kui teil on juba olemas olemasolev infrastruktuur, kasutage import käsku. Kui alustate Terraformi kasutamist juba olemasoleva infrastruktuuriga, saate selle lisada olekufaili abil käsku terraform import. Nii juhib Terraform selle infrastruktuuri haldamist. Import käsk võtab vastu kaks argumenti. Esimene on ressursi aadress teie konfiguratsioonifailides. Siin kehtib sama süntaks kui ressursside linkide puhul: _. (näiteks aws_iam_user.existing_user). Teine argument on ressursi identifikaator, mida tuleb importida. Näiteks aws_iam_user identifikaatorina on kasutajanimi (nt yevgeniy.brikman), samas kui aws_instance identifikaator on EC2 serveri identifikaator (nt i-190e22e5). Kuidas ressursi importimine toimub, on tavaliselt näidatud selle lehe dokumentatsioonis.
Allpool on näidatud import käsk, mis võimaldab sünkroonida aws_iam_user ressurssi, mille olete lisanud oma Terraform konfiguratsiooni koos IAM kasutajaga peatükis 2 (loomulikult tuleb yevgeniy.brikman asendada teie nimega):
$ terraform import aws_iam_user.existing_user yevgeniy.brikmanTerraform pöördub AWS API poole, et leida teie IAM kasutaja ja luua seisundi failis seos selle ja teie Terraformi konfiguratsioonis oleva aws_iam_user.existing_user ressursi vahel. Sellest hetkest alates teab Terraform plaanimise käivitamisel, et IAM kasutaja olemas on, ning ei püüa seda uuesti luua.
Oluline on märkida, et kui teil on juba palju ressursse, mida soovite Terraformi importida, võib igaühe käsitsi kodeerimine ja importimine osutuda tülikaks. Seetõttu tasub kaaluda sellist tööriista nagu Terraforming (http://terraforming.dtan4.net/), mis suudab automaatselt importida teie AWS kontolt koodi ja seisundi.
Refactoring võib sisaldada oma komistuskive
Refactoring — levinud praktika programmeerimises, kus muudate koodi sisemist struktuuri, jättes samas välise käitumise muutumatuks. See on vajalik, et muuta kood arusaadavamaks, puhtamaks ja hooldatavamaks. Refaktoreerimine on asendamatu meetod, mida tuleks regulaarselt rakendada. Kuid kui rääkida Terraformist või mistahes muust IaC vahendist, tuleb olla äärmiselt ettevaatlik, mida mõistetakse «välise käitumise» all, vastasel juhul võivad tekkida ettenägematud probleemid.
Näiteks on levinud refaktoreerimise tüüp muutuja või funktsiooni nimede asendamine arusaadavamatega. Paljud IDE-d toetavad refaktoreerimist ja suudavad automaatselt muuta muutujaid ja funktsioone kogu projekti ulatuses. Üldotstarbelistes programmeerimiskeeltes on see triviaalne protseduur, millele ei pea mõtlema, kuid Terraformi puhul tuleb olla äärmiselt ettevaatlik, muidu võib tekkida töökatkestusi.
Näiteks on moodulil webserver-cluster sisendmuutuja cluster_name:
variable "cluster_name" { description = "Nimi, mida kasutada kõigi klastrite ressursside jaoks" type = string }Kujutage ette, et hakkasite seda moodulit kasutama mikroteenusena nimega foo. Hiljem soovisite oma teenust nimetada ümber bariks. See muudatus võib tunduda triviaalne, kuid tegelikult võib see põhjustada katkestusi.
Asi on selles, et moodul webserver-cluster kasutab muutujaid cluster_name paljude ressursside, sealhulgas kahe turvagruppi ja ALB parameetrites name:
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 mõne ressursi parameetrit name, siis Terraform kustutab selle ressursi vana versiooni ja loob selle asemel uue. Kuid kui see ressurss on ALB, siis ajavahemikus, mil see kustutatakse ja uus versioon laaditakse, ei ole teil mehhanismi liikluse suunamiseks oma veebiserverisse. Samamoodi, kui kustutatakse turvagrupp, hakkavad teie serverid keelama igasuguse võrgu liikluse, kuni uus grupp on loodud.
Teine refaktooringu tüüp, mis võiks sind huvitada, on Terraformi identifikaatori muutmine. Vaatame näiteks aws_security_group ressurssi webserver-cluster moodulis:
resource "aws_security_group" "instance" { # (...) }Selle ressursi identifikaator on nimetatud instance. Kujutage ette, et refaktooringu käigus otsustasite selle asendada arusaadavamate (teie arvates) nimedega, näiteks cluster_instance:
resource "aws_security_group" "cluster_instance" { # (...) }Mida see siis kaasa toob? Õige: katkemise.
Terraform sidub iga ressursi ID pilveteenuse pakkuja identifikaatoriga. Näiteks iam_user seotakse AWS-i IAM kasutaja identifikaatoriga ja aws_instance – AWS EC2 serveri ID-ga. Kui muudate ressursi identifikaatorit (nt instance'ist cluster_instance'iks nagu aws_security_group puhul), tundub Terraformile, et olete vana ressursi kustutanud ja uue lisanud. Kui need muutused rakendada, eemaldab Terraform vana turvagrupi ja loob uue, samal ajal kui teie serverid hakkavad kõiki võrgu liiklust tagasi lükkama.
Siin on neli põhijäreldust, mida peaksite sellest arutelust õppima.
- Kasutage alati käsku plan. Selle abil saate tuvastada kõik need probleemid. Uurige hoolikalt selle väljundit ja pöörake tähelepanu olukordadele, kus Terraform kavandab ressursside kustutamist, mida ilmselt ei peaks eemaldama.
- Looge enne kustutamist. Kui soovite ressursi asendada, kaaluge hoolikalt, kas on vajalik asenduse loomine enne originaali kustutamist. Kui vastus on jaatav, võib aidata create_before_destroy. Sama tulemuse saab saavutada ka käsitsi, tehes kaks sammu: esmalt lisage konfiguratsiooni uus ressurss ja käivitage käsk apply, seejärel kustutage konfiguratsioonist vana ressurss ja kasutage uuesti käsku apply.
- Identifikaatorite muutmine nõuab oleku muutmist. Kui soovite muuta ressurssiga seotud identifikaatorit (näiteks ümber nimetada aws_security_group instance'ilt cluster_instance'iks), vältides samas ressursi kustutamist ja uue versiooni loomist, peate vastavalt uuendama Terraformi olekufaili. Ärge tehke seda kunagi käsitsi — kasutage selle asemel käsku terraform state. Identifikaatorite ümber nimetamisel tuleks kasutada käsku terraform state mv, millel on järgmine süntaks:
terraform state mvORIGINAL_REFERENCE on väljend, mis viitab ressursile selle praeguses vormis, ja NEW_REFERENCE on koht, kuhu soovite selle teisaldada. Näiteks, kui soovite nimetada aws_security_group rühm oma nime instance'ilt cluster_instance'iks, peate käivitama järgmise käsu:
$ terraform state mv aws_security_group.instance aws_security_group.cluster_instanceNii teavitate Terraformi, et olek, mis varem kuulus aws_security_group.instance'le, peaks nüüd olema seotud aws_security_group.cluster_instance'iga. Kui pärast ümbernimetamist ja selle käsu käivitamist terraform plan ei näita mingeid muudatusi, on see märk, et olete kõik õigesti teinud.
- Mõningaid parameetreid ei saa muuta. Paljude ressursside parameetrid on muutumatud. Kui proovite neid muuta, kustutab Terraform vana ressursi ja loob selle asemel uue. Iga ressursi lehel on tavaliselt mainitud, mis juhtub konkreetse parameetri muutmisel, seetõttu ärge unustage dokumentatsiooniga tutvuda. Alati kasutage käsku plan ja hindake create_before_destroy strateegia rakendamise mõistlikkust.
Viivitusega kooskõlastamine kooskõlastub... viivitusega.
Mõnede pilveteenuste pakkujate API-d, nagu AWS, on asünkroonsed ja neil on viivitusega kooskõlastamine. Asünkroonsus tähendab, et liides võib kohe vastuse anda, ootamata taotletud toimingu lõpetamist. Viivitusega kooskõlastamine tähendab, et muudatuste levimiseks kogu süsteemis võib kuluda aega; seni, kuni see toimub, võivad teie vastused olla järgitavad ja sõltuda sellest, milline andmeallika koopia teie API-kõnedele vastab.
Kujutage ette, et teete API-kõne AWS-ile, paludes luua EC2-server. API tagastab peaaegu koheselt "eduka" vastuse (201 Created), ootamata serveri loomist. Kui proovite sellele kohe juurde pääseda, ei õnnestu tõenäoliselt midagi, kuna AWS initsialiseerib veel ressursse või alternatiivselt on server veel käivitumisel. Veelgi enam, kui teete veel ühe kõne, et saada teavet selle serveri kohta, võib tulla viga (404 Not Found). Asi on selles, et teave selle EC2-serveri kohta võib endiselt levida AWS-is, et see oleks kõikjal kättesaadav, nagu oleks vaja oodata paar sekundit.
Iga kord, kui kasutate asünkroonset API-d, millel on viivitatud kooskõla, peate oma päringut perioodiliselt kordama, kuni toiming on lõpule viidud ja levinud süsteemis. Kahjuks ei paku AWS SDK selleks mingeid häid tööriistu, ja Terraformi projekt on varem kannatanud mitme vea, nagu 6813 (https://github.com/hashicorp/terraform/issues/6813) tõttu:
$ terraform apply aws_subnet.private-persistence.2: InvalidSubnetID.NotFound: Alamvõrgu ID 'subnet-xxxxxxx' puudubTeisisõnu loote ressursi (näiteks alamvõrgu) ja üritate seejärel saada teavet selle kohta (nt just loodud alamvõrgu ID), kuid Terraform ei suuda neid leida. Enamik selliseid vigu (sealhulgas 6813) on juba parandatud, kuid aeg-ajalt esinevad need ikka, eriti kui Terraform lisab toetuse uuele ressursitüübile. See on tüütav, kuid enamikul juhtudel ei põhjusta mingit kahju. Kui käitate uuesti terraform apply, peaks kõik toimima, kuna selleks ajaks on teave juba süsteemi laiali levinud.
See lõik on välja toodud Jevgeni Brikmani raamatust .
Allikas: habr.com
