Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

27 красавіка на канферэнцыі Страйк-2019, у рамках секцыі "DevOps", прагучаў даклад "Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes". У ім распавядаецца аб тым, як з дапамогай K8s забяспечыць высокую даступнасць прыкладанняў і гарантаваць іх максімальную прадукцыйнасць.

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Па традыцыі рады прадставіць відэа з дакладам (44 хвіліны, значна інфарматыўныя за артыкул) і асноўны выцісканне ў тэкставым выглядзе. Паехалі!

Разбяром тэму даклада па словах і пачнем з канца.

Kubernetes

Няхай у нас на хасце ёсць Docker-кантэйнеры. Навошта? Для забеспячэння паўтаранасці і ізаляцыі, якія ў сваю чаргу дазваляюць зрабіць проста і добра дэплой, CI/CD. Такіх машын з кантэйнерамі ў нас шмат.

Што ў гэтым выпадку дае Kubernetes?

  1. Мы перастаем думаць пра гэтыя машыны і пачынаем працаваць з «воблакам», кластарам з кантэйнераў ці pod'аў (груп з кантэйнераў).
  2. Больш за тое, мы не думаем нават пра асобныя pod'ы, а кіруем яшчэ большымі групамі. Такія высокаўзроўневыя прымітывы дазваляюць нам сказаць, што ёсць шаблон для запуску нейкай працоўнай нагрузкі, а вось патрэбная колькасць асобнікаў для яе запуску. Калі мы пасля памяняем шаблон - памяняюцца і ўсе асобнікі.
  3. З дапамогай дэкларатыўнага API мы замест выканання паслядоўнасці пэўных каманд апісваем "прылада міру" (у YAML), які ствараецца Kubernetes'ам. І зноў: пры зменах апісання будзе мяняцца і яго рэальнае адлюстраванне.

Кіраванне рэсурсамі

CPU

Няхай мы запускаем на серверы nginx, php-fpm і mysql. У гэтых службаў у рэчаіснасці будзе яшчэ больш працавальных працэсаў, кожны з якіх патрабуе вылічальных рэсурсаў:

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)
(лікі на слайдзе - «папугаі», абстрактнае запатрабаванне кожнага працэсу ў вылічальных магутнасцях)

Каб з гэтым можна было зручна працаваць, лагічна аб'яднаць працэсы па групах (напрыклад, усе працэсы nginx у адну групу "nginx"). Просты і відавочны спосаб зрабіць гэта - змясціць кожную групу ў кантэйнер:

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Каб працягнуць, неабходна ўспомніць, што ж такое кантэйнер (у Linux). Іх з'яўленне стала магчымым дзякуючы тром ключавым магчымасцям у ядры, рэалізаваным ужо дастаткова даўно: магчымасці, прасторы імёнаў и групоўкі. А далейшаму развіццю спрыялі іншыя тэхналогіі (уключаючы зручныя "абалонкі" тыпу Docker):

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

У кантэксце даклада нас цікавіць толькі групоўкі, таму што менавіта кантрольныя групы - тая частка функцыянальных магчымасцяў кантэйнераў (Docker'а і да т.п.), што рэалізуе кіраванне рэсурсамі. Працэсы, аб'яднаныя ў групы, як мы таго хацелі, - гэта і ёсць кантрольныя групы.

Вернемся да патрэбаў у CPU у гэтых працэсаў, а зараз ужо – у груп працэсаў:

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)
(паўтаруся, што ўсе лікі - абстрактнае выраз патрэбы ў рэсурсах)

Пры гэтым у самога CPU ёсць нейкі канчатковы рэсурс. (у прыкладзе гэта 1000), якога ўсім можа не хапаць (сума запатрабаванняў усіх груп - 150 850 460 = 1460). Што будзе адбывацца ў такім разе?

Ядро пачынае раздаваць рэсурсы і робіць гэта "сумленна", выдаючы аднолькавую колькасць рэсурсаў кожнай групе. Але ў першым выпадку іх больш патрэбнага (333>150), таму лішак (333-150=183) застаецца ў рэзерве, які таксама роўна размяркоўваецца паміж двума іншымі кантэйнерамі:

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

