Terraformako zuloak

Terraformako zuloak
Azpimarra ditzagun hutsune batzuk, begiztak, if adierazpenak eta hedapen-teknikak barne, baita orokorrean Terraformi eragiten dioten arazo orokorragoak ere:

  • count eta for_each parametroek mugak dituzte;
  • mugatu zero geldialdi-denbora inplementazioak;
  • plan on batek ere huts egin dezake;
  • birfaktorizazioak bere hutsuneak izan ditzake;
  • koherentzia geroratua koherentea da... atzerapenarekin.

Count eta for_each parametroek mugak dituzte

Kapitulu honetako adibideek count parametroa eta for_each adierazpena erabiltzen dituzte begiztetan eta baldintzazko logikan. Ondo funtzionatzen dute, baina bi muga garrantzitsu dituzte, kontuan izan behar dituzunak.

  • Count eta for_each ezin dute inolako baliabideen irteera-aldagairik erreferentzia.
  • count eta for_each ezin dira moduluaren konfigurazioan erabili.

count eta for_each ezin dute inolako baliabideen irteera-aldagairik erreferentzia

Imajinatu EC2 zerbitzari batzuk zabaldu behar dituzula eta arrazoiren batengatik ez duzula ASG erabili nahi. Zure kodea honelakoa izan daiteke:

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

Ikus ditzagun banan-banan.

Zenbaketa-parametroa balio estatiko batean ezarrita dagoenez, kode honek arazorik gabe funtzionatuko du: apply komandoa exekutatzen duzunean, hiru EC2 zerbitzari sortuko ditu. Baina zerbitzari bat inplementatu nahi baduzu erabilgarritasun gune bakoitzean (AZ) zure egungo AWS eskualdean? Zure kodea aws_availability_zones datu-iturburutik guneen zerrenda kargatu eta, ondoren, bakoitzean zehar begiratu eta bertan EC2 zerbitzari bat sor dezakezu zenbaketa-parametroa eta array-indizearen sarbidea erabiliz:

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" {}

Kode honek ere ondo funtzionatuko du, zenbaketa parametroak inolako arazorik gabe datu-iturriak erreferentzia ditzakeelako. Baina zer gertatzen da sortu behar duzun zerbitzari kopurua baliabide batzuen irteeraren araberakoa bada? Hori frogatzeko, modurik errazena random_integer baliabidea erabiltzea da, izenak dioen bezala, ausazko zenbaki oso bat itzultzen duena:

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

Kode honek 1 eta 3 arteko ausazko zenbaki bat sortzen du. Ikus dezagun zer gertatzen den baliabide honen irteera aws_instance baliabidearen zenbaketa parametroan erabiltzen saiatzen bagara:

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

Kode honetan terraform plan exekutatzen baduzu, errore hau jasoko duzu:

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-ek count eta for_each kalkulatzea eskatzen du plangintza-fasean, baliabideak sortu edo aldatu aurretik. Horrek esan nahi du count eta for_each literalei, aldagaiei, datu-iturburuei eta baita baliabide-zerrendei ere erreferentzia egin diezaiekeela (betiere haien luzera programazio garaian zehaztu daitekeela), baina ez kalkulatutako baliabideen irteera-aldagaietara.

count eta for_each ezin dira moduluaren konfigurazioan erabili

Baliteke noizbait zure moduluaren konfigurazioari zenbaketa-parametro bat gehitzeko tentazioa izatea:

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

     count = 3

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

Kode hau modulu baten barruan zenbaketa erabiltzen saiatzen da web zerbitzari-kluster baliabidearen hiru kopia sortzeko. Edo baliteke modulu bat konektatzea aukerako egoera boolear batzuetan oinarrituta, bere zenbaketa-parametroa 0-n ezarriz. Arrazoizko kodea dirudi, baina errore hau jasoko duzu terraform plana exekutatzen duzunean:

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.

