Терраформдык тузактар

Терраформдык тузактар
Келгиле, бир нече тузактарга, анын ичинде циклдерге, if билдирүүлөрүнө жана жайылтуу ыкмаларына, ошондой эле жалпысынан Terraformго таасир этүүчү жалпы маселелерди бөлүп көрөлү:

  • count жана for_each параметрлеринде чектөөлөр бар;
  • нөл токтоп калууларды чектөө;
  • жакшы план да ишке ашпай калышы мүмкүн;
  • рефакторинг өзүнүн тузактары болушу мүмкүн;
  • deferred coherence ырааттуу... кийинкиге калтыруу менен.

count жана for_each параметрлеринде чектөөлөр бар

Бул бөлүмдөгү мисалдар циклдерде жана шарттуу логикада count параметрин жана for_each туюнтмасын кеңири колдонот. Алар жакшы иштешет, бирок аларда эки маанилүү чектөө бар, алар сиз билишиңиз керек.

  • Count жана for_each эч кандай ресурс чыгаруу өзгөрмөлөрүнө шилтеме кыла албайт.
  • count жана for_each модулдун конфигурациясында колдонулушу мүмкүн эмес.

count жана for_each эч кандай ресурстун чыгуу өзгөрмөлөрүнө шилтеме кыла албайт

Элестетиңиз, сизге бир нече EC2 серверлерин жайгаштырышыңыз керек жана кандайдыр бир себептерден улам ASGди колдонгуңуз келбейт. Сиздин код төмөнкүдөй болушу мүмкүн:

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

Келгиле, аларды бирден карап көрөлү.

Эсептөө параметри статикалык мааниге коюлгандыктан, бул код көйгөйсүз иштейт: колдонуу буйругун иштеткенде, ал үч EC2 серверин түзөт. Бирок, эгер сиз учурдагы AWS аймагындагы ар бир Жеткиликтүү Аймакка (AZ) бир серверди жайгаштыргыңыз келсе эмне болот? Сиз өз кодуңузду aws_availability_zones маалымат булагынан аймактардын тизмесин жүктөөнү жана андан кийин ар бирин цикл аркылуу өткөрүп, анда count параметрин жана массив индексинин мүмкүнчүлүгүн колдонуу менен EC2 серверин түзө аласыз:

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

Бул код да жакшы иштейт, анткени count параметри эч кандай көйгөйсүз маалымат булактарына кайрыла алат. Бирок сиз түзүшүңүз керек болгон серверлердин саны кандайдыр бир ресурстун чыгышынан көз каранды болсо эмне болот? Муну көрсөтүү үчүн, эң оңой жолу - аты айтып тургандай, кокус бүтүн санды кайтарып турган random_integer ресурсун колдонуу:

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

Бул код 1 жана 3 ортосундагы кокус санды жаратат. Келгиле, бул ресурстун чыгышын aws_instance ресурсунун count параметринде колдонууга аракет кылсак, эмне болорун карап көрөлү:

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

Эгер сиз бул код боюнча terraform планын иштетсеңиз, сиз төмөнкү катаны аласыз:

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 ар кандай ресурстарды түзүүдөн же өзгөртүүдөн мурда пландаштыруу баскычында count жана for_each эсептелүүсүн талап кылат. Бул count жана for_each литералдарга, өзгөрмөлөргө, маалымат булактарына, жада калса ресурс тизмелерине (алардын узундугу пландаштырылган убакта аныкталышы мүмкүн болсо), бирок эсептелген ресурс чыгаруу өзгөрмөлөрүнө эмес экенин билдирет.

count жана for_each модулдун конфигурациясында колдонулушу мүмкүн эмес

Бир күнү сиз модулуңуздун конфигурациясына эсептөө параметрин кошууга азгырылышыңыз мүмкүн:

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

     count = 3

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

Бул код веб-сервер-кластер ресурсунун үч көчүрмөсүн түзүү үчүн модулдун ичинде эсептөөнү колдонууга аракет кылат. Же кандайдыр бир логикалык шартка жараша модулду кошууну анын count параметрин 0 кылып коюуну кааласаңыз болот. Бул акылга сыярлык код сыяктуу көрүнүшү мүмкүн, бирок терраформа планын аткарууда сиз бул катаны аласыз:

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.

