Terraform tələləri

Terraform tələləri
Gəlin bir neçə tələləri, o cümlədən döngələrlə, if ifadələri və yerləşdirmə üsulları, həmçinin ümumiyyətlə Terraforma təsir edən daha ümumi məsələləri vurğulayaq:

  • count və for_each parametrlərinin məhdudiyyətləri var;
  • sıfır iş vaxtının yerləşdirilməsini məhdudlaşdırmaq;
  • hətta yaxşı bir plan uğursuz ola bilər;
  • refaktorinqin öz tələləri ola bilər;
  • təxirə salınmış uyğunluq uyğundur... təxirə salınma ilə.

count və for_each parametrlərinin məhdudiyyətləri var

Bu fəsildəki nümunələr dövrlərdə və şərti məntiqdə count parametrindən və for_each ifadəsindən geniş istifadə edir. Yaxşı performans göstərirlər, lakin onların bilməli olduğunuz iki vacib məhdudiyyəti var.

  • Count və for_each heç bir resurs çıxış dəyişənlərinə istinad edə bilməz.
  • count və for_each modul konfiqurasiyasında istifadə edilə bilməz.

count və for_each heç bir resurs çıxış dəyişənlərinə istinad edə bilməz

Təsəvvür edin ki, bir neçə EC2 serverini yerləşdirməlisiniz və nədənsə ASG-dən istifadə etmək istəmirsiniz. Kodunuz belə ola bilər:

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

Gəlin onlara bir-bir baxaq.

Count parametri statik dəyərə təyin edildiyi üçün bu kod problemsiz işləyəcək: siz tətbiq əmrini işlətdiyiniz zaman o, üç EC2 serveri yaradacaq. Bəs cari AWS regionunuzda hər bir Əlçatımlılıq Zonasında (AZ) bir server yerləşdirmək istəsəniz nə etməli? Siz kodunuzun aws_availability_zones məlumat mənbəyindən zonaların siyahısını yükləməsini və sonra hər biri arasında dövrə vurmasını və count parametrindən və massiv indeksinə girişdən istifadə edərək orada EC2 serverini yarada bilərsiniz:

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

Bu kod da yaxşı işləyəcək, çünki count parametri heç bir problem olmadan məlumat mənbələrinə istinad edə bilər. Bəs yaratmalı olduğunuz serverlərin sayı hansısa resursun çıxışından asılıdırsa nə baş verir? Bunu nümayiş etdirmək üçün ən asan yol adından göründüyü kimi təsadüfi tam ədədi qaytaran random_integer resursundan istifadə etməkdir:

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

Bu kod 1 və 3 arasında təsadüfi ədəd yaradır. Gəlin görək aws_instance resursunun count parametrində bu resursun çıxışından istifadə etməyə çalışsaq nə baş verəcək:

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

Bu kodda terraform planını işlədirsinizsə, aşağıdakı xətanı alacaqsınız:

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 hər hansı resurs yaradılmazdan və ya dəyişdirilmədən əvvəl planlaşdırma mərhələsində say və hər biri üçün hesablanmasını tələb edir. Bu o deməkdir ki, count və for_each hərflərə, dəyişənlərə, məlumat mənbələrinə və hətta resurs siyahılarına (onların uzunluğu planlaşdırma zamanı müəyyən edilə bildiyi müddətcə) istinad edə bilər, lakin hesablanmış resurs çıxış dəyişənlərinə deyil.

count və for_each modul konfiqurasiyasında istifadə edilə bilməz

Bir gün modul konfiqurasiyanıza sayma parametri əlavə etmək istəyi yarana bilər:

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

     count = 3

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

Bu kod, vebserver-klaster resursunun üç nüsxəsini yaratmaq üçün modul daxilində count istifadə etməyə çalışır. Yaxud siz modulun count parametrini 0-a təyin etməklə bəzi Boolean şərtlərinə əsasən qoşulmağı istəyə bilərsiniz. Bu, ağlabatan kod kimi görünə bilər, lakin terraform planını işlədən zaman bu xətanı alacaqsınız:

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.

