Calico для сеткі ў Kubernetes: знаёмства і крыху з вопыту
Мэта артыкула – пазнаёміць чытача з асновамі сеткавага ўзаемадзеяння і кіраваннем сеткавымі палітыкамі ў Kubernetes, а таксама са іншым плагінам Calico, які пашырае стандартныя магчымасці. Адначасна будуць прадэманстраваны зручнасць канфігурацыі і некаторыя фічы на рэальных прыкладах з вопыту нашай эксплуатацыі.
У кантэксце гэтага артыкула важна адзначыць, што за сеткавую складнасць паміж кантэйнерамі і вузламі адказвае не сам K8s: для гэтага выкарыстоўваюцца разнастайныя убудовы CNI (Container Networking Interface). Больш падрабязна аб гэтай канцэпцыі мы таксама расказвалі.
Напрыклад, найбольш распаўсюджаны з такіх плагінаў. фланель - забяспечвае поўную сеткавую складнасць паміж усімі вузламі кластара з дапамогай узняцця мастоў на кожным вузле, замацоўваючы за ім падсетку. Аднак поўная і нерэгулюемая даступнасць не заўсёды карысная. Каб забяспечыць нейкую мінімальную ізаляцыю ў кластары, неабходна ўмяшацца ў канфігураванне firewall'а. Увогуле выпадку яно аддадзена ва ўпраўленне таго самага CNI, з-за чаго любыя іншыя ўмяшанні ў iptables могуць быць інтэрпрэтаваныя некарэктна ці ігнаравацца зусім.
А "са скрынкі" для арганізацыі кіравання сеткавымі палітыкамі ў кластары Kubernetes прадастаўляецца NetworkPolicy API. Гэты рэсурс, які распаўсюджваецца на абраныя прасторы імёнаў, можа ўтрымоўваць правілы для размежавання доступу ад адных прыкладанняў да іншых. Ён таксама дазваляе наладжваць даступнасць паміж пэўнымі pod'амі, асяроддзямі (прасторамі імёнаў) або блокамі IP-адрасоў:
Гэты не самы прымітыўны прыклад з афіцыйнай дакументацыі можа раз і назаўжды адбіць жаданне разбірацца ў логіцы працы сеткавых палітык. Аднак мы ўсё ж паспрабуем зразумець асноўныя прынцыпы і метады апрацоўкі плыняў трафіку з дапамогай сеткавых палітык…
Лагічна, што ёсць 2 тыпу трафіку: які ўваходзіць у pod (Ingress) і выходны з яго (Egress).
Уласна, на гэтыя дзве катэгорыі па кірунку руху і падзяляецца палітыка.
Наступны абавязковы атрыбут - селектар; той, да каго прымяняецца правіла. Гэта можа быць pod (ці група pod'аў) ці асяроддзе (г.зн. прастора імёнаў). Важная дэталь: абодва віды гэтых аб'ектаў павінны ўтрымліваць пазнаку (этыкетка у тэрміналогіі Kubernetes) - менавіта імі аперуюць палітыкі.
Апроч канчатковага ліку селектараў, аб'яднаных нейкай пазнакай, існуе магчымасць напісання правіл накшталт "Дазволіць/забараніць усё/усім" у розных варыяцыях. Для гэтага выкарыстоўваюцца канструкцыі выгляду:
Вяртаючыся да выбару CNI-плагіна для кластара, варта адзначыць, што не кожны сеткавы плягін падтрымлівае працу з NetworkPolicy. Напрыклад, ужо згаданы Flannel не ўмее канфігураваць сеткавыя палітыкі, аб чым прама сказана у афіцыйным рэпазітары. Там жа згаданая альтэрнатыва – Open Source-праект каленкор, які прыкметна пашырае стандартны набор API Kubernetes у плане сеткавых палітык.
Знаёмімся з Calico: тэорыя
Убудова Calico можа выкарыстоўвацца ў інтэграцыі з Flannel (падпраект Канал) або самастойна, пакрываючы як функцыі па забеспячэнні сеткавай складнасці, так і магчымасці кіравання даступнасцю.
Якія магчымасці дае выкарыстанне "скрынкавага" рашэнні K8s і набору API з Calico?
Вось што ўбудавана ў NetworkPolicy:
палітыкі абмежаваны асяроддзем;
палітыкі прымяняюцца да pod'ах, пазначаных лэйбламі;
правілы могуць быць ужытыя да pod'аў, асяроддзем або падсеткам;
правілы могуць змяшчаць пратаколы, названыя або сімвалальныя ўказанні партоў.
А вось як Calico пашырае гэтыя функцыі:
палітыкі могуць прымяняцца да любога аб'екта: pod, кантэйнер, віртуальная машына або інтэрфейс;
правілы могуць змяшчаць канкрэтнае дзеянне (забарона, дазвол, лагіраванне);
у якасці мэты або крыніцы правілаў можа быць порт, дыяпазон партоў, пратаколы, HTTP- або ICMP-атрыбуты, IP або падсетку (4 ці 6 пакаленні), любыя селектары (вузлоў, хастоў, асяроддзяў);
дадаткова можна рэгуляваць праходжанне трафіку з дапамогай налад DNAT і палітык пракіду трафіку.
Першыя коміты на GitHub у рэпазітары Сalico датуюцца ліпенем 2016 года, а ўжо праз год праект заняў лідзіруючыя пазіцыі ў арганізацыі сеткавай складнасці Kubernetes – пра гэта абвяшчаюць, напрыклад, вынікі апытання, праведзенага The New Stack:
Многія буйныя managed-рашэнні з K8s, такія як Amazon EKS, Azure AKS, Google GKE і іншыя, сталі рэкамендаваць яго да выкарыстання.
Што да прадукцыйнасці, тут усё выдатна. Пры тэставанні свайго прадукта каманда распрацоўкі Calico прадэманстравала астранамічныя паказчыкі, запусціўшы больш за 50000 кантэйнераў на 500 фізічных вузлах з хуткасцю стварэння 20 кантэйнераў у секунду. Праблем пры маштабаванні не выяўлена. Такія вынікі былі агучаныя ужо пры анонсе першай версіі. Незалежныя даследаванні, накіраваныя на прапускную здольнасць і аб'ёмы спажывання рэсурсаў, таксама пацвярджаюць прадукцыйнасць Calico, практычна не якая саступае Flannel. Напрыклад:
Праект вельмі хутка развіваецца, падтрымліваецца праца ў папулярных рашэннях managed K8s, OpenShift, OpenStack, маецца магчымасць выкарыстоўваць Calico пры разгортванні кластара з дапамогай удар нагамі, сустракаюцца згадкі пабудовы Service Mesh-сетак (вось прыклад выкарыстання сумесна з Istio).
Практыка з Calico
У агульным выпадку выкарыстання ванільнага Kubernetes усталёўка CNI зводзіцца да ўжывання файла calico.yaml, запампаванага з афіцыйнага сайта, з дапамогай kubectl apply -f.
Як правіла, актуальная версія плагіна сумяшчальная з 2-3 апошнімі версіямі Kubernetes: працу ў больш старых версіях не тэсціруюць і не гарантуюць. Па заявах распрацоўнікаў, Calico працуе на ядры Linux вышэй 3.10 пад кіраваннем CentOS 7, Ubuntu 16 ці Debian 8, па-над iptables ці IPVS.
Ізаляцыя ўнутры акружэння
Для агульнага разумення разгледзім просты выпадак, каб зразумець, чым адрозніваюцца сеткавыя палітыкі ў натацыі Calico ад стандартных і як падыход да складання правіл спрашчае іх чытальнасць і гнуткасць канфігуравання:
У кластары разгорнутыя 2 вэб-прыкладанні: на Node.js і PHP, - адно з якіх выкарыстоўвае Redis. Каб закрыць доступ да Redis з PHP, пакінуўшы пры гэтым складнасць з Node.js, дастаткова прымяніць наступную палітыку:
Па сутнасці мы дазволілі ўваходзіць трафік на порт Redis з Node.js. І відавочна не забаранялі нічога іншага. Як толькі з'яўляецца NetworkPolicy, то ўсе селектары, згаданыя ў ім, пачынаюць ізалявацца, калі не пазначана іншае. Пры гэтым правілы ізаляцыі не распаўсюджваюцца на іншыя аб'екты, якія не пакрываюцца селектарам.
У прыкладзе выкарыстоўваецца apiVersion Kubernetes'а "са скрынкі", але нішто не мяшае выкарыстоўваць аднайменны рэсурс з пастаўкі Calico. Сінтаксіс там больш разгорнуты, таму спатрэбіцца перапісаць правіла для вышэйапісанага выпадку ў наступным выглядзе:
Згаданыя вышэй канструкцыі для дазволу ці забароны ўсяго трафіку пасродкам звычайнага NetworkPolicy API утрымоўваюць складаныя для ўспрымання і запамінання канструкцыі са дужкамі. У выпадку з Calico, каб змяніць логіку працы правілы firewall'а на процілеглую, дастаткова змяніць action: Allow на action: Deny.
Ізаляцыя па асяродках
Цяпер прадставім сітуацыю, калі прыкладанне генеруе бізнес-метрыкі для іх збору ў Prometheus і далейшага аналізу з дапамогай Grafana. У выгрузцы могуць змяшчацца адчувальныя дадзеныя, якія па змаўчанні зноў жа даступныя для ўсеагульнага агляду. Закрыем ад старонніх вачэй гэтыя дадзеныя:
Prometheus, як правіла, вынесены ў асобнае службовае асяроддзе - у прыкладзе гэта будзе namespace наступнага выгляду:
Поле metadata.labels тут аказалася не выпадкова. Як вышэй ужо згадвалася, namespaceSelector (як і podSelector) аперуе лэйбламі. Таму, каб дазволіць забіраць метрыкі са ўсіх pod'аў на вызначаным порце, прыйдзецца дадаць якую-небудзь пазнаку (ці ўзяць з існых), а затым ужыць канфігурацыю накшталт:
У цэлым, дадаючы падобнага роду палітыкі пад канкрэтныя патрэбы, можна ахаваць ад зламыснага або выпадковага ўмяшання ў працу прыкладанняў у кластары.
Лепшай практыкай, па меркаванні стваральнікаў Calico, з'яўляецца падыход "Забарані ўсё і відавочна адчыняй неабходнае", зафіксаваны ў афіцыйнай дакументацыі (аналагічнага падыходу прытрымліваюцца і іншыя - у прыватнасці, у ужо згаданым артыкуле).
Ужыванне дадатковых аб'ектаў Calico
Нагадаю, што пасродкам пашыранага набору API Calico можна рэгуляваць даступнасць вузлоў, не абмяжоўваючыся pod'амі. У наступным прыкладзе з дапамогай GlobalNetworkPolicy зачыняецца магчымасць праходжання ICMP-запытаў у кластары (напрыклад, пінгі з pod'а на вузел, паміж pod'мі ці з вузла на IP pod'а):
У прыведзеным вышэй кейсе застаецца магчымасць вузлам кластара "дастукацца" паміж сабой па ICMP. І гэтае пытанне вырашаецца сродкамі GlobalNetworkPolicy, ужытай да сутнасці HostEndpoint:
Нарэшце, прывяду суцэль рэальны прыклад выкарыстання функцый Calico для выпадку з околокластерным узаемадзеяннем, калі стандартнага набору палітык бракуе. Для доступу да вэб-дадатку кліентамі выкарыстоўваецца VPN-тунэль, і гэты доступ жорстка кантралюем і абмежаваны канкрэтным спісам дазволеных да выкарыстання сэрвісаў:
Кліенты падключаюцца да VPN праз стандартны UDP-порт 1194 і пры падключэнні атрымліваюць маршруты да кластарных падсетак pod'аў і сэрвісаў. Падсеткі push'ацца цалкам, каб не губляць сэрвісы пры перазапусках і змене адрасоў.
Порт у канфігурацыі - стандартны, што накладвае некаторыя нюансы на працэс канфігуравання прыкладання і яго перанос у Kubernetes-кластар. Напрыклад, у тым жа AWS LoadBalancer для UDP з'явіўся літаральна ў канцы мінулага года ў абмежаваным спісе рэгіёнаў, а NodePort нельга выкарыстоўваць з-за яго пракіду на ўсіх вузлах кластара і немагчыма маштабаваць колькасць інстансаў сервера ў мэтах адмоваўстойлівасці. Плюс, прыйдзецца мяняць дыяпазон партоў, які выбіраецца па змаўчанні…
У выніку перабору магчымых рашэнняў было абрана наступнае:
Pod'ы з VPN плануюцца на вузел у рэжыме hostNetwork, гэта значыць на фактычны IP.
Сэрвіс вывешваецца вонкі праз ClusterIP. На вузле фізічна паднімаецца порт, які даступны звонку з невялікімі агаворкамі (умоўнае наяўнасць рэальнага IP-адрасы).
Вызначэнне вузла, на якім падняўся pod, ляжыць за межамі нашага апавядання. Скажу толькі, што можна цвёрда «прыбіць» сэрвіс да вузла ці ж напісаць невялікі sidecar-сэрвіс, які будзе сачыць за бягучым IP-адрасам VPN-сэрвісу і кіраваць DNS-запісы, прапісаныя ў кліентаў – у каго на што хопіць фантазіі.
З пункту гледжання маршрутызацыі мы можам адназначна ідэнтыфікаваць кліента за VPN па ім IP-адрасу, які выдаецца серверам VPN. Ніжэй – прымітыўны прыклад абмежавання доступу такому кліенту да сэрвісаў, ілюстрацыя на вышэйзгаданым Redis:
Тут цвёрда забараняецца падлучэнне на порт 6379, але пры гэтым захавана праца службы DNS, функцыянаванне якой даволі часта пакутуе пры складанні правіл. Таму што, як раней згадвалася, пры з'яўленні селектара да яго прымяняецца забаронная палітыка па змаўчанні, калі не пазначана іншае.
Вынікі
Такім чынам, з дапамогай пашыранага API Calico можна гнутка канфігураваць і дынамічна мяняць маршрутызацыю ў кластары і вакол яго. У агульным выпадку яго выкарыстанне можа выглядаць як стральба з гарматы па вераб'ях, а ўкараненне L3-сеткі з BGP- і IP-IP-тунэлямі выглядае монструозна ў простай усталёўцы Kubernetes у плоскай сетцы… Аднак у астатнім прылада выглядае суцэль жыццяздольным і карысным.
Ізаляцыя кластара для забеспячэння патрабаванняў бяспекі не заўсёды можа быць рэалізаваная, і менавіта ў такіх выпадках на дапамогу прыходзіць Calico (ці падобнае рашэнне). Прыведзеныя ў артыкуле прыклады (з невялікай дапрацоўкай) выкарыстоўваюцца ў некалькіх усталёўках нашых кліентаў у AWS.