Тилекке каршы, Terraform 0.12.6 боюнча, модулдук ресурста count же for_each колдонуу колдоого алынбайт. Terraform 0.12 релиз эскертүүлөрүнө ылайык (http://bit.ly/3257bv4), HashiCorp бул мүмкүнчүлүктү келечекте кошууну пландаштырууда, андыктан бул китепти качан окуганыңызга жараша, ал мурунтан эле жеткиликтүү болушу мүмкүн. анык билүү үчүн, Terraform өзгөртүүлөр журналын бул жерден окуңуз.

Нөл үзгүлтүккө учуратуу боюнча чектөөлөр

Create_before_destroy блогун ASG менен айкалыштырып колдонуу бир эскертүүдөн тышкары, нөлдүк иштебей жайгаштырууларды түзүү үчүн эң сонун чечим: автомасштабдоо эрежелери колдоого алынбайт. Же тагыраак айтканда, бул ар бир жайгаштырууда ASG өлчөмүн min_size абалына кайтарат, эгер сиз иштеп жаткан серверлердин санын көбөйтүү үчүн автомасштабдоо эрежелерин колдонуп жатсаңыз, көйгөй жаралышы мүмкүн.

Мисалы, веб-сервер-кластер модулу aws_autoscaling_schedule ресурстарынын жуптарын камтыйт, алар таңкы саат 9да кластердеги серверлердин санын экиден онго чейин көбөйтөт. Эгер сиз, айталы, саат 11:9дө жайгаштырсаңыз, жаңы ASG он эмес, эки сервер менен жүктөлөт жана кийинки күнү эртең мененки саат XNUMXга чейин ошол бойдон калат.

Бул чектөө бир нече жол менен айланып өтүүгө болот.

  • aws_autoscaling_schedule ичиндеги кайталануу параметрин 0 9 * * * («эртең мененки саат 9да чуркоо») 0-59 9-17 * * * («эртең мененки саат 9дан кечки саат 5ке чейин мүнөт сайын чуркоо») сыяктуу бир нерсеге өзгөртүңүз. Эгерде ASG мурунтан эле он серверге ээ болсо, бул автоматтык масштабдоо эрежесин кайра иштетүү эч нерсени өзгөртпөйт, бул биз каалаган нерсе. Бирок ASG жакында эле орнотулган болсо, бул эреже бир мүнөттүн ичинде анын серверлеринин саны онго жетет. Бул таптакыр элеганттуу ыкма эмес, ондон эки серверге жана артка чоң секирүү да колдонуучулар үчүн көйгөйлөрдү жаратышы мүмкүн.
  • ASGдеги активдүү серверлердин санын аныктоо үчүн AWS API колдонгон ыңгайлаштырылган скрипт түзүңүз, аны тышкы маалымат булагы аркылуу чакырыңыз (249-беттеги "Тышкы маалымат булагы" караңыз) жана ASG'нин каалаган_кубаттуулугу параметрин кайтарылган мааниге коюңуз. сценарий. Ошентип, ар бир жаңы ASG инстанциясы ар дайым учурдагы Terraform коду менен бирдей кубаттуулукта иштейт жана аны сактоону кыйындатат.

Албетте, Terraform идеалдуу түрдө нөлдүк иштөө убактысын орнотуу үчүн орнотулган колдоого ээ болмок, бирок 2019-жылдын май айына карата HashiCorp командасы бул функцияны кошууну пландаган эмес (чоо-жайы - бул жерде).

Туура план ишке ашпай калышы мүмкүн

Кээде план буйругу кемчиликсиз туура жайылтуу планын чыгарат, бирок колдонуу буйругу катаны кайтарат. Мисалы, 2-бөлүмдө мурда түзгөн IAM колдонуучусу үчүн колдонгон атыңыз менен aws_iam_user ресурсун кошуп көрүңүз:

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

Эми, эгер сиз план буйругун иштетсеңиз, Terraform акылга сыярлык көрүнгөн жайылтуу планын чыгарат:

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.

Колдонуу буйругун иштетсеңиз, сиз төмөнкү катаны аласыз:

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

Көйгөй, албетте, ушундай аталыштагы IAM колдонуучусу бар экенинде. Жана бул IAM колдонуучуларына гана эмес, дээрлик бардык ресурстарга да болушу мүмкүн. Кимдир бирөө бул ресурсту кол менен же буйрук сабын колдонуп жараткан болушу мүмкүн, бирок кандай болбосун, дал келүүчү идентификаторлор чыр-чатакка алып келет. Бул катанын көптөгөн варианттары бар, алар көбүнчө Терраформга жаңы келгендерди күтүлбөгөн жерден кармашат.

Негизги нерсе, terraform планы буйругу Terraform мамлекеттик файлында көрсөтүлгөн ресурстарды гана эске алат. Эгерде ресурстар башка жол менен түзүлсө (мисалы, кол менен AWS консолуна чыкылдатуу менен), алар мамлекеттик файлга түшпөйт, ошондуктан Terraform план буйругун аткарууда аларды эске албайт. Натыйжада, бир караганда туура көрүнгөн план ийгиликсиз болуп чыгат.

Мындан эки сабак алууга болот.

  • Эгер сиз Terraform менен иштей баштаган болсоңуз, башка эч нерсе колдонбоңуз. Эгер инфраструктураңыздын бир бөлүгү Terraform аркылуу башкарылса, аны мындан ары кол менен өзгөртө албайсыз. Болбосо, сиз кызыктай Terraform каталарын гана тобокелге салбастан, ошондой эле IaCтин көптөгөн артыкчылыктарын жокко чыгарасыз, анткени код мындан ары инфраструктураңыздын так өкүлү болбой калат.
  • Эгер сизде кандайдыр бир инфраструктура бар болсо, импорттоо буйругун колдонуңуз. Эгер сиз Terraformду учурдагы инфраструктура менен колдоно баштасаңыз, аны терраформ импорттоо буйругун колдонуп мамлекеттик файлга кошсоңуз болот. Ошентип, Terraform кандай инфраструктураны башкаруу керек экенин билет. Импорттоо буйругу эки аргумент алат. Биринчиси - конфигурация файлдарыңыздагы ресурстун дареги. Бул жердеги синтаксис ресурстук шилтемелер менен бирдей: _. (мисалы, aws_iam_user.existing_user). Экинчи аргумент - импорттолуучу ресурстун идентификатору. Бул ресурстун ID aws_iam_user колдонуучунун аты (мисалы, yevgeniy.brikman), ал эми aws_instance ресурсунун ID EC2 серверинин идентификатору (i-190e22e5 сыяктуу) дейли. Ресурсту кантип импорттоо керектиги, адатта, анын бетинин ылдый жагындагы документтерде көрсөтүлөт.

    Төмөндө сиз Terraform конфигурацияңызга кошкон aws_iam_user ресурсун 2-бөлүмдөгү IAM колдонуучусу менен синхрондоштуруучу импорт буйругу бар (албетте yevgeniy.brikman үчүн атыңызды алмаштырып):

    $ terraform import aws_iam_user.existing_user yevgeniy.brikman

    Terraform сиздин IAM колдонуучуңузду табуу жана анын Terraform конфигурацияңыздагы aws_iam_user.existing_user ресурсу менен мамлекеттик файл ассоциациясын түзүү үчүн AWS API'ге чакырат. Мындан ары, план буйругун иштеткенде, Terraform IAM колдонуучусу мурунтан эле бар экенин билет жана аны кайра түзүүгө аракет кылбайт.

    Белгилей кетчү нерсе, эгер сизде Terraform'ка импорттоону каалаган көптөгөн ресурстарыңыз болсо, кодду кол менен жазып, ар бирин бир убакта импорттоо кыйынчылык жаратышы мүмкүн. Ошентип, Terraforming (http://terraforming.dtan4.net/) сыяктуу куралды карап көрүү керек, ал автоматтык түрдө AWS каттоо эсебиңизден кодду жана абалды импорттой алат.

    Рефакторингдин тузактары болушу мүмкүн

    Рефакторинг программалоодо кеңири таралган практика болуп саналат, анда сиз тышкы жүрүм-турумун өзгөртүүсүз калтырып, коддун ички түзүмүн өзгөртөсүз. Бул кодду ачык, тыкан жана тейлөөнү жеңилдетүү үчүн. Рефакторинг үзгүлтүксүз колдонулушу керек болгон алмаштырылгыс техника. Бирок сөз Terraform же башка IaC инструментине келгенде, коддун бир бөлүгүнүн "тышкы жүрүм-туруму" менен эмнени айткыңыз келгенине өтө этият болушуңуз керек, антпесе күтүлбөгөн көйгөйлөр пайда болот.

    Мисалы, рефакторингдин кеңири таралган түрү бул өзгөрмөлөрдүн же функциялардын аттарын түшүнүктүүрөөк менен алмаштыруу. Көптөгөн IDE'лер рефакторинг үчүн орнотулган колдоого ээ жана долбоор боюнча өзгөрмөлөрдүн жана функциялардын атын автоматтык түрдө өзгөртө алат. Жалпы максаттагы программалоо тилдеринде, бул сиз ойлонбогон майда-чүйдө процедура, бирок Terraform'до бул жагынан өтө этият болушуңуз керек, антпесе үзгүлтүккө учурашыңыз мүмкүн.

    Мисалы, веб-сервер-кластер модулу cluster_name киргизүү өзгөрмөсүнө ээ:

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

    Бул модулду foo деп аталган микросервисти жайылтуу үчүн колдоно баштаганыңызды элестетиңиз. Кийинчерээк кызматыңыздын атын тилкеге ​​өзгөрткүңүз келет. Бул өзгөртүү анча маанилүү эместей сезилиши мүмкүн, бирок чындыгында бул кызматтын үзгүлтүккө учурашына алып келиши мүмкүн.

    Чындыгында, веб-сервер-кластер модулу бир катар ресурстарда cluster_name өзгөрмөсүн колдонот, анын ичинде эки коопсуздук тобунун аталышы жана 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]
    }

    Эгер сиз ресурстун аталышынын параметрин өзгөртсөңүз, Terraform ал ресурстун эски версиясын жок кылып, анын ордуна жаңысын түзөт. Бирок бул ресурс ALB болсо, аны жок кылуу менен жаңы версиясын жүктөөнүн ортосунда, сизде трафикти веб-сервериңизге багыттоо механизми болбойт. Ошо сыяктуу эле, эгер коопсуздук тобу жок кылынса, сервериңиз жаңы топ түзүлгөнгө чейин бардык тармак трафигин четке кага баштайт.

    Сизди кызыктырышы мүмкүн болгон рефакторингдин дагы бир түрү - Terraform идентификаторун өзгөртүү. Мисал катары вебсервер-кластер модулундагы aws_security_group ресурсун алалы:

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

    Бул ресурстун идентификатору инстанция деп аталат. Элестетиңиз, рефакторинг учурунда сиз аны түшүнүктүү (сиздин оюңузча) cluster_instance атына өзгөртүүнү чечтиңиз:

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

    Акыры эмне болот? Бул туура: бузулуу.

    Terraform ар бир ресурс идентификаторун булут камсыздоочу ID менен байланыштырат. Мисалы, iam_user AWS IAM колдонуучу ID менен, ал эми aws_instance AWS EC2 сервер ID менен байланышкан. Эгер сиз ресурстун идентификаторун өзгөртсөңүз (айталы, aws_security_group сыяктуу инстанциядан cluster_instanceге), Терраформга ал эски ресурсту жок кылып, жаңысын кошкондой көрүнөт. Эгер сиз бул өзгөртүүлөрдү колдонсоңуз, Terraform эски коопсуздук тобун жок кылып, жаңысын түзөт, ал эми серверлериңиз бардык тармак трафигинен баш тарта баштайт.

    Бул жерде сиз бул талкуудан алып салуу керек болгон төрт негизги сабак болуп саналат.

    • Ар дайым план буйругун колдонуңуз. Бул бардык кемчиликтерди ачып бере алат. Анын жыйынтыгын кылдаттык менен карап чыгыңыз жана Terraform жок кылбоо керек болгон ресурстарды жок кылууну пландаштырган жагдайларга көңүл буруңуз.
    • Жок кылуудан мурун түзүңүз. Эгерде сиз ресурсту алмаштыргыңыз келсе, түпнускасын жок кылуудан мурун алмаштырууну түзүү керекпи же жокпу, жакшылап ойлонуңуз. Эгер жооп ооба болсо, create_before_destroy жардам бере алат. Ошол эле натыйжага эки кадамды аткаруу менен кол менен жетүүгө болот: адегенде конфигурацияга жаңы ресурсту кошуп, колдонуу буйругун иштетиңиз, андан кийин эски ресурсту конфигурациядан алып салыңыз жана кайра колдонуу буйругун колдонуңуз.
    • Идентификаторлорду өзгөртүү абалды өзгөртүүнү талап кылат. Эгер сиз ресурс менен байланышкан идентификаторду өзгөртүүнү кааласаңыз (мисалы, aws_security_group атын инстанциядан cluster_instance деп өзгөрткүңүз келсе), ресурсту жок кылбастан жана анын жаңы версиясын түзбөсөңүз, Terraform мамлекеттик файлын ошого жараша жаңыртышыңыз керек. Муну эч качан кол менен жасабаңыз - анын ордуна terraform state буйругун колдонуңуз. Идентификаторлордун атын өзгөртүүдө, төмөнкү синтаксиске ээ болгон terraform state mv буйругун иштетүү керек:
      terraform state mv <ORIGINAL_REFERENCE> <NEW_REFERENCE>

      ORIGINAL_REFERENCE - бул ресурска учурдагы формадагы сөз айкашы, ал эми NEW_REFERENCE аны жылдыргыңыз келген жер. Мисалы, aws_security_group тобунун атын инстанциядан cluster_instance деп өзгөрткөндө, төмөнкү буйрукту аткарышыңыз керек:

      $ terraform state mv 
         aws_security_group.instance 
         aws_security_group.cluster_instance

      Бул Terraformга мурда aws_security_group.instance менен байланышкан абал эми aws_security_group.cluster_instance менен байланыштырылышы керектигин айтат. Эгерде бул команданын атын өзгөртүп, иштеткенден кийин terraform планы эч кандай өзгөртүүлөрдү көрсөтпөсө, анда сиз бардыгын туура кылдыңыз.

    • Кээ бир орнотууларды өзгөртүү мүмкүн эмес. Көптөгөн ресурстардын параметрлери өзгөрүлбөйт. Аларды өзгөртүүгө аракет кылсаңыз, Terraform эски ресурсту жок кылып, анын ордуна жаңысын түзөт. Ар бир ресурс барагында, адатта, белгилүү бир жөндөөнү өзгөрткөндө эмне болору көрсөтүлөт, андыктан документтерди текшерүүнү унутпаңыз. Ар дайым план буйругун колдонуңуз жана create_before_destroy стратегиясын колдонуңуз.

    Кийинкиге калтырылган ырааттуулук... кийинкиге калтыруу менен

    Кээ бир булут провайдерлеринин API'лери, мисалы, AWS, асинхрондуу жана ырааттуулугу кечеңдетилген. Асинхрондук интерфейс суралган аракетти күтпөстөн жоопту дароо кайтара ала тургандыгын билдирет. Кечиктирилген ырааттуулук өзгөрүүлөрдүн система боюнча жайылышына убакыт талап кылынышы мүмкүн дегенди билдирет; бул болуп жатканда, жоопторуңуз дал келбей калышы мүмкүн жана кайсы маалымат булагы репликасы API чалууларыңызга жооп берип жатканына жараша болушу мүмкүн.

    Мисалы, сиз AWSге API чалуу жасап, андан EC2 серверин түзүүнү суранганыңызды элестетиңиз. API сервердин өзү түзүлүшүн күтпөстөн, дээрлик ошол замат "ийгиликтүү" жоопту (201 Түзүлгөн) кайтарып берет. Эгер сиз ага дароо кошулууга аракет кылсаңыз, ал дээрлик ишке ашпай калат, анткени ал учурда AWS дагы эле ресурстарды инициализациялоодо же, же болбосо, сервер али жүктөлө элек. Мындан тышкары, бул сервер жөнүндө маалымат алуу үчүн дагы бир чалсаңыз, ката (404 Табылган жок) аласыз. Бул EC2 сервери жөнүндө маалымат ал бардык жерде жеткиликтүү болгонго чейин дагы эле AWS боюнча жайылтылат, бир нече секунд күтүшүңүз керек болот.

    Жалкоо ырааттуулугу бар асинхрондук API колдонгон сайын, аракет аягына чыгып, система аркылуу жайылмайынча сурамыңызды мезгил-мезгили менен кайталап көрүшүңүз керек. Тилекке каршы, AWS SDK бул үчүн эч кандай жакшы куралдарды бербейт жана Terraform долбоору 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

    Башкача айтканда, сиз ресурсту (субсет сыяктуу) түзүп, андан кийин ал жөнүндө кандайдыр бир маалымат алууга аракет кыласыз (жаңы түзүлгөн субсеттин идентификатору сыяктуу) жана Terraform аны таба албайт. Бул мүчүлүштүктөрдүн көбү (анын ичинде 6813) оңдолду, бирок алар дагы эле мезгил-мезгили менен пайда болот, айрыкча Terraform жаңы ресурс түрү үчүн колдоо кошкондо. Бул тажатма, бирок көпчүлүк учурда эч кандай зыян алып келбейт. Терраформ колдонмосун кайра иштеткенде, баары иштеши керек, анткени бул убакытка чейин маалымат бүт системага тараган болот.

    Бул үзүндү Евгений Брикмандын китебинен берилген "Terraform: код деңгээлиндеги инфраструктура".

Source: www.habr.com

Комментарий кошуу