Xemgîniyên Terraform

Xemgîniyên Terraform
Werin em çend xeletiyan ronî bikin, di nav de yên ku bi loopan ve girêdayî ne, heke daxuyanî û teknîkên bicîhkirinê, û her weha pirsgirêkên gelemperî yên ku bi gelemperî bandorê li Terraform dikin:

  • parametreyên hejmartin û for_each sînor hene;
  • sifir bicihkirina dema domandinê sînordar bike;
  • planek baş jî dikare têk biçe;
  • refactoring dikare kêmasiyên xwe hebin;
  • hevahengiya paşvexistî lihevhatî ye... bi deferral.

Parametreyên hejmartin û for_each sînor hene

Nimûneyên di vê beşê de bi berfirehî parametreya hejmartinê û îfadeya for_each di lûp û mantiqa şertî de bikar tînin. Ew baş tevdigerin, lê du tixûbên wan ên girîng hene ku hûn hewce ne ku ji wan haydar bin.

  • Count û for_each nikarin guhêrbarên derana çavkaniyê referans bikin.
  • count û for_each nikare di veavakirina modulê de were bikar anîn.

count û for_each nikare guhêrbarên derana çavkaniyê referans bike

Bifikirin ku hûn hewce ne ku çend serverên EC2 bicîh bikin û ji ber hin sedeman hûn naxwazin ASG bikar bînin. Koda we dikare bi vî rengî be:

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

Ka em yek bi yek li wan binêrin.

Ji ber ku pîvana hejmartinê li ser nirxek statîk tête danîn, ev kod dê bê pirsgirêk bixebite: gava ku hûn fermana serîlêdanê bimeşînin, ew ê sê serverên EC2 biafirîne. Lê heke we bixwesta ku di nav devera xweya AWS ya heyî de yek serverek li her Qada Berdestbûnê (AZ) bicîh bikin? Hûn dikarin koda xwe navnîşek deveran ji çavkaniya daneya aws_availability_zones dakêşin û dûv re li her yekê bigerin û bi karanîna pîvana hejmartinê û gihîştina nîşana rêzê ve serverek EC2 tê de çêbikin:

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

Ev kod dê di heman demê de baş bixebite, ji ber ku pîvana hejmartinê dikare çavkaniyên daneyê bêyî pirsgirêk referans bike. Lê çi diqewime heke hejmara serverên ku hûn hewce ne ku biafirînin bi hilberîna hin çavkaniyê ve girêdayî ye? Ji bo nîşankirina vê yekê, awayê herî hêsan ev e ku meriv çavkaniya random_integer bikar bîne, ku, wekî nav diyar dike, hejmareke rasthatî vedigerîne:

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

Ev kod di navbera 1 û 3-an de jimareyek birêkûpêk çêdike. Ka em bibînin ka çi diqewime ger em hewl bidin ku hilberîna vê çavkaniyê di pîvana hejmartina çavkaniya aws_instance de bikar bînin:

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

Ger hûn plansaziya terraform li ser vê kodê bimeşînin, hûn ê xeletiya jêrîn bistînin:

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 hewce dike ku hejmartin û for_her di qonaxa plansazkirinê de, berî ku çavkanî werin afirandin an guheztin, bêne hesibandin. Ev tê vê wateyê ku hejmartin û ji bo_herek dikare biwêje, guhêrbar, çavkaniyên daneyê, û tewra navnîşên çavkaniyê vebêje (heta ku dirêjahiya wan di dema plansazkirinê de were destnîşankirin), lê ne guhêrbarên hilberîna çavkaniyê ya hesabkirî.

count û for_each nikare di veavakirina modulê de were bikar anîn

Rojekê dibe ku hûn werin ceribandin ku hûn pîvanek hejmartinê li veavakirina modula xwe zêde bikin:

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

     count = 3

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

Vê kodê hewl dide ku hejmarê di hundurê modulek de bikar bîne da ku sê kopiyên çavkaniya webserver-cluster biafirîne. An jî dibe ku hûn bixwazin girêdana modulek li ser bingeha hin şertên Boolean vebijarkî bikin bi danîna parametreya hejmartina wê li ser 0. Dibe ku ev wekî kodek maqûl xuya bike, lê hûn ê dema ku plana terraformê dimeşînin vê xeletiyê bistînin:

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.