У выніку: першаму кантэйнеру хапіла рэсурсаў, другому - моцна не хапіла, трэцяму - трохі не хапіла. Такі вынік дзеянняў «сумленнага» планавальніка ў Linux - CFS. Яго працу можна рэгуляваць з дапамогай прызначэння вагі кожнаму з кантэйнераў. Напрыклад, так:

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Паглядзім на выпадак недахопу рэсурсаў у другога кантэйнера (php-fpm). Усе рэсурсы кантэйнера размяркоўваюцца паміж працэсамі пароўну. У выніку, master-працэс працуе добра, а ўсе worker'ы тармозяць, атрымаўшы меней паловы ад патрэбнага:

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Так працуе планавальнік CFS. Вагі, якія мы прызначаем кантэйнерам, у далейшым будзем назваць request'амі. Чаму менавіта так - гл. далей.

Зірнем на ўсю сітуацыю з другога боку. Як вядома, усе дарогі вядуць у Рым, а ў выпадку кампутара – у CPU. CPU адзін, задач шмат - патрэбен святлафор. Самы просты спосаб кіравання рэсурсамі – «святлафорны»: выдалі аднаму працэсу фіксаваны час доступу да CPU, затым – наступнага і да т.п.

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Гэты падыход называецца жорсткім кватаваннем (hard limiting). Запомнім яго проста як ліміты. Аднак, калі раздаць усім кантэйнерамі ліміты, узнікае праблема: mysql ехаў па дарозе і ў нейкі момант яго запатрабаванне ў CPU скончылася, але ўсе астатнія працэсы змушаныя чакаць, пакуль CPU прастойвае.

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Вернемся да ядра Linux і яго ўзаемадзеянню з CPU – агульная карціна атрымліваецца наступнай:

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

