Апісанне інфраструктуры ў Terraform на будучыню. Антон Бабенка (2018г)
Многія ведаюць і выкарыстоўваюць Terraform у паўсядзённай працы, але для яго да гэтага часу не сфармаваліся лепшыя практыкі. Кожнай камандзе даводзіцца вынаходзіць свае падыходы, метады.
Ваша інфраструктура амаль напэўна пачынаецца проста: некалькі рэсурсаў + некалькі распрацоўшчыкаў. З часам яна расце ў разнастайныя бакі. Вы знаходзіце спосабы згрупаваць рэсурсы ў Terraform-модулі, арганізаваць код па тэчках, і што тут увогуле можа пайсці не так? (вядомыя апошнія словы)
Праходзіць час, і вы адчуваеце, што ваша інфраструктура - гэта ваш новы гадаванец, але чаму? Вас турбуюць невытлумачальныя змены ў інфраструктуры, вы баіцеся дакранацца да інфраструктуры і коду - у выніку вы затрымліваеце новы функцыянал або зніжаеце якасць…
Пасля трох гадоў кіравання на Github калекцыяй community-модуляў Terraform для AWS і доўгатэрміновым падтрыманні Terraform у прадакшэне, Антон Бабенка гатовы падзяліцца сваім досведам: як пісаць TF-модулі, каб не было балюча ў будучыні.
Да канца дакладу ўдзельнікі будуць лепей знаёмыя з прынцыпамі кіравання рэсурсамі ў Terraform, лепшымі практыкамі, звязанымі з модулямі ў Terraform, і некаторымі прынцыпамі бесперапыннай інтэграцыі, звязанымі з кіраваннем інфраструктурай.
Адмова ад адказнасці:Заўважу, што даклад гэты датаваны лістападам 2018 года - прайшло ўжо 2 гады. Разгляданая ў дакладзе версія Terraform 0.11 ужо не падтрымліваецца. За мінулыя 2 гады выйшла 2 новых рэлізаў, у якіх з'явілася маса навін, паляпшэнняў і змен. Прашу на гэта звярнуць увагу і зверацца з дакументацыяй.
Мяне клічуць Антон Бабенка. Хтосьці з вас, напэўна, выкарыстаў код, які я пісаў. Я зараз буду пра гэта казаць з большай упэўненасцю, чым калі-небудзь, таму што ў мяне ёсць доступ да статыстыкі.
Я займаюся Terraform і з'яўляюся актыўным удзельнікам і кантрыб'ютарам у вялікай колькасці open source праектаў, звязаных з Terraform і Amazon з 2015-га года.
Прыкладна з тых часоў я напісаў дастаткова кода, каб выкласці гэта ў цікавым выглядзе. І пра гэта я паспрабую зараз расказаць.
Я буду расказваць пра тонкасці і пра спецыфіку працы з Terraform. Але на самой справе гэта не з'яўляецца прадметам для HighLoad. І зараз вы зразумееце чаму.
З часам я пачаў пісаць Terraform-модулі. Карыстальнікі пісалі пытанні, я іх перапісваў. Пасля я напісаў розныя ўтыліты для фарматавання кода з дапамогай pre-commit hook і г.д.
Было шмат цікавых праектаў. Мне падабаецца займацца кодагенераваннем, таму што я люблю, каб кампутар рабіў усё больш і больш працы за мяне і за праграміста, таму зараз працую над генератарам Terraform-кода з візуальных дыяграм. Магчыма, нехта з вас іх бачыў. Гэта прыгожыя скрыначкі са стрэлачкамі. І я лічу, што гэта выдатна, калі можна націснуць кнопачку "Экспарт" і атрымаць гэта ўсё як код.
Я з Украіны. Я жыву шмат гадоў у Нарвегіі.
Таксама інфармацыя для гэтага даклада была сабрана ад людзей, якія ведаюць маё імя і знаходзяць мяне ў сацыяльных сетках. У мяне амаль заўсёды адзін і той жа нік.
Як я згадаў, я з'яўляюся галоўным мэйнтэйнерам Terraform AWS modules, які з'яўляецца адной з самых вялікіх рэпазітароў на GitHub, дзе мы хостым модулі для самых распаўсюджаных задач: VPC, Autoscaling, RDS.
І тое, што вы чулі зараз, гэта самае-самае базавае. Калі вы сумняваецеся, што вы разумееце, што такое Terraform, то лепш бавіць час дзе-небудзь у іншым месцы. Тут будзе шмат тэхнічных тэрмінаў. І ўзровень даклада я не пасаромеўся заявіць самым максімальным. Гэта значыць, што я магу расказваць, выкарыстоўваючы ўсе-ўсе магчымыя тэрміны без асаблівага тлумачэння.
Terraform з'явіўся ў 2014 годзе як утыліта, якая дазваляла пісаць, планаваць і кіраваць інфраструктурай як код. Ключавое паняцце тут "інфраструктура як код".
Уся дакументацыя, як я сказаў, напісана на terraform.io. Я спадзяюся, што большасць ведаюць пра гэты сайт і прачыталі дакументацыю. Калі так, то вы ў патрэбным месцы.
Вось так выглядае звычайны Terraform-канфігурацыйны файл, дзе мы спачатку вызначаем нейкія зменныя.
У дадзеным выпадку мы вызначаем "aws_region".
Пасля мы апісваем, якія рэсурсы мы хочам стварыць.
Запускаем нейкія каманды, у прыватнасці "terraform init" для таго, каб загрузіць залежнасці, правайдэры.
І запускаем каманду "terraform apply" для таго, каб праверыць ці адпавядае паказаная канфігурацыя тым рэсурсам, якія стварылі. Бо мы нічога не стваралі да гэтага, то Terraform прапануе нам стварыць гэтыя рэсурсы.
Мы пацвярджаем гэта. Такім чынам мы ствараем bucket, які называецца seasnail.
Ёсць таксама некалькі падобных утыліт. Многія з вас, хто карыстаецца Amazon, ведаюць AWS CloudFormation ці Google Cloud Deployment Manager, ці Azure Resource Manager. У кожнага з іх ёсць свая нейкая рэалізацыя для кіравання рэсурсамі ўсярэдзіне кожнага з гэтых public cloud правайдэраў. Terraform асабліва карысны ў той сувязі, што ён дазваляе кіраваць больш за 100 правайдэрамі. (Больш падрабязна тут)
Мэты, якія пераследваў Terraform з самага пачатку:
Terraform дае адзіны від рэсурсаў.
Дазваляе падтрымліваць усе сучасныя платформы.
І Terraform з самага пачатку задумваўся як утыліта, якая дазваляе мяняць інфраструктуру бяспечна і прадказальна.
У 2014-ым годзе слова "прадказальна" гучала вельмі незвычайна ў дадзеным кантэксце.
Terraform з'яўляецца ўніверсальнай утылітай. Калі ў вас ёсць API, то можна кіраваць зусім усім:
Можна выкарыстоўваць больш за 120 правайдэраў для кіравання ўсім, да чаго душа ляжыць.
Напрыклад, можна выкарыстоўваць Terraform для апісання доступу да GitHub рэпазітарам.
Можна нават багі ў Jira ствараць і зачыняць.
Можна кіраваць New Relic-метрыкамі.
Можна нават файлы ў dropbox ствараць, калі вельмі жадаецца.
Гэта ўсё дасягаецца з дапамогай Terraform-правайдэраў, у якіх адчынены API, якія можна апісаць на Go.
Дапусцім, мы пачалі выкарыстоўваць Terraform, прачыталі нейкую дакументацыю на сайце, паглядзелі нейкае відэа, пачалі пісаць main.tf, як я паказваў на папярэдніх слайдах.
І ў вас усё класна, у вас атрымаўся файл, які стварае VPC.
Калі вы жадаеце стварыць VPC, тыя вы паказваеце прыкладна вось гэтыя 12 радкоў. Апісваеце ў якім рэгіёне вы хочаце стварыць, які cidr_block IP-адрасоў выкарыстоўваць. І ўсё.
Натуральна, паступова праект будзе расці.
І вы будзеце дадаваць туды кучу новага за ўсё: рэсурсы, крыніцы дадзеных, вы будзеце інтэгравацца з новымі правайдэрамі, нечакана вы захочаце выкарыстоўваць Terraform для таго, каб кіраваць карыстальнікамі ў вашым GitHub-акаўнце і г. д. Вы можаце захацець выкарыстоўваць розныя DNS-правайдэры , скрыжаваць усё запар. Terraform лёгка дазваляе гэта рабіць.
Разгледзім наступны прыклад.
Вы паступова дадаеце internet_gateway, таму што вы хочаце, каб рэсурсы з вашага VPC мелі доступ у інтэрнэт. Гэта добрая ідэя.
У выніку атрымліваецца вось такі main.tf:
Гэта верхняя частка main.tf.
Гэта ніжняя частка main.tf.
Потым вы дадаеце subnet. Да таго моманту, калі вы захочаце дадаць NAT gateways, routes, routing tables і кучу іншых subnets, у вас будзе не 38 радкоў, а прыкладна 200-300 радкоў.
Т. е. ваш main.tf файл паступова расце. І даволі часта людзі складаюць усё ў адзін файл. У main.tf з'яўляецца 10-20 Kb. Уявіце, што 10-20 Kb - гэта тэкставы кантэнт. І ўсё з усім звязана. З гэтым працаваць паступова робіцца складана. 10-20 Kb - гэта добры user case, бывае і больш. І не заўжды людзі лічаць, што гэта дрэнна.
Як і ў звычайным праграмаванні, т. е. не інфраструктура як код, мы абвыклі выкарыстаць кучу розных класаў, пакетаў, модуляў, групоўкі. Terraform дазваляе рабіць прыкладна тое ж самае.
Код расце.
Залежнасці паміж рэсурсамі таксама растуць.
І ў нас узнікае вялікая-вялікая галеча. Мы разумеем, што гэтак жыць мы далей не можам. У нас код становіцца неабсяжным. 10-20 Kb - гэта, вядома, не вельмі неабсяжны, але гэта мы гаворым толькі аб network stack, г. зн. вы дадалі толькі сеткавыя рэсурсы. Мы не гаворым яшчэ аб Application Load Balancer, deployment ES cluster, Kubernetes і г. д., куды яшчэ лёгка можна ўплесці 100 Kb. Калі вы ўсё гэта напішыце, тыя вы вельмі хутка даведаецеся, што Terraform падае Terraform-модулі.
Terraform-модулі - гэта самадастатковая Terraform-канфігурацыя, якая кіруецца як група. Гэта ўсё, што трэба ведаць аб Terraform-модулях. Яны ніякія не разумныя, яны не дазваляюць рабіць вам нейкія складаныя падключэнні ў залежнасці ад чагосьці. Гэта ўсё кладзецца на плечы распрацоўшчыкаў. Гэта проста нейкая Terraform-канфігурацыя, якую вы ўжо напісалі. І можна проста яе выклікаць як групу.
Такім чынам мы спрабуем зразумець, як мы будзем аптымізаваць нашы 10-20-30 Kb кода. Мы паступова разумеем, што трэба выкарыстоўваць нейкія модулі.
Першы тып модуляў, які сустракаецца, гэта рэсурсныя модулі. Яны не разумеюць, пра што ваша інфраструктура, пра што ваш бізнэс, дзе і якія ўмовы. Гэта менавіта тыя модулі, якія я разам з open source супольнасцю адмініструем, і якія мы выстаўляем, як самы пачатковы building blocks для вашай інфраструктуры.
Прыклад рэсурснага модуля.
Калі мы выклікаем рэсурсны модуль, мы паказваем, з якога шляху мы павінны загрузіць яго змесціва.
Мы паказваем якой версіі мы хочам загрузіць.
Мы перадаем кучу аргументаў туды. І ўсё. Гэта ўсё, што нам трэба ведаць, калі мы выкарыстоўваем гэты модуль.
Многія думаюць, што калі выкарыстоўваць апошнюю версію, то ўсё будзе стабільна. Але не. Інфраструктура павінна быць версійнай, мы дакладна павінны адказаць, якой версіі была задэплоена тая ці іншая кампанента.
Перад вамі код, які знаходзіцца ўнутры гэтага модуля. Модуль security-group. Тут скролл ідзе да 640-га радка. Стварэнне security-croup рэсурсу ў Amazon у разнастайнай канфігурацыі - гэта вельмі нетрывіяльная задача. Нядосыць проста стварыць security-group і сказаць, якія правілы ёй перадаваць. Гэта было б вельмі проста. Унутры Amazon ёсць мільён розных абмежаванняў. Напрыклад, калі вы карыстаецеся VPC endpoint, prefix list, розныя API і спрабуе гэта ўсё з усім скрыжаваць, то Terraform не дазваляе вам гэта зрабіць. І Amazon API таксама не дазваляе гэта. Таму трэба схаваць гэтую ўсю страшную логіку ў модуль і карыстачу выдаваць код, які выглядае толькі вось так.
Карыстальніку не трэба ведаць, як унутры яно зроблена.
Другі тып модуляў, які складаецца з рэсурсных модуляў, ужо вырашае задачы, якія больш дастасавальныя для вашага бізнесу. Часта гэтае месца, якое з'яўляецца пашырэннем для Terraform і задае нейкія цвёрдыя значэнні для тэгаў, для стандартаў кампаніі. Таксама там можна дадаваць функцыянал, які Terraform не дазваляе зараз выкарыстоўваць. Гэта менавіта зараз. Цяпер версія 0.11, якая вось-вось адыдзе ў мінулае. Але ўсё роўна прэпрацэсары, jsonnet, cookiecutter і куча іншых рэчаў з'яўляюцца тым дапаможным механізмам, які трэба выкарыстоўваць для паўнавартаснай працы.
Далей я пакажу некаторыя прыклады гэтага.
Інфраструктурны модуль выклікаецца сапраўды такім жа спосабам.
Указваецца крыніца, адкуль загрузіць кантэнт.
Перадаецца куча значэнняў, якія перадаюцца ў гэты модуль.
Далей усярэдзіне гэтага модуля выклікаецца куча рэсурсных модуляў для стварэння VPC ці Application Load Balancer, ці для стварэння security-group ці для Elastic Container Service кластара.
Ёсць два тыпу модуляў. Гэта важна разумець, таму што большасць інфармацыі, якую я згрупаваў у гэтым дакладзе, не напісана ў дакументацыі.
І дакументацыя ў Terraform прама цяпер дастаткова праблематычная, таму што яна проста кажа, што ёсць такія фічы, вы можаце іх выкарыстоўваць. Але яна не кажа, як гэтыя фічы выкарыстоўваць, чаму так лепш выкарыстоўваць. Таму вельмі шмат людзей пішуць нешта, з чым потым нельга жыць.
Давайце далей паглядзім, як пісаць гэтыя модулі. Потым паглядзім, як іх выклікаць і як працаваць з кодам.
Савет № 0 - гэта не пісаць рэсурсныя модулі. Большасць гэтых модуляў ужо напісана за вас. Як я казаў, яны open source, яны не ўтрымліваюць ніякай вашай бізнес-логікі, у іх няма захардскураныя значэнняў для IP-адрасоў, пароляў і г. д. Модуль з'яўляецца вельмі flexible. І ён ужо, хутчэй за ўсё, напісаны. Для рэсурсаў ад Amazon модуляў шмат. Каля 650. І большасць з іх добрай якасці.
На дадзеным прыкладзе да вас прыйшоў нехта і сказаў: «Я хачу мець магчымасць кіраваць базай дадзеных. Ствары модуль, каб я мог ствараць базу дадзеных». Чалавек не ведае падрабязнасцяў рэалізацыі ні Amazon, ні Terraform. Ён проста кажа: "Я хачу кіраваць MSSQL". Т. е. мы маем на ўвазе, што ён будзе выклікаць наш модуль, перадасць туды тып рухавічка, пакажа time-зону.
І чалавек не павінен ведаць, што мы ўсярэдзіне гэтага модуля будзем ствараць два розных рэсурсу: адзін для MSSQL, другі для ўсяго астатняга толькі таму, што ў Terraform 0.11 нельга паказваць значэнні time-зоны неабавязковым.
І на выхадзе з гэтага модуля чалавек будзе мець магчымасць атрымліваць адрас. Ён не будзе ведаць з якой базы дадзеных, з якога рэсурсу мы ўнутры гэта ўсё ствараем. Гэта вельмі важны элемент утойвання. І гэта дастасавальна не толькі для тых модуляў, якія знаходзяцца ў public у open source, а таксама для тых модуляў, якія вы будзеце пісаць усярэдзіне сваіх праектаў, каманд.
Вось гэта другі аргумент, які зяўляецца даволі важным, калі вы карыстаецеся Terraform нейкі час. У вас ёсць рэпазітар, у якім вы складаеце ўсе свае Terraform-модулі для вашай кампаніі. І цалкам нармальна, што з часам гэты праект вырасце да памеру аднаго-двух мегабайт. Гэта нармальна.
Але праблема заключаецца ў тым, як Terraform выклікае гэтыя модулі. Напрыклад, калі вы будзеце выклікаць модуль для стварэння кожнага індывідуальнага карыстача, то Terraform спачатку будзе загружаць увесь рэпазітар, а потым пераходзіць у тэчку, дзе знаходзяцца менавіта гэты модуль. Такім чынам вы будзеце кожны раз загружаць па адным мегабайце. Калі вы кіруеце 100 ці 200 карыстачамі, тыя вы загрузіце 100 ці 200 мегабайт, а потым ужо пяройдзеце ў тую тэчку. Такім чынам, натуральна, вы не хочаце кожны раз, калі націскаеце "Terraform init" загружаць кучу за ўсё.
Ёсць два рашэнні гэтай праблемы. Першае заключаецца ў тым, каб выкарыстоўваць адносныя шляхі. Такім чынам вы ў кодзе паказваеце, што тэчка лакальная (./). І перад тым, як нешта запускаць, вы робіце Git clone гэтага рэпазітара лакальна. Такім чынам, вы робіце гэта адзін раз.
Ёсць, вядома, куча downsides. Напрыклад, што нельга выкарыстоўваць versioning. І з гэтым часам цяжка жыць.
Другое рашэнне. Калі ў вас шмат падмодуляў і ў вас ёсць ужо нейкі ўстаканены pipeline, гэта значыць праект MBT, які дазваляе збіраць з монорепозитория шмат розных пакетаў і загружаць іх на S3. Гэта вельмі добры спосаб. Такім чынам, файл iam-user-1.0.0.zip будзе важыць усяго толькі 1 Kb, таму што код для стварэння гэтага рэсурсу вельмі маленькі. І гэта будзе нашмат хутчэй працаваць.
Пагаворым аб тым, што нельга выкарыстоўваць у модулях.
Чаму ў модулях гэта зло? Самая страшная рэч - гэта assume user. Assume user - гэта такі варыянт аўтэнтыфікацыі ў правайдэр, які могуць выкарыстоўваць розныя людзі. Напрыклад, мы ўсё будзем асюміць ролю. Гэта значыць, што Terraform будзе прымаць гэтую ролю. І потым з гэтай роляй будзе выконваць астатнія дзеянні.
І зло складаецца ў тым, што калі Вася кахае падлучацца да Amazon адным спосабам, напрыклад, выкарыстаючы па змаўчанні пераменнае асяроддзе, а Пеця кахае выкарыстаць свой shared key, які ў яго знаходзіцца ў сакрэтным месцы, то ў Terraform нельга паказваць і тое і іншае. І для таго, каб яны не зведвалі пакут, не трэба гэты блок паказваць у модулі. Гэта трэба ўказваць узроўнем вышэй. Т. е. у нас ёсць рэсурсны модуль, інфраструктурны модуль і кампазіцыя зверху. І дзе-небудзь вышэй гэта трэба ўказваць.
Другое зло заключаецца ў provisioner. Тут зло не настолькі трывіяльнае, таму што калі пішыце код і для вас ён працуе, тыя вы можаце падумаць, што калі ён працуе, то навошта змяняць.
Зло заключаецца ў тым, што гэты provisioner вы не заўсёды кантралюеце, калі ен канкрэтна будзе запускацца, па-першае. І, па-другое, вы не кантралюеце, што значыць aws ec2, т. е. мы гаворым зараз пра Linux ці пра Windows. Такім чынам, вы не можаце пісаць нешта, што будзе працаваць аднолькава ў розных аперацыйных сістэмах ці для розных user cases.
Самы распаўсюджаны прыклад, які ў тым ліку паказаны ў афіцыйнай дакументацыі, гэта тое, што калі вы пішыце aws_instance, паказваеце кучу аргументаў, то нічога дрэннага ў гэтым няма, калі вы ўкажаце там і provisioner «local-exec» і запусціце свой ansible-playbook .
Насамрэч - так, нічога дрэннага ў гэтым няма. Але літаральна хутка вы ўсведамляеце, што вось гэтая штука local-exec не існуе, напрыклад, у launch_configuration.
І калі вы выкарыстоўваеце launch_configuration, і вы жадаеце з аднаго instance стварыць autoscaling group, то ў launch_configuration няма паняцця "provisioner". Там ёсць паняцце "user data".
Таму больш універсальным рашэннем з`яўляецца выкарыстанне user data. І будзе запускацца альбо на самай instance, калі instance уключыцца, альбо ў гэтым жа user data, калі autoscaling group будзе выкарыстоўваць гэты launch_configuration.
Калі ўсё ж такі ёсць жаданне запусціць provisioner, таму што ён з'яўляецца склейвае кампанентам, калі адзін рэсурс будзе створаны і ў гэты момант трэба запусціць свой provisioner, сваю каманду. Такіх сітуацый вельмі шмат.
І самы правільны рэсурс для гэтага завецца null_resource. Null_resource - гэта фіктыўны рэсурс, які на самой справе не ствараецца ніколі. Ён нічога не чапае, няма API, няма autoscaling. Але ён дазваляе рэгуляваць, калі запускаць каманду. У дадзеным выпадку запускаецца каманда падчас стварэння.
Ёсць некалькі прыкмет. Я ня буду спыняцца на ўсіх прыкметах вельмі дэталёва. Ёсць артыкул аб гэтым. Але калі вы працавалі з Terraform або выкарыстоўвалі чужыя модулі, тыя вы часта заўважалі, што шматлікія модулі, як і большую частку кода ў open source, людзі пішуць для сваіх нейкіх патрэб. Чалавек яго напісаў, рашыў сваю задачу. Забіў яго ў GitHub, няхай жыве. Ён будзе жыць, але калі тамака няма ніякай дакументацыі і прыкладаў, то ніхто ім карыстацца не будзе. І калі там няма функцыяналу, які дазваляе вырашаць крыху больш, чым яго канкрэтную задачу, то ім таксама ніхто не будзе карыстацца. Ёсць вельмі шмат спосабаў страціць карыстальнікаў.
Калі вы хочаце напісаць нешта, каб людзі гэтым карысталіся, то я рэкамендую прытрымлівацца гэтых прыкмет.
гэта:
Дакументацыя і прыклады.
Поўны функцыянал.
Разумныя значэння па змаўчанні.
Чысты код.
Тэсты.
Тэсты - гэта асобная сітуацыя, таму што іх даволі складана напісаць. Я больш веру ў дакументацыю і ў прыклады.
Такім чынам, мы паглядзелі, як пісаць модулі. Ёсць два аргументы. Першы, які найболей важны, гэта не пішы, калі можаш, т. да. кучу-куча людзей ужо зрабілі гэтыя задачы да вас. І другі, калі ўсёткі вырашыўся, то правайдэры ў модулях і provisioner імкніся не выкарыстоўваць.
Гэта шэрая частка дакументацыі. Вы можаце зараз падумаць: «Нешта незразумела. Не пераканаў». Але паглядзім праз паўгода.
Цяпер пагаворым аб тым, як выклікаць гэтыя модулі.
Мы разумеем, што з цягам часу наш код расце. У нас ужо не адзін файл, у нас ужо 20 файлаў. Усе яны ляжаць у адной тэчцы. Ці, можа, у пяці тэчках. Можа быць, мы пачынаем іх неяк разбіваць па рэгіёнах, па нейкіх кампанентах. Потым мы разумеем, што зараз у нас нейкія зародкі сінхранізацыі, аркестрацыі павінны ўзнікаць. Т. е. павінны зразумець, што нам рабіць, калі мы памянялі сеткавыя рэсурсы, што нам рабіць з астатнімі нашымі рэсурсамі, як выклікаць гэтыя залежнасці і т. д.
Ёсць дзве крайнасці. Першая крайнасць - гэта ўсё ў адным. У нас ёсць адзін майстар-файл. Да сітавіны да часу гэта быў афіцыйная best practice на сайце Terraform.
Але зараз гэта напісана як deprecated і прыбрана. З цягам часу Terraform-супольнасць зразумела, што гэта далёка не best practice, таму што людзі пачынаюць выкарыстоўваць праект у розных відах. І ёсць праблемы. Напрыклад, калі мы паказваем усе залежнасці ў адным месцы. Бывае сітуацыі, калі мы націскаем "Terraform plan" і пакуль Terraform абновіць стану ўсіх рэсурсаў, можа прайсці куча часу.
Куча часу - гэта, напрыклад, 5 хвілін. Для кагосьці гэта шмат часу. Я бачыў выпадкі, калі гэта займала 15 хвілін. 15 хвілін AWS API тузаўся для таго, каб зразумець, што са станам кожнага рэсурсу. Гэта вельмі вялікая вобласць.
І, натуральна, з'явіцца звязаная праблема, калі вы захочаце памяняць нешта ў адным месцы, потым пачакалі 15 хвілін, а яно вам выдала палатно нейкіх змен. Вы плюнулі, напісалі "Yes", і нешта пайшло не так. Гэта суцэль рэальны прыклад. Terraform не імкнецца вас адгарадзіць ад праблем. Т. е. пішыце, што хочаце. Будуць праблемы - вашы праблемы. Пакуль Terraform 0.11 не імкнецца вам дапамагчы ніяк. У 0.12 ёсць пэўныя цікавыя месцы, якія дазваляюць вам сказаць: "Вася, ты сапраўды гэтага хочаш, можаш раздумаешся?".
Другі спосаб складаецца ў памяншэнне гэтай вобласці, т. е. мага менш злучаць выклікі аднаго месца з іншага месца.
Адзіная праблема ў тым, што трэба пісаць больш кода, т. е. трэба апісваць зменныя ў вялікай колькасці файлаў, абнаўляць гэта. Камусьці гэта не падабаецца. Для мяне гэта нармальна. А некаторыя думаюць: "Навошта гэта пісаць у розных месцах, я гэта ўсё ў адным месцы закаўбасю". Можна і так, але гэта другая крайнасць.
У каго гэта ўсё жыве ў адным месцы? Адзін, два, тры чалавекі, г.зн. нехта выкарыстоўвае.
А хто выклікае адзін канкрэтна кампанент, адзін блок ці адзін інфраструктурны модуль? Чалавек пяць-сем. Гэта выдатна.
Самы часты адказ - гэта дзесьці пасярэдзіне. Калі праект вялікі, то ў вас часта будзе сітуацыя, калі ні тое рашэнне не падыходзіць і там не ўсё атрымліваецца, таму ў вас атрымліваецца сумесь. У гэтым нічога дрэннага няма, абы вы разумелі, што ёсць перавага і ў таго, і ў таго.
Калі змянілася нешта ў stack VPC і вы захацелі прымяніць гэтыя змены EC2, т. е. вы захацелі абнавіць autoscaling group, таму што ў вас з'явілася новая subnet, то такога роду залежнасці я заву аркестрацыяй. Ёсць нейкія рашэнні: хто як выкарыстоўвае?
Я магу падказаць, якія ёсьць рашэньні. Можна выкарыстоўваць Terraform для таго, каб рабіць магію, а можна выкарыстоўваць make-файлы для выкарыстання Terraform. І глядзець, калі там нешта памянялася, можна тут запусціць.
Як вам такое рашэньне? Нехта верыць, што гэта класнае рашэнне? Я бачу ўсмешку, відаць сумневы закраліся.
Вядома, не паўтарайце гэта дома. Terraform ніколі не быў створаны для таго, каб запускацца з Terraform.
Мне на адным дакладзе сказалі: "Не, гэта не будзе працаваць". Справа ў тым, што яна і не павінна працаваць. Хоць яно і выглядае так эфектна, калі ты можаш з Terraform запусціць Terraform, а тамака яшчэ Terraform, але не трэба так рабіць. Terraform павінен заўседы запускацца вельмі проста.
Вы паказваеце, які канкрэтна модуль вы хочаце выклікаць.
Якія ў модуля ёсць залежнасці.
І якія аргументы гэты модуль прымае. Гэта ўсё, што трэба ведаць аб Terragrunt.
Дакументацыя там ёсць, 1 зорачак на GitHub таксама ёсць. Але ў большасці выпадкаў гэта тое, што трэба ведаць. І гэта вельмі лёгка ўжывіць у кампаніі, якія толькі пачалі працаваць з Terraform.
Такім чынам, аркестрацыя - гэта Terragrunt. Іншыя варыянты ёсць.
Цяпер давайце пагаворым, як працаваць з кодам.
Калі ў вас ёсць неабходнасць дадаць новыя фічы ў код у большасці выпадкаў гэта лёгка. Вы пішыце новы рэсурс, тут усё проста.
Калі ў вас ёсць нейкі рэсурс, які вы стварылі загадзя, напрыклад, вы пра Terraform даведаліся пасля таго, як вы адкрылі AWS-акаўнт і хочаце выкарыстаць тыя рэсурсы, якія ў вас ужо ёсць, то будзе дарэчы пашырыць свой модуль такім чынам, каб ён падтрымліваў выкарыстанне існуючых рэсурсаў.
І падтрымліваў стварэньне новых рэсурсаў, выкарыстоўваючы рэсурс block.
На выхадзе мы заўсёды вяртаем output id у залежнасці ад таго, што было скарыстана.
Другая вельмі істотная праблема ў Terraform 0.11 - гэта праца са спісамі.
Складанасць у тым, што калі мы маем такі спіс users.
І калі мы ствараем гэтых users, выкарыстоўваючы block resource, тое ўсё праходзіць звычайна. Мы праходзім па ўсім спісе, ствараем кожнаму файлік. Усё нармальна. І потым, напрыклад, user3, які па сярэдзіне, павінен быць прыбраны адсюль, то ўсе рэсурсы, якія былі створаны пасля яго, яны будуць пераствараць, таму што індэкс зменіцца.
Праца са спісамі ў stateful-акружэнні. Што такое stateful-асяроддзе? Гэта тая сітуацыя, калі ўзнікае новае значэнне пры стварэнні гэтага рэсурса. Напрыклад, AWS Access Key ці AWS Secret Key, т. е. калі мы ствараем user'а, нам прыходзіць новы Access ці Secret Key. І кожны раз, калі мы будзем выдаляць нейкага user'а, у гэтага user'а будзе новы ключ. Але гэта не па фэншуй, таму што user не захоча з намі сябраваць, калі мы будзем кожны раз ствараць новага user'а для яго, калі нехта пакідае каманду.
Рашэнне такое. Гэта код, напісаны на Jsonnet. Jsonnet - Гэта мова стварэння шаблонаў ад Google.
Гэтая каманда дазваляе прыняць гэты шаблон і на выхадзе ён вяртае json-файл, які зроблены па вашаму шаблону.
Шаблон выглядае вось так.
Terraform дазваляе працаваць і з HCL, і з Json аднолькава, таму калі ў вас ёсць магчымасць генераваць Json, тыя вы можаце яго падсунуць у Terraform. Файл з пашырэньнем .tf.json будзе пасьпяхова загружаны.
І потым мы працуем з гэтым як звычайна: terraform init, terramorm apply. І мы ствараем двух user'аў.
Цяпер нам не страшна, калі нехта пакіне каманду. Мы проста адрэдагуем json-файл. Вася Пупкін сышоў, Пеця Пятакін застаўся. Пеця Пятачкін не атрымае новы ключ.
Інтэграцыя Terraform з іншымі сродкамі, у сутнасці, не з'яўляецца задачай Terraform. Terraform ствараўся як платформа для стварэння рэсурсаў і ўсё. І ўсё, што падыходзіць потым - гэта не клопат Terraform. І не трэба туды ўплятаць яго. Ёсць Ansible, які робіць усё, што трэба.
Але ўзнікаюць сітуацыі, калі мы жадаем дапоўніць Terraform і выклікаць нейкую каманду пасля таго, як нешта выканалася.
Першы спосаб. Мы ствараем output, дзе мы пішам гэтую каманду.
А потым гэтую каманду выклікаем з shell terraform output і паказваем гэтае значэнне, якое мы жадаем. Такім чынам выконваецца каманда са ўсімі падстаўленымі значэннямі. Гэта вельмі зручна.
Другі спосаб. Гэта выкарыстанне null_resource у залежнасці ад змен у нашай інфраструктуры. Мы можам выклікаць той жа local-exeс, як толькі зменіцца ID нейкага рэсурса.
Натуральна, гэта ўсё гладка на паперы, таму што Amazon як і ўсе астатнія public-правайдэры мае кучу сваіх edge cases.
Самы распаўсюджаны edge cases заключаецца ў тым, што, калі вы адкрылі AWS-акаўнт, важна, якія вы рэгіёны карыстаецеся; ці ўключана гэтая фіча там; магчыма, вы яго адкрылі пасля снежня 2013-га года; можа быць, вы карыстаецеся дэфолт у VPC і г. д. Ёсць шмат абмежаванняў. І Amazon раскідаў іх па ўсёй дакументацыі.
Ёсць некалькі рэчаў, якія я рэкамендую пазбягаць.
Для пачатку пазбягайце ўсіх несакрэтных аргументаў усярэдзіне Terraform plan ці Terraform CLI. Усё гэта можна скласці або ў tfvars-файл, або ў пераменнае асяроддзе.
Але не трэба запамінаць усю гэтую магічную каманду. Terraform plan - var і панеслася. Першая пераменная - var, другая пераменная - var, трэцяя, чацвёртая. Найважнейшы прынцып інфраструктуры як код, які я часцей за ўсё выкарыстоўваю, гэта тое, што, проста зірнуўшы на код, я павінен выдатна разумець, што там задэплоена, у якім стане і з якімі значэннямі. І таму мне не трэба чытаць дакументацыю ці пытаць Васю пра тое, якія параметры ён выкарыстоўваў для стварэння нашага кластара. Мне дастаткова адкрыць файл з пашырэннем tfvars, які часта супадае з асяроддзем, і паглядзець усё там.
Таксама не трэба выкарыстоўваць аргументы target для памяншэння вобласці дзеяння. Для гэтага нашмат прасцей выкарыстоўваць маленькія інфраструктурныя модулі.
Таксама не трэба абмяжоўваць і павялічваць parallelism. Калі ў мяне 150 рэсурсаў і я хачу павялічыць parallelism Amazon з 10, якія па змаўчанні, да 100, то, хутчэй за ўсё, нешта пойдзе не так. Ці можа пайсці добра зараз, але, калі Amazon скажа, што вы занадта шмат робіце выклікаў, у вас пасыплюцца праблемы.
Terraform большасць гэтых праблем будзе спрабаваць перазапусціць, але вы не даможацеся амаль нічога. Parallelism=1 – гэта важная рэч, якую трэба выкарыстоўваць, калі вы спатыкнуліся аб нейкі баг усярэдзіне AWS API або ўсярэдзіне Terraform-правайдэра. І тады трэба паказаць: parallelism=1 і чакаць, пакуль Terraform скончыць адзін выклік, потым другі, потым трэці. Па чарзе ён іх будзе запускаць.
Часта мяне пытаюцца: "Чаму я лічу, што Terraform workspaces - гэта зло?". Я веру, што прынцып інфраструктуры як код палягае ў тым, каб бачыць, якая інфраструктура была створана і з якімі значэннямі.
Workspaces было створана не са боку карыстачоў. Гэта не значыць, што карыстачы напісалі ў GitHub issues, што жыць не можам без Terraform workspaces. Не, не так. Terraform Enterprise - гэта камерцыйнае рашэнне. Terraform ад HashiCorp вырашыла, што нам трэба workspaces, таму мы гэта запілуем. Я лічу, што нашмат прасцей гэта пакласці ў асобную тэчку. Тады будзе крыху больш за файлаў, але будзе зразумелей.
Як працаваць з кодам? Па сутнасці, праца са спісамі - адзіны боль. І ўспрымайце Terraform прасцей. Гэта не тая рэч, якая будзе вам рабіць усё файна. Не трэба пхаць туды ўсё, што напісана ў дакументацыі.
У тэме дакладу было напісана "на будучыню". Я вельмі коратка пра гэта скажу. На будучыню - гэта значыць, што хутка выйдзе 0.12.
0.12 - гэта куча ўсяго новага. Калі вы прыйшлі са звычайнага праграмавання, тыя вы сумуеце па ўсякіх дынамічных блоках, цыклам, па правільных і ўмоўных аперацыях параўнання, дзе левая і правая частка вылічаюцца не адначасова, а ў залежнасці ад сітуацыі. Вы вельмі моцна па гэтым сумуеце, таму 0.12 вам вырашыць гэта.
Але! Калі вы будзеце пісаць менш і прасцей, выкарыстаючы гатовыя модулі, іншыя рашэнні, то вам не трэба будзе чакаць і спадзявацца, што 0.12 прыйдзе і ўсё за вас паправіць.
Дзякуй за даклад! Ты казаў пра інфраструктуру як код і пра тэсты сказаў літаральна адно слова. Ці патрэбны тэсты ў модулях? Чыя гэта адказнасць? Трэба самому пісаць ці гэта адказнасць модуляў?
Наступны год будзе засыпаны дакладамі аб тым, што мы вырашылі ўсё тэсціраваць. Што тэставаць - гэта самае вялікае пытанне. Ёсць куча залежнасцяў, куча абмежаванняў розных правайдэраў. Калі мы з табой размаўляем, і ты кажаш: "Мне патрэбны тэсты", то я пытаю: "Што ты будзеш тэставаць?". Ты кажаш, што будзеш тэсціраваць у сваім рэгіёне. Тады я гавару, што ў маім рэгіёне гэта не працуе. Т. е. мы нават на гэтым з табой не зможам дамовіцца. Не гаворачы ўжо аб тым, што ёсць куча тэхнічных праблем. Т. е. як напісаць гэтыя тэсты, каб яны былі адэкватнымі.
Я даследую гэтую тэму актыўна, т. е. як аўтаматычна генераваць тэсты на падставе той інфраструктуры, якую ты напісаў. Гэта значыць, калі ты напісаў гэты код, то мне трэба яго запусціць, на падставе гэтага я змагу стварыць тэсты.
Terratest - гэта адна з самых часта згадваных бібліятэк, якая дазваляе пісаць тэсты інтэграцыйныя для Terraform. Гэта адна з утыліт. Мне больш падабаецца тып DSL, напрыклад, rspec.
Антон, дзякуй за даклад! Мяне клічуць Валеры. Дазволю сябе крыху філасофскае пытанне. Ёсць, умоўна, provisioning, ёсць deployment. Provisioning маю інфраструктуру стварае, у deployment мы яе нечым наліваем карысным, напрыклад, серверамі, прыкладаннямі і г. д. І ў мяне ў галаве сядзіць, што Terraform больш для provisioning, а Ansible больш для deployment, таму што Ansible і на фізічную інфраструктуру дазваляе паставіць nginx, Postgres. Але пры гэтым і Ansible быццам бы дазваляе зрабіць provisioning, напрыклад, амазонскіх ці гуглавых рэсурсаў. Але і Terraform дазваляе з дапамогай сваіх модуляў задэплоіць нейкі софт. З твайго пункту гледжання, ці ёсць нейкая мяжа, якая праходзіць паміж Terraform і Ansible, дзе і што лепш выкарыстоўваць? Ці, напрыклад, ты думаеш, што Ansible - гэта ўжо бздура, трэба спрабаваць Terraform для ўсяго выкарыстоўваць?
Добрае пытанне, Валеры. Я лічу, што Terraform з 2014 года не змяніўся ў плане прызначэння. Ён створаны для інфраструктуры і памёр для інфраструктуры. У нас па-ранейшаму была і будзе патрэба ў configuration management Ansible. Выклік у тым, што там ёсць user data ўнутры launch_configuration. І там ты тузаеш Ansible і т. д. Вось гэтае стандартнае размежаванне, якое мне больш за ўсё падабаецца.
Калі мы гаворым пра in beautiful infrastructure, гэта значыць утыліты тыпу Packer, якая збірае гэты вобраз. І далей Terraform выкарыстоўвае data source для пошуку гэтай выявы і абнаўленні сваёй launch_configuration. Т. е. такім чынам pipeline складаецца ў тым, што мы тузаем спачатку Tracker, потым тузаем Terraform. І калі адбыўся build, тое адбываецца новая змена.
Добры дзень! Дзякуй за даклад! Мяне клічуць Міша, кампанія RBS. Можна Ansible выклікаць праз provisioner пры стварэньні рэсурсу. А таксама ў Ansible ёсць такая тэма, як дынамічны інвентар. І можна спачатку выклікаць Terraform, а потым выклікаць Ansible, які са state возьме рэсурсы і выканае. Што лепш?
І тое і тое людзі выкарыстоўваюць з аднолькавым поспехам. Мне здаецца, што дынамічны інвентар у Ansible гэта зручная рэч, калі мы не гаворым пра autoscaling group. Таму што ў autoscaling group у нас есць ужо свой інструментар, які называецца launch_configuration. Мы ў launch_configuration запісваем усё, што трэба запускаць, калі ствараем новы рэсурс. Таму з Amazon выкарыстоўваць дынамічны інвентар і чытаць Terraform ts файл, па-мойму, гэта залішняе. А калі вы выкарыстоўваеце іншыя сродкі, дзе няма паняцця «autoscaling group», напрыклад, вы карыстаецеся DigitalOcean ці нейкі іншы правайдэр, дзе няма autoscaling group, то там вам трэба будзе ручкамі тузаць API, знаходзіць IP-адрасы, фармаваць dynamic inventory файл , і Ansible будзе ўжо па ім блукаць. Т. е. для Amazon ёсць launch_configuration, а для ўсяго астатняга ёсць dynamic inventory.