Təəssüf ki, Terraform 0.12.6-dan etibarən modul resursunda count və ya for_each istifadə dəstəklənmir. Terraform 0.12 buraxılış qeydlərinə (http://bit.ly/3257bv4) əsasən, HashiCorp gələcəkdə bu qabiliyyəti əlavə etməyi planlaşdırır, ona görə də bu kitabı nə vaxt oxumağınızdan asılı olaraq, o, artıq mövcud ola bilər. Əmin olmaq üçün, Terraform dəyişikliklər jurnalını burada oxuyun.

Sıfır fasilə zamanı yerləşdirmə məhdudiyyətləri

Create_before_destroy blokunun ASG ilə birlikdə istifadəsi bir xəbərdarlıq istisna olmaqla, sıfır fasiləsiz yerləşdirmələr yaratmaq üçün əla həlldir: avtomatik miqyaslama qaydaları dəstəklənmir. Və ya daha dəqiq desək, bu, hər yerləşdirmədə ASG ölçüsünü min_size-ə sıfırlayır, bu, işləyən serverlərin sayını artırmaq üçün avtomatik miqyaslama qaydalarından istifadə etsəniz, problem ola bilər.

Məsələn, veb-server-klaster modulu bir cüt aws_autoscaling_schedule resursunu ehtiva edir ki, bu da səhər saat 9-da klasterdəki serverlərin sayını ikidən on-a qədər artırır. Deyək ki, səhər saat 11-də yerləşdirsəniz, yeni ASG on deyil, yalnız iki serverlə işə düşəcək və növbəti gün səhər saat 9-a qədər belə qalacaq.

Bu məhdudiyyəti bir neçə yolla keçmək olar.

  • aws_autoscaling_schedule-də təkrarlanma parametrini 0 9 * * * (“səhər 9-da işləyin”) ilə 0-59 9-17 * * * (“səhər saat 9-dan axşam 5-ə qədər hər dəqiqə qaçış”) kimi bir şeyə dəyişin. Əgər ASG artıq on serverə malikdirsə, bu avtomatik miqyaslama qaydasını yenidən işə salmaq heç nəyi dəyişməyəcək, bizim istədiyimiz budur. Lakin ASG bu yaxınlarda yerləşdirilibsə, bu qayda maksimum bir dəqiqə ərzində onun serverlərinin sayının ona çatmasını təmin edəcək. Bu, tamamilə zərif bir yanaşma deyil və ondan iki serverə və arxaya böyük atlamalar da istifadəçilər üçün problemlər yarada bilər.
  • ASG-də aktiv serverlərin sayını müəyyən etmək üçün AWS API-dən istifadə edən fərdi skript yaradın, xarici məlumat mənbəyindən istifadə edərək ona zəng edin (bax: “Xarici Məlumat Mənbəsi” səhifə 249) və ASG-nin arzu olunan_tutum parametrini qaytarılan dəyərə təyin edin. ssenari. Bu yolla, hər bir yeni ASG nümunəsi həmişə mövcud Terraform kodu ilə eyni gücdə işləyəcək və ona qulluq etməyi çətinləşdirir.

Əlbəttə ki, Terraform ideal olaraq sıfır fasiləsiz yerləşdirmələr üçün daxili dəstəyə sahib olardı, lakin 2019-cu ilin may ayından etibarən HashiCorp komandasının bu funksiyanı əlavə etmək planları yox idi (təfərrüatlar - burada).

Düzgün plan uğursuz həyata keçirilə bilər

Bəzən plan əmri mükəmməl düzgün yerləşdirmə planı yaradır, lakin tətbiq əmri xəta qaytarır. Məsələn, 2-ci Fəsildə əvvəllər yaratdığınız IAM istifadəçisi üçün istifadə etdiyiniz eyni adla aws_iam_user resursunu əlavə etməyə cəhd edin:

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

İndi plan əmrini yerinə yetirsəniz, Terraform ağlabatan görünən yerləşdirmə planını çıxaracaq:

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.

Tətbiq əmrini işlətsəniz, aşağıdakı xətanı alacaqsınız:

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

Problem, əlbəttə ki, bu ada malik bir IAM istifadəçisinin artıq mövcud olmasıdır. Və bu, təkcə IAM istifadəçilərinə deyil, demək olar ki, istənilən resursda baş verə bilər. Mümkündür ki, kimsə bu resursu əl ilə və ya komanda xəttindən istifadə edərək yaradıb, lakin hər iki halda uyğunluq identifikatorları münaqişələrə gətirib çıxarır. Tez-tez Terraforma yeni gələnləri təəccübləndirən bu səhvin bir çox variantı var.

Əsas məqam ondan ibarətdir ki, terraform planı əmri yalnız Terraform dövlət faylında göstərilən resursları nəzərə alır. Resurslar başqa bir şəkildə yaradılarsa (məsələn, AWS konsolunda klikləməklə) onlar dövlət faylına düşməyəcək və buna görə də Terraform plan əmrini yerinə yetirərkən onları nəzərə almayacaq. Nəticədə ilk baxışda düzgün görünən plan uğursuzluqla nəticələnəcək.

Bundan iki dərs çıxarmaq lazımdır.

  • Əgər siz artıq Terraform ilə işləməyə başlamışsınızsa, başqa heç nə istifadə etməyin. İnfrastrukturunuzun bir hissəsi Terraform istifadə edərək idarə olunursa, siz onu daha əl ilə dəyişdirə bilməzsiniz. Əks halda, siz nəinki qəribə Terraform səhvlərini riskə atırsınız, həm də IaC-nin bir çox üstünlüklərini inkar etmiş olursunuz, çünki kod artıq infrastrukturunuzun dəqiq təmsilçisi olmayacaq.
  • Əgər artıq bəzi infrastrukturunuz varsa, idxal əmrindən istifadə edin. Əgər siz Terraform-u mövcud infrastrukturla istifadə etməyə başlayırsınızsa, onu terraform import əmrindən istifadə edərək dövlət faylına əlavə edə bilərsiniz. Bu yolla Terraform hansı infrastrukturun idarə edilməsi lazım olduğunu biləcək. Import əmri iki arqument alır. Birincisi, konfiqurasiya fayllarınızdakı resurs ünvanıdır. Buradakı sintaksis resurs keçidləri ilə eynidir: _. (aws_iam_user.existing_user kimi). İkinci arqument idxal ediləcək resursun ID-sidir. Tutaq ki, aws_iam_user resurs ID-si istifadəçi adıdır (məsələn, yevgeniy.brikman), aws_instance resurs ID-si isə EC2 server ID-sidir (i-190e22e5 kimi). Resursun necə idxal ediləcəyi adətən onun səhifəsinin altındakı sənədlərdə göstərilir.

    Aşağıda Terraform konfiqurasiyanıza əlavə etdiyiniz aws_iam_user resursunu 2-ci Fəsildə IAM istifadəçisi ilə sinxronlaşdıran idxal əmri verilmişdir (əlbəttə, adınızı yevgeniy.brikman ilə əvəz etməklə):

    $ terraform import aws_iam_user.existing_user yevgeniy.brikman

    Terraform sizin IAM istifadəçinizi tapmaq və onunla Terraform konfiqurasiyanızda aws_iam_user.existing_user resursu arasında dövlət fayl assosiasiyası yaratmaq üçün AWS API-yə zəng edəcək. Bundan sonra siz plan əmrini işə saldığınız zaman Terraform IAM istifadəçisinin artıq mövcud olduğunu biləcək və onu yenidən yaratmağa cəhd etməyəcək.

    Qeyd etmək lazımdır ki, Terraform-a idxal etmək istədiyiniz çoxlu resursunuz varsa, kodu əl ilə yazmaq və hər birini bir anda idxal etmək əngəl ola bilər. Beləliklə, AWS hesabınızdan kodu və vəziyyəti avtomatik idxal edə bilən Terraforming (http://terraforming.dtan4.net/) kimi alətə baxmağa dəyər.

    Refaktorinqin öz tələləri ola bilər

    Refaktorinq xarici davranışı dəyişmədən kodun daxili strukturunu dəyişdirdiyiniz proqramlaşdırmada ümumi bir təcrübədir. Bu kodu daha aydın, səliqəli və saxlanmasını asanlaşdırmaq üçündür. Refaktorinq mütəmadi olaraq istifadə edilməli olan əvəzsiz bir texnikadır. Ancaq Terraform və ya hər hansı digər IaC alətinə gəldikdə, bir kod parçasının "xarici davranışı" ilə nə demək istədiyinizə son dərəcə diqqətli olmalısınız, əks halda gözlənilməz problemlər yaranacaq.

    Məsələn, refaktorinqin ümumi növü dəyişənlərin və ya funksiyaların adlarını daha başa düşülənlərlə əvəz etməkdir. Bir çox IDE-lər refaktorinq üçün daxili dəstəyə malikdir və layihə boyu dəyişənlərin və funksiyaların adını avtomatik olaraq dəyişdirə bilər. Ümumi təyinatlı proqramlaşdırma dillərində bu, sizin düşünmədiyiniz mənasız bir prosedurdur, lakin Terraform-da bununla bağlı son dərəcə diqqətli olmalısınız, əks halda kəsintilərlə üzləşə bilərsiniz.

    Məsələn, veb-server-klaster modulunda cluster_name giriş dəyişəni var:

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

    Təsəvvür edin ki, siz bu moduldan foo adlı mikroservisi yerləşdirmək üçün istifadə etməyə başladınız. Daha sonra xidmətinizin adını bar olaraq dəyişmək istəyirsiniz. Bu dəyişiklik mənasız görünə bilər, amma əslində xidmətin pozulmasına səbəb ola bilər.

    Fakt budur ki, veb-server-klaster modulu iki təhlükəsizlik qrupunun ad parametri və ALB daxil olmaqla bir sıra resurslarda cluster_name dəyişənindən istifadə edir:

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

    Resursda ad parametrini dəyişdirsəniz, Terraform həmin resursun köhnə versiyasını siləcək və onun yerində yenisini yaradacaq. Lakin bu resurs ALB-dirsə, onu silmək və yeni versiyanı yükləmək arasında, trafiki veb serverinizə yönləndirmə mexanizminiz olmayacaq. Eyni şəkildə, təhlükəsizlik qrupu silinərsə, serverləriniz yeni qrup yaradılana qədər istənilən şəbəkə trafikini rədd etməyə başlayacaq.

    Sizi maraqlandıra biləcək başqa bir refaktorinq növü Terraform ID-ni dəyişdirməkdir. Nümunə olaraq vebserver-klaster modulunda aws_security_group resursunu götürək:

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

    Bu resursun identifikatoru instansiya adlanır. Təsəvvür edin ki, refaktorinq zamanı siz onu daha başa düşülən (sizin fikrincə) cluster_instance adına dəyişməyə qərar verdiniz:

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

    Axırda nə olacaq? Düzdür: pozulma.

    Terraform hər bir resurs ID-ni bulud provayderi ID-si ilə əlaqələndirir. Məsələn, iam_user AWS IAM istifadəçi ID-si ilə, aws_instance isə AWS EC2 server ID-si ilə əlaqələndirilir. Resurs identifikatorunu (məsələn, aws_security_group-da olduğu kimi misaldan cluster_instance-a) dəyişsəniz, Terraform-a köhnə resursu silib yenisini əlavə etdiyiniz kimi görünəcək. Bu dəyişiklikləri tətbiq etsəniz, Terraform köhnə təhlükəsizlik qrupunu siləcək və yenisini yaradacaq, eyni zamanda serverləriniz istənilən şəbəkə trafikini rədd etməyə başlayacaq.

    Bu müzakirədən götürməli olduğunuz dörd əsas dərsdir.

    • Həmişə plan əmrindən istifadə edin. Bütün bu qüsurları aşkar edə bilər. Çıxışını diqqətlə nəzərdən keçirin və Terraformun çox güman ki, silinməməli olan resursları silməyi planlaşdırdığı vəziyyətlərə diqqət yetirin.
    • Silmədən əvvəl yaradın. Əgər resursu əvəz etmək istəyirsinizsə, orijinalı silməzdən əvvəl əvəzedici yaratmağınız lazım olub-olmadığını diqqətlə düşünün. Cavab bəlidirsə, create_befor_destroy kömək edə bilər. Eyni nəticəni iki addımı yerinə yetirməklə əl ilə əldə etmək olar: əvvəlcə konfiqurasiyaya yeni resurs əlavə edin və tətbiq əmrini işə salın, sonra isə köhnə resursu konfiqurasiyadan çıxarın və tətbiq əmrindən yenidən istifadə edin.
    • İdentifikatorların dəyişdirilməsi vəziyyətin dəyişdirilməsini tələb edir. Resursu silmədən və onun yeni versiyasını yaratmadan resursla əlaqəli identifikatoru dəyişmək istəyirsinizsə (məsələn, aws_security_group adını misaldan cluster_instance olaraq dəyişdirin), Terraform dövlət faylını müvafiq olaraq yeniləməlisiniz. Bunu heç vaxt əl ilə etməyin - əvəzinə terraform dövlət əmrindən istifadə edin. İdentifikatorların adını dəyişdirərkən, aşağıdakı sintaksisə malik olan terraform state mv əmrini işlətməlisiniz:
      terraform state mv <ORIGINAL_REFERENCE> <NEW_REFERENCE>

      ORIGINAL_REFERENCE cari formada resursa istinad edən ifadədir və YENİ_REFERENCE onu köçürmək istədiyiniz yerdir. Məsələn, aws_security_group qrupunun adını misaldan cluster_instance olaraq dəyişdirərkən aşağıdakı əmri yerinə yetirməlisiniz:

      $ terraform state mv 
         aws_security_group.instance 
         aws_security_group.cluster_instance

      Bu, Terraform-a deyir ki, əvvəllər aws_security_group.instance ilə əlaqəli olan dövlət indi aws_security_group.cluster_instance ilə əlaqələndirilməlidir. Bu əmrin adını dəyişdirdikdən və işlətdikdən sonra terraform planında heç bir dəyişiklik göstərilmirsə, deməli hər şeyi düzgün etdiniz.

    • Bəzi parametrləri dəyişdirmək mümkün deyil. Bir çox resursların parametrləri dəyişməzdir. Onları dəyişdirməyə çalışsanız, Terraform köhnə resursu siləcək və onun yerində yenisini yaradacaq. Hər bir resurs səhifəsi adətən müəyyən parametri dəyişdirdiyiniz zaman nə baş verdiyini göstərəcək, buna görə də sənədləri yoxladığınızdan əmin olun. Həmişə plan əmrindən istifadə edin və create_before_destroy strategiyasından istifadə etməyi düşünün.

    Təxirə salınmış ardıcıllıq uyğundur... təxirə salınma ilə

    Bəzi bulud provayderlərinin API-ləri, məsələn, AWS, asinxrondur və gecikmiş ardıcıllığa malikdir. Asinxroniya o deməkdir ki, interfeys tələb olunan hərəkətin tamamlanmasını gözləmədən dərhal cavab qaytara bilər. Gecikmiş ardıcıllıq o deməkdir ki, dəyişikliklərin bütün sistemdə yayılması vaxt tələb edə bilər; bu baş verərkən, cavablarınız uyğunsuz ola bilər və hansı məlumat mənbəyi replikasının API zənglərinizə cavab verməsindən asılı ola bilər.

    Təsəvvür edin ki, məsələn, AWS-ə API zəngi edərək ondan EC2 server yaratmağı xahiş edirsiniz. API serverin özünün yaradılmasını gözləmədən, demək olar ki, dərhal “uğurlu” cavabı (201 Yaradıldı) qaytaracaq. Dərhal ona qoşulmağa çalışsanız, o, demək olar ki, uğursuz olacaq, çünki həmin anda AWS hələ də resursları işə salır və ya alternativ olaraq server hələ işə düşməyib. Bundan əlavə, bu server haqqında məlumat almaq üçün başqa zəng etsəniz, xəta ala bilərsiniz (404 Tapılmadı). Məsələ ondadır ki, bu EC2 serveri haqqında məlumat hər yerdə əlçatan olana qədər hələ də AWS-də yayıla bilər, bir neçə saniyə gözləməli olacaqsınız.

    Tənbəl ardıcıllıqla asinxron API istifadə etdiyiniz zaman, əməliyyat tamamlanana və sistem vasitəsilə yayılana qədər sorğunuzu vaxtaşırı təkrar sınamalısınız. Təəssüf ki, AWS SDK bunun üçün yaxşı alətlər təqdim etmir və Terraform layihəsi 6813 (https://github.com/hashicorp/terraform/issues/6813) kimi bir çox səhvlərdən əziyyət çəkirdi:

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

    Başqa sözlə, siz resurs yaradırsınız (alt şəbəkə kimi) və sonra bu barədə bəzi məlumat əldə etməyə çalışırsınız (yeni yaradılmış alt şəbəkənin ID-si kimi) və Terraform onu ​​tapa bilmir. Bu səhvlərin əksəriyyəti (6813 daxil olmaqla) düzəldilib, lakin onlar hələ də zaman-zaman yaranır, xüsusən də Terraform yeni resurs növü üçün dəstək əlavə etdikdə. Bu bezdiricidir, lakin əksər hallarda heç bir zərər vermir. Terraform tətbiqini yenidən işə saldıqda hər şey işləməlidir, çünki bu vaxta qədər məlumat artıq bütün sistemə yayılacaq.

    Bu parça Evgeni Brikmanın kitabından təqdim olunur "Terraform: kod səviyyəsində infrastruktur".

Mənbə: www.habr.com

Добавить комментарий