Терраформ замке

Терраформ замке
Хајде да истакнемо неколико замки, укључујући оне везане за петље, иф изјаве и технике распоређивања, као и општија питања која утичу на Терраформ уопште:

  • параметри цоунт и фор_еацх имају ограничења;
  • ограничити нулте застоје у примени;
  • чак и добар план може пропасти;
  • рефакторинг може имати своје замке;
  • одложена кохерентност је у складу... са одлагањем.

Параметри цоунт и фор_еацх имају ограничења

Примери у овом поглављу у великој мери користе параметар бројања и израз фор_еацх у петљама и условној логици. Они раде добро, али имају два важна ограничења којих морате бити свесни.

  • Цоунт и фор_еацх не могу референцирати ниједну излазну променљиву ресурса.
  • цоунт и фор_еацх се не могу користити у конфигурацији модула.

цоунт и фор_еацх не могу референцирати ниједну излазну променљиву ресурса

Замислите да морате да примените неколико ЕЦ2 сервера и из неког разлога не желите да користите АСГ. Ваш код би могао бити овакав:

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

Погледајмо их један по један.

Пошто је параметар бројања постављен на статичку вредност, овај код ће радити без проблема: када покренете команду примени, креираће три ЕЦ2 сервера. Али шта ако желите да примените један сервер у свакој зони доступности (АЗ) у оквиру вашег тренутног АВС региона? Ваш код можете учитати листу зона из извора података авс_аваилабилити_зонес, а затим проћи кроз сваку од њих и креирати ЕЦ2 сервер у њој користећи параметар бројања и приступ индексу низа:

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

Овај код ће такође добро функционисати, пошто параметар бројања може без проблема да упућује на изворе података. Али шта се дешава ако број сервера које треба да креирате зависи од излаза неког ресурса? Да бисте то демонстрирали, најлакши начин је да користите ресурс рандом_интегер, који, као што име каже, враћа насумични цео број:

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

Овај код генерише насумични број између 1 и 3. Хајде да видимо шта се дешава ако покушамо да користимо излаз овог ресурса у параметру бројања ресурса авс_инстанце:

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

Ако покренете терраформ план на овом коду, добићете следећу грешку:

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.

Терраформ захтева да се цоунт и фор_еацх израчунају током фазе планирања, пре него што се креирају или модификују било какви ресурси. То значи да се цоунт и фор_еацх могу односити на литерале, променљиве, изворе података, па чак и листе ресурса (све док се њихова дужина може одредити у време планирања), али не и на израчунате излазне варијабле ресурса.

цоунт и фор_еацх се не могу користити у конфигурацији модула

Једног дана ћете можда бити у искушењу да додате параметар бројања у конфигурацију модула:

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

     count = 3

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

Овај код покушава да користи цоунт унутар модула за креирање три копије ресурса кластера веб сервера. Или бисте можда желели да повезивање модула учините опционим на основу неког Буловог услова тако што ћете поставити његов параметар бројања на 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.