Zoritxarrez, Terraform 0.12.6-tik aurrera, modulu-baliabide batean count edo for_each erabiltzea ez da onartzen. Terraform 0.12 bertsioaren oharren arabera (http://bit.ly/3257bv4), HashiCorp-ek etorkizunean gaitasun hau gehitzeko asmoa du, beraz, liburu hau irakurtzen duzunaren arabera, baliteke dagoeneko eskuragarri egotea. Ziur jakiteko, irakurri Terraform aldaketaren erregistroa hemen.

Zero Downtime inplementazioen mugak

ASG-rekin batera create_before_destroy blokea erabiltzea irtenbide bikaina da zero-denborarik gabeko inplementazioak sortzeko, ohar bat izan ezik: eskalatze automatikoko arauak ez dira onartzen. Edo zehatzago izateko, honek ASG tamaina berrezartzen du inplementazio bakoitzean min_size-ra, eta hori arazo bat izan liteke eskalatze automatikoko arauak erabiltzen ari bazenitu exekutatzen ari diren zerbitzari kopurua handitzeko.

Adibidez, webserver-cluster moduluak aws_autoscaling_schedule baliabide pare bat dauka, 9:11etan klusterreko zerbitzari kopurua bitik hamarrera handitzen duena. Demagun, 9:XNUMXetan zabaltzen bazara, ASG berria hamarretan baino bi zerbitzariekin abiaraziko da eta horrela jarraituko du hurrengo eguneko XNUMX:XNUMXak arte.

Muga hori hainbat modutan saihes daiteke.

  • Aldatu aws_autoscaling_schedule-n errepikapen-parametroa 0 9 * * * ("exekutatu 9:0etan") 59-9 17-9 * * * bezalako zerbaitetara ("exekutatu minuturo 5:XNUMXetatik XNUMX:XNUMXetara"). ASG-k dagoeneko hamar zerbitzari baditu, autoeskalatze-arau hau berriro martxan jartzeak ez du ezer aldatuko, horixe da nahi duguna. Baina ASG duela gutxi zabaldu bada, arau honek bermatuko du gehienez minutu batean bere zerbitzarien kopurua hamarra iritsiko dela. Hau ez da guztiz dotorea den ikuspegia, eta hamar zerbitzarietatik bi eta atzera jauzi handiak ere arazoak sor ditzake erabiltzaileei.
  • Sortu AWS APIa erabiltzen duen script pertsonalizatua, ASG-ko zerbitzari aktibo kopurua zehazteko, deitu kanpoko datu-iturburu bat erabiliz (ikus "Kanpoko datu-iturburua" 249. orrialdean) eta ezarri ASG-ren want_capacity parametroak itzultzen duen balioarekin. gidoia. Horrela, ASG instantzia berri bakoitza lehendik dagoen Terraform kodearen ahalmen berean exekutatu eta mantentzea zailagoa da.

Jakina, Terraform-ek ezin hobea izango luke zero geldialdi-denbora inplementatzeko laguntza integratua, baina 2019ko maiatzean, HashiCorp taldeak ez zuen funtzionalitate hau gehitzeko asmorik (xehetasunak - hemen).

Baliteke plan zuzena arrakastarik gabe gauzatzea

Batzuetan plan komandoak inplementazio plan guztiz zuzena sortzen du, baina apply komandoak errore bat itzultzen du. Saiatu, adibidez, gehitzen aws_iam_user baliabidea 2. kapituluan lehenago sortu zenuen IAM erabiltzailearentzat erabili zenuen izen berarekin:

resource "aws_iam_user" "existing_user" {
   # ΠŸΠΎΠ΄ΡΡ‚Π°Π²ΡŒΡ‚Π΅ сюда имя ΡƒΠΆΠ΅ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ IAM,
   # Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠΎΠ²Π°Ρ‚ΡŒΡΡ Π² использовании ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ terraform import
   name = "yevgeniy.brikman"
}

Orain, plan komandoa exekutatzen baduzu, Terraform-ek itxuraz zentzuzkoa den inplementazio-plan bat aterako du:

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.

Aplikatu komandoa exekutatzen baduzu, errore hau jasoko duzu:

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" {

Arazoa, noski, izen hori duen IAM erabiltzaile bat badagoela da. Eta hori IAM erabiltzaileei ez ezik, ia edozein baliabideri ere gerta dakioke. Baliteke norbaitek baliabide hau eskuz edo komando-lerroa erabiliz sortu izana, baina edozein modutan, IDak bat datozenak gatazkak sortzen ditu. Errore honen aldaera asko daude Terraform-era etorri berriak ezustean harrapatzen dituztenak.

Gakoa da terraform planaren komandoak Terraform egoera fitxategian zehaztutako baliabideak soilik hartzen dituela kontuan. Baliabideak beste modu batean sortzen badira (adibidez, eskuz AWS kontsolan klik eginez), ez dira egoera fitxategian amaituko eta, beraz, Terraformek ez ditu kontuan hartuko planaren komandoa exekutatzeko. Ondorioz, lehen begiratuan zuzena dirudien plan batek ez du arrakastarik izango.

Hortik bi ikasgai atera behar dira.

  • Dagoeneko Terraform-ekin lanean hasi bazara, ez erabili beste ezer. Zure azpiegituraren zati bat Terraform erabiliz kudeatzen bada, ezin duzu eskuz aldatu. Bestela, Terraform errore arraroak arriskuan jartzen ez ezik, IaC-ren onura asko ezeztatzen dituzu, kodea ez baita zure azpiegituraren irudikapen zehatza izango.
  • Dagoeneko azpiegituraren bat baduzu, erabili inportazio komandoa. Terraform lehendik dagoen azpiegiturekin erabiltzen hasten bazara, egoera fitxategira gehi dezakezu terraform inportatzeko komandoa erabiliz. Horrela Terraformek jakingo du zer azpiegitura kudeatu behar den. Inportazio komandoak bi argumentu hartzen ditu. Lehenengoa zure konfigurazio fitxategietako baliabideen helbidea da. Hemengo sintaxia baliabideen esteketarako berdina da: _. (aws_iam_user.existing_user bezala). Bigarren argumentua inportatu beharreko baliabidearen IDa da. Demagun baliabide-ID aws_iam_user erabiltzaile-izena dela (adibidez, yevgeniy.brikman), eta baliabide-ID aws_instance EC2 zerbitzariaren IDa (i-190e22e5 bezala). Baliabide bat nola inportatu bere orriaren behealdean dagoen dokumentazioan adierazi ohi da.

    Jarraian, 2. kapituluan IAM erabiltzailearekin batera Terraform konfigurazioan gehitu duzun aws_iam_user baliabidea sinkronizatzen duen inportazio komando bat dago (zure izena yevgeniy.brikman ordezkatuz, noski):

    $ terraform import aws_iam_user.existing_user yevgeniy.brikman

    Terraformek AWS APIra deituko du zure IAM erabiltzailea aurkitzeko eta egoera-fitxategi-asoziazioa sortzeko eta aws_iam_user.existing_user baliabidearen artean zure Terraform konfigurazioan. Hemendik aurrera, planaren komandoa exekutatzen duzunean, Terraform-ek jakingo du IAM erabiltzailea jada existitzen dela eta ez da berriro sortzen saiatuko.

    Aipatzekoa da dagoeneko Terraform-era inportatu nahi dituzun baliabide asko badituzu, kodea eskuz idaztea eta bakoitza aldi berean inportatzea arazo bat izan daitekeela. Beraz, merezi du Terraforming bezalako tresna bat aztertzea (http://terraforming.dtan4.net/), zure AWS kontutik kodea eta egoera automatikoki inporta ditzakeena.

    Birfaktorizazioak bere hutsuneak izan ditzake

    Birfaktorizazioa Programazioan ohiko praktika bat da, non kodearen barne egitura aldatzen duzun bitartean kanpoko portaera aldatu gabe. Hau da kodea argiagoa, txukunagoa eta mantentzeko errazago egiteko. Refactoring ezinbesteko teknika da, aldizka erabili behar dena. Baina Terraform edo IaC beste edozein tresnari dagokionez, kontu handiz ibili behar duzu kode baten "kanpoko portaera"rekin zer esan nahi duzun, bestela ustekabeko arazoak sortuko dira.

    Esaterako, birfactorizazio mota arrunt bat aldagaien edo funtzioen izenak ulergarriagoak diren beste batzuekin ordezkatzea da. IDE askok birfactorizaziorako euskarria dute eta automatikoki aldagaiak eta funtzioak aldatu ditzakete proiektu osoan zehar. Erabilera orokorreko programazio-lengoaietan, agian pentsatu ez duzun prozedura hutsala da, baina Terraform-en kontu handiz ibili behar duzu honekin, bestela etenaldiak izan ditzakezu.

    Adibidez, webzerbitzari-kluster moduluak sarrerako aldagai bat dauka cluster_name:

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

    Imajinatu modulu hau erabiltzen hasi zarela foo izeneko mikrozerbitzua zabaltzeko. Geroago, zure zerbitzua barra izena aldatu nahi duzu. Aldaketa hau hutsala dirudi, baina, egia esan, zerbitzua eten ditzake.

    Kontua da webzerbitzari-kluster moduluak cluster_name aldagaia erabiltzen duela hainbat baliabidetan, bi segurtasun talderen izen-parametroa eta ALB barne:

    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]
    }

    Baliabide batean izena-parametroa aldatzen baduzu, Terraformek baliabide horren bertsio zaharra ezabatuko du eta beste bat sortuko du bere ordez. Baina baliabide hori ALB bat bada, ezabatu eta bertsio berri bat deskargatu bitartean, ez duzu trafikoa zure web zerbitzarira birbideratzeko mekanismorik izango. Era berean, segurtasun-talde bat ezabatzen bada, zure zerbitzariak sareko edozein trafiko baztertzen hasiko dira talde berri bat sortu arte.

    Interesgarria izan daitekeen beste birfactorizazio mota bat Terraform IDa aldatzea da. Har dezagun adibide gisa webzerbitzari-kluster moduluko aws_security_group baliabidea:

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

    Baliabide honen identifikatzaileari instantzia deitzen zaio. Imajinatu birfactorizazioan zehar cluster_instance izen ulergarriagoa (zure ustez) aldatzea erabaki duzula:

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

    Zer gertatuko da azkenean? Hori bai: eten bat.

    Terraformek baliabideen ID bakoitza hodeiko hornitzailearen IDarekin lotzen du. Adibidez, iam_user AWS IAM erabiltzaile IDarekin asoziatuta dago eta aws_instance AWS EC2 zerbitzariaren IDarekin. Baliabidearen IDa aldatzen baduzu (esan instantziatik cluster_instancera, aws_security_group-ekin gertatzen den bezala), Terraform-era baliabide zaharra ezabatu eta berri bat gehituko bazenu bezala agertuko da. Aldaketa hauek aplikatzen badituzu, Terraformek segurtasun-talde zaharra ezabatu eta berri bat sortuko du, zure zerbitzariak sareko trafikoa baztertzen hasten diren bitartean.

    Hona hemen eztabaida honetatik atera behar dituzun lau ikasgai nagusiak.

    • Erabili beti plan komandoa. Zailtasun horiek guztiak agerian utzi ditzake. Berrikusi bere irteera arretaz eta arreta jarri Terraformek ziurrenik ezabatu behar ez diren baliabideak ezabatzeko asmoa duen egoerei.
    • Sortu ezabatu aurretik. Baliabide bat ordezkatu nahi baduzu, pentsatu arretaz ordezko bat sortu behar duzun jatorrizkoa ezabatu aurretik. Erantzuna baiezkoa bada, create_before_destroy lagun dezake. Emaitza bera eskuz lor daiteke bi urrats eginez: lehenik eta behin, gehitu baliabide berri bat konfigurazioan eta exekutatu aplikatu komandoa, eta gero kendu baliabide zaharra konfiguraziotik eta erabili berriro aplikatu komandoa.
    • Identifikatzaileak aldatzeak egoera aldatzea eskatzen du. Baliabide bati lotutako IDa aldatu nahi baduzu (adibidez, aws_security_group izena aldatu instantziatik cluster_instance izatera) baliabidea ezabatu eta horren bertsio berri bat sortu gabe, horren arabera eguneratu beharko duzu Terraform egoera fitxategia. Inoiz ez egin eskuz - erabili terraform state komandoa ordez. Identifikatzaileak izena aldatzean, terraform state mv komandoa exekutatu beharko zenuke, zeina sintaxi hau duena:
      terraform state mv <ORIGINAL_REFERENCE> <NEW_REFERENCE>

      ORIGINAL_REFERENCE baliabideari erreferentzia egiten dion adierazpena da, eta NEW_REFERENCE da mugitu nahi duzun tokira. Adibidez, aws_security_group taldea instantziatik cluster_instancera izena aldatzean, komando hau exekutatu behar duzu:

      $ terraform state mv 
         aws_security_group.instance 
         aws_security_group.cluster_instance

      Honek Terraform-i esaten dio lehen aws_security_group.instance-rekin erlazionatuta zegoen egoera orain aws_security_group.cluster_instance-rekin lotu behar dela. Komando terraform plan hau izena aldatu eta exekutatu ondoren ez badu aldaketarik erakusten, orduan dena behar bezala egin duzu.

    • Ezarpen batzuk ezin dira aldatu. Baliabide askoren parametroak aldaezinak dira. Horiek aldatzen saiatzen bazara, Terraformek baliabide zaharra ezabatu eta berri bat sortuko du bere ordez. Baliabide-orri bakoitzak ezarpen jakin bat aldatzen duzunean zer gertatzen den adieraziko du normalean, beraz, ziurtatu dokumentazioa egiaztatu duzula. Erabili beti plan komandoa eta kontuan hartu create_before_destroy estrategia erabiltzea.

    Geroratutako koherentzia koherentea da... atzerapenarekin

    Hodeiko hornitzaile batzuen APIak, AWS adibidez, asinkronoak dira eta koherentzia atzeratua dute. Asinkroniak esan nahi du interfazeak berehala erantzun dezakeela eskatutako ekintza amaitu arte itxaron gabe. Koherentzia atzeratuak esan nahi du aldaketak denbora behar duela sistema osoan hedatzeko; hori gertatzen ari den bitartean, zure erantzunak koherenteak izan daitezke eta zure API deiei erantzuten dien datu-iturburuen erreplikaren araberakoak izan daitezke.

    Imajinatu, adibidez, API dei bat egiten diozula AWSri EC2 zerbitzari bat sortzeko eskatuz. APIak erantzun "arrakastatsua" (201 sortua) itzuliko du ia berehala, zerbitzaria bera sortuko den arte itxaron gabe. Berehala konektatzen saiatzen bazara, ia ziur huts egingo du une horretan AWS oraindik baliabideak hasieratzen ari delako edo, bestela, zerbitzaria oraindik ez baita abiarazi. Gainera, zerbitzari honi buruzko informazioa lortzeko beste dei bat egiten baduzu, baliteke errore bat jasotzea (404 Ez da aurkitu). Gauza da EC2 zerbitzari honi buruzko informazioa oraindik AWS osoan hedatu daitekeela edonon eskuragarri egon aurretik, segundo batzuk itxaron beharko dituzula.

    Koherentzia alferra duen API asinkrono bat erabiltzen duzun bakoitzean, aldian-aldian zure eskaera berriro saiatu behar duzu ekintza amaitu eta sisteman zehar hedatu arte. Zoritxarrez, AWS SDK-k ez du horretarako tresna onik eskaintzen, eta Terraform proiektuak 6813 bezalako akats asko jasaten zituen (https://github.com/hashicorp/terraform/issues/6813):

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

    Beste era batera esanda, baliabide bat sortzen duzu (azpisare bat bezala) eta ondoren horri buruzko informazio bat lortzen saiatzen zara (sortu berri den azpisarearen IDa adibidez), eta Terraformek ezin du aurkitu. Akats horietako gehienak (6813 barne) konpondu dira, baina oraindik ere noizean behin agertzen dira, batez ere Terraformek baliabide mota berri baterako laguntza gehitzen duenean. Hau gogaikarria da, baina kasu gehienetan ez du kalterik eragiten. Terraform application berriro exekutatzen duzunean, denak funtzionatu beharko luke, ordurako informazioa sistema osoan zabalduta egongo baita.

    Zati hau Evgeniy Brikmanen liburutik aurkezten da "Terraform: azpiegitura kode mailan".

Iturria: www.habr.com

Gehitu iruzkin berria