У cgroup ёсць дзве налады - па сутнасці гэта дзве простыя «круцілкі», якія дазваляюць вызначаць:

  1. вага для кантэйнера (request'ы) - гэта акцый;
  2. працэнт ад агульнага часу CPU для працы над задачамі кантэйнера (ліміты) - гэта квота.

У чым мераць CPU?

Ёсць розныя шляхі:

  1. Што такое папугаі, ніхто не ведае - трэба кожны раз дамаўляцца.
  2. працэнты больш зразумела, але адносныя: 50% ад сервера з 4 ядрамі і з 20 ядрамі – зусім розныя рэчы.
  3. Можна выкарыстоўваць ужо згаданыя вагі, якія ведае Linux, але яны таксама адносныя.
  4. Самы адэкватны варыянт - мераць вылічальныя рэсурсы ў секундах. Г.зн. у секундах працэсарнага часу ў адносінах да секунд рэальнага часу: выдалі 1 секунду працэсарнага часу ў 1 рэальную секунду - гэта адно ядро ​​CPU цалкам.

Каб стала казаць яшчэ прасцей, вымяраць сталі прама ў ядрах, Маючы на ​​ўвазе пад імі той самы час CPU адносна рэальнага. Паколькі Linux разумее вагі, а не такі працэсарны час/ядры, спатрэбіўся механізм перакладу з аднаго ў іншае.

Разгледзім просты прыклад з серверам з 3 ядрамі CPU, дзе тром pod'ам будуць абраныя такія вагі (500, 1000 і 1500), якія лёгка канвертуюцца ў адпаведныя часткі вылучаных ім ядраў (0,5, 1 і 1,5).

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Калі ўзяць другі сервер, дзе ядраў будзе ўдвая больш (6), і размясціць тамака тыя ж pod'ы, размеркаванне ядраў лёгка палічыць простым множаннем на 2 (1, 2 і 3 адпаведна). Але важны момант адбываецца тады, калі на гэтым серверы з'явіцца чацвёрты pod, вага ў якога няхай для зручнасці будзе 3000. Ён забірае сабе частку рэсурсаў CPU (палову ядраў), а ў астатніх pod'аў яны пералічваюцца (зменшацца ўдвая):

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Kubernetes і рэсурсы CPU

У Kubernetes рэсурсы CPU прынята вымяраць у міліядрах, г.зн. у якасці базавай вагі бярэцца 0,001 ядра. (Тое ж самае ў тэрміналогіі Linux/cgroups завуць CPU share, хоць, калі казаць дакладней, то 1000 міліядэр = 1024 CPU shares.) K8s сочыць за тым, каб не размяшчаць на серверы больш pod'аў, чым ёсць рэсурсаў CPU для сумы шаляў усіх pod'аў.

Як гэта адбываецца? Пры даданні сервера ў кластар Kubernetes паведамляецца, колькі ў яго даступна ядраў CPU. А пры стварэнні новага pod'а планавальнік Kubernetes ведае, колькі ядраў запатрабуецца гэтаму pod'у. Такім чынам, pod будзе вызначаны на сервер, дзе ядраў дастаткова.

Што ж адбудзецца, калі ня паказаны request (г.зн. у pod'а не вызначана колькасць патрэбных яму ядраў)? Давайце разбяромся, як Kubernetes наогул лічыць рэсурсы.

У pod'а можна паказаць і request'ы (планавальнік CFS), і ліміты (памятаеце святлафор?):

  • Калі яны пазначаны роўныя, то pod'у прызначаецца QoS-клас гарантаваны. Такая колькасць заўсёды даступных для яго ядраў гарантуецца.
  • Калі request менш ліміту - QoS-клас burstable. Г.зн. мы чакаем, што pod, напрыклад, заўсёды выкарыстоўвае 1 ядро, аднак гэтае значэнне не з'яўляецца для яго абмежаваннем: часам pod можа выкарыстоўваць і больш (калі на серверы ёсць вольныя рэсурсы для гэтага).
  • Ёсць яшчэ QoS-клас лепшыя намаганні - Да яго ставяцца тыя самыя pod'ы, для якіх не паказаны request. Рэсурсы ім выдаюцца ў апошнюю чаргу.

памяць

З памяццю сітуацыя падобная, але крыху іншая — усё ж прырода ў гэтых рэсурсаў розная. У цэлым жа аналогія такая:

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Давайце паглядзім, як у памяці рэалізуюцца request'ы. Няхай pod'ы жывуць на серверы, змяняючы спажываную памяць, пакуль адзін з іх не стане такім вялікім, што памяць скончыцца. У гэтым выпадку з'яўляецца OOM killer і забівае самы вялікі працэс:

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Нас гэта не заўсёды задавальняе, таму ёсць магчымасць рэгуляваць, якія працэсы для нас важныя і не павінны забівацца. Для гэтага выкарыстоўваецца параметр oom_score_adj.

Вернемся да QoS-класаў CPU і правядзем аналогію са значэннямі oom_score_adj, якія вызначаюць для pod'ов прыярытэты па спажыванні памяці:

  • Самае нізкае значэнне oom_score_adj у pod'а -998 - азначае, што такі pod павінен забівацца ў самую апошнюю чаргу, гэта гарантаваны.
  • Самае высокае - 1000 - гэта лепшыя намаганні, такія pod'ы забіваюцца раней за ўсіх.
  • Для разліку астатніх значэнняў (burstable) ёсць формула, сутнасць якой зводзіцца да таго, што чым больш pod запытаў рэсурсаў, тым менш шанцаў, што яго заб'юць.

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Другая круцілка limit_in_bytes - Для лімітаў. З ёй усё прасцей: мы проста прызначаем максімальную колькасць выдаванай памяці, і тут (у адрозненне ад CPU) няма пытання, у чым яе (памяць) вымяраць.

Разам

Кожнаму pod'у ў Kubernetes задаюцца requests и limits - Абодва параметры для CPU і для памяці:

  1. на падставе requests працуе планавальнік Kubernetes, які размяркоўвае pod'ы па серверах;
  2. на падставе ўсіх параметраў вызначаецца QoS-клас pod'а;
  3. на падставе CPU requests разлічваюцца адносныя вагі;
  4. на падставе CPU requests наладжваецца CFS-планавальнік;
  5. на падставе memory requests наладжваецца OOM killer;
  6. на падставе CPU limits наладжваецца "святлафор";
  7. на падставе memory limits наладжваецца ліміт на cgroup'у.

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

У цэлым гэтая карцінка адказвае на ўсе пытанні, як адбываецца асноўная частка кіравання рэсурсамі ў Kubernetes.

Аўтамаштабаванне

K8s cluster-autoscaler

Уявім сабе, што ўвесь кластар ужо заняты і павінен быць створаны новы pod. Пакуль pod не можа з'явіцца, ён вісіць у статуце У чаканні. Каб ён усёткі з'явіўся, мы можам падлучыць новы сервер да кластара ці ж… паставіць cluster-autoscaler, які зробіць гэта за нас: замовіць віртуальную машыну ў хмарнага правайдэра (запытам па API) і падлучыць яе да кластара, пасля чаго pod будзе дададзены .

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Гэта і ёсць аўтамаштабаванне кластара Kubernetes, якое выдатна (па нашым досведзе) працуе. Аднак, як і ўсюды, тут не без нюансаў…

Пакуль мы павялічвалі памеры кластара, усё было добра, але што адбываецца, калі кластар стаў вызваляцца? Праблема ў тым, што міграваць pod'ы (для вызвалення хастоў) вельмі тэхнічна складана і дорага па рэсурсах. У Kubernetes працуе зусім іншы падыход.

Разгледзім кластар з 3 сервераў, у якім ёсць Deployment. У яго 6 pod'аў: зараз гэта па 2 на кожны сервер. Мы па нейкай прычыне захацелі выключыць адзін з сервераў. Для гэтага скарыстаемся камандай kubectl drain, якая:

  • забароніць адпраўляць новыя pod'ы на гэты сервер;
  • выдаліць існуючыя pod'ы на сэрвэры.

Паколькі Kubernetes сочыць за падтрыманнем ліку pod'аў (6), ён проста перастворыць іх на іншых вузлах, але не на які адключаецца, паколькі ён ужо пазначаны як недаступны для месцавання новых pod'аў. Гэта асноватворная механіка для Kubernetes.

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Аднак і тут ёсць нюанс. У аналагічнай сітуацыі для StatefulSet (замест Deployment) дзеянні будуць іншымі. Цяпер у нас ужо stateful-дадатак - напрыклад, тры pod'а з MongoDB, у аднаго з якіх узнікла нейкая праблема (дадзеныя сапсаваліся або іншая памылка, якая не дазваляе карэктна запусціцца pod'у). І мы зноў развязальны адключыць адзін сервер. Што адбудзецца?

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

MongoDB мог бы памерці, паколькі яму неабходны кворум: для кластара з трох усталёвак хоць бы дзве павінны функцыянаваць. Аднак гэтага не адбываецца - дзякуючы PodDisruptionBudget. Гэты параметр вызначыць мінімальна неабходную колькасць працуючых pod'аў. Ведаючы, што адзін з pod'аў з MongoDB ужо не працуе, і ўбачыўшы, што для MongoDB у PodDisruptionBudget усталяваны minAvailable: 2, Kubernetes не дасць выдаліць pod.

Вынік: для таго, каб карэктна працавала перасоўванне (а насамрэч - перастварэнне) pod'ов пры вызваленні кластара, неабходна наладжваць PodDisruptionBudget.

Гарызантальнае маштабаванне

Разгледзім іншую сітуацыю. Ёсць дадатак, запушчанае як Deployment у Kubernetes. На яго pod'ы (напрыклад, іх тры) прыходзіць карыстацкі трафік, а мы ў іх замяраем нейкі паказчык (скажам, нагрузку на CPU). Калі нагрузка ўзрастае, мы гэта фіксуем па графіку і павялічваем колькасць pod'аў для размеркавання запытаў.

Сёння ў Kubernetes гэта не трэба рабіць уручную: наладжваецца аўтаматычнае павелічэнне/памяншэнне колькасці pod'аў у залежнасці ад значэнняў замераных паказчыкаў нагрузкі.

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Галоўныя пытанні тут у тым, што менавіта вымяраць и як інтэрпрэтаваць атрыманыя значэнні (для прыняцця рашэння аб змене ліку pod'ов). Вымяраць можна вельмі шматлікае:

Аўтамаштабаванне і кіраванне рэсурсамі ў Kubernetes (агляд і відэа даклада)

Як рабіць гэта тэхнічна - збіраць метрыкі і да т.п. — я падрабязна расказваў у дакладзе пра Маніторынг і Kubernetes. А асноўны савет для выбару аптымальных параметраў эксперыментуйце!

Ёсць метад USE (Utilization Saturation and Errors), сэнс якога ў наступным. На падставе чаго мае сэнс маштабаваць, напрыклад, php-fpm? На падставе таго, што worker'ы сканчаюцца, - гэта ўтылізацыя. А калі worker'ы скончыліся і новыя падлучэнні не прымаюцца – гэта ўжо насычэнне. Абодва гэтых параметра неабходна вымяраць, а ў залежнасці ад значэнняў і праводзіць маштабаванне.

замест заключэння

У даклада ёсць працяг: пра вертыкальнае маштабаванне і пра тое, як правільна падбіраць рэсурсы. Пра гэта я раскажу ў будучых роліках на нашым YouTube - падпісвайцеся, каб не прапусціць!

Відэа і слайды

Відэа з выступу (44 хвіліны):

Прэзентацыя даклада:

PS

Іншыя даклады пра Kubernetes у нашым блогу:

Крыніца: habr.com

Дадаць каментар