Нажалост, од Терраформ 0.12.6, коришћење цоунт или фор_еацх у ресурсу модула није подржано. Према напоменама о издању Терраформ 0.12 (хттп://бит.ли/3257бв4), ХасхиЦорп планира да дода ову могућност у будућности, тако да у зависности од тога када прочитате ову књигу, можда ће већ бити доступна. Да сазнам сигурно, прочитајте Терраформ дневник промена овде.

Ограничења имплементације без застоја

Коришћење блока цреате_бефоре_дестрои у комбинацији са АСГ-ом је одлично решење за креирање имплементација без прекида рада, осим једног упозорења: правила аутоматског скалирања нису подржана. Или да будемо прецизнији, ово враћа АСГ величину на мин_сизе при сваком постављању, што би могао бити проблем ако користите правила за аутоматско скалирање да бисте повећали број сервера који раде.

На пример, модул вебсервер-цлустер садржи пар ресурса авс_аутосцалинг_сцхедуле, који у 9 ујутро повећава број сервера у кластеру са два на десет. Ако се распоредите у, рецимо, 11:9, нови АСГ ће се покренути са само два сервера, а не са десет и тако ће остати до XNUMX:XNUMX следећег дана.

Ово ограничење се може заобићи на неколико начина.

  • Промените параметар понављања у авс_аутосцалинг_сцхедуле са 0 9 * * * („покрени у 9 ујутро“) на нешто попут 0-59 9-17 * * * („покрени сваког минута од 9 до 5 часова“). Ако АСГ већ има десет сервера, поновно покретање овог правила аутоматског скалирања неће ништа променити, што и желимо. Али ако је АСГ тек недавно распоређен, ово правило ће обезбедити да за највише минут број његових сервера достигне десет. Ово није сасвим елегантан приступ, а велики скокови са десет на два сервера и назад такође могу да изазову проблеме корисницима.
  • Креирајте прилагођену скрипту која користи АВС АПИ за одређивање броја активних сервера у АСГ-у, позовите је помоћу екстерног извора података (погледајте „Спољни извор података” на страници 249) и подесите жељени параметар АСГ-а на вредност коју враћа скрипта. На овај начин, свака нова АСГ инстанца ће увек радити са истим капацитетом као постојећи Терраформ код и отежава је одржавање.

Наравно, Терраформ би идеално имао уграђену подршку за имплементације без застоја, али од маја 2019, ХасхиЦорп тим није планирао да дода ову функционалност (детаљи - овде).

Исправан план може бити неуспешно спроведен

Понекад команда план производи савршено исправан план примене, али команда аппли враћа грешку. Покушајте, на пример, да додате ресурс авс_иам_усер са истим именом које сте користили за ИАМ корисника којег сте креирали раније у 2. поглављу:

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

Сада, ако покренете команду плана, Терраформ ће произвести наизглед разуман план распоређивања:

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

Проблем је, наравно, што ИАМ корисник са тим именом већ постоји. И то се може догодити не само корисницима ИАМ-а, већ и скоро сваком ресурсу. Могуће је да је неко креирао овај ресурс ручно или користећи командну линију, али у сваком случају, подударање ИД-ова доводи до сукоба. Постоји много варијација ове грешке које често изненаде новопридошлице у Терраформу.

Кључна ствар је да команда терраформ плана узима у обзир само оне ресурсе који су наведени у датотеци стања Терраформ. Ако су ресурси креирани на неки други начин (на пример, ручно кликом на АВС конзоли), они неће завршити у датотеци стања и стога их Терраформ неће узети у обзир приликом извршавања команде плана. Као резултат тога, план који се на први поглед чини исправним ће се показати неуспешним.

Из овога се могу извући две лекције.

  • Ако сте већ почели да радите са Терраформом, немојте користити ништа друго. Ако се делом ваше инфраструктуре управља помоћу Терраформа, више не можете ручно да га мењате. У супротном, не само да ризикујете чудне грешке Терраформа, већ такође негирате многе предности ИаЦ-а јер код више неће бити тачан приказ ваше инфраструктуре.
  • Ако већ имате неку инфраструктуру, користите команду импорт. Ако почињете да користите Терраформ са постојећом инфраструктуром, можете га додати у датотеку стања помоћу команде терраформ импорт. На овај начин Терраформ ће знати којом инфраструктуром треба управљати. Команда импорт узима два аргумента. Прва је адреса ресурса у вашим конфигурационим датотекама. Овде је синтакса иста као и за везе ресурса: _. (као авс_иам_усер.екистинг_усер). Други аргумент је ИД ресурса за увоз. Рецимо да је ИД ресурса авс_иам_усер корисничко име (на пример, иевгении.брикман), а ИД ресурса авс_инстанце је ИД ЕЦ2 сервера (као и-190е22е5). Како да увезете ресурс је обично назначено у документацији на дну његове странице.

    Испод је команда за увоз која синхронизује ресурс авс_иам_усер који сте додали у своју Терраформ конфигурацију заједно са ИАМ корисником у поглављу 2 (наравно, замењујући ваше име за иевгении.брикман):

    $ terraform import aws_iam_user.existing_user yevgeniy.brikman

    Терраформ ће позвати АВС АПИ да пронађе вашег ИАМ корисника и креира асоцијацију датотеке стања између њега и ресурса авс_иам_усер.екистинг_усер у вашој Терраформ конфигурацији. Од сада, када покренете команду плана, Терраформ ће знати да ИАМ корисник већ постоји и неће покушати поново да га креира.

    Вреди напоменути да ако већ имате пуно ресурса које желите да увезете у Терраформ, ручно писање кода и увоз сваког појединачно може бити проблем. Дакле, вреди погледати алат као што је Терраформинг (хттп://терраформинг.дтан4.нет/), који може аутоматски да увезе код и стање са вашег АВС налога.

    Рефакторинг може имати своје замке

    Рефакторинг је уобичајена пракса у програмирању где мењате унутрашњу структуру кода, а спољашње понашање остављате непромењеним. Ово је да би код био јаснији, уреднији и лакши за одржавање. Рефакторинг је незаменљива техника коју треба редовно користити. Али када је у питању Терраформ или било који други ИаЦ алат, морате бити изузетно опрезни шта подразумевате под „спољним понашањем“ дела кода, иначе ће се појавити неочекивани проблеми.

    На пример, уобичајен тип рефакторинга је замена имена променљивих или функција разумљивијим. Многи ИДЕ имају уграђену подршку за рефакторисање и могу аутоматски преименовати променљиве и функције током целог пројекта. У програмским језицима опште намене, ово је тривијална процедура о којој можда нећете размишљати, али у Терраформу морате бити изузетно опрезни са овим, иначе можете доживети прекиде.

    На пример, модул вебсервер-цлустер има улазну променљиву цлустер_наме:

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

    Замислите да сте почели да користите овај модул за примену микросервиса под називом фоо. Касније желите да преименујете своју услугу у бар. Ова промена може изгледати тривијално, али у стварности може изазвати поремећаје у услузи.

    Чињеница је да модул веб сервер-цлустер користи променљиву цлустер_наме у бројним ресурсима, укључујући параметар имена две безбедносне групе и АЛБ:

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

    Ако промените параметар имена на ресурсу, Терраформ ће избрисати стару верзију тог ресурса и креирати нову на њеном месту. Али ако је тај ресурс АЛБ, између брисања и преузимања нове верзије, нећете имати механизам за преусмеравање саобраћаја на ваш веб сервер. Слично томе, ако се безбедносна група избрише, ваши сервери ће почети да одбијају сваки мрежни саобраћај док се не креира нова група.

    Други тип рефакторисања који би вас могао занимати је промена Терраформ ИД-а. Узмимо за пример ресурс авс_сецурити_гроуп у модулу веб сервер-кластера:

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

    Идентификатор овог ресурса се назива инстанца. Замислите да сте током рефакторисања одлучили да га промените у разумљивије (по вашем мишљењу) име цлустер_инстанце:

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

    Шта ће се на крају десити? Тако је: поремећај.

    Терраформ повезује сваки ИД ресурса са ИД-ом добављача у облаку. На пример, иам_усер је повезан са АВС ИАМ корисничким ИД-ом, а авс_инстанце је повезан са ИД-ом АВС ЕЦ2 сервера. Ако промените ИД ресурса (рецимо са инстанце на цлустер_инстанце, као што је случај са авс_сецурити_гроуп), у Терраформ ће изгледати као да сте избрисали стари ресурс и додали нови. Ако примените ове промене, Терраформ ће избрисати стару безбедносну групу и креирати нову, док ће ваши сервери почети да одбијају сваки мрежни саобраћај.

    Ево четири кључне лекције које треба да извучете из ове дискусије.

    • Увек користите команду план. Може открити све ове препреке. Пажљиво прегледајте његов излаз и обратите пажњу на ситуације у којима Терраформ планира да избрише ресурсе који највероватније не би требало да буду избрисани.
    • Креирајте пре него што избришете. Ако желите да замените ресурс, добро размислите да ли треба да направите замену пре него што избришете оригинал. Ако је одговор да, цреате_бефоре_дестрои може помоћи. Исти резултат се може постићи ручно извођењем два корака: прво додајте нови ресурс у конфигурацију и покрените команду примени, а затим уклоните стари ресурс из конфигурације и поново користите команду примени.
    • Промена идентификатора захтева промену стања. Ако желите да промените ИД повезан са ресурсом (на пример, преименујте авс_сецурити_гроуп из инстанце у цлустер_инстанце) без брисања ресурса и креирања нове верзије истог, морате у складу са тим ажурирати датотеку стања Терраформ. Никада немојте ово радити ручно - уместо тога користите команду терраформ стате. Када преименујете идентификаторе, требало би да покренете команду терраформ стате мв, која има следећу синтаксу:
      terraform state mv <ORIGINAL_REFERENCE> <NEW_REFERENCE>

      ОРИГИНАЛ_РЕФЕРЕНЦЕ је израз који се односи на ресурс у његовом тренутном облику, а НЕВ_РЕФЕРЕНЦЕ је место на које желите да га преместите. На пример, када преименујете групу авс_сецурити_гроуп из инстанце у цлустер_инстанце, потребно је да покренете следећу команду:

      $ terraform state mv 
         aws_security_group.instance 
         aws_security_group.cluster_instance

      Ово говори Терраформу да стање које је претходно било повезано са авс_сецурити_гроуп.инстанце сада треба да буде повезано са авс_сецурити_гроуп.цлустер_инстанце. Ако након преименовања и покретања ове команде терраформ план не покаже никакве промене, онда сте све урадили исправно.

    • Нека подешавања се не могу променити. Параметри многих ресурса су непроменљиви. Ако покушате да их промените, Терраформ ће избрисати стари ресурс и на његовом месту створити нови. Свака страница ресурса ће обично назначити шта се дешава када промените одређену поставку, па обавезно проверите документацију. Увек користите команду план и размислите о коришћењу стратегије цреате_бефоре_дестрои.

    Одложена доследност је у складу... са одлагањем

    АПИ-ји неких добављача облака, као што је АВС, су асинхрони и имају одложену доследност. Асинхрони значи да интерфејс може одмах да врати одговор без чекања да се захтевана радња заврши. Одложена доследност значи да променама може бити потребно време да се прошире кроз систем; док се ово дешава, ваши одговори могу бити недоследни и зависе од тога која реплика извора података одговара на ваше АПИ позиве.

    Замислите, на пример, да упутите АПИ позив АВС-у тражећи од њега да креира ЕЦ2 сервер. АПИ ће вратити „успешан“ одговор (201 Цреатед) скоро тренутно, без чекања да се сам сервер креира. Ако покушате да се одмах повежете са њим, готово сигурно неће успети јер у том тренутку АВС још увек иницијализује ресурсе или, алтернативно, сервер се још није покренуо. Штавише, ако упутите други позив да бисте добили информације о овом серверу, можда ћете добити грешку (404 Није пронађено). Ствар је у томе што се информације о овом ЕЦ2 серверу и даље могу ширити кроз АВС пре него што постану доступне свуда, мораћете да сачекате неколико секунди.

    Кад год користите асинхрони АПИ са лењом конзистентношћу, морате периодично да понављате свој захтев док се радња не заврши и прошири кроз систем. Нажалост, АВС СДК не пружа никакве добре алате за ово, а пројекат Терраформ је патио од много грешака као што је 6813 (хттпс://гитхуб.цом/хасхицорп/терраформ/иссуес/6813):

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

    Другим речима, креирате ресурс (попут подмреже) и затим покушавате да добијете неке информације о њему (као што је ИД новокреиране подмреже), а Терраформ не може да га пронађе. Већина ових грешака (укључујући 6813) је исправљена, али се и даље појављују с времена на време, посебно када Терраформ додаје подршку за нови тип ресурса. Ово је неугодно, али у већини случајева не узрокује никакву штету. Када поново покренете терраформ аппли, све би требало да функционише, пошто ће се до тада информације већ проширити по систему.

    Овај одломак је представљен из књиге Евгенија Брикмана „Терраформ: инфраструктура на нивоу кода“.

Извор: ввв.хабр.цом

Додај коментар