Mixabin, ji Terraform 0.12.6-ê ve, di çavkaniyek modulê de karanîna count an for_each nayê piştgirî kirin. Li gorî notên berdana Terraform 0.12 (http://bit.ly/3257bv4), HashiCorp plan dike ku di pêşerojê de vê kapasîteyê zêde bike, ji ber vê yekê li gorî dema ku hûn vê pirtûkê dixwînin, dibe ku ew jixwe peyda bibe. Ji bo ku bê guman bibînin, guhertoya Terraform li vir bixwînin.

Sînorkirinên Zero Downtime Deployments

Bikaranîna bloka create_before_destroy bi hev re bi ASG re çareseriyek girîng e ji bo afirandina veqetandinên zero-downtime, ji xeynî yek hişyariyek: qaîdeyên pîvandina otomatîkî nayên piştgirî kirin. An jî rasttir be, ev mezinahiya ASG-ê li ser her vesazkirinê vedigere nav_size, ku dibe ku pirsgirêkek be heke hûn qaîdeyên pîvana xweser bikar bînin da ku hejmara serverên ku dixebitin zêde bikin.

Mînakî, modula webserver-cluster cotek çavkaniyên aws_autoscaling_schedule dihewîne, ku di 9-ê sibehê de hejmara serverên di komê de ji du-deh zêde dike. Ger hûn li, bêje, 11 danê sibê bicîh bikin, ASG-a nû dê ji deh deh de tenê bi du serveran ve were destpêkirin û heya 9 ê sibê bi vî rengî bimîne.

Ev sînor dikare bi çend awayan were dorpêç kirin.

  • Di aws_autoscaling_schedule de pîvana dûbarebûnê ji 0 9 * * * ("sat 9ê sibehê bimeşîne") biguhezînin tiştek wekî 0-59 9-17 * * * ("her deqe ji 9ê sibehê heya 5ê êvarê bimeşin"). Ger ASG jixwe deh server hene, vê qaîdeya otoscaling dîsa bimeşîne dê tiştek neguhere, ya ku em dixwazin ev e. Lê heke ASG tenê vê dawiyê hatibe bicîh kirin, ev rêgez dê piştrast bike ku herî zêde di deqeyekê de hejmara serverên wê bigihîje deh. Ev ne nêzîkatiyek bi tevahî elegant e, û avêtinên mezin ji deh ber du server û paşve jî dikarin ji bo bikarhêneran pirsgirêkan derxînin.
  • Skrîptek xwerû biafirînin ku API-ya AWS bikar tîne da ku hejmara pêşkêşkerên çalak di ASG-ê de diyar bike, jê re bi karanîna çavkaniyek daneya derveyî bang bike (li "Çavkaniya Daneyên Derve" li rûpela 249 binêre), û pîvana kapasîteya_xwestî ya ASG-ê li ser nirxa ku ji hêla vegerandiye destnîşan bike. senaryoyê. Bi vî rengî, her mînakek nû ya ASG-ê dê her gav bi heman kapasîteya koda Terraformê ya heyî bimeşe û domandina wê dijwartir dike.

Bê guman, Terraform dê bi îdeal ji bo bicîhkirina zero-downtime piştgirîya çêkirî hebe, lê ji Gulana 2019-an ve, tîmê HashiCorp ti planek tune ku vê fonksiyonê zêde bike (hûragahiyan - li vir).

Dibe ku plana rast bi serneketî were sepandin

Carinan fermana plansaziyê plansaziyek birêkûpêk rast çêdike, lê fermana sepanê xeletiyek vedigerîne. Mînakî, biceribînin ku çavkaniya aws_iam_user bi heman navî ku we ji bo bikarhênerê IAM-ê ku we berê di Beşa 2-ê de afirandiye ve zêde bike:

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

Naha, heke hûn fermana plansaziyê bimeşînin, Terraform dê plansaziyek bicîhkirina maqûl derxe:

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.

Heke hûn fermana serîlêdanê bimeşînin hûn ê xeletiya jêrîn bistînin:

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

Pirsgirêk, bê guman ev e ku bikarhênerek IAM-ê bi wî navî jixwe heye. Û ev ne tenê ji bikarhênerên IAM-ê re, lê hema hema her çavkaniyek dikare bibe. Mimkun e ku kesek vê çavkaniyê bi destan an bi karanîna rêzika fermanê afirandiye, lê bi her awayî, hevberdana nasnameyan dibe sedema pevçûnan. Gelek guhertoyên vê xeletiyê hene ku bi gelemperî nûhatiyên Terraform bi surprîz digirin.

Xala sereke ev e ku fermana plana terraform tenê wan çavkaniyên ku di pelê dewleta Terraform de hatine destnîşan kirin hesab dike. Ger çavkanî bi rengek din têne afirandin (mînakek, bi destan bi tikandina konsolê AWS), ew ê di pelê dewletê de nemînin û ji ber vê yekê Terraform dê wan gava ku fermana plansaziyê bicîh tîne hesab neke. Wekî encamek, planek ku di nihêrîna pêşîn de rast xuya dike dê bibe neserkeftî.

Ji vê yekê du ders hene.

  • Ger we berê bi Terraform re dest bi xebatê kiriye, tiştek din bikar neynin. Ger beşek ji binesaziya we bi karanîna Terraform ve were rêve kirin, hûn êdî nikarin wê bi destan biguhezînin. Wekî din, hûn ne tenê xetera xeletiyên Terraform-ê yên xerîb dikin, lê hûn di heman demê de gelek feydeyên IaC-ê jî red dikin ji ber ku kod dê êdî ne nûnerek rast a binesaziya we be.
  • Ger jixwe hin binesaziya we heye, emrê import bikar bînin. Ger hûn dest bi karanîna Terraform-ê bi binesaziya heyî dikin, hûn dikarin wê bi karanîna fermana importa terraform li pelê dewletê zêde bikin. Bi vî rengî Terraform dê zanibe ka kîjan binesaziyê divê were rêvebirin. Fermana import du argumanan digire. Ya yekem navnîşana çavkaniyê di pelên veavakirina we de ye. Hevoksazî li vir mîna girêdanên çavkaniyê ye: _. (wek aws_iam_user.existing_user). Argumana duyemîn nasnameya çavkaniyê ye ku tê veguheztin. Ka em bibêjin nasnameya çavkaniyê aws_iam_user navê bikarhêner e (mînak, yevgeniy.brikman), û ID-ya çavkaniyê aws_instance ID-ya servera EC2 ye (mîna i-190e22e5). Meriv çawa çavkaniyekê bi gelemperî di belgeya li binê rûpela wê de tête destnîşan kirin.

    Li jêr fermanek import heye ku çavkaniya aws_iam_user ya ku we li veavakirina Terraformê ligel bikarhênerê IAM-ê di Beşa 2-ê de zêde kiriye hevdem dike (navê we li şûna yevgeniy.brikman, bê guman):

    $ terraform import aws_iam_user.existing_user yevgeniy.brikman

    Terraform dê gazî AWS API-yê bike da ku bikarhênerê IAM-a we bibîne û di nav veavakirina Terraform-ê de di navbera wê û çavkaniya aws_iam_user.existing_user de têkiliyek pelê dewletê biafirîne. Ji niha û pê ve, gava ku hûn fermana plansaziyê bimeşînin, Terraform dê zanibe ku bikarhênerê IAM-ê jixwe heye û dê hewl nede ku wê dîsa biafirîne.

    Hêjayî gotinê ye ku heke we jixwe gelek çavkaniyên ku hûn dixwazin têxin nav Terraformê hebin, bi destan nivîsandina kodê û anîna her yekê yek li yek carî dibe ku bibe pirsgirêk. Ji ber vê yekê hêja ye ku li amûrek mîna Terraforming (http://terraforming.dtan4.net/) bigerin, ku dikare bixweber kod û dewletê ji hesabê weya AWS-ê derxîne.

    Refactoring dikare kêmasiyên xwe hebin

    Refactoring Di bernamekirinê de pratîkek hevpar e ku hûn strukturên hundurîn ên kodê diguhezînin dema ku tevgera derveyî neguherî dihêlin. Ev e ku kodê zelaltir, xweştir û parastinê hêsantir bike. Refactoring teknolojiyek domdar e ku divê bi rêkûpêk were bikar anîn. Lê gava ku dor tê ser Terraform an amûrek din a IaC, divê hûn pir baldar bin ku hûn bi "tevgera derve" ya perçeyek kodê tê çi wateyê, wekî din dê pirsgirêkên nediyar derkevin holê.

    Mînakî, celebek refaktorkirinê ya hevpar ew e ku navên guhêrbar an fonksiyonan bi yên têgihiştî veguherînin. Gelek IDE ji bo refaktorkirinê piştgiriyek çêkirî heye û dikarin bixweber navên guhêrbar û fonksiyonan li seranserê projeyê biguherînin. Di zimanên bernamesaziya gelemperî de, ev pêvajoyek hindik e ku dibe ku hûn li ser nefikirin, lê di Terraform de divê hûn bi vê yekê pir baldar bin, wekî din hûn dikarin qutbûnan ​​biceribînin.

    Mînakî, modula webserver-kluster xwedan guhêrbarek cluster_name ye:

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

    Bifikirin ku we dest bi karanîna vê modulê kir da ku mîkroxizmetek bi navê foo bicîh bikin. Dûv re, hûn dixwazin navê karûbarê xwe bi bar bikin. Dibe ku ev guhertin sivik xuya bike, lê di rastiyê de ew dikare bibe sedema astengiyên karûbarê.

    Rastî ev e ku modula webserver-cluster di gelek çavkaniyan de guherbara cluster_name bikar tîne, di nav de pîvana navê du komên ewlehiyê û ALB:

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

    Ger hûn pîvana navekî li ser çavkaniyekê biguhezînin, Terraform dê guhertoya kevn a wê çavkaniyê jêbibe û li şûna wê yekî nû biafirîne. Lê heke ew çavkanî ALB be, di navbera jêbirina wê û dakêşana guhertoyek nû de, hûn ê ne xwediyê mekanîzmayek be ku seyrûseferê beralî bike ser servera xweya malperê. Bi vî rengî, heke komek ewlehiyê were jêbirin, serverên we dê dest bi redkirina seyrûsefera torê bikin heya ku komek nû were afirandin.

    Cûreyek din a refaktorkirina ku hûn jê re eleqedar dibin guheztina nasnama Terraform e. Werin em çavkaniya aws_security_group di modula webserver-cluster-ê de wekî mînak bigirin:

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

    Nasnameya vê çavkaniyê wekî mînak tê gotin. Bifikirin ku di dema vesazkirinê de we biryar da ku hûn wê biguhezînin navek cluster_instance ku têgihîştîtir (li gorî we) ye:

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

    Di dawiyê de dê çi bibe? Rast e: têkçûnek.

    Terraform her nasnameya çavkaniyê bi nasnameya pêşkêşkarê ewr re têkildar dike. Mînakî, iam_user bi nasnameya bikarhênerê AWS IAM re têkildar e, û aws_instance bi nasnameya servera AWS EC2 re têkildar e. Ger hûn nasnameya çavkaniyê biguhezînin (ji nimûneyê bibêjin cluster_instance, wek ku di aws_security_group de ye), li Terraform xuya dike ku we çavkaniya kevin jê kiriye û yekî nû lê zêde kiriye. Ger hûn van guhertinan bicîh bînin, Terraform dê koma ewlehiyê ya kevn jê bibe û yekî nû biafirîne, dema ku serverên we dest bi redkirina seyrûsefera torê dikin.

    Li vir çar dersên sereke hene ku divê hûn ji vê nîqaşê dûr bixin.

    • Her dem fermana planê bikar bînin. Ew dikare van hemî kêşeyan eşkere bike. Hilbera wê bi baldarî binihêrin û bala xwe bidin rewşên ku Terraform plan dike ku çavkaniyên ku bi îhtîmalek mezin divê neyên jêbirin jêbirin.
    • Berî ku hûn jêbirin çêbikin. Heke hûn dixwazin çavkaniyek biguhezînin, bi baldarî bifikirin ka hûn hewce ne ku cîhgirek çêbikin berî ku orjînal jêbirin. Ger bersiv erê ye, create_before_destroy dikare alîkariyê bike. Heman encam bi kirina du gavan bi destan dikare were bidestxistin: pêşî çavkaniyek nû li veavakirinê zêde bike û fermana serîlêdanê bimeşîne, û dûv re çavkaniya kevn ji veavakirinê derxîne û fermana sepanê dîsa bikar bîne.
    • Guhertina nasnameyan pêwîstî bi guhertina dewletê heye. Ger hûn dixwazin nasnameya ku bi çavkaniyek ve girêdayî ye biguhezînin (mînak, navê aws_security_group ji nimûneyê biguhezînin cluster_instance) bêyî jêbirina çavkaniyê û guhertoyek nû ya wê biafirînin, divê hûn pelê dewleta Terraform li gorî wê nûve bikin. Tu carî vê yekê bi destan nekin - li şûna wê fermana dewleta terraform bikar bînin. Dema ku navên nasnameyan biguhezînin, divê hûn fermana mv ya dewleta terraform, ku hevoksaziya jêrîn heye, bimeşînin:
      terraform state mv <ORIGINAL_REFERENCE> <NEW_REFERENCE>

      ORIGINAL_REFERENCE vegotinek e ku çavkaniyê di forma xweya heyî de vedibêje, û NEW_REFERENCE cihê ku hûn dixwazin wê biguhezînin e. Mînakî, dema ku navê koma aws_security_group ji nimûneyê vediguhezîne cluster_instance, hûn hewce ne ku emrê jêrîn bimeşînin:

      $ terraform state mv 
         aws_security_group.instance 
         aws_security_group.cluster_instance

      Ev ji Terraformê re dibêje ku dewleta ku berê bi aws_security_group.instance re têkildar bû, divê nuha bi aws_security_group.cluster_instance re têkildar be. Ger piştî nav û xebitandina vê fermanê plana terraform tu guheztinê nîşan nede, wê hingê we her tişt rast kir.

    • Hin mîheng nayên guhertin. Parametreyên gelek çavkaniyan nayên guhertin. Ger hûn hewl bidin ku wan biguhezînin, Terraform dê çavkaniya kevn jê bibe û li şûna wê yekî nû biafirîne. Her rûpela çavkaniyê dê bi gelemperî destnîşan bike ka çi diqewime dema ku hûn mîhengek taybetî biguhezînin, ji ber vê yekê piştrast bin ku belgeyê kontrol bikin. Her gav fermana planê bikar bînin û stratejiya create_before_destroy bikar bînin.

    Lihevhatina paşveçûn lihevhatî ye ... bi paşdexistin

    API-yên hin pêşkêşkerên ewr, yên wekî AWS, asynkron in û domdariya derengmayî ne. Asynkronî tê vê wateyê ku navber dikare tavilê bersivek vegerîne bêyî ku li benda qedandina çalakiya daxwazkirî bimîne. Lihevhatina derengmayî tê vê wateyê ku dibe ku guhertin li seranserê pergalê belav bibin; dema ku ev diqewime, dibe ku bersivên we nakokî bin û bi wê ve girêdayî bin ku kîjan kopya çavkaniya daneyê bersivê dide bangên API-ya we.

    Mînakî, bifikirin ku hûn bangek API-yê ji AWS-ê re dikin û jê dipirsin ku serverek EC2 biafirîne. API dê hema di cih de bersivek "serketî" (201 Afirandin) vegerîne, bêyî ku li bendê bimîne ku server bixwe were afirandin. Ger hûn hewl bidin ku tavilê pê ve girêbidin, ew ê hema bê guman têk biçe ji ber ku di wê nuqteyê de AWS hîn jî çavkaniyan dest pê dike an jî, wekî din, server hîna boot nekiriye. Wekî din, heke hûn bangek din bikin ku agahdariya li ser vê serverê bistînin, dibe ku hûn xeletiyek bistînin (404 Not Found). Tişt ev e ku agahdariya di derbarê vê servera EC2 de hîn jî dibe ku li seranserê AWS-ê were belav kirin berî ku ew li her deverê peyda bibe, hûn ê neçar bimînin ku çend saniyan li bendê bin.

    Kengê ku hûn API-ya asynchronous bi domdariya tembel bikar tînin, divê hûn bi periyodîk daxwaza xwe ji nû ve biceribînin heya ku kiryar biqede û di nav pergalê de belav bibe. Mixabin, AWS SDK ji bo vê yekê amûrên baş peyda nake, û projeya Terraform ji gelek xeletiyên mîna 6813 cefayê dikişand (https://github.com/hashicorp/terraform/issues/6813):

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

    Bi gotineke din, hûn çavkaniyek (wek jêrtorêk) diafirînin û dûv re hewl didin ku hin agahdarî li ser wê bistînin (wek nasnama jêrtora nû hatî afirandin), û Terraform nikare wê bibîne. Piraniya van xeletiyan (tevî 6813) hatine rast kirin, lê ew hîn jî dem bi dem derdikevin, nemaze dema ku Terraform piştgirî ji celebek çavkaniyek nû zêde dike. Ev aciz e, lê di pir rewşan de zirarê nade. Dema ku hûn terraform dîsa serîlêdanê dimeşînin, divê her tişt bixebite, ji ber ku di vê demê de agahdarî dê berê li seranserê pergalê belav bibe.

    Ev beş ji pirtûka Evgeniy Brikman hatiye pêşkêşkirin "Terraform: binesaziya di asta kodê de".

Source: www.habr.com

Add a comment