Терраформалық тұзақтар

Терраформалық тұзақтар
Бірнеше қателіктерді, соның ішінде циклдерге, if мәлімдемелеріне және орналастыру әдістеріне, сондай-ақ жалпы Terraform-ға әсер ететін жалпы мәселелерге тоқталайық:

  • count және for_each параметрлерінде шектеулер бар;
  • нөлдік тоқтау уақытын орналастыруды шектеу;
  • тіпті жақсы жоспар да сәтсіздікке ұшырауы мүмкін;
  • рефакторингтің өз қателері болуы мүмкін;
  • кейінге қалдырылған когеренция сәйкес келеді... кейінге қалдырумен.

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

Бұл код та жақсы жұмыс істейді, өйткені санау параметрі деректер көздеріне еш қиындықсыз сілтеме жасай алады. Бірақ жасау керек серверлердің саны қандай да бір ресурстың шығысына байланысты болса не болады? Мұны көрсету үшін ең оңай жолы - аты айтып тұрғандай, кездейсоқ бүтін санды қайтаратын 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"
}

Егер сіз осы кодта терраформ жоспарын іске қоссаңыз, келесі қатені аласыз:

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 мәніне қайтарады, егер сіз іске қосылған серверлер санын көбейту үшін автомасштабтау ережелерін пайдалансаңыз, бұл мәселе болуы мүмкін.

Мысалы, веб-сервер-кластер модулінде таңғы 9-да кластердегі серверлер санын екіден онға дейін көбейтетін aws_autoscaling_schedule ресурстарының жұбы бар. Егер сіз, айталық, таңғы 11-де орналастырсаңыз, жаңа ASG он емес, екі сервермен жүктеледі және келесі күні таңғы 9-ға дейін сол күйінде қалады.

Бұл шектеуді бірнеше жолмен айналып өтуге болады.

  • 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 қандай инфрақұрылымды басқару керек екенін біледі. Импорттау пәрмені екі аргумент қабылдайды. Біріншісі - конфигурация файлдарындағы ресурс мекенжайы. Мұндағы синтаксис ресурс сілтемелерімен бірдей: _. (мысалы, aws_iam_user.existing_user). Екінші аргумент импортталатын ресурстың идентификаторы болып табылады. aws_iam_user ресурс идентификаторы пайдаланушы аты (мысалы, yevgeniy.brikman) және aws_instance ресурс идентификаторы 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-ға импорттағыңыз келетін ресурстар көп болса, кодты қолмен жазу және әрқайсысын бір уақытта импорттау қиындық тудыруы мүмкін. Сондықтан AWS есептік жазбаңыздан код пен күйді автоматты түрде импорттай алатын Terraforming (http://terraforming.dtan4.net/) сияқты құралды іздеген жөн.

    Рефакторингтің өз қателері болуы мүмкін

    Рефакторинг сыртқы әрекетті өзгеріссіз қалдыра отырып, кодтың ішкі құрылымын өзгертетін бағдарламалаудағы кең таралған тәжірибе. Бұл кодты түсінікті, ұқыпты және техникалық қызмет көрсетуді жеңілдету үшін. Рефакторинг - бұл үнемі қолданылуы керек таптырмас әдіс. Бірақ Terraform немесе кез келген басқа IaC құралы туралы сөз болғанда, код бөлігінің «сыртқы әрекеті» дегенді білдіретініңізге өте мұқият болуыңыз керек, әйтпесе күтпеген мәселелер туындайды.

    Мысалы, рефакторингтің кең таралған түрі айнымалылардың немесе функциялардың атауларын неғұрлым түсінікті атаулармен ауыстыру болып табылады. Көптеген IDE-де рефакторингке кірістірілген қолдау бар және бүкіл жобада айнымалылар мен функциялардың атын автоматты түрде өзгерте алады. Жалпы мақсаттағы бағдарламалау тілдерінде бұл тривиальды процедура, ол туралы сіз ойламауыңыз мүмкін, бірақ Terraform-да сіз мұны өте сақтықпен орындауыңыз керек, әйтпесе үзілістерге тап болуыңыз мүмкін.

    Мысалы, веб-сервер-кластер модулінде cluster_name кіріс айнымалысы бар:

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

    Сіз бұл модульді foo деп аталатын микросервисті қолдану үшін пайдалана бастадыңыз деп елестетіңіз. Кейінірек қызмет атауын жолақ деп өзгерткіңіз келеді. Бұл өзгеріс елеусіз болып көрінуі мүмкін, бірақ іс жүзінде бұл қызметтің бұзылуына әкелуі мүмкін.

    Мәселе мынада, веб-сервер-кластер модулі екі қауіпсіздік тобының атау параметрін және ALB қоса алғанда, бірқатар ресурстарда cluster_name айнымалысын пайдаланады:

    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 әрбір ресурс идентификаторын бұлт провайдері идентификаторымен байланыстырады. Мысалы, iam_user AWS IAM пайдаланушы идентификаторымен, ал aws_instance AWS EC2 сервер идентификаторымен байланысты. Ресурс идентификаторын өзгертсеңіз (айталық, aws_security_group сияқты мысалдан кластер_данасына), Terraform түріне ол ескі ресурсты жойып, жаңасын қосқан сияқты пайда болады. Осы өзгертулерді қолдансаңыз, Terraform ескі қауіпсіздік тобын жояды және жаңасын жасайды, ал серверлер кез келген желі трафигінен бас тарта бастайды.

    Міне, осы талқылаудан алу керек төрт негізгі сабақ.

    • Әрқашан жоспар пәрменін пайдаланыңыз. Ол осы бөртпелердің барлығын аша алады. Оның нәтижесін мұқият қарап шығыңыз және Terraform жойылмауы мүмкін ресурстарды жоюды жоспарлаған жағдайларға назар аударыңыз.
    • Жоймас бұрын жасаңыз. Ресурсты ауыстырғыңыз келсе, түпнұсқаны жоймас бұрын ауыстыруды жасау керек пе, соны мұқият ойластырыңыз. Жауап иә болса, create_befor_destroy көмектесе алады. Дәл осындай нәтижеге екі қадамды орындау арқылы қолмен қол жеткізуге болады: алдымен конфигурацияға жаңа ресурс қосып, қолдану пәрменін іске қосыңыз, содан кейін конфигурациядан ескі ресурсты жойып, қолдану пәрменін қайта пайдаланыңыз.
    • Идентификаторларды өзгерту күйді өзгертуді қажет етеді. Ресурспен байланысты идентификаторды өзгерткіңіз келсе (мысалы, aws_security_group атын данадан кластер_данасына өзгерту) ресурсты жоймай және оның жаңа нұсқасын жасамай-ақ, Terraform күй файлын сәйкесінше жаңартуыңыз керек. Мұны ешқашан қолмен жасамаңыз - орнына terraform күй пәрменін пайдаланыңыз. Идентификаторлардың атын өзгерту кезінде келесі синтаксисі бар 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 серверіне EC2 серверін жасауды сұрайтын API қоңырауын жасайсыз деп елестетіңіз. 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 application қолданбасын қайта іске қосқан кезде бәрі жұмыс істеуі керек, өйткені осы уақытқа дейін ақпарат бүкіл жүйеге таралып қойған болады.

    Бұл үзінді Евгений Брикманның кітабынан ұсынылған «Терраформа: код деңгейіндегі инфрақұрылым».

Ақпарат көзі: www.habr.com

пікір қалдыру