diff --git a/content/ru/docker-envs.md b/content/ru/docker-envs.md index 80e5b5b50d83feb739bae556987bba7e1374219b..e450755e4c7c8a3627bb167742706fcd3f38cddc 100644 --- a/content/ru/docker-envs.md +++ b/content/ru/docker-envs.md @@ -1,7 +1,7 @@ --- title: Разделение докера на Ñреды. description: Как работать Ñ Ð½ÐµÑколькими docker-compose. -position: 3 +position: 2 category: DevOps --- diff --git a/content/ru/makefiles.md b/content/ru/makefiles.md index 1a0508fcfad506654f7441975533a80650bd50e6..c9fa26afaa8e89d2f472a5c2fd9ba2678c6c2296 100644 --- a/content/ru/makefiles.md +++ b/content/ru/makefiles.md @@ -1,7 +1,7 @@ --- title: Makefiles Ð´Ð»Ñ Ñ‡Ð°Ð¹Ð½Ð¸ÐºÐ¾Ð². description: Ðвтоматизируем по Ñтаринке. -position: 1 +position: 3 category: 'DevOps' --- diff --git a/content/ru/project-start.md b/content/ru/project-start.md index fc51a07b68f827128537db2e08483609deba1952..767bc3fedafbb7c5bf5845f0ba4a4c4c7f5180b7 100644 --- a/content/ru/project-start.md +++ b/content/ru/project-start.md @@ -246,25 +246,31 @@ $ wemake-python-styleguide --dev Теперь добавим конфигурационных файлов в корень проекта. Ðто мои конфигурации, которые Ñ Ð½Ð°Ñтроил под ÑебÑ, можешь менÑть их как хочешь. -`.mypy.ini` Ð´Ð»Ñ Ð½Ð°Ñтройки валидации типов. -```ini{}[.mypy.ini] -[mypy] -strict = True -ignore_missing_imports=True -allow_subclassing_any=True -allow_untyped_calls=True -pretty=True -show_error_codes=True -implicit_reexport=True -allow_untyped_decorators=True -``` -`.isort.cfg` Ð´Ð»Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¸ Ñортировки импортов. -```ini{}[.isort.cfg] -[isort] +Ð”Ð»Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¸ Ñортировки импортов и проверки типов добавим Ñледющее +в наш оÑновной файл проекта. + +Обычно Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÑÑŽ Ñти Ñекции Ñразу поÑле Ñекции `[tool.poetry.dev-dependencies]`. + +```toml{}[pyproject.toml] +... + +[tool.mypy] +strict = true +ignore_missing_imports = true +allow_subclassing_any = true +allow_untyped_calls = true +pretty = true +show_error_codes = true +implicit_reexport = true +allow_untyped_decorators = true +warn_return_any = false + +[tool.isort] +profile = "black" multi_line_output = 3 -include_trailing_comma = true -use_parentheses = true + +... ``` `.flake8` - ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð»Ð¸Ð½Ñ‚Ð¸Ð½Ð³Ð°. Тут довольно много. Ðто игнорирование ненужных кодов ошибок, которые не оÑобо-то и ошибки. @@ -416,13 +422,6 @@ repos: entry: yesqa language: system types: [ python ] - - - id: pytest - name: pytest - entry: pytest - language: system - pass_filenames: false - types: [ python ] ``` И не забываем про `.gitignore`. Его можно найти [тут](https://github.com/github/gitignore/blob/master/Python.gitignore). diff --git a/content/ru/start-with-k8s.md b/content/ru/start-with-k8s.md new file mode 100644 index 0000000000000000000000000000000000000000..02f6dcda0e3d1dd7c370aadfa0931b0acced8633 --- /dev/null +++ b/content/ru/start-with-k8s.md @@ -0,0 +1,753 @@ +--- +title: Ðачало работы Ñ kubernetes +description: Как там Ñто вÑÑ‘ разворачивать в двух Ñловах. +category: DevOps +position: 4 +--- + +# Проблема в изучении ÐºÑƒÐ±ÐµÑ€Ð½ÐµÑ‚ÐµÑ + +Многие люди, кто задавалиÑÑŒ вопроÑом как начать работать Ñ +кубернетеÑом ÑталкивалиÑÑŒ Ñ Ñ‚ÐµÐ¼, что Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ ÐºÑ€Ð°Ð¹Ð½Ðµ +Ð±Ð¾Ð»ÑŒÑˆÐ°Ñ ÑÐ»Ð¾Ð¶Ð½Ð°Ñ Ð¸ нет нормального опиÑÐ°Ð½Ð¸Ñ ÐºÐ°Ðº +завернуть маленький проект из одного проекта в Ñвой клаÑтер или +как развернуть Ñвой клаÑтер без боли. + +РвÑÑ‘ потому что вÑÑ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ð½Ð°Ñ†ÐµÐ»ÐµÐ½Ð° на большие +production-ready ÑиÑтемы Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ð¼ rps и тому подобным. + +Ð’ данной Ñтатье Ñ Ð¿Ð¾Ð¿Ñ€Ð¾Ð±ÑƒÑŽ иÑправить Ñто вÑеленÑкое +недопонимание иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ k3s, Ñвой комплюктер и немного знаний по кодингу. + +<div align="center"> + + + +</div> + +# Что такое ÐºÑƒÐ±ÐµÑ€Ð½ÐµÑ‚ÐµÑ Ð¸ почему Ñто лучше докера + +Многие ребÑта, кто хорошо знаком Ñ Ð´Ð¾ÐºÐµÑ€Ð¾Ð¼ и его +возможноÑÑ‚Ñми могут задаватьÑÑ Ñ‚Ð°ÐºÐ¸Ð¼ вопроÑом. +Ð”Ð»Ñ Ñ‚ÐµÑ… кто в танке, напомню, что докер +имеет вариант запуÑка в режиме клаÑтера. +Ðтот функционал называетÑÑ docker swarm. +Ð’ целом, swarm отдалённо напоминает kubernetes, +так как в Ñтом режиме докер, худо-бедно но умеет +автоÑкейлитÑÑ Ð¸ запуÑкатьÑÑ Ð² клаÑтере, +но Ñто вÑÑ‘ равно немного не то. + +<b-message type="is-info" has-icon> + Также замечу, что кубер активно развиваетÑÑ Ð¸ поддерживаетÑÑ. + огромным количеÑтво компаний. Рвот docker swarm уже по-немногу + умирает и Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ð¿Ð¾ нему не то чтобы Ñупер хороша. +</b-message> + +По большей чаÑти ÐºÑƒÐ±ÐµÑ€Ð½ÐµÑ‚ÐµÑ Ñто ÑиÑтема, +ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±ÑƒÐ´ÐµÑ‚ управлÑть вашими приложениÑми, +Ñледить за их ÑоÑтоÑнием и помогать вам в их +конфигурации. Кубер умеет очень много, поÑтому +вÑе интереÑные ÑпоÑобноÑти Ñ Ð² Ñтой Ñтатье не Ñмогу оÑветить, +но Ñамую базу попробую раÑÑказать. + +# Из чего ÑоÑтоит ÐºÑƒÐ±ÐµÑ€Ð½ÐµÑ‚ÐµÑ + +Так как Ñ Ð² Ñтой Ñтатье хотел затронуть +ÑовÑем базовые и практичеÑкие вещи, то раÑÑматривать +мы будем только крайне полезные компоненты. + +- Container +- Pod +- Deployment +- Service +- Ingress +- Namespace +- Secret +- ConfigMap + +Ртеперь раÑÑмотрим немного поподробнее. + +## Container + +Контейнеры не то чтобы чаÑть ÑÐ¿ÐµÑ†Ð¸Ñ„Ð¸Ñ‡Ð½Ð°Ñ Ð´Ð»Ñ ÐºÑƒÐ±ÐµÑ€Ð½ÐµÑ‚ÐµÑ. +С контейнерами вы можете быть знакомы из кучи ÑиÑтем. +Ð’ контекÑте кубера они не обладают никакими дополнительными +ÑвойÑтвами. Ðто ровно то же, что и контейнеры `containerd` +или те, Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼Ð¸ вы возилиÑÑŒ Ñ Ð´Ð¾ÐºÐµÑ€Ð¾Ð¼. Ðичего нового. + +СобираютÑÑ ÐºÐ¾Ð½Ñ‚ÐµÐ¹Ð½ÐµÑ€Ñ‹ Ð´Ð»Ñ ÐºÑƒÐ±ÐµÑ€Ð½ÐµÑ‚ÐµÑа ровно тем же образом, +что и Ð´Ð»Ñ Ð´Ð¾ÐºÐµÑ€Ð°. + +<b-message type="is-warning" has-icon> + + Ð’Ð°Ð¶Ð½Ð°Ñ Ñ€ÐµÐ¼Ð°Ñ€ÐºÐ°. Кубер Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ 2021 ÐºÑƒÐ±ÐµÑ€Ð½ÐµÑ‚ÐµÑ Ð½Ðµ поддерживает + докер как бÑкенд. Теперь кубер будет общатьÑÑ Ñ + containerd напрÑмую. Ðто значит, что теперь перед иÑпользованием + контейнеров Ñобранных на локальной машине надо будет импортировать их + в `containerd` иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ `ctr image import`. + +Как импортировать образы почитать можно в [Ñтой Ñтатье](https://cwienczek.com/2020/06/import-images-to-k3s-without-docker-registry/). + +</b-message> + +## Pod + +<div align="center"> + <img alt="Pods" style="width: 100%" src="/images/k3s_start/pods.svg"> +</div> + +Поды - Ñто логичеÑки ÑвÑзанные группы контейнеров. +Ðто ÑÐ°Ð¼Ð°Ñ Ð±Ð°Ð·Ð¾Ð²Ð°Ñ ÐµÐ´ÐµÐ½Ð¸Ñ†Ð° кубернетеÑа. + +Ð’ поде находитÑÑ Ð¾Ñ‚ одного до множеÑтва контейнеров. +ИнтереÑÐ½Ð°Ñ Ð¾ÑобенноÑть пода в том, что вÑе контейнеры +делÑÑ‚ один Ñетевой адреÑÑ. Другими Ñловами, +еÑли у Ð²Ð°Ñ Ð¾Ð´Ð¸Ð½ из контейнеров открыл порт `3000`, +то другие контейнеры из пода Ñти порты иÑпользовать не Ñмогут. + +То еÑть, еÑли вы хотите логичеÑки ÑвÑзанные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ +помеÑтить в под, то они могут ходить друг к другу через лупбек +адреÑа. Такие как `localhost` или `127.0.0.1`. + +## Deployment + +Поды Ñто круто, но еÑть одно но. Данные объекты неизменÑемые +и Ñам под Ñкейлить вручную занÑтие Ñомнительное. + +Конечно, никто не мешает Ñоздать вам вручную [ReplicaSet](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/) +и Ñамому крутить там нужные значениÑ. Ðо в Ñреднем +вам Ñ Ñтим возитьÑÑ Ð½Ðµ очень то хочетÑÑ. + +<br> + +Deployment нужна именно Ð´Ð»Ñ Ð¾Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ Ð¿Ð¾Ð´Ð¾Ð² и ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ +некоторых реÑурÑов, нужных Ð´Ð»Ñ Ñкейлинга. +Также Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ деплойментов можно делать откаты Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñ‡ÐµÑ€ÐµÐ· +механиз роллбеков. Я Ñто раÑÑматривать не буду. Тут только база. + +## Service + +Ð¡ÐµÑ€Ð²Ð¸Ñ - Ñто реÑурÑ, Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ которого поды могут общатьÑÑ +между Ñобой. По факту ÑÐµÑ€Ð²Ð¸Ñ Ð¾Ð¿Ð¸Ñывает, какие порты пода +открыты и перенаправлÑет трафик на них. + +ПредÑтавьте Ñебе под, который проÑто прокÑирует веÑÑŒ трафик Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ +порта на какой-нибудь порт пода. Ðто и еÑть Service. + +<div align="center"> + + + +</div> + +ВыглÑдит ÑÐµÑ€Ð²Ð¸Ñ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð½Ð¾ так как показано на кртинке выше. +Он направлÑет веÑÑŒ входной трафик Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ð¾Ð³Ð¾ порта на +порты подов. + +Также ÑÐµÑ€Ð²Ð¸Ñ Ð²Ñ‹Ñтупает как баланÑировщик. + +<b-message type="is-info" has-icon> + ЕÑли вы хотите Ñделать Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¾Ñ‚ одного пода до дргого внутри клаÑтера, то + вам придётÑÑ Ð¸Ñпользовать ÑервиÑ. + <br> + ЕÑли вы попробуете Ñделать Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð°Ð¿Ñ€Ñмую по IP пода, то у ваÑ, конечно же, + получитÑÑ, но Ñто довольно ÑÑ‚Ñ€Ð°Ð½Ð½Ð°Ñ Ð¸Ð´ÐµÑ Ð¸Ð·-за того, что при переÑоздании + пода у него может обновитÑÑ IP внутри клаÑтера. ПоÑтому лучше иÑпользовать ÑервиÑÑ‹. Также они потребуютÑÑ Ð´Ð»Ñ Ð¸Ð½Ð³Ñ€ÐµÑÑа. +</b-message> + +## Ingress + +ИнгреÑÑÑ‹ Ñто ÑÐµÑ€Ð²Ð¸Ñ Ð¾Ð¿Ð¸Ñывающий куда пуÑкать трафик, +который поÑтупает Ñнаружи клаÑтера. + +<div align="center"> + + + +</div> + +Принцип работы ингреÑÑа Ñледующий: + +Ð’Ñ‹ указываете хоÑÑ‚ ингреÑÑа и различные регекÑÑ‹ пути. +Ð’ завиÑимоÑти от входÑщего запроÑа ингреÑÑ Ð²Ñ‹Ð±Ð¸Ñ€Ð°ÐµÑ‚ в какой ÑÐµÑ€Ð²Ð¸Ñ +направить его и в какой порт. + +ÐаÑтройка ингреÑÑа доÑтаточно Ð³Ð¸Ð±ÐºÐ°Ñ Ð¸ Ñ Ð½Ðµ думаю, +что вы можете ÑтолкнутьÑÑ Ñ ÐºÐ°ÐºÐ¸Ð¼Ð¸ либо проблемами. + +## Namespace + +ÐеймÑпейÑÑ‹ Ñто логичеÑкие разделители ÑƒÑ€Ð¾Ð²Ð½Ñ Ð´Ð¾Ñтупа. + +Я предпочитаю иÑпользовать разные неймÑпейÑÑ‹ под различные логичеÑкие группы приложений. + +Ðапример, в моём клаÑтере еÑть отдельные неймÑпейÑÑ‹ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ приложениÑ. + +Скажем, у Ð¼ÐµÐ½Ñ ÐµÑть проект, в котором еÑть база данных и веб Ñервер. +Я держу их в одном неймÑпейÑе, который называетÑÑ Ñ‚Ð°ÐºÐ¶Ðµ, как и приложени. + +Рвот телеграм боты -- Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтаточно лёгкие. +ПоÑтому у Ð¼ÐµÐ½Ñ ÐµÑть неймÑÐ¿ÐµÐ¹Ñ Ñо вÑеми телеграм ботами. + +Ðта штука позволÑет проÑто лучше организовать Ñвой ÐºÑƒÐ±ÐµÑ€Ð½ÐµÑ‚ÐµÑ ÐºÐ»Ð°Ñтер. + +Также неймÑпейÑÑ‹ очень полезны Ð´Ð»Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡Ð¸Ð²Ð°Ð½Ð¸Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñтей +конкретного пользователÑ. +Ðапример, вы можете Ñоздать правило, которое будет разрешать пользователю +Ñмотреть на поды в каком-то неймÑпейÑе, но при Ñтом ему Ð½ÐµÐ»ÑŒÐ·Ñ Ð±ÑƒÐ´ÐµÑ‚ +что либо изменÑть. + +## Secret и ConfigMap + +Данные реÑурÑÑ‹ нужны только чтобы хранить +внутри клаÑтера какую-нибудь информацию. + +Ðапример вы можете Ñохранить в ConfigMap +переменные Ñреды и потом иÑпользовать их в подах в одном неймÑпейÑе. + +Ð’ Ñекреты обычно кидают Ñертификаты или какие-нибудь ключи. +Ðо так как Ñекреты не оÑобо Ñекретные принÑто иÑпользовать [Vault](https://www.vaultproject.io/docs/platform/k8s). Ðо так как Ñта ÑÑ‚Ð°Ñ‚ÑŒÑ Ð·Ð°Ñ‚Ñ€Ð°Ð³Ð¸Ð²Ð°ÐµÑ‚ только +оÑновы раÑÑматривать развертку и наÑтройку Vault мы не будем, ну и также HashiCorp +вÑÑ‘ довольно подробно раÑпиÑали Ñами. + +# Как развернуть k8s у ÑÐµÐ±Ñ + +Ð”Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ кубера еÑть пара вариантов. + +- k3s (ÐедоÑтупен под Windows) +- minikube + +Ðа первый взглÑд minikube может показатьÑÑ Ð»ÑƒÑ‡ÑˆÐ¸Ð¼ вариантом. +И он дейÑтвительно хорош тем, что его легко почиÑтить поÑле +Ñвоих ÑкÑпериментов. Однако, там еÑть проблемы Ñ Ð¸Ð½Ð³Ñ€ÐµÑÑами. +По факту они не работают и там надо окольными путÑми получать +адреÑа приложениÑ. + +<br> + +k3s - Ñто легковеÑÐ½Ð°Ñ production-ready Ñ€ÐµÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ k8s. Ingress у него работают +отлично, поÑтому Ñ Ð±ÑƒÐ´Ñƒ иÑпользовать его. + +<br> + +Я не буду зацикливатьÑÑ Ð½Ð° уÑтановке `minikube`, так как +он проÑÑ‚ в уÑтановке и первоначальной наÑтройке. Почитать подробнее можно в +[официальном гайде от minikube](https://minikube.sigs.k8s.io/docs/start/). + +С `k3s` вÑÑ‘ немного поÑложнее, но тоже доÑтаточно проÑто, еÑли немного разобратьÑÑ. ÐŸÐµÑ€Ð²Ð¾Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ ÑƒÑтановка опиÑана в [официальной доке k3s](https://rancher.com/docs/k3s/latest/en/installation/install-options/). + +## Подключение клаÑтера + +ПоÑле уÑтановки в домашней дериктории должен был быть +Ñгенерирован файл `.kube/config`. Ðтот файл Ñодержит данные Ð´Ð»Ñ +Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº различным клаÑтерам. `minikube` Сам добавлÑет +ключи Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº .kube/config. `K3S` не изменÑет +никаким образом `.kube/config`, поÑтому надо будет Ñто Ñделать вручную. + +Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы Ñто Ñделать Ñначала разберёмÑÑ ÐºÐ°Ðº выглÑдит конфиг. + +```yaml{}[.kube/config] +apiVersion: v1 +kind: Config +preferences: {} +# МаÑÑив клаÑтеров. +# Каждый Ñлемент -- данные Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ +# Тут также еÑть Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ клаÑтера. +clusters: +- name: hyper + cluster: + certificate-authority-data: DATA+OMITTED + server: https://192.168.1.55:6443 +- name: k3s-local + cluster: + certificate-authority-data: DATA+OMITTED + server: https://127.0.0.1:6443 +# МаÑÑив данных пользователÑ. +# Тут указаны пользователи Ñ +# различными Ñертификатами. +# Обычно Ð´Ð»Ñ Ñ€Ð°Ð·Ð½Ñ‹Ñ… Ñерверов у Ð²Ð°Ñ Ð±ÑƒÐ´ÑƒÑ‚ +# Различные данные Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ð°. +users: +- name: hyper-s3rius + user: + client-certificate-data: REDACTED + client-key-data: REDACTED +- name: k3s-user + user: + client-certificate-data: REDACTED + client-key-data: REDACTED +# МаÑÑив контекÑтов. +# КонтекÑÑ‚ - Ñто ÑвÑзующее звено +# между клаÑтероами и пользователÑми. +contexts: +- context: + cluster: hyper + user: hyper-s3rius + name: hyper +- context: + cluster: k3s-local + user: k3s-user + name: k3s +# Текущий контекÑÑ‚ указывает какой +# контекÑÑ‚ иÑпользовать по умолчанию. +current-context: "k3s" +``` + +Ð”Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ Ñ ÐºÑƒÐ±ÐµÑ€Ð¾Ð¼ из командной Ñтроки +можно иÑпользовать `kubectl`. Чтобы Ñменить контекÑÑ‚ в любой команде вы +можете передать параметр `--context $CONTEXT_NAME`, где `$CONTEXT_NAME` Ñто название контекÑта. + +Чтобы доÑтать данные Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº `k3s` надо поÑмотреть его конфиг +и Ñкопировать данные. Либо выÑтавить переменную Ñреды, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±ÑƒÐ´ÐµÑ‚ +указывать конфиг k3s. Конфиг Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ `k3s` лежит в файле `/etc/rancher/k3s/k3s.yaml`. + +Можете выполнить команду, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±ÑƒÐ´ÐµÑ‚ проÑить kubectl иÑпользовать указанный конфиг: +`export KUBE_CONFIG=/etc/rancher/k3s/k3s.yaml` + +<br> + +Либо Ñкопируйте нужные данные Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ñебе в `.kube/config`. + +ПоÑле наÑтройки выполните команду и проверьте что вам вернулоÑÑŒ +что-то подобное. Ðто значит, что никаких реÑурÑов пока в +клаÑтере нет. Ðто мы иÑправим позже. Пока что можно Ñказать, +что подключение прошло уÑпешно. + +```bash +$ kubectl --context "my-context" get pods +No resources found in default namespace. +``` + +ЕÑли же у Ð²Ð°Ñ Ð²Ñ‹Ð¿Ð°Ð´Ð°ÐµÑ‚ ошибка, например такаÑ. + +``` +The connection to the server localhost:8080 was refused - did you specify the right host or port? +``` + +То либо запуÑтите клаÑтер + +``` +sudo systemctl start k3s.service +``` + +Либо у Ð²Ð°Ñ Ð½ÐµÐ²ÐµÑ€Ð½Ñ‹Ðµ данные Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ð°. + +### Мониторинг клаÑтера + +Ð”Ð»Ñ Ð¿Ñ€Ð¾ÑÐ¼Ð°Ñ‚Ñ€Ð¸Ð²Ð°Ð½Ð¸Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ»Ð°Ñтером иÑпользуетÑÑ cli утилита `kubectl`. +Ðо Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы Ñ Ð½ÐµÐ¹ работать нужно получше понÑть что вообще в клаÑтере еÑть. + +Ð”Ð»Ñ Ñтого Ñ Ñоветую иÑпользовать [Lens](https://k8slens.dev/). Ðто крайне +удобный Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð´Ð»Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñвоим клаÑтером. +Также там еÑть очень ÐºÐ»Ñ‘Ð²Ð°Ñ Ð½Ð°Ñтрока, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ñама включит мониторинг +Ð¿Ð¾Ñ‚Ñ€ÐµÐ±Ð»ÐµÐ½Ð¸Ñ Ð¿Ð°Ð¼Ñти и процеÑÑора Ð´Ð»Ñ Ð²Ñех подов и клаÑтера в общем. + +Ðа локальной машине Ñто не очень много ÑмыÑла имеет, +а вот в проде было бы очень полезно. + +ВыглÑдит Lens примерно так: + +<div align="center" style="margin-top:15px;"> + + + +</div> + +Ð”Ð»Ñ Ð¸Ð·ÑƒÑ‡ÐµÐ½Ð¸Ñ **крайне наÑтоÑтельно рекомендую** наÑтроить Lens. + +# Ваше первое приложение в клаÑтере. + +### Сервер + +Давайте Ñоздадим Ñвоё первое приложение. + +Ð”Ð»Ñ Ñтого Ñ Ð±ÑƒÐ´Ñƒ иÑпользовать [express.js](https://expressjs.com/), так как он крайне популÑрен и проÑÑ‚. + +Ð”Ð»Ñ Ñтого Ñначала напишем Ñам Ñервер. Я буду иÑпользовать yarn, но можете и npm, +Ñути не поменÑет. + +Создайте какую-нибудь папку, где вы будете ÑкÑперементировать, откройте в ней ваш любимый тектовый редактор и проÑто копируйте файлы ниже. + +```json{}[package.json] +{ + "name": "req_counter", + "version": "1.0.0", + // Указан модуль, + // чтобы иÑпользовать нормальны импорты, + // а не require. + "type": "module", + "license": "MIT", + "scripts": { + // Скрипт Ñтарта Ñервера. + "server": "node index.js" + }, + // ЗавиÑимоÑти проекта. + "dependencies": { + "express": "^4.17.1" + } +} +``` + +И Ñамо приложение + +```js{}[index.js] +import express from "express"; +import { hostname } from "os"; +import { argv, exit } from "process"; + +// Серверное приложение. +const app = express(); + +// Глобальный Ñчётчик входÑщих запроÑов. +let requests = 0; + +// Обработка входÑщего запроÑа. +app.get("*", (req, res) => { + // Увеличиваем глобальный Ñчётчик запроÑов. + requests += 1; + // Логгируем входÑщий запроÑ. + console.log(`${req.method} ${req.url}`); + // Возвращаем информацию о текущем хоÑте и количеÑтве запроÑов. + res.json({ + requests: requests, + hostname: hostname(), + }); +}); + +// Ðргументы командной Ñтроки. +// Ðапрмиер yarn run server 127.0.0.1 8000 +const args = argv.slice(2); + +// ЕÑли передано неверное количеÑтво аргументов. +if (args.length != 2) { + console.error("Usage: yarn run server {host} {port}"); + exit(1); +} + +// ПроÑтейший "парÑинг" аргументов командной Ñтроки. +const host = args[0]; +const port = args[1]; + +// Старт Ñервера. +app.listen(port, host, () => { + console.log(`Server listening at http://${host}:${port}`); +}); +``` + +Ðто вÑÑ‘. Сервер готов. + +<hr> +ПротеÑтируем запуÑк Ñервера выполнив команду ниже и открыв в +Ñвоём любимом браузере http://localhost:8080. + +``` +yarn run server 0.0.0.0 8080 +``` + +У Ð¼ÐµÐ½Ñ Ð²ÑÑ‘ работает и уÑпешно отдаётÑÑ Ð½ÑƒÐ¶Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ. + +```json +{ + "requests": 1, + "hostname": "s3rius-pc" +} +``` + +### Docker образ + +Теперь Ñоздадим докер образ приложениÑ. + +Добавим `.dockerignore`, чтобы игнорировать ненужные файлы во Ð²Ñ€ÐµÐ¼Ñ Ñборки образа. + +```gitignore{}[.dockerignore] +node_modules/ +``` + +И добавим в проект `Dockerfile` Ð´Ð»Ñ Ð¾Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ Ñамого процеÑÑа Ñборки. + +```dockerfile{}[Dockerfile] +FROM node:17-alpine + +WORKDIR /app +COPY . /app/ + +RUN yarn install + +CMD [ "yarn", "run", "server", "0.0.0.0", "8000"] +``` + +Давайте Ñоберём и запуÑтим проект в контейнере. + +```bash +docker build --tag="s3rius/req-counter-express:latest" . + +docker run --rm -it -p 3400:8000 "s3rius/req-counter-express:latest" +``` + +Можете проверить, что приложение работает уÑпешно, открыв в браузере http://localhost:3400. + +У Ð¼ÐµÐ½Ñ Ð² ответ пришло то же Ñообщение. Только, как можно заметить, +`hostname` поменÑлÑÑ. Ðа Ñамом деле контейнеры иÑпользуют Ñвои hostname +отличные от `hostname` локальной машины. + +```json +{ + "requests": 10, + "hostname": "8f23adadc640" +} +``` + +Вариантов как положить Ñто приложение в K8S неÑколько. + +- Ð’Ñ‹ можете запушить Ñобранное приложение в [Docker HUB](https://hub.docker.com/) и иÑпользовать его. +- Можете иÑпользовать мой образ `s3rius/req-counter-express:latest` +- Импортировать Ñобранный образ как tar файл и импортировать его в containerd напрÑмую. + Как Ñто Ñделать почитать можно в [Ñтой Ñтатье](https://cwienczek.com/2020/06/import-images-to-k3s-without-docker-registry/). + +### Деплой в k8s + +Создайте папку `kube` в папке проекта и теперь мы будем работать в ней. +Ð’Ñе реÑурÑÑ‹ будут опиÑаны yaml-файлами. + +```yaml{}[kube/deployment.yml] +--- +apiVersion: apps/v1 +kind: Deployment +# метаданные Ñамого деплоймента. +metadata: + name: req-counter-deployment +spec: + # КоличеÑтво реплик пода. + replicas: 1 + # Селектор, который выбирает + # какие поды принадлежат Ñтому деплойменту. + selector: + matchLabels: + app: req-counter + # Шаблон пода, + # который будет иÑпользоватьÑÑ Ð¿Ñ€Ð¸ + # маштабировании. + template: + # Метаданные пода. + # тут обычно помещаютÑÑ Ð»ÐµÐ¹Ð±Ð»Ñ‹, + # Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ которых деплоймент идентифицирует + # Ñвои поды. + metadata: + labels: + app: req-counter + spec: + # МаÑÑÑив контейнеров + containers: + # Ðазвание контейнера внутри пода. + - name: req-counter-app + # Образ приложениÑ. + image: s3rius/req-counter-express:latest + # РеÑурÑÑ‹ требуемые Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ приложениÑ. + resources: + # Минимальное количеÑтво реÑурÑов, + # которое клаÑтер гарантированно предоÑтавит приложению. + # Также данные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¸ÑпользуютÑÑ Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, + # чтобы выÑÑнить на какой ноде запуÑкать приложение. + requests: + memory: "50Mi" + cpu: "30m" + # МакÑимально возможные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ. + # ЕÑли приложение выйдет за лимиты, + # то кубер убьёт приложение. + limits: + memory: "128Mi" + cpu: "100m" + # Порты на которых открыты приложениÑ. + ports: + - containerPort: 8000 + protocol: TCP +``` + +Теперь опишем ÑÐµÑ€Ð²Ð¸Ñ Ð´Ð»Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñ‚Ñ€Ð°Ñ„Ð¸ÐºÐ¾Ð¼. + +```yaml{}[kube/service.yml] +--- +apiVersion: v1 +kind: Service +# Метадата ÑервиÑа. +metadata: + name: req-counter-service +spec: + # Селектор подов, + # которым будет пуÑкатьÑÑ Ñ‚Ñ€Ð°Ñ„Ð¸Ðº. + # Трафик может идти в любой под, + # который матчит данному Ñелектору. + selector: + app: req-counter + # Порты Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐºÑÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñоединений. + ports: + # Порт ÑервиÑа + - port: 80 + # Порт пода, куда будет идти трафик дальше. + targetPort: 8000 +``` + +И в поÑледнюю очередь опишем наш ингреÑ. + +```yaml{}[kube/ingress.yml] +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +# Метаданные ингреÑÑа. +metadata: + name: req-counter-ingress + labels: + name: req-counter-ingress +spec: + # Правила роутинга. + rules: + # Требуемый хоÑÑ‚. + - host: req-counter.local + http: + paths: + # Тип пути Prefix значит, + # что вÑе запроÑÑ‹, которые начинаютÑÑ c + # ${path} будут матчитÑÑ Ñ‚ÑƒÑ‚. + - pathType: Prefix + # Сам путь. + path: "/" + backend: + service: + # Ðазвание нашего ÑервиÑа. + name: req-counter-service + # Порт ÑервиÑа, куда перенаправлÑть входÑщий трафик. + port: + number: 80 +``` + +Перед тем, как Ñоздать вÑе опиÑанные реÑурÑÑ‹ Ñоздадим неймÑпейÑ. + +```bash +$ kubectl --context k3s create namespace req-couter-ns +namespace/req-couter-ns created +``` + +ПоÑле того, как неймÑÐ¿ÐµÐ¹Ñ Ñоздан Ñамое Ð²Ñ€ÐµÐ¼Ñ Ñделать поÑледний штрих. + +<div align="center"> + + + +</div> + +```bash +$ kubectl --context k3s --namespace req-couter-ns apply -f ./kube/ +deployment.apps/req-counter-deployment created +ingress.networking.k8s.io/req-counter-ingress created +service/req-counter-service created +``` + +Готово. Теперь вы можете зайти в lens, выбрать Ñвой клаÑтер из ÑпиÑка +и поÑмотреть как там поживает ваше приложение. + +Также не забудьте указать неймÑпей, в который вы беплоиди приложение. + +ВыглÑдит Ñто чудо примерно так: + +<div align="center"> + + + +</div> + +Также можно иÑпользовать команду и вывеÑти вÑÑ‘ Ñебе в терминал. + +``` +$ kubectl --context k3s --namespace req-couter-ns get all +NAME READY STATUS RESTARTS AGE +pod/req-counter-deployment-764476db97-dt2tc 1/1 Running 0 8m11s + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/req-counter-service ClusterIP 10.43.50.23 <none> 80/TCP 8m11s + +NAME READY UP-TO-DATE AVAILABLE AGE +deployment.apps/req-counter-deployment 1/1 1 1 8m11s + +NAME DESIRED CURRENT READY AGE +replicaset.apps/req-counter-deployment-764476db97 1 1 1 8m11s +``` + +### Маштабирование + +Ð’ рамках демонÑтрации давате поменÑем значение +`replicas` в нашем файле деплоймента до `3`. + +```yaml{}[kube/deployment.yml] +... +spec: + # КоличеÑтво реплик пода. + replicas: 3 +... +``` + +ПоÑле Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ñто ещё раз вызовите команду apply. + +```bash +$ kubectl --context k3s --namespace req-couter-ns apply -f ./kube/ +deployment.apps/req-counter-deployment configured +ingress.networking.k8s.io/req-counter-ingress unchanged +service/req-counter-service unchanged +``` + +Как можно видеть изменилÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ наш `Deployment`. +ОÑтальные реÑурÑÑ‹ оÑталиÑÑŒ нетронутыми. + +Давайте поÑмотрим на поды в нашем неймÑпейÑе. + +``` +$ kubectl --context k3s --namespace req-couter-ns get pods +NAME READY STATUS RESTARTS AGE +req-counter-deployment-764476db97-dt2tc 1/1 Running 0 13m +req-counter-deployment-764476db97-tdjrb 1/1 Running 0 69s +req-counter-deployment-764476db97-x28fr 1/1 Running 0 69s +``` + +Как видно, вÑÑ‘ правильно. Теперь у Ð½Ð°Ñ 3 пода +нашего приложениÑ. + + +Теперь Ñ Ð¿Ð¾Ð¹Ð´Ñƒ и выполню кучу запроÑов по адреÑу http://req-counter.local/ +и получу баланÑировку между подами из коробки, без дополнительных +конфигураций. + +ЕÑли у Ð²Ð°Ñ Ð½Ðµ получаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ адреÑ. Добавьте данный хоÑÑ‚ Ñебе в +`/etc/hosts` на линукÑе или в `C:\Windows\System32\drivers\etc\hosts` на windows, +допиÑав в конец файла Ñледующее: + +``` +... +127.0.0.1 req-couter.local +``` + +И теперь вы можете открыть в браузере Ñвоё приложение и увидеть, +как ÐºÑƒÐ±ÐµÑ€Ð½ÐµÑ‚ÐµÑ Ð·Ð°Ð±Ð¾Ñ‚Ð»Ð¸Ð²Ð¾ направлÑет трафик туда, куда вы хотите. + +<div align="center"> + + + +</div> + + +### Как мне очиÑтить мой клаÑтер? + +Ð’ÑÑ‘ очень проÑто. + +Так как у Ð½Ð°Ñ Ð¸Ð¼ÐµÑŽÑ‚ÑÑ Ð¾Ð¿Ð¸ÑÐ½Ð¸Ñ Ñ€ÐµÑурÑов, то мы +можем удалить вÑÑ‘ Ñразу иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñƒ + +```bash +$ kubectl --context k3s --namespace req-couter-ns delete -f ./kube/ +deployment.apps "req-counter-deployment" deleted +ingress.networking.k8s.io "req-counter-ingress" deleted +service "req-counter-service" deleted +``` + +Таким образом k8s удалит вÑе опиÑанные реÑурÑÑ‹ из вашего клаÑтера. + +До новых вÑтреч. diff --git a/content/ru/traefik.md b/content/ru/traefik.md index c82f17bdb0a6220c998b87389d9e393d807159ed..f6d69cad70bf4b2927d17b8ab688bbc138d4763c 100644 --- a/content/ru/traefik.md +++ b/content/ru/traefik.md @@ -7,7 +7,6 @@ category: DevOps # Traefik - роутинг проÑто - Ð¡ÐµÐ³Ð¾Ð´Ð½Ñ Ñ Ð±Ñ‹ хотел раÑÑказать о такой клёвой штуке, как [Traefik](https://traefik.io/traefik/). Ðе так давно Ñ Ð¿ÐµÑ€ÐµÐ²Ñ‘Ð» вÑе ÑервиÑÑ‹ Ñвоего Ñервера на traefik и Ñто буквально Ñделало жизнь проще. Ð¡ÐµÐ³Ð¾Ð´Ð½Ñ Ñ Ñ€Ð°ÑÑкажу вам зачем он нужен, как его наÑтроить, и покажу на примере, как именно он помогает. По факту, Ñто nginx на Ñтероидах, в плане конфигурации, потому что в traefik за Ñ‚ÐµÐ±Ñ Ñделано гораздо больше. # Что такое traefik @@ -33,6 +32,7 @@ Traefik - Ñто ÑиÑтема, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет наÑтро </div> ## Ðрхитектура + Ð’ официальной документации зариÑована ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ñхема работы traefik: <div align="center"> @@ -43,21 +43,24 @@ Traefik - Ñто ÑиÑтема, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет наÑтро Как можно видеть по данному изображению, еÑть 5 оÑновных ÑоÑтавлÑющих traefik, а именно: -* entrypoints -* routers -* rules (чаÑть routers) -* middlewares (чать routers) -* services +- entrypoints +- routers +- rules (чаÑть routers) +- middlewares (чать routers) +- services ### Entrypoint + ЯвлÑÑŽÑ‚ÑÑ Ð¾Ñновными ÑлушателÑми входÑщих Ñоединений. Через них проходит веÑÑŒ трафик. ЕÑли попробовать объÑÑнить в двух Ñловах: "Порт, на который должно прийти входÑщее Ñоединение", - вполне Ñебе неплохое объÑÑнение. Ð’ данном туториале Ñ Ñоздам 2 `entrypoint`, которые будут Ñлушать на http и https. -### Routers, Rules и Middlewares -Роутер - ÑвÑзующее звено между `entrypoint` и ÑервиÑом, куда нужно направить трафик. Роутер хранит в Ñебе информацию, куда направить входÑщий трафик, и +### Routers, Rules и Middlewares + +Роутер - ÑвÑзующее звено между `entrypoint` и ÑервиÑом, куда нужно направить трафик. Роутер хранит в Ñебе информацию, куда направить входÑщий трафик, и правила, по которым можно определить, пуÑкать ли трафик дальше. Rules - Ñто и еÑть те Ñамые правила, которые определÑÑŽÑ‚, через какой роутер пуÑтить трафик. ДопуÑтим, у Ð²Ð°Ñ Ð² конфиге еÑть Ñледующие правила: + ``` Host(`myapp.com`) && (PathPrefix(`/api`) || PathPrefix(`/memes`)) ``` @@ -75,7 +78,6 @@ Host(`myapp.com`) && (PathPrefix(`/api`) || PathPrefix(`/memes`)) Ð’Ñ‹, конечно же, можете иÑпользовать локально уÑтановленную верÑию, вÑÑ‘ будет работать, как чаÑÑ‹. </b-message> - Ð”Ð»Ñ Ð½Ð°ÑˆÐµÐ³Ð¾ оÑновного traefik на Ñервере мы Ñоздадим небольшой docker-compose.yml, файл конфига и папочку Ñ Ñертификатами. Структура будет ÑледующаÑ: @@ -100,13 +102,20 @@ services: # The official v2.0 Traefik docker image image: traefik:v2.4.8 container_name: traefik_main - command: + command: + # Включает проÑлушивание докера на новые ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð¸ Ñледит за лейблами контейнеров. - --providers.docker=true + # Отключает автоматичеÑкое Ñоздание роутеров ко вÑем контейнерам на Ñервере. - --providers.docker.exposedbydefault=false + # Сеть докера, по которой будет выполнÑÑ‚ÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ðµ к контейнерам. - --providers.docker.network=traefik-shared + # Папка Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ñ‹Ð¼ файлом. - --providers.file.directory=/etc/traefik/dynamic + # Включает отÑлеживание изменений файла конфигурации. - --providers.file.watch=true + # Создаёт entrypoint Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ http и Ñлушает 80 порт. - --entrypoints.http.address=:80 + # Создаёт entrypoint Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ https и Ñлушает 443 порт. - --entrypoints.https.address=:443 ports: # The HTTP port @@ -119,12 +128,16 @@ services: environment: MAIN_HOST: 192.168.1.89 volumes: - # So that Traefik can listen to the Docker events + # ОбÑзательный вольюм. Так траефик может Ñлушать + # ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð¿Ñ€Ð¾Ð¸ÑходÑщие в демоне докера. - /var/run/docker.sock:/var/run/docker.sock + # Вольюм Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð¼ конфигурации. - ./config.toml:/etc/traefik/dynamic/traefik.toml + # Папка Ñертификатов. - ./certs:/etc/certs/ networks: + # Сетка, внутри которой будут находитÑÑ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ. traefik-shared: name: traefik-shared @@ -132,16 +145,6 @@ networks: Вот какие параметры Ñ Ð¿ÐµÑ€ÐµÐ´Ð°ÑŽ в `traefik-cli`. -| Параметр | Что делает | -|-------------------------------------------------|----------------------------------------------------------------------------------| -| `providers.docker=true` | Включает проÑлушивание докера на новые ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð¸ Ñледит за лейблами контейнеров. | -| `providers.docker.exposedbydefault=false` | Отключает автоматичеÑкое Ñоздание роутеров ко вÑем контейнерам на Ñервере. | -| `providers.docker.network=traefik-shared` | Сеть докера, по которой будет выполнÑÑ‚ÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ðµ к контейнерам. | -| `providers.file.directory=/etc/traefik/dynamic` | Папка Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ñ‹Ð¼ файлом. | -| `providers.file.watch=true` | Включает отÑлеживание изменений файла конфигурации. | -| `entrypoints.http.address=:80` | Создаёт entrypoint Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ http и Ñлушает 80 порт. | -| `entrypoints.https.address=:443` | Создаёт entrypoint Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ https и Ñлушает 443 порт. | - Конечно, вы вÑегда можете глÑнуть `traefik --help` и подобрать Ñебе желаемые параметры. Также из docker-compose файла видно, что Ñ Ñоздал докер Ñеть `traefik-shared`, которую в дальнейшем буду иÑпользовать на вÑех контейнерах, которым требуетÑÑ Ñвой домен. @@ -153,16 +156,19 @@ networks: Ð”Ð»Ñ Ð³ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ð¸ локальных Ñертификатов Ñ Ð¸Ñпользую тулу [mkcert](https://github.com/FiloSottile/mkcert). Ð”Ð»Ñ Ð»ÑŽÐ±Ð¾Ð³Ð¾ локального домена Ñ Ð´ÐµÐ»Ð°ÑŽ что-то типа: + ```bash mkcert "*.local" mv _wildcard.local-key.pem local.key mv _wildcard.local.pem local.pem ``` + И помещаю Ñто в папочку `certs` Ñ€Ñдом Ñ `docker-compose.yml`. ПоÑле того как Ñ Ñоздал вÑе нужные Ñертефикаты Ð´Ð»Ñ Ð²Ñех доменов, их надо указать в файле `config.toml` в папочке traefik. Вот пример: + ```toml{}[config.toml] [tls.options] [tls.options.default] @@ -173,7 +179,7 @@ mv _wildcard.local.pem local.pem [[tls.certificates]] # Я тут указываю /etc/certs, потому что в docker-compose # у Ð½Ð°Ñ volume на Ñту папку. - certFile = "/etc/certs/local.pem" + certFile = "/etc/certs/local.pem" keyFile = "/etc/certs/local.key" ``` @@ -183,16 +189,18 @@ mv _wildcard.local.pem local.pem ```toml [[tls.certificates]] - certFile = "/etc/certs/<certFile>" + certFile = "/etc/certs/<certFile>" keyFile = "/etc/certs/<keyFile>" ``` ПоÑле Ñтого вы можете запуÑкать traefik и наÑлаждатьÑÑ Ð´Ð¾Ð¼ÐµÐ½Ð°Ð¼Ð¸ Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… контейнеров. # ЗапуÑк приложений + Теперь Ñконфигурируем приложение таким образом, чтобы к нему можно было обращатьÑÑ Ñ‡ÐµÑ€ÐµÐ· доменное имÑ. Ð”Ð»Ñ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð° возьмем мелкое приложение на nodejs Ñо Ñледующей Ñтруктурой проекта: + ``` . ├── docker-compose.yml @@ -223,18 +231,18 @@ app.listen(PORT, () => { ``` ```json{}[package.json] -{ - "name": "express-test", - "version": "1.0.0", - "main": "index.js", - "author": "s3rius", - "license": "MIT", - "scripts": { - "runserver": "node index.js" - }, - "dependencies": { - "express": "^4.17.1" - } +{ + "name": "express-test", + "version": "1.0.0", + "main": "index.js", + "author": "s3rius", + "license": "MIT", + "scripts": { + "runserver": "node index.js" + }, + "dependencies": { + "express": "^4.17.1" + } } ``` @@ -260,10 +268,15 @@ services: server: build: . labels: + # Включить поддержку роутинга через traefik. - traefik.enable=true + # ПоÑтавить правило роутинга, еÑли Host запроÑа равен test_node.local. - traefik.http.routers.test_node.rule=Host(`test_node.local`) + # Слушать на entrypoint http (80 порт, Ñто было объÑвлено в параметрах запуÑка traefik). - traefik.http.routers.test_node.entrypoints=http + # СервиÑ, ÑвÑзанный Ñ Ñ€Ð¾ÑƒÑ‚ÐµÑ€Ð¾Ð¼ test_node. - traefik.http.routers.test_node.service=node_test + # Порт, куда направлÑть запроÑÑ‹ в ÑÐµÑ€Ð²Ð¸Ñ node_test. - traefik.http.services.node_test.loadbalancer.server.port=3000 command: runserver networks: @@ -271,6 +284,7 @@ services: networks: + # Докер Ñеть, в которой находитÑÑ traefik. traefik-shared: name: traefik-shared external: true @@ -282,14 +296,6 @@ networks: Как вы видите, приложение Ñлушает на порт `3000` и отвечает Ñвим hostname и количеÑтвом обработанных запроÑов. Рв docker-compose.yml, в отличие от обычного проекта, поÑвилиÑÑŒ labels. -| Лейбл | Что делает | -|---------------------------------------------------------------|---------------------------------------------------------------------------------------| -| ``traefik.enable=true`` | Включить поддержку роутинга через traefik | -| ``traefik.http.routers.<router>.rule=Host(`test_node.local`)`` | ПоÑтавить правило роутинга, еÑли Host запроÑа равен test_node.local | -| ``traefik.http.routers.<router>.entrypoints=http`` | Слушать на entrypoint http (80 порт, Ñто было объÑвлено в параметрах запуÑка traefik) | -| ``traefik.http.routers.<router>.service=<service>`` | СервиÑ, ÑвÑзанный Ñ Ñ€Ð¾ÑƒÑ‚ÐµÑ€Ð¾Ð¼ test_node | -| ``traefik.http.services.<service>.loadbalancer.server.port=3000`` | Порт, куда направлÑть запроÑÑ‹ в ÑÐµÑ€Ð²Ð¸Ñ node_test | - <hr/> <b-message type="is-danger" has-icon> @@ -300,14 +306,15 @@ networks: Обратите внимание на коÑые кавычки при указании хоÑта! Ðто обÑзательно. -Ð’ объÑвлении labels могут быть иÑпользованы переменные Ñреды. Ðапример: -``traefik.http.routers.test_node.rule=Host(`${APP_HOST}`)`` +Ð’ объÑвлении labels могут быть иÑпользованы переменные Ñреды. Ðапример: +`` traefik.http.routers.test_node.rule=Host(`${APP_HOST}`) `` </b-message> Также можно видеть, что Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ð» контейнер к Ñети, которую мы указывали в контейнере traefik. ЗдеÑÑŒ она помечена как external. Теперь мы можем Ñпокойно запуÑтить наш ÑервиÑ. Ð”Ð»Ñ Ñтого воÑпользуемÑÑ Ñледующей командой: + ```bash docker-compose up --build --scale server=3 ``` @@ -328,6 +335,7 @@ $ curl -H "Host: test_node.local" "http://localhost" Как вы видите, traefik баланÑирует между контейнерами за наÑ. И Ñ Ñчитаю, что Ñто - победа. ## Подключение TLS и Ñертификатов + Тут вÑÑ‘ не намного Ñложнее. Давайте немного поменÑем лейблы нашего контейнера. ```yaml @@ -347,11 +355,12 @@ services: Ðа данном Ñтапе вам потребуетÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ Ñвой хоÑÑ‚ в `/etc/hosts`, еÑли вы иÑпользуете нормальную ÑиÑтему. Ðо еÑли вы вÑÑ‘ же на windows, то вам потребуетÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ правило в `C:\Windows\System32\drivers\etc\hosts`. И добавлÑем в конец файла запиÑÑŒ: + ``` 127.0.0.1 test_node.local ``` -И также вам потребуетÑÑ cертификат на Ñтот домен. +И также вам потребуетÑÑ cертификат на Ñтот домен. Ð”Ð»Ñ Ñтого: 1. Создадим Ñертификат через `mkcert`, как упоминалоÑÑŒ ранее; @@ -365,12 +374,12 @@ $ curl --insecure https://test_node.local {"request_num":0,"host":"7417ac8fda92"} ``` - ## Добавление локальных ÑервиÑов не из докера Ð’Ñе те флаги, которые мы указываем в labels, вы также можете указать в файле конфигурации Ñ€Ñдом Ñ docker-compose.yml, указав конкретный ip адреÑ. Ðапример: + ```toml [http.routers] # Define a connection between requests and services @@ -387,9 +396,9 @@ $ curl --insecure https://test_node.local url = "http://192.168.1.89:8100" ``` - # Создание локального DNS -Ð’ данном пункте Ñ Ð±Ñ‹ хотел раÑÑказать, как наÑтроить Ñвой DNS-Ñервер, чтобы ваши домены были доÑтупны вÑем уÑтройÑтвам в локальной Ñети. Ð”Ð»Ñ Ñтого Ñ Ð±ÑƒÐ´Ñƒ иÑпользовать dnsmasq. ПользователÑм винды он недоÑтупен, поÑтому Ñоветую развернуть маленький домашний Ñервер на линукÑе. + +Ð’ данном пункте Ñ Ð±Ñ‹ хотел раÑÑказать, как наÑтроить Ñвой DNS-Ñервер, чтобы ваши домены были доÑтупны вÑем уÑтройÑтвам в локальной Ñети. Ð”Ð»Ñ Ñтого Ñ Ð±ÑƒÐ´Ñƒ иÑпользовать dnsmasq. ПользователÑм винды он недоÑтупен, поÑтому Ñоветую развернуть маленький домашний Ñервер на линукÑе. Ð”Ð»Ñ Ñтого уÑтановите `dnsmasq` и найдите и раÑкомментируйте, либо добавьте Ñледующие Ñтрочки в файл `/etc/dnsmasq.conf`: @@ -406,6 +415,7 @@ address=/.<other_domain>/<your_local_ip> Чтобы Ñто узнать, поÑмотрите Ñвой ip через роутер или выполните `ip addr`. Вообще, `dnsmasq` парÑит файл `/etc/hosts` и вы можете туда добавлÑть запиÑи, типа: + ``` 192.168.1.1 mydomain.local ``` @@ -413,6 +423,7 @@ address=/.<other_domain>/<your_local_ip> Ðо так как Ñ ÑƒÐºÐ°Ð·Ð°Ð» `address`, то Ñто необÑзательно. `dnsmasq` и без Ñвного ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð¿Ð¾Ð´Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð² должен будет работать отлично. ЗапуÑтите `dnsmasq` в режиме ÑревиÑа: + ```bash sudo systemctl enable dnsmasq.service sudo systemctl start dnsmasq.service @@ -445,7 +456,7 @@ services: - traefik.http.routers.traefik_router.entrypoints=https - traefik.http.routers.traefik_router.tls=true - command: + command: - --api.dashboard=true ... ``` @@ -457,5 +468,4 @@ services: [](/images/traefik_imgs/traefik_web.png) - Разве Ñто не круто? diff --git a/layouts/default.vue b/layouts/default.vue index 42bd8ba84026c5a2e338e927f2dfea46dcf6347a..80912f79ed096da4d38fef6beed3bc401aa42a01 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -1,9 +1,9 @@ <template> <div class="page"> - <b-navbar type="is-primary w-100"> + <b-navbar type="is-primary w-100" :fixed-top="true"> <template #brand> <NuxtLink to="/" class="navbar-item"> - <img src="/icon.png" alt="Logo" /> S3rius' dev blog + <img src="/icon.png" alt="Logo" /> Dev blog </NuxtLink> </template> <template #end> @@ -24,7 +24,7 @@ :key="category" class="is-hidden-desktop" > - <p class="navbar-item is-inactive divider"> + <p class="navbar-item is-inactive category"> <span>{{ category }}</span> </p> <NuxtLink @@ -73,7 +73,8 @@ export default defineComponent({ const categories = ref([]) $content({ deep: true }) .only(['category', 'slug', 'title', 'position']) - .sortBy('createdAt', 'asc') + .sortBy('category', 'asc') + .sortBy('position', 'asc') .fetch() .then((pages) => { let cats = new Map() @@ -94,12 +95,11 @@ export default defineComponent({ </script> <style scoped lang="scss"> -.divider { +.category { width: 100%; text-align: center; - border-bottom: 1px solid #000; - line-height: 0.1em; margin: 10px 0 20px; + color: gray; span { background: #fff; diff --git a/nuxt.config.js b/nuxt.config.js index 5d998f999d059fe200d08995436efb676376cc9c..d9db53483ccbd6aa00aafcc455e72354f41627e3 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -70,7 +70,7 @@ export default { short_name: 'Dev blog', lang: 'ru', background_color: '#fafdff', - theme_color: '#fafdff', + theme_color: '#687cec', }, icon: { fileName: 'icon.png', diff --git a/pages/_slug.vue b/pages/_slug.vue index 0d0578f9ab9d056eb6f55e054e3315999167d0a3..8063ad73c9bd7e5619420fd70ab01647b4115f20 100644 --- a/pages/_slug.vue +++ b/pages/_slug.vue @@ -44,10 +44,16 @@ export default defineComponent({ ] if (doc.image) { meta_data.push({ - hid: 'og:description', - name: 'og:description', + hid: 'og:image', + name: 'og:image', content: doc.image, }) + } else { + meta_data.push({ + hid: 'og:image', + name: 'og:image', + content: 'https://s3rius.blog/logo.png', + }) } meta.value = meta_data }) @@ -83,7 +89,7 @@ export default defineComponent({ font-weight: 300; letter-spacing: -0.01em; color: rgba(0, 0, 0, 0.54); - margin: 1em 0.5em; + margin: 1em 0; } h1 { @@ -139,5 +145,10 @@ export default defineComponent({ margin-bottom: 0.5em !important; margin-left: 1.25em !important; } + + table { + display: inline-block; + overflow: auto; + } } </style> diff --git a/static/images/k3s_start/ingress-overview.png b/static/images/k3s_start/ingress-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..a912cb15fd29e8acbcd8ac90b75ec057e73b16be Binary files /dev/null and b/static/images/k3s_start/ingress-overview.png differ diff --git a/static/images/k3s_start/kube_intro.jpg b/static/images/k3s_start/kube_intro.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0bc3e34514f1565c45152ec6a917a7a8bd77d36c Binary files /dev/null and b/static/images/k3s_start/kube_intro.jpg differ diff --git a/static/images/k3s_start/kubectl-apply.png b/static/images/k3s_start/kubectl-apply.png new file mode 100644 index 0000000000000000000000000000000000000000..d29ba4cf6479c1235d5dad7613ed3261ec77033d Binary files /dev/null and b/static/images/k3s_start/kubectl-apply.png differ diff --git a/static/images/k3s_start/lens-deployed.png b/static/images/k3s_start/lens-deployed.png new file mode 100644 index 0000000000000000000000000000000000000000..65478472a1e5741395fc12dbfc91c55b98b52fc6 Binary files /dev/null and b/static/images/k3s_start/lens-deployed.png differ diff --git a/static/images/k3s_start/lens-example.png b/static/images/k3s_start/lens-example.png new file mode 100644 index 0000000000000000000000000000000000000000..6619403de1014f69cc92fbfd1524c0b730888178 Binary files /dev/null and b/static/images/k3s_start/lens-example.png differ diff --git a/static/images/k3s_start/pods.svg b/static/images/k3s_start/pods.svg new file mode 100644 index 0000000000000000000000000000000000000000..b63f415f3019e0f92c442c3ca14fa973d89b5d3f --- /dev/null +++ b/static/images/k3s_start/pods.svg @@ -0,0 +1,484 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 668 277" style="enable-background:new 0 0 668 277;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#FFFFFF;stroke:#326DE6;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st1{opacity:0.71;fill:#326CE6;} + .st2{opacity:0.45;fill:#FFFFFF;} + .st3{fill:#FFFFFF;stroke:#006DE9;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st4{fill:#006DE9;} + .st5{fill:#A0CAEA;} + .st6{fill:#FFFFFF;} + .st7{opacity:0.13;} + .st8{fill:url(#SVGID_1_);} + .st9{fill:url(#SVGID_2_);} + .st10{fill:#FFFFFF;stroke:#006DE9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st11{fill:#FFFFFF;stroke:#006DE9;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st12{fill:#FFFFFF;stroke:#326DE6;stroke-width:3.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st13{fill:#326DE6;} + .st14{fill:none;stroke:#326DE6;stroke-width:2.4;stroke-miterlimit:10;} + .st15{fill:#A0CAE9;} + .st16{fill:#FFFFFF;stroke:#326DE6;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st17{fill:#FFFFFF;stroke:#326DE6;stroke-width:1.6;stroke-miterlimit:10;} + .st18{fill:none;stroke:#06F7C9;stroke-width:2;stroke-miterlimit:10;} + .st19{fill:none;stroke:#06F7C9;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:2.3749,1.5832;} + .st20{fill:none;stroke:#06F7C9;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:2.4006,1.6004;} + .st21{fill:none;stroke:#EEF406;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:2.4,1.6;} + .st22{fill:none;stroke:#EEF406;stroke-width:2;stroke-miterlimit:10;} + .st23{fill:none;stroke:#EEF406;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:2.3975,1.5984;} + .st24{fill:none;stroke:#EEF406;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:2.395,1.5966;} + .st25{fill:none;stroke:#EEF406;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:2.3963,1.5976;} + .st26{opacity:0.1;fill:#EEF406;} + .st27{opacity:2.000000e-02;fill:#EEF406;} + .st28{opacity:0.1;fill:#06F7C9;} + .st29{fill:none;stroke:#006DE9;stroke-width:0.8;stroke-miterlimit:10;} + .st30{opacity:0.1;fill:url(#SVGID_3_);} + .st31{opacity:0.1;fill:url(#SVGID_4_);} + .st32{opacity:0.1;fill:url(#SVGID_5_);} + .st33{opacity:0.1;fill:url(#SVGID_6_);} + .st34{fill:none;stroke:#326DE6;stroke-width:1.2;stroke-miterlimit:10;} + .st35{opacity:0.1;fill:url(#SVGID_7_);} + .st36{opacity:0.1;fill:url(#SVGID_8_);} + .st37{opacity:0.1;fill:url(#SVGID_9_);} + .st38{opacity:0.1;fill:url(#SVGID_10_);} + .st39{fill:none;stroke:#326DE6;stroke-width:2;stroke-miterlimit:10;} + .st40{opacity:0.4;fill:none;stroke:#EEF406;stroke-width:2;stroke-miterlimit:10;} + .st41{fill:none;stroke:#EEF406;stroke-width:2.4596;stroke-miterlimit:10;} + .st42{fill:#011F38;} + .st43{opacity:0.4;} + .st44{opacity:0.1;} + .st45{fill:#326DE6;stroke:#EEF406;stroke-width:2;stroke-miterlimit:10;} + .st46{fill:none;stroke:#FFFFFF;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;} + .st47{fill:#06F7C9;stroke:#FFFFFF;stroke-width:0.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st48{fill:none;stroke:#011F38;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;} + .st49{fill:#326DE6;stroke:#06F7C9;stroke-width:2;stroke-miterlimit:10;} + .st50{fill:#06F7C9;stroke:#011F38;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st51{fill:#8115FF;stroke:#011F38;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st52{opacity:0.3;} + .st53{opacity:0.2;fill:#6D6E71;} + .st54{fill:#EEF406;} + .st55{fill:#06F7C9;} + .st56{fill:#FFFFFF;stroke:#06F7C9;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:2.4,1.6;} + .st57{fill:#FFFFFF;stroke:#EEF406;stroke-width:1.6;stroke-miterlimit:10;stroke-dasharray:2.4,1.6;} + .st58{fill:none;stroke:#06F7C9;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:2.4938,1.6626;} + .st59{fill:none;stroke:#06F7C9;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:2.0084,1.3389;} + .st60{fill:none;stroke:#06F7C9;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:2.724,1.816;} + .st61{fill:#011F38;stroke:#414042;stroke-width:0.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st62{fill:none;stroke:#011F38;stroke-width:0.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st63{fill:none;stroke:#011F38;stroke-width:0.2813;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} +</style> +<symbol id="node_high_level" viewBox="-81 -93 162 186.1"> + <polygon class="st0" points="-80,-46 -80,46 0,92 80,46 80,-46 0,-92 "/> + <g id="Isolation_Mode_3_"> + </g> +</symbol> +<symbol id="node_x5F_empty" viewBox="-87.5 -100.6 175.1 201.1"> + + <use xlink:href="#node_high_level" width="162" height="186.1" id="XMLID_201_" x="-81" y="-93" transform="matrix(1.0808 0 0 1.0808 -3.292006e-05 -3.749943e-05)" style="overflow:visible;"/> + <g> + <polygon class="st1" points="76.8,-28.1 -14,-80.3 0,-88.3 76.7,-44.4 "/> + <polygon class="st2" points="76.8,-28.1 32.1,-53.8 38.8,-66.1 76.7,-44.4 "/> + </g> +</symbol> +<symbol id="node_x5F_new" viewBox="-87.6 -101 175.2 202"> + <polygon class="st3" points="0,-100 -86.6,-50 -86.6,50 0,100 86.6,50 86.6,-50 "/> + <polygon class="st4" points="-86.6,-20.2 -86.6,-50 0,-100 25.8,-85.1 "/> + <polygon class="st5" points="-40.8,-70.7 -32.9,-57 15.7,-85.1 0,-94.3 "/> + + <text transform="matrix(0.866 -0.5 -0.5 -0.866 -33.9256 -70.7388)" class="st6" style="font-family:'RobotoSlab-Regular'; font-size:11.3632px;">Docker</text> + + <text transform="matrix(0.866 -0.5 -0.5 -0.866 -76.0668 -46.4087)" class="st6" style="font-family:'RobotoSlab-Regular'; font-size:11.3632px;">Kubelt</text> +</symbol> +<g id="CLUSTER"> +</g> +<g id="master"> + <g id="master_x5F_level1"> + </g> +</g> +<g id="Node"> + <g id="Node_x5F_level3_x5F_1"> + <g id="Isolation_Mode"> + </g> + </g> +</g> +<g id="service"> +</g> +<g id="pods"> + <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="122.1878" y1="127.5093" x2="204.1367" y2="127.5093"> + <stop offset="0" style="stop-color:#326DE6"/> + <stop offset="1" style="stop-color:#10FFC6"/> + </linearGradient> + <circle style="opacity:0.1;fill:url(#SVGID_1_);" cx="163.2" cy="127.5" r="41"/> + <linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="238.2856" y1="127.5093" x2="347.5509" y2="127.5093"> + <stop offset="0" style="stop-color:#326DE6"/> + <stop offset="1" style="stop-color:#10FFC6"/> + </linearGradient> + <circle style="opacity:0.1;fill:url(#SVGID_2_);" cx="292.9" cy="127.5" r="54.6"/> + <linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="390.5175" y1="77.3348" x2="517.7111" y2="179.9297"> + <stop offset="0" style="stop-color:#326DE6"/> + <stop offset="1" style="stop-color:#10FFC6"/> + </linearGradient> + <circle class="st30" cx="452.7" cy="127.5" r="71"/> + <linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="16.3336" y1="127.5093" x2="77.7953" y2="127.5093"> + <stop offset="0" style="stop-color:#326DE6"/> + <stop offset="1" style="stop-color:#10FFC6"/> + </linearGradient> + <circle class="st31" cx="47.1" cy="127.5" r="30.7"/> + <circle class="st39" cx="163.2" cy="127.5" r="41"/> + <circle class="st39" cx="47.1" cy="127.5" r="30.7"/> + <circle class="st39" cx="292.9" cy="127.5" r="54.6"/> + <circle class="st39" cx="452.7" cy="127.5" r="71"/> +</g> +<g id="IP"> + <g> + <path class="st42" d="M121.7,110.7l0.6-1.4l-6.6-3l-0.5,1.6l-0.4-0.2l0.5-2.4l7.3,3.3l0.7-1.4l0.5,0.2l-1.6,3.4L121.7,110.7z"/> + <path class="st42" d="M124.1,100.5c0.9,0.6,1.5,1.2,1.8,1.9c0.3,0.7,0.2,1.4-0.3,2.1c-0.4,0.7-1,1.1-1.8,1.2 + c-0.8,0.1-1.6-0.2-2.5-0.7l-1.6-1c-0.9-0.6-1.5-1.2-1.8-1.9c-0.3-0.7-0.2-1.4,0.3-2.1c0.4-0.7,1-1.1,1.8-1.2 + c0.8-0.1,1.6,0.2,2.5,0.7L124.1,100.5z M122,100c-0.7-0.5-1.4-0.7-2-0.6c-0.6,0-1,0.3-1.4,0.9c-0.3,0.5-0.4,1.1-0.2,1.6 + c0.2,0.5,0.7,1,1.5,1.5l1.8,1.1c0.7,0.5,1.4,0.7,2,0.6c0.6,0,1-0.3,1.4-0.9c0.3-0.5,0.4-1.1,0.2-1.6c-0.2-0.5-0.7-1-1.5-1.5 + L122,100z"/> + <path class="st42" d="M128.3,100.4l-0.5,0.6l-0.8-0.6l0.5-0.6L128.3,100.4z"/> + <path class="st42" d="M128.9,98.8l1-1.2l-5.3-4.8l-1,1.4l-0.4-0.3l1.2-2.1l5.9,5.3l1.1-1.1l0.4,0.3l-2.5,2.8L128.9,98.8z"/> + <path class="st42" d="M134.2,89.8c0.7,0.8,1.1,1.6,1.1,2.4c0,0.8-0.3,1.4-0.9,1.9c-0.6,0.5-1.3,0.7-2.1,0.6 + c-0.7-0.1-1.5-0.6-2.2-1.5l-1.2-1.4c-0.7-0.8-1.1-1.6-1.1-2.4c0-0.8,0.3-1.4,0.9-1.9c0.6-0.5,1.3-0.7,2.1-0.6 + c0.7,0.1,1.5,0.6,2.2,1.5L134.2,89.8z M132.4,88.7c-0.6-0.7-1.1-1.1-1.7-1.2c-0.6-0.1-1.1,0-1.6,0.4c-0.5,0.4-0.7,0.9-0.6,1.5 + c0.1,0.6,0.4,1.2,0.9,1.9l1.4,1.6c0.6,0.7,1.1,1.1,1.7,1.2c0.6,0.1,1.1,0,1.6-0.4c0.5-0.4,0.7-0.9,0.6-1.5 + c-0.1-0.6-0.4-1.2-0.9-1.9L132.4,88.7z"/> + <path class="st42" d="M138.3,91l-0.7,0.5l-0.5-0.8l0.7-0.5L138.3,91z"/> + <path class="st42" d="M139.3,89.7l1.3-0.8l-3.6-6.2l-1.3,1.1l-0.2-0.4l1.8-1.6l4,6.9l1.4-0.7l0.3,0.4l-3.3,1.9L139.3,89.7z"/> + <path class="st42" d="M147.2,82.7c0.4,1,0.5,1.9,0.3,2.6c-0.2,0.7-0.7,1.3-1.5,1.6c-0.8,0.3-1.5,0.3-2.1-0.1 + c-0.7-0.4-1.2-1.1-1.6-2.1l-0.7-1.8c-0.4-1-0.5-1.9-0.3-2.6s0.7-1.3,1.4-1.6c0.8-0.3,1.5-0.3,2.1,0.1c0.7,0.4,1.2,1.1,1.6,2.1 + L147.2,82.7z M145.8,81.1c-0.3-0.8-0.8-1.4-1.2-1.7c-0.5-0.3-1-0.3-1.6-0.1c-0.6,0.2-0.9,0.7-1.1,1.2c-0.1,0.6,0,1.2,0.3,2.1 + l0.8,2c0.3,0.8,0.8,1.4,1.2,1.7c0.5,0.3,1,0.3,1.6,0.1c0.6-0.2,0.9-0.7,1.1-1.2c0.1-0.6,0-1.3-0.3-2.1L145.8,81.1z"/> + <path class="st42" d="M150.6,85.2l-0.8,0.2l-0.3-0.9l0.8-0.2L150.6,85.2z"/> + <path class="st42" d="M152,84.7l-0.1-0.5l2.1-3.6c0.4-0.7,0.7-1.2,0.8-1.6s0.2-0.8,0.1-1.2c-0.1-0.5-0.3-0.9-0.7-1.2 + c-0.4-0.3-0.8-0.3-1.3-0.2c-0.6,0.1-1.1,0.4-1.3,0.8c-0.3,0.4-0.3,0.9-0.2,1.5l-0.6,0.1l0,0c-0.2-0.7,0-1.3,0.3-1.9 + c0.4-0.6,1-0.9,1.8-1.1c0.7-0.1,1.3,0,1.8,0.3s0.8,0.8,1,1.5c0.1,0.5,0,1-0.2,1.5s-0.5,1.1-0.9,1.8l-1.8,3.1l0,0l3.7-0.7l-0.2-1.2 + l0.6-0.1l0.3,1.8L152,84.7z"/> + </g> + <g> + <path class="st42" d="M15.9,114.8l0.6-1.4l-6.5-3.1l-0.5,1.6L9,111.7l0.6-2.4l7.2,3.4l0.7-1.3l0.5,0.2l-1.6,3.4L15.9,114.8z"/> + <path class="st42" d="M18.6,104.6c0.9,0.6,1.5,1.3,1.7,2c0.2,0.7,0.1,1.4-0.4,2.1c-0.5,0.7-1.1,1-1.8,1.1s-1.6-0.2-2.5-0.9 + l-1.6-1.1c-0.9-0.6-1.5-1.3-1.7-2s-0.1-1.4,0.4-2.1c0.5-0.7,1.1-1,1.9-1.1c0.8,0,1.6,0.2,2.5,0.9L18.6,104.6z M16.6,104 + c-0.7-0.5-1.4-0.7-1.9-0.7s-1,0.3-1.4,0.8c-0.4,0.5-0.4,1.1-0.2,1.6s0.7,1.1,1.4,1.6l1.7,1.2c0.7,0.5,1.4,0.7,1.9,0.7 + s1.1-0.3,1.4-0.8c0.4-0.5,0.4-1.1,0.2-1.6c-0.2-0.5-0.7-1.1-1.4-1.6L16.6,104z"/> + <path class="st42" d="M22.8,104.9l-0.5,0.6l-0.7-0.6l0.5-0.6L22.8,104.9z"/> + <path class="st42" d="M23.5,103.4l1.1-1.1l-4.8-5.4l-1.1,1.3l-0.3-0.4l1.5-2l5.3,6l1.2-1l0.3,0.4l-2.8,2.5L23.5,103.4z"/> + <path class="st42" d="M30.1,95.2c0.6,0.9,0.8,1.8,0.7,2.5c-0.1,0.8-0.5,1.3-1.2,1.8c-0.7,0.4-1.4,0.5-2.1,0.3s-1.4-0.9-1.9-1.8 + l-1-1.6c-0.6-0.9-0.8-1.8-0.7-2.5c0.1-0.8,0.5-1.3,1.2-1.8c0.7-0.4,1.4-0.5,2.1-0.3c0.7,0.3,1.4,0.9,1.9,1.8L30.1,95.2z + M28.4,93.8c-0.5-0.7-1-1.2-1.5-1.4c-0.5-0.2-1.1-0.2-1.6,0.2c-0.5,0.3-0.8,0.8-0.9,1.4c0,0.6,0.2,1.2,0.6,2l1.1,1.8 + c0.5,0.7,1,1.2,1.5,1.4c0.5,0.2,1.1,0.2,1.6-0.2c0.5-0.3,0.8-0.8,0.9-1.4s-0.2-1.2-0.6-2L28.4,93.8z"/> + <path class="st42" d="M33.8,97.1l-0.7,0.3l-0.4-0.9l0.7-0.3L33.8,97.1z"/> + <path class="st42" d="M35.1,96l1.4-0.5l-2.2-6.8l-1.5,0.7l-0.2-0.5l2.1-1.2l2.4,7.6l1.5-0.4l0.2,0.5l-3.6,1.2L35.1,96z"/> + <path class="st42" d="M44.4,91.1c0.2,1.1,0.1,2-0.3,2.6c-0.4,0.7-1,1-1.8,1.2c-0.8,0.1-1.5-0.1-2.1-0.6s-0.9-1.3-1.1-2.4L38.8,90 + c-0.2-1.1,0-2,0.3-2.6c0.4-0.7,1-1,1.8-1.2c0.8-0.1,1.5,0.1,2.1,0.6c0.6,0.5,0.9,1.3,1.1,2.4L44.4,91.1z M43.4,89.2 + c-0.1-0.9-0.4-1.5-0.8-1.9s-0.9-0.6-1.5-0.5c-0.6,0.1-1.1,0.4-1.3,0.9c-0.3,0.5-0.3,1.2-0.2,2.1l0.3,2.1c0.1,0.9,0.4,1.5,0.8,1.9 + c0.4,0.4,0.9,0.6,1.5,0.5c0.6-0.1,1.1-0.4,1.3-0.9s0.3-1.2,0.2-2.1L43.4,89.2z"/> + <path class="st42" d="M47,94.4l-0.8,0l0-1l0.8,0L47,94.4z"/> + <path class="st42" d="M48.6,93.9l1.5,0.1l0.7-7.2l-1.7,0.1l0-0.5l2.4-0.3L50.8,94l1.5,0.2l-0.1,0.5l-3.7-0.4L48.6,93.9z"/> + </g> + <g> + <path class="st42" d="M246.8,91.7l0.9-1.2l-5.5-4.6l-0.9,1.4l-0.4-0.3l1.1-2.2l6.1,5.1l1-1.1l0.4,0.3l-2.4,2.9L246.8,91.7z"/> + <path class="st42" d="M251.7,82.3c0.8,0.8,1.2,1.5,1.3,2.3c0.1,0.8-0.2,1.4-0.8,2c-0.6,0.6-1.3,0.8-2,0.7 + c-0.8-0.1-1.5-0.5-2.3-1.3l-1.3-1.4c-0.8-0.8-1.2-1.5-1.3-2.3c-0.1-0.8,0.2-1.4,0.7-2c0.6-0.6,1.3-0.8,2-0.7 + c0.8,0.1,1.5,0.5,2.3,1.3L251.7,82.3z M249.8,81.4c-0.6-0.6-1.2-1-1.8-1.1c-0.6-0.1-1.1,0.1-1.5,0.5c-0.4,0.4-0.6,1-0.5,1.5 + c0.1,0.6,0.5,1.2,1.1,1.8l1.5,1.5c0.6,0.6,1.2,1,1.8,1.1c0.6,0.1,1.1-0.1,1.5-0.5c0.4-0.4,0.6-1,0.5-1.5s-0.5-1.2-1.1-1.8 + L249.8,81.4z"/> + <path class="st42" d="M255.8,83.2l-0.6,0.5l-0.6-0.7l0.6-0.5L255.8,83.2z"/> + <path class="st42" d="M256.7,81.7l1.2-1l-4.3-5.8l-1.2,1.2l-0.3-0.4l1.6-1.8l4.8,6.4l1.3-0.9l0.3,0.4l-3,2.2L256.7,81.7z"/> + <path class="st42" d="M263.6,73.8c0.6,0.9,0.8,1.8,0.7,2.5c-0.1,0.7-0.5,1.3-1.2,1.8c-0.7,0.4-1.4,0.5-2.1,0.2 + c-0.7-0.3-1.3-0.9-1.9-1.8l-1-1.6c-0.6-0.9-0.8-1.8-0.7-2.5c0.1-0.8,0.5-1.3,1.2-1.8c0.7-0.4,1.4-0.5,2.1-0.2 + c0.7,0.3,1.4,0.9,1.9,1.8L263.6,73.8z M262,72.4c-0.5-0.7-0.9-1.2-1.5-1.5s-1.1-0.2-1.6,0.1c-0.5,0.3-0.8,0.8-0.9,1.4 + c0,0.6,0.2,1.2,0.6,2l1.1,1.8c0.4,0.7,0.9,1.2,1.5,1.5c0.5,0.2,1.1,0.2,1.6-0.1c0.5-0.3,0.8-0.8,0.9-1.4c0-0.6-0.2-1.2-0.6-2 + L262,72.4z"/> + <path class="st42" d="M267.4,75.6l-0.7,0.4l-0.4-0.9l0.7-0.4L267.4,75.6z"/> + <path class="st42" d="M268.6,74.4l1.4-0.7l-2.8-6.6l-1.5,0.9l-0.2-0.5l2-1.4l3.1,7.3l1.4-0.5l0.2,0.5l-3.5,1.5L268.6,74.4z"/> + <path class="st42" d="M277.3,68.3c0.3,1.1,0.4,1.9,0.1,2.6c-0.3,0.7-0.8,1.2-1.6,1.4c-0.8,0.2-1.5,0.2-2.1-0.3 + c-0.6-0.4-1.1-1.2-1.4-2.2l-0.6-1.8c-0.3-1-0.4-1.9-0.1-2.6c0.3-0.7,0.8-1.2,1.6-1.4c0.8-0.2,1.5-0.2,2.1,0.3 + c0.6,0.4,1.1,1.2,1.4,2.2L277.3,68.3z M276,66.6c-0.3-0.8-0.6-1.4-1.1-1.8s-1-0.4-1.6-0.2c-0.6,0.2-1,0.6-1.2,1.1 + c-0.2,0.6-0.1,1.2,0.1,2.1l0.6,2c0.3,0.8,0.6,1.4,1.1,1.8c0.5,0.4,1,0.4,1.6,0.3c0.6-0.2,1-0.6,1.2-1.1s0.1-1.2-0.1-2.1L276,66.6z + "/> + <path class="st42" d="M280.5,71l-0.8,0.2l-0.2-0.9l0.8-0.2L280.5,71z"/> + <path class="st42" d="M282.9,65.8l0.8-0.1c0.6-0.1,1.1-0.3,1.3-0.7c0.3-0.4,0.4-0.8,0.3-1.3c-0.1-0.5-0.3-0.9-0.6-1.2 + c-0.3-0.3-0.8-0.4-1.4-0.3c-0.5,0.1-1,0.3-1.3,0.7c-0.3,0.4-0.4,0.8-0.3,1.3l-0.6,0.1l0,0c-0.1-0.7,0-1.2,0.5-1.7 + c0.4-0.5,1-0.8,1.7-0.9c0.8-0.1,1.4,0,1.9,0.4c0.5,0.3,0.8,0.9,0.9,1.6c0.1,0.4,0,0.8-0.2,1.2c-0.2,0.4-0.5,0.7-0.9,0.9 + c0.5,0.1,1,0.3,1.3,0.6c0.3,0.3,0.5,0.7,0.6,1.2c0.1,0.7,0,1.4-0.5,1.9c-0.4,0.5-1,0.8-1.8,0.9c-0.7,0.1-1.4,0-2-0.4 + c-0.6-0.3-0.9-0.9-1-1.6l0,0l0.6-0.1c0.1,0.5,0.3,0.9,0.8,1.2c0.4,0.3,0.9,0.4,1.5,0.3c0.6-0.1,1-0.3,1.3-0.7s0.4-0.8,0.3-1.4 + c-0.1-0.6-0.3-1-0.7-1.2c-0.4-0.2-0.9-0.3-1.6-0.2l-0.8,0.1L282.9,65.8z"/> + </g> + <g> + <path class="st42" d="M397.1,77.6l1-1.2l-5.2-4.9l-1,1.4l-0.4-0.3l1.3-2.1l5.8,5.5l1.1-1.1l0.4,0.4l-2.6,2.7L397.1,77.6z"/> + <path class="st42" d="M402.5,68.5c0.7,0.8,1.1,1.6,1.2,2.4c0.1,0.8-0.2,1.4-0.8,2c-0.6,0.6-1.3,0.8-2,0.7s-1.5-0.6-2.2-1.4 + l-1.3-1.4c-0.7-0.8-1.1-1.6-1.2-2.4s0.2-1.4,0.8-2c0.6-0.6,1.3-0.8,2-0.7c0.8,0.1,1.5,0.6,2.2,1.4L402.5,68.5z M400.6,67.4 + c-0.6-0.6-1.2-1-1.7-1.2c-0.6-0.1-1.1,0-1.6,0.5c-0.5,0.4-0.7,0.9-0.6,1.5c0.1,0.6,0.4,1.2,1,1.8l1.4,1.6c0.6,0.6,1.2,1,1.7,1.2 + c0.6,0.1,1.1,0,1.6-0.4c0.5-0.4,0.7-0.9,0.6-1.5c-0.1-0.6-0.4-1.2-1-1.8L400.6,67.4z"/> + <path class="st42" d="M406.5,69.5l-0.6,0.5l-0.6-0.7l0.6-0.5L406.5,69.5z"/> + <path class="st42" d="M407.5,68l1.2-1l-4.2-5.8l-1.2,1.2L403,62l1.6-1.8l4.7,6.4l1.3-0.8l0.3,0.4l-3,2.2L407.5,68z"/> + <path class="st42" d="M414.5,60c0.6,0.9,0.8,1.8,0.7,2.5c-0.1,0.8-0.5,1.3-1.2,1.8c-0.7,0.4-1.4,0.5-2.1,0.3 + c-0.7-0.3-1.4-0.9-1.9-1.8l-1-1.6c-0.6-0.9-0.8-1.8-0.7-2.5c0.1-0.8,0.5-1.3,1.2-1.8c0.7-0.4,1.4-0.5,2.1-0.3 + c0.7,0.3,1.4,0.9,1.9,1.8L414.5,60z M412.8,58.7c-0.5-0.7-1-1.2-1.5-1.5c-0.5-0.2-1.1-0.2-1.6,0.2c-0.5,0.3-0.8,0.8-0.9,1.4 + c0,0.6,0.2,1.2,0.6,2l1.1,1.8c0.5,0.7,1,1.2,1.5,1.5c0.5,0.2,1.1,0.2,1.6-0.1c0.5-0.3,0.8-0.8,0.9-1.4s-0.2-1.2-0.6-2L412.8,58.7z + "/> + <path class="st42" d="M418.2,61.8l-0.7,0.4l-0.5-0.8l0.7-0.4L418.2,61.8z"/> + <path class="st42" d="M419.5,60.6l1.4-0.7l-3.1-6.5l-1.4,0.9l-0.2-0.4l1.9-1.5l3.4,7.2l1.4-0.6l0.2,0.5l-3.4,1.6L419.5,60.6z"/> + <path class="st42" d="M427.8,54.1c0.4,1,0.5,1.9,0.2,2.6s-0.7,1.2-1.5,1.5c-0.8,0.3-1.5,0.2-2.1-0.1c-0.7-0.4-1.2-1.1-1.6-2.1 + l-0.7-1.8c-0.4-1-0.5-1.9-0.2-2.6c0.2-0.7,0.7-1.2,1.5-1.5c0.8-0.3,1.5-0.2,2.1,0.1c0.7,0.4,1.2,1.1,1.6,2.1L427.8,54.1z + M426.4,52.4c-0.3-0.8-0.7-1.4-1.2-1.7c-0.5-0.3-1-0.4-1.6-0.1c-0.6,0.2-1,0.6-1.1,1.2c-0.1,0.6-0.1,1.2,0.2,2.1l0.8,2 + c0.3,0.8,0.7,1.4,1.2,1.7s1,0.4,1.6,0.2c0.6-0.2,1-0.6,1.1-1.2s0.1-1.3-0.3-2.1L426.4,52.4z"/> + <path class="st42" d="M431.2,56.5l-0.8,0.2l-0.3-0.9l0.8-0.2L431.2,56.5z"/> + <path class="st42" d="M436.3,52.3l1.3-0.3l0.1,0.6l-1.3,0.3l0.4,1.5l0.9-0.1l0.1,0.5l-2.5,0.6l-0.1-0.5l0.9-0.3l-0.4-1.5l-3.9,0.9 + l-0.1-0.4l2.4-6.7l0.7-0.2L436.3,52.3z M432.6,53.2l3.1-0.7l-1.1-4.7l0,0l-0.1,0.7L432.6,53.2z"/> + </g> +</g> +<g id="deployments"> +</g> +<g id="containers_x2F_volumes"> + <g> + <g> + <polygon class="st50" points="138.1,120.8 148.6,114.7 159.2,120.8 148.6,126.9 "/> + <polygon class="st50" points="138.1,133 138.1,120.8 148.6,126.9 148.6,139.1 "/> + <polygon class="st50" points="148.6,139.1 148.6,126.9 159.2,120.8 159.2,133 "/> + </g> + <g> + <path class="st51" d="M188.2,132.2C188.2,132.2,188.2,132.2,188.2,132.2C188.2,132.1,188.2,132.1,188.2,132.2v-10.6h-21.1v10.6 + c0,0,0,0,0,0c0,0,0,0,0,0v0.2h0c0.2,2.9,4.9,5.2,10.5,5.2c5.7,0,10.3-2.3,10.5-5.2h0V132.2z"/> + <ellipse class="st51" cx="177.7" cy="121.7" rx="10.6" ry="5.4"/> + </g> + </g> + <g> + <g> + <polygon class="st50" points="36.5,121.4 47.1,115.3 57.6,121.4 47.1,127.5 "/> + <polygon class="st50" points="36.5,133.6 36.5,121.4 47.1,127.5 47.1,139.7 "/> + <polygon class="st50" points="47.1,139.7 47.1,127.5 57.6,121.4 57.6,133.6 "/> + </g> + </g> + <g> + <g> + <polygon class="st50" points="282.4,108.7 292.9,102.6 303.5,108.7 292.9,114.8 "/> + <polygon class="st50" points="282.4,120.9 282.4,108.7 292.9,114.8 292.9,127 "/> + <polygon class="st50" points="292.9,127 292.9,114.8 303.5,108.7 303.5,120.9 "/> + </g> + <g> + <polygon class="st50" points="270.5,132 278.4,127.4 286.3,132 278.4,136.5 "/> + <polygon class="st50" points="270.5,141.1 270.5,132 278.4,136.5 278.4,145.7 "/> + <polygon class="st50" points="278.4,145.7 278.4,136.5 286.3,132 286.3,141.1 "/> + </g> + <g> + <path class="st51" d="M318,141.8C318,141.8,318,141.8,318,141.8C318,141.8,318,141.8,318,141.8v-10.6h-21.1v10.6c0,0,0,0,0,0 + c0,0,0,0,0,0v0.2h0c0.2,2.9,4.9,5.2,10.5,5.2c5.7,0,10.3-2.3,10.5-5.2h0V141.8z"/> + <ellipse class="st51" cx="307.4" cy="131.3" rx="10.6" ry="5.4"/> + </g> + </g> + <g> + <g> + <path class="st51" d="M435.6,133.6C435.6,133.5,435.6,133.5,435.6,133.6C435.6,133.5,435.6,133.5,435.6,133.6v-10.6h-21.1v10.6 + c0,0,0,0,0,0c0,0,0,0,0,0v0.2h0c0.2,2.9,4.9,5.2,10.5,5.2c5.7,0,10.3-2.3,10.5-5.2h0V133.6z"/> + <ellipse class="st51" cx="425.1" cy="123" rx="10.6" ry="5.4"/> + </g> + <g> + <path class="st51" d="M479,111.8C479,111.8,479,111.8,479,111.8C479,111.8,479,111.8,479,111.8v-10.6h-21.1v10.6c0,0,0,0,0,0 + c0,0,0,0,0,0v0.2h0c0.2,2.9,4.9,5.2,10.5,5.2s10.3-2.3,10.5-5.2h0V111.8z"/> + <ellipse class="st51" cx="468.5" cy="101.3" rx="10.6" ry="5.4"/> + </g> + <g> + <polygon class="st50" points="443.4,122.2 454,116.1 464.6,122.2 454,128.3 "/> + <polygon class="st50" points="443.4,134.4 443.4,122.2 454,128.3 454,140.5 "/> + <polygon class="st50" points="454,140.5 454,128.3 464.6,122.2 464.6,134.4 "/> + </g> + <g> + <polygon class="st50" points="475.1,123.7 483,119.1 490.9,123.7 483,128.3 "/> + <polygon class="st50" points="475.1,132.8 475.1,123.7 483,128.3 483,137.4 "/> + <polygon class="st50" points="483,137.4 483,128.3 490.9,123.7 490.9,132.8 "/> + </g> + </g> + <g> + <g> + <polygon class="st50" points="442.6,146.8 437.3,143.8 432,146.8 437.3,149.9 "/> + <polygon class="st50" points="442.6,152.9 442.6,146.8 437.3,149.9 437.3,156 "/> + <polygon class="st50" points="437.3,156 437.3,149.9 432,146.8 432,152.9 "/> + </g> + </g> +</g> +<g id="labels_x2F_selectors"> +</g> +<g id="description"> + <g> + <path class="st42" d="M150.5,220.6c1.1,0,2,0.3,2.6,0.9s1,1.3,1,2.2c0,0.9-0.3,1.7-1,2.2c-0.6,0.6-1.5,0.8-2.6,0.8h-1.6v2.1l1,0.2 + v1.2h-4v-1.2l1-0.2V222l-1-0.2v-1.2h1H150.5z M148.9,225.3h1.6c0.5,0,0.9-0.1,1.2-0.4c0.3-0.3,0.4-0.7,0.4-1.1 + c0-0.5-0.1-0.8-0.4-1.2c-0.3-0.3-0.7-0.5-1.2-0.5h-1.6V225.3z"/> + <path class="st42" d="M154.7,226.6c0-1.1,0.3-1.9,0.9-2.6c0.6-0.7,1.4-1,2.5-1c1.1,0,1.9,0.3,2.5,1c0.6,0.7,0.9,1.6,0.9,2.6v0.1 + c0,1.1-0.3,2-0.9,2.6c-0.6,0.7-1.4,1-2.5,1c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.6V226.6z M156.6,226.8 + c0,0.7,0.1,1.2,0.3,1.6c0.2,0.4,0.6,0.6,1.1,0.6c0.5,0,0.9-0.2,1.1-0.6s0.3-0.9,0.3-1.6v-0.1c0-0.6-0.1-1.2-0.4-1.6 + c-0.2-0.4-0.6-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.1,0.6c-0.2,0.4-0.3,0.9-0.3,1.6V226.8z"/> + <path class="st42" d="M167,229.4c-0.2,0.3-0.5,0.6-0.8,0.8c-0.3,0.2-0.7,0.3-1.1,0.3c-0.9,0-1.6-0.3-2.1-1s-0.7-1.5-0.7-2.6v-0.1 + c0-1.1,0.2-2,0.7-2.7c0.5-0.7,1.2-1,2.1-1c0.4,0,0.7,0.1,1,0.2c0.3,0.2,0.5,0.4,0.8,0.7v-2.6l-1-0.2v-1.2h1h1.9v9l0.9,0.2v1.2 + h-2.6L167,229.4z M164.3,226.9c0,0.6,0.1,1.1,0.3,1.5s0.6,0.5,1,0.5c0.3,0,0.5-0.1,0.7-0.2s0.4-0.3,0.5-0.5v-3 + c-0.1-0.2-0.3-0.4-0.5-0.5c-0.2-0.1-0.4-0.2-0.7-0.2c-0.5,0-0.8,0.2-1,0.6s-0.3,1-0.3,1.6V226.9z"/> + <path class="st42" d="M173.7,230.3V229l3.1-3.4c0.5-0.5,0.8-1,1-1.3c0.2-0.4,0.3-0.7,0.3-1c0-0.4-0.1-0.7-0.3-1 + c-0.2-0.3-0.5-0.4-0.9-0.4c-0.4,0-0.8,0.2-1,0.5c-0.2,0.3-0.3,0.7-0.3,1.2h-1.9l0,0c0-0.9,0.3-1.6,0.9-2.2 + c0.6-0.6,1.4-0.9,2.4-0.9c1,0,1.8,0.3,2.4,0.8s0.9,1.2,0.9,2.1c0,0.6-0.2,1.1-0.5,1.6c-0.3,0.5-0.9,1.1-1.6,1.9l-1.7,1.9l0,0h2.5 + l0.1-1h1.5v2.4H173.7z"/> + </g> + <g> + <path class="st42" d="M35.2,220.6c1.1,0,2,0.3,2.6,0.9s1,1.3,1,2.2c0,0.9-0.3,1.7-1,2.2c-0.6,0.6-1.5,0.8-2.6,0.8h-1.6v2.1l1,0.2 + v1.2h-4v-1.2l1-0.2V222l-1-0.2v-1.2h1H35.2z M33.5,225.3h1.6c0.5,0,0.9-0.1,1.2-0.4c0.3-0.3,0.4-0.7,0.4-1.1 + c0-0.5-0.1-0.8-0.4-1.2c-0.3-0.3-0.7-0.5-1.2-0.5h-1.6V225.3z"/> + <path class="st42" d="M39.3,226.6c0-1.1,0.3-1.9,0.9-2.6c0.6-0.7,1.4-1,2.5-1c1.1,0,1.9,0.3,2.5,1c0.6,0.7,0.9,1.6,0.9,2.6v0.1 + c0,1.1-0.3,2-0.9,2.6c-0.6,0.7-1.4,1-2.5,1c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.6V226.6z M41.3,226.8 + c0,0.7,0.1,1.2,0.3,1.6c0.2,0.4,0.6,0.6,1.1,0.6c0.5,0,0.9-0.2,1.1-0.6s0.3-0.9,0.3-1.6v-0.1c0-0.6-0.1-1.2-0.4-1.6 + c-0.2-0.4-0.6-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.1,0.6c-0.2,0.4-0.3,0.9-0.3,1.6V226.8z"/> + <path class="st42" d="M51.6,229.4c-0.2,0.3-0.5,0.6-0.8,0.8c-0.3,0.2-0.7,0.3-1.1,0.3c-0.9,0-1.6-0.3-2.1-1s-0.7-1.5-0.7-2.6v-0.1 + c0-1.1,0.2-2,0.7-2.7c0.5-0.7,1.2-1,2.1-1c0.4,0,0.7,0.1,1,0.2c0.3,0.2,0.5,0.4,0.8,0.7v-2.6l-1-0.2v-1.2h1h1.9v9l0.9,0.2v1.2 + h-2.6L51.6,229.4z M48.9,226.9c0,0.6,0.1,1.1,0.3,1.5s0.6,0.5,1,0.5c0.3,0,0.5-0.1,0.7-0.2s0.4-0.3,0.5-0.5v-3 + c-0.1-0.2-0.3-0.4-0.5-0.5c-0.2-0.1-0.4-0.2-0.7-0.2c-0.5,0-0.8,0.2-1,0.6s-0.3,1-0.3,1.6V226.9z"/> + <path class="st42" d="M58.4,229.1l1.6-0.2v-6.5h-1.7v-1.1l3.6-0.7v8.3l1.6,0.2v1.2h-5.2V229.1z"/> + </g> + <g> + <path class="st42" d="M280.3,220.6c1.1,0,2,0.3,2.6,0.9s1,1.3,1,2.2c0,0.9-0.3,1.7-1,2.2c-0.6,0.6-1.5,0.8-2.6,0.8h-1.6v2.1l1,0.2 + v1.2h-4v-1.2l1-0.2V222l-1-0.2v-1.2h1H280.3z M278.7,225.3h1.6c0.5,0,0.9-0.1,1.2-0.4c0.3-0.3,0.4-0.7,0.4-1.1 + c0-0.5-0.1-0.8-0.4-1.2c-0.3-0.3-0.7-0.5-1.2-0.5h-1.6V225.3z"/> + <path class="st42" d="M284.5,226.6c0-1.1,0.3-1.9,0.9-2.6c0.6-0.7,1.4-1,2.5-1c1.1,0,1.9,0.3,2.5,1c0.6,0.7,0.9,1.6,0.9,2.6v0.1 + c0,1.1-0.3,2-0.9,2.6c-0.6,0.7-1.4,1-2.5,1c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.6V226.6z M286.4,226.8 + c0,0.7,0.1,1.2,0.3,1.6c0.2,0.4,0.6,0.6,1.1,0.6c0.5,0,0.9-0.2,1.1-0.6s0.3-0.9,0.3-1.6v-0.1c0-0.6-0.1-1.2-0.4-1.6 + c-0.2-0.4-0.6-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.1,0.6c-0.2,0.4-0.3,0.9-0.3,1.6V226.8z"/> + <path class="st42" d="M296.8,229.4c-0.2,0.3-0.5,0.6-0.8,0.8c-0.3,0.2-0.7,0.3-1.1,0.3c-0.9,0-1.6-0.3-2.1-1s-0.7-1.5-0.7-2.6 + v-0.1c0-1.1,0.2-2,0.7-2.7c0.5-0.7,1.2-1,2.1-1c0.4,0,0.7,0.1,1,0.2c0.3,0.2,0.5,0.4,0.8,0.7v-2.6l-1-0.2v-1.2h1h1.9v9l0.9,0.2 + v1.2h-2.6L296.8,229.4z M294.1,226.9c0,0.6,0.1,1.1,0.3,1.5s0.6,0.5,1,0.5c0.3,0,0.5-0.1,0.7-0.2s0.4-0.3,0.5-0.5v-3 + c-0.1-0.2-0.3-0.4-0.5-0.5c-0.2-0.1-0.4-0.2-0.7-0.2c-0.5,0-0.8,0.2-1,0.6s-0.3,1-0.3,1.6V226.9z"/> + <path class="st42" d="M305.6,224.6h1.1c0.5,0,0.8-0.1,1-0.4s0.3-0.6,0.3-1c0-0.4-0.1-0.7-0.3-0.9c-0.2-0.2-0.5-0.4-1-0.4 + c-0.4,0-0.7,0.1-0.9,0.3c-0.2,0.2-0.4,0.5-0.4,0.8h-1.9l0,0c0-0.8,0.3-1.4,0.9-1.9c0.6-0.5,1.4-0.7,2.3-0.7c1,0,1.8,0.2,2.4,0.7 + c0.6,0.5,0.9,1.2,0.9,2c0,0.4-0.1,0.8-0.4,1.2s-0.6,0.7-1.1,0.9c0.5,0.2,0.9,0.5,1.2,0.9s0.4,0.9,0.4,1.4c0,0.9-0.3,1.6-1,2.1 + c-0.6,0.5-1.5,0.8-2.5,0.8c-0.9,0-1.7-0.2-2.3-0.7c-0.6-0.5-1-1.1-0.9-2l0,0h1.9c0,0.4,0.1,0.7,0.4,0.9s0.6,0.4,1,0.4 + c0.4,0,0.8-0.1,1.1-0.4c0.3-0.2,0.4-0.6,0.4-1c0-0.5-0.1-0.9-0.4-1.1c-0.3-0.2-0.6-0.4-1.1-0.4h-1.1V224.6z"/> + </g> + <g> + <path class="st42" d="M440.2,220.6c1.1,0,2,0.3,2.6,0.9s1,1.3,1,2.2c0,0.9-0.3,1.7-1,2.2c-0.6,0.6-1.5,0.8-2.6,0.8h-1.6v2.1l1,0.2 + v1.2h-4v-1.2l1-0.2V222l-1-0.2v-1.2h1H440.2z M438.6,225.3h1.6c0.5,0,0.9-0.1,1.2-0.4c0.3-0.3,0.4-0.7,0.4-1.1 + c0-0.5-0.1-0.8-0.4-1.2c-0.3-0.3-0.7-0.5-1.2-0.5h-1.6V225.3z"/> + <path class="st42" d="M444.4,226.6c0-1.1,0.3-1.9,0.9-2.6c0.6-0.7,1.4-1,2.5-1c1.1,0,1.9,0.3,2.5,1c0.6,0.7,0.9,1.6,0.9,2.6v0.1 + c0,1.1-0.3,2-0.9,2.6c-0.6,0.7-1.4,1-2.5,1c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.6V226.6z M446.3,226.8 + c0,0.7,0.1,1.2,0.3,1.6c0.2,0.4,0.6,0.6,1.1,0.6c0.5,0,0.9-0.2,1.1-0.6s0.3-0.9,0.3-1.6v-0.1c0-0.6-0.1-1.2-0.4-1.6 + c-0.2-0.4-0.6-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.1,0.6c-0.2,0.4-0.3,0.9-0.3,1.6V226.8z"/> + <path class="st42" d="M456.7,229.4c-0.2,0.3-0.5,0.6-0.8,0.8c-0.3,0.2-0.7,0.3-1.1,0.3c-0.9,0-1.6-0.3-2.1-1s-0.7-1.5-0.7-2.6 + v-0.1c0-1.1,0.2-2,0.7-2.7c0.5-0.7,1.2-1,2.1-1c0.4,0,0.7,0.1,1,0.2c0.3,0.2,0.5,0.4,0.8,0.7v-2.6l-1-0.2v-1.2h1h1.9v9l0.9,0.2 + v1.2h-2.6L456.7,229.4z M454,226.9c0,0.6,0.1,1.1,0.3,1.5s0.6,0.5,1,0.5c0.3,0,0.5-0.1,0.7-0.2s0.4-0.3,0.5-0.5v-3 + c-0.1-0.2-0.3-0.4-0.5-0.5c-0.2-0.1-0.4-0.2-0.7-0.2c-0.5,0-0.8,0.2-1,0.6s-0.3,1-0.3,1.6V226.9z"/> + <path class="st42" d="M469.2,226.7h1.1v1.3h-1.1v0.9l1,0.2v1.2h-4v-1.2l1-0.2V228h-3.9l-0.1-0.9l4-6.4h2V226.7z M465,226.7h2.2 + v-3.5l0,0l-0.2,0.3L465,226.7z"/> + </g> + <g> + <path class="st42" d="M560.2,131.7c0.4,0,0.7-0.1,1-0.4s0.4-0.5,0.4-0.9h1l0,0c0,0.5-0.2,1-0.7,1.5s-1.1,0.6-1.8,0.6 + c-0.9,0-1.6-0.3-2.1-0.9s-0.7-1.4-0.7-2.3v-0.2c0-0.9,0.2-1.7,0.7-2.3s1.2-0.9,2.1-0.9c0.5,0,1,0.1,1.4,0.3s0.7,0.4,1,0.7l0.1,1.4 + h-0.9l-0.3-1c-0.1-0.1-0.3-0.2-0.5-0.3s-0.5-0.1-0.7-0.1c-0.6,0-1,0.2-1.3,0.7s-0.4,1-0.4,1.6v0.2c0,0.6,0.1,1.2,0.4,1.6 + S559.6,131.7,560.2,131.7z"/> + <path class="st42" d="M563.8,129.2c0-0.9,0.3-1.7,0.8-2.3s1.2-0.9,2.1-0.9c0.9,0,1.6,0.3,2.1,0.9s0.8,1.4,0.8,2.3v0.1 + c0,0.9-0.3,1.7-0.8,2.3s-1.2,0.9-2.1,0.9c-0.9,0-1.6-0.3-2.1-0.9s-0.8-1.4-0.8-2.3V129.2z M565,129.3c0,0.7,0.1,1.2,0.4,1.7 + s0.7,0.7,1.3,0.7c0.5,0,1-0.2,1.2-0.7s0.4-1,0.4-1.7v-0.1c0-0.7-0.1-1.2-0.4-1.7s-0.7-0.7-1.3-0.7s-1,0.2-1.3,0.7s-0.4,1-0.4,1.7 + V129.3z"/> + <path class="st42" d="M570.4,131.7l1-0.2V127l-1-0.2v-0.7h2l0.1,0.9c0.2-0.3,0.5-0.6,0.8-0.8s0.7-0.3,1.1-0.3 + c0.7,0,1.2,0.2,1.6,0.6s0.6,1,0.6,1.9v3.1l1,0.2v0.7h-3.1v-0.7l1-0.2v-3.1c0-0.6-0.1-1-0.3-1.2s-0.6-0.4-1-0.4 + c-0.3,0-0.6,0.1-0.9,0.2s-0.5,0.4-0.6,0.7v3.7l1,0.2v0.7h-3.1V131.7z"/> + <path class="st42" d="M580.3,124.6v1.5h1.2v0.9h-1.2v3.8c0,0.3,0.1,0.5,0.2,0.6s0.3,0.2,0.5,0.2c0.1,0,0.2,0,0.3,0s0.2,0,0.3-0.1 + l0.2,0.8c-0.1,0.1-0.3,0.1-0.5,0.2s-0.4,0.1-0.6,0.1c-0.5,0-0.8-0.1-1.1-0.4s-0.4-0.7-0.4-1.3v-3.8h-1v-0.9h1v-1.5H580.3z"/> + <path class="st42" d="M586.8,132.4c0-0.2-0.1-0.3-0.1-0.5s0-0.3,0-0.4c-0.2,0.3-0.5,0.5-0.8,0.7s-0.7,0.3-1.1,0.3 + c-0.7,0-1.2-0.2-1.5-0.5s-0.5-0.8-0.5-1.4c0-0.6,0.2-1.1,0.7-1.4s1.2-0.5,2-0.5h1.2v-0.7c0-0.4-0.1-0.7-0.4-0.9s-0.6-0.3-1-0.3 + c-0.3,0-0.5,0-0.8,0.1s-0.4,0.2-0.5,0.3l-0.1,0.7H583v-1.2c0.3-0.2,0.6-0.4,1-0.6s0.9-0.2,1.3-0.2c0.7,0,1.3,0.2,1.7,0.6 + s0.7,0.9,0.7,1.6v3.1c0,0.1,0,0.2,0,0.2s0,0.2,0,0.2l0.5,0.1v0.7H586.8z M585,131.6c0.4,0,0.7-0.1,1-0.3s0.5-0.4,0.7-0.7v-1h-1.2 + c-0.5,0-0.8,0.1-1.1,0.3s-0.4,0.5-0.4,0.8c0,0.3,0.1,0.5,0.3,0.6S584.6,131.6,585,131.6z"/> + <path class="st42" d="M589.3,131.7l1-0.2V127l-1-0.2v-0.7h2.1v5.4l1,0.2v0.7h-3.1V131.7z M591.4,124.5h-1.2v-1.2h1.2V124.5z"/> + <path class="st42" d="M593.1,131.7l1-0.2V127l-1-0.2v-0.7h2l0.1,0.9c0.2-0.3,0.5-0.6,0.8-0.8s0.7-0.3,1.1-0.3 + c0.7,0,1.2,0.2,1.6,0.6s0.6,1,0.6,1.9v3.1l1,0.2v0.7H597v-0.7l1-0.2v-3.1c0-0.6-0.1-1-0.3-1.2s-0.6-0.4-1-0.4 + c-0.3,0-0.6,0.1-0.9,0.2s-0.5,0.4-0.6,0.7v3.7l1,0.2v0.7h-3.1V131.7z"/> + <path class="st42" d="M603.8,132.6c-0.9,0-1.6-0.3-2.1-0.9s-0.8-1.4-0.8-2.3v-0.3c0-0.9,0.3-1.7,0.8-2.3s1.2-0.9,1.9-0.9 + c0.9,0,1.5,0.3,1.9,0.8s0.7,1.2,0.7,2.1v0.7h-4.1l0,0c0,0.6,0.2,1.1,0.5,1.5s0.7,0.6,1.2,0.6c0.4,0,0.7-0.1,1-0.2s0.5-0.3,0.8-0.5 + l0.5,0.8c-0.2,0.2-0.5,0.4-0.9,0.6S604.3,132.6,603.8,132.6z M603.6,126.9c-0.4,0-0.7,0.2-1,0.5s-0.4,0.7-0.5,1.2l0,0h2.9v-0.2 + c0-0.5-0.1-0.8-0.4-1.1S604.1,126.9,603.6,126.9z"/> + <path class="st42" d="M607.3,126.8v-0.7h2l0.1,0.9c0.2-0.3,0.4-0.6,0.7-0.8s0.6-0.3,0.9-0.3c0.1,0,0.2,0,0.3,0s0.2,0,0.2,0 + l-0.2,1.1l-0.7,0c-0.3,0-0.6,0.1-0.8,0.2s-0.4,0.3-0.5,0.6v3.6l1,0.2v0.7h-3.1v-0.7l1-0.2V127L607.3,126.8z"/> + <path class="st42" d="M612.3,131.7l1-0.2V127l-1-0.2v-0.7h2.1v5.4l1,0.2v0.7h-3.1V131.7z M614.4,124.5h-1.2v-1.2h1.2V124.5z"/> + <path class="st42" d="M617.8,131.5h2.6l0.1-1h1v1.9h-5v-0.8l3.4-4.6h-2.3l-0.1,1h-1v-1.9h4.8v0.8L617.8,131.5z"/> + <path class="st42" d="M625.4,132.6c-0.9,0-1.6-0.3-2.1-0.9s-0.8-1.4-0.8-2.3v-0.3c0-0.9,0.3-1.7,0.8-2.3s1.2-0.9,1.9-0.9 + c0.9,0,1.5,0.3,1.9,0.8s0.7,1.2,0.7,2.1v0.7h-4.1l0,0c0,0.6,0.2,1.1,0.5,1.5s0.7,0.6,1.2,0.6c0.4,0,0.7-0.1,1-0.2s0.5-0.3,0.8-0.5 + l0.5,0.8c-0.2,0.2-0.5,0.4-0.9,0.6S625.9,132.6,625.4,132.6z M625.2,126.9c-0.4,0-0.7,0.2-1,0.5s-0.4,0.7-0.5,1.2l0,0h2.9v-0.2 + c0-0.5-0.1-0.8-0.4-1.1S625.7,126.9,625.2,126.9z"/> + <path class="st42" d="M633.2,131.7c-0.2,0.3-0.5,0.5-0.8,0.7s-0.6,0.2-1,0.2c-0.8,0-1.4-0.3-1.8-0.8s-0.7-1.3-0.7-2.2v-0.1 + c0-1,0.2-1.8,0.7-2.5s1-0.9,1.8-0.9c0.4,0,0.7,0.1,1,0.2s0.5,0.3,0.7,0.6v-2.6l-1-0.2v-0.7h1h1.2v8.2l1,0.2v0.7h-2L633.2,131.7z + M630.1,129.5c0,0.6,0.1,1.1,0.4,1.5s0.7,0.6,1.2,0.6c0.3,0,0.6-0.1,0.9-0.2s0.4-0.4,0.6-0.7v-2.9c-0.1-0.3-0.3-0.5-0.6-0.6 + s-0.5-0.2-0.9-0.2c-0.6,0-1,0.2-1.2,0.7s-0.4,1.1-0.4,1.8V129.5z"/> + <path class="st42" d="M643.3,132.4c0-0.2-0.1-0.3-0.1-0.5s0-0.3,0-0.4c-0.2,0.3-0.5,0.5-0.8,0.7s-0.7,0.3-1.1,0.3 + c-0.7,0-1.2-0.2-1.5-0.5s-0.5-0.8-0.5-1.4c0-0.6,0.2-1.1,0.7-1.4s1.2-0.5,2-0.5h1.2v-0.7c0-0.4-0.1-0.7-0.4-0.9s-0.6-0.3-1-0.3 + c-0.3,0-0.5,0-0.8,0.1s-0.4,0.2-0.5,0.3l-0.1,0.7h-0.9v-1.2c0.3-0.2,0.6-0.4,1-0.6s0.9-0.2,1.3-0.2c0.7,0,1.3,0.2,1.7,0.6 + s0.7,0.9,0.7,1.6v3.1c0,0.1,0,0.2,0,0.2s0,0.2,0,0.2l0.5,0.1v0.7H643.3z M641.4,131.6c0.4,0,0.7-0.1,1-0.3s0.5-0.4,0.7-0.7v-1 + h-1.2c-0.5,0-0.8,0.1-1.1,0.3s-0.4,0.5-0.4,0.8c0,0.3,0.1,0.5,0.3,0.6S641.1,131.6,641.4,131.6z"/> + <path class="st42" d="M645.6,134.1l1-0.2v-7l-1-0.2v-0.7h1.9l0.1,0.8c0.2-0.3,0.5-0.5,0.8-0.7s0.7-0.2,1.1-0.2 + c0.8,0,1.4,0.3,1.8,0.9s0.7,1.4,0.7,2.5v0.1c0,0.9-0.2,1.7-0.7,2.2s-1,0.8-1.8,0.8c-0.4,0-0.7-0.1-1-0.2s-0.5-0.3-0.8-0.6v2.2 + l1,0.2v0.7h-3.1V134.1z M650.8,129.4c0-0.7-0.1-1.3-0.4-1.8s-0.7-0.7-1.3-0.7c-0.3,0-0.6,0.1-0.8,0.2s-0.4,0.4-0.6,0.6v3.1 + c0.1,0.3,0.3,0.5,0.6,0.6s0.5,0.2,0.9,0.2c0.5,0,1-0.2,1.2-0.6s0.4-0.9,0.4-1.6V129.4z"/> + <path class="st42" d="M652.9,134.1l1-0.2v-7l-1-0.2v-0.7h1.9l0.1,0.8c0.2-0.3,0.5-0.5,0.8-0.7s0.7-0.2,1.1-0.2 + c0.8,0,1.4,0.3,1.8,0.9s0.7,1.4,0.7,2.5v0.1c0,0.9-0.2,1.7-0.7,2.2s-1,0.8-1.8,0.8c-0.4,0-0.7-0.1-1-0.2s-0.5-0.3-0.8-0.6v2.2 + l1,0.2v0.7h-3.1V134.1z M658.1,129.4c0-0.7-0.1-1.3-0.4-1.8s-0.7-0.7-1.3-0.7c-0.3,0-0.6,0.1-0.8,0.2s-0.4,0.4-0.6,0.6v3.1 + c0.1,0.3,0.3,0.5,0.6,0.6s0.5,0.2,0.9,0.2c0.5,0,1-0.2,1.2-0.6s0.4-0.9,0.4-1.6V129.4z"/> + </g> + <line class="st61" x1="554.8" y1="130" x2="481.7" y2="130"/> + <g> + <path class="st42" d="M559.5,106.8l-0.8,0.1l1.3,3.6l0.1,0.5h0l0.1-0.5l1.3-3.6l-0.8-0.1V106h2.4v0.7l-0.5,0.1l-2.1,5.5h-0.9 + l-2.2-5.5l-0.5-0.1V106h2.4V106.8z"/> + <path class="st42" d="M564,109.1c0-0.9,0.3-1.7,0.8-2.3s1.2-0.9,2.1-0.9c0.9,0,1.6,0.3,2.1,0.9s0.8,1.4,0.8,2.3v0.1 + c0,0.9-0.3,1.7-0.8,2.3s-1.2,0.9-2.1,0.9c-0.9,0-1.6-0.3-2.1-0.9s-0.8-1.4-0.8-2.3V109.1z M565.1,109.3c0,0.7,0.1,1.2,0.4,1.7 + s0.7,0.7,1.3,0.7c0.5,0,1-0.2,1.2-0.7s0.4-1,0.4-1.7v-0.1c0-0.7-0.1-1.2-0.4-1.7s-0.7-0.7-1.3-0.7s-1,0.2-1.3,0.7s-0.4,1-0.4,1.7 + V109.3z"/> + <path class="st42" d="M570.4,104v-0.7h2.1v8.2l1,0.2v0.7h-3.1v-0.7l1-0.2v-7.3L570.4,104z"/> + <path class="st42" d="M578.9,111.4c-0.2,0.3-0.5,0.6-0.8,0.8s-0.7,0.3-1.1,0.3c-0.7,0-1.2-0.2-1.6-0.7s-0.6-1.1-0.6-2.1v-2.8 + l-0.7-0.2V106h0.7h1.2v3.8c0,0.7,0.1,1.1,0.3,1.4s0.5,0.4,0.9,0.4c0.4,0,0.7-0.1,1-0.2s0.5-0.4,0.6-0.7v-3.7l-0.8-0.2V106h0.8h1.2 + v5.4l0.7,0.2v0.7H579L578.9,111.4z"/> + <path class="st42" d="M581.4,111.6l1-0.2v-4.5l-1-0.2V106h2l0.1,0.8c0.2-0.3,0.5-0.5,0.8-0.7s0.7-0.2,1.1-0.2s0.8,0.1,1.1,0.3 + s0.5,0.5,0.7,0.9c0.2-0.4,0.5-0.6,0.8-0.9s0.7-0.3,1.1-0.3c0.6,0,1.2,0.2,1.5,0.7s0.6,1.1,0.6,2v2.9l1,0.2v0.7h-3.1v-0.7l1-0.2 + v-2.9c0-0.6-0.1-1.1-0.3-1.3s-0.5-0.4-1-0.4c-0.4,0-0.7,0.1-1,0.4s-0.4,0.6-0.4,1.1v3.1l1,0.2v0.7h-3.1v-0.7l1-0.2v-2.9 + c0-0.6-0.1-1-0.3-1.3s-0.5-0.4-1-0.4c-0.4,0-0.6,0.1-0.9,0.2s-0.4,0.3-0.5,0.6v3.8l1,0.2v0.7h-3.1V111.6z"/> + <path class="st42" d="M595.8,112.5c-0.9,0-1.6-0.3-2.1-0.9s-0.8-1.4-0.8-2.3v-0.3c0-0.9,0.3-1.7,0.8-2.3s1.2-0.9,1.9-0.9 + c0.9,0,1.5,0.3,1.9,0.8s0.7,1.2,0.7,2.1v0.7h-4.1l0,0c0,0.6,0.2,1.1,0.5,1.5s0.7,0.6,1.2,0.6c0.4,0,0.7-0.1,1-0.2s0.5-0.3,0.8-0.5 + l0.5,0.8c-0.2,0.2-0.5,0.4-0.9,0.6S596.3,112.5,595.8,112.5z M595.6,106.8c-0.4,0-0.7,0.2-1,0.5s-0.4,0.7-0.5,1.2l0,0h2.9v-0.2 + c0-0.5-0.1-0.8-0.4-1.1S596.1,106.8,595.6,106.8z"/> + </g> + <line class="st61" x1="554.8" y1="110" x2="468.4" y2="110"/> + <g> + <path class="st42" d="M557.2,46.7V46h3.1v0.7l-1,0.2v6.7l1,0.2v0.7h-3.1v-0.7l1-0.2v-6.7L557.2,46.7z"/> + <path class="st42" d="M565,46c0.9,0,1.6,0.2,2.1,0.7s0.8,1.1,0.8,1.9c0,0.8-0.3,1.4-0.8,1.9s-1.2,0.7-2.1,0.7h-1.8v2.5l1,0.2v0.7 + h-3.1v-0.7l1-0.2v-6.7l-1-0.2V46h1H565z M563.2,50.2h1.8c0.6,0,1-0.2,1.3-0.5s0.4-0.7,0.4-1.2s-0.1-0.9-0.4-1.2s-0.7-0.5-1.3-0.5 + h-1.8V50.2z"/> + <path class="st42" d="M576,54.5c0-0.2-0.1-0.3-0.1-0.5s0-0.3,0-0.4c-0.2,0.3-0.5,0.5-0.8,0.7s-0.7,0.3-1.1,0.3 + c-0.7,0-1.2-0.2-1.5-0.5s-0.5-0.8-0.5-1.4c0-0.6,0.2-1.1,0.7-1.4s1.2-0.5,2-0.5h1.2v-0.7c0-0.4-0.1-0.7-0.4-0.9s-0.6-0.3-1-0.3 + c-0.3,0-0.5,0-0.8,0.1s-0.4,0.2-0.5,0.3l-0.1,0.7h-0.9v-1.2c0.3-0.2,0.6-0.4,1-0.6s0.9-0.2,1.3-0.2c0.7,0,1.3,0.2,1.7,0.6 + s0.7,0.9,0.7,1.6v3.1c0,0.1,0,0.2,0,0.2s0,0.2,0,0.2l0.5,0.1v0.7H576z M574.1,53.6c0.4,0,0.7-0.1,1-0.3s0.5-0.4,0.7-0.7v-1h-1.2 + c-0.5,0-0.8,0.1-1.1,0.3s-0.4,0.5-0.4,0.8c0,0.3,0.1,0.5,0.3,0.6S573.8,53.6,574.1,53.6z"/> + <path class="st42" d="M582.7,53.7c-0.2,0.3-0.5,0.5-0.8,0.7s-0.6,0.2-1,0.2c-0.8,0-1.4-0.3-1.8-0.8s-0.7-1.3-0.7-2.2v-0.1 + c0-1,0.2-1.8,0.7-2.5s1-0.9,1.8-0.9c0.4,0,0.7,0.1,1,0.2s0.5,0.3,0.7,0.6v-2.6l-1-0.2v-0.7h1h1.2v8.2l1,0.2v0.7h-2L582.7,53.7z + M579.6,51.6c0,0.6,0.1,1.1,0.4,1.5s0.7,0.6,1.2,0.6c0.3,0,0.6-0.1,0.9-0.2s0.4-0.4,0.6-0.7v-2.9c-0.1-0.3-0.3-0.5-0.6-0.6 + s-0.5-0.2-0.9-0.2c-0.6,0-1,0.2-1.2,0.7s-0.4,1.1-0.4,1.8V51.6z"/> + <path class="st42" d="M589.9,53.7c-0.2,0.3-0.5,0.5-0.8,0.7s-0.6,0.2-1,0.2c-0.8,0-1.4-0.3-1.8-0.8s-0.7-1.3-0.7-2.2v-0.1 + c0-1,0.2-1.8,0.7-2.5s1-0.9,1.8-0.9c0.4,0,0.7,0.1,1,0.2s0.5,0.3,0.7,0.6v-2.6l-1-0.2v-0.7h1h1.2v8.2l1,0.2v0.7h-2L589.9,53.7z + M586.8,51.6c0,0.6,0.1,1.1,0.4,1.5s0.7,0.6,1.2,0.6c0.3,0,0.6-0.1,0.9-0.2s0.4-0.4,0.6-0.7v-2.9c-0.1-0.3-0.3-0.5-0.6-0.6 + s-0.5-0.2-0.9-0.2c-0.6,0-1,0.2-1.2,0.7s-0.4,1.1-0.4,1.8V51.6z"/> + <path class="st42" d="M592.9,48.9v-0.7h2l0.1,0.9c0.2-0.3,0.4-0.6,0.7-0.8s0.6-0.3,0.9-0.3c0.1,0,0.2,0,0.3,0s0.2,0,0.2,0 + l-0.2,1.1l-0.7,0c-0.3,0-0.6,0.1-0.8,0.2s-0.4,0.3-0.5,0.6v3.6l1,0.2v0.7h-3.1v-0.7l1-0.2v-4.5L592.9,48.9z"/> + <path class="st42" d="M600.6,54.6c-0.9,0-1.6-0.3-2.1-0.9s-0.8-1.4-0.8-2.3v-0.3c0-0.9,0.3-1.7,0.8-2.3s1.2-0.9,1.9-0.9 + c0.9,0,1.5,0.3,1.9,0.8s0.7,1.2,0.7,2.1v0.7h-4.1l0,0c0,0.6,0.2,1.1,0.5,1.5s0.7,0.6,1.2,0.6c0.4,0,0.7-0.1,1-0.2s0.5-0.3,0.8-0.5 + l0.5,0.8c-0.2,0.2-0.5,0.4-0.9,0.6S601.1,54.6,600.6,54.6z M600.4,48.9c-0.4,0-0.7,0.2-1,0.5s-0.4,0.7-0.5,1.2l0,0h2.9v-0.2 + c0-0.5-0.1-0.8-0.4-1.1S600.9,48.9,600.4,48.9z"/> + <path class="st42" d="M609,50.1h-0.9l-0.2-0.8c-0.1-0.1-0.3-0.2-0.5-0.3s-0.5-0.1-0.7-0.1c-0.4,0-0.7,0.1-0.9,0.3 + s-0.3,0.4-0.3,0.7c0,0.2,0.1,0.4,0.3,0.6s0.5,0.3,1.1,0.4c0.8,0.2,1.4,0.4,1.8,0.7s0.6,0.7,0.6,1.2c0,0.6-0.2,1-0.7,1.4 + s-1,0.5-1.8,0.5c-0.5,0-0.9-0.1-1.3-0.2s-0.7-0.3-1-0.5l0-1.4h0.9l0.2,0.8c0.1,0.1,0.3,0.2,0.5,0.3s0.5,0.1,0.7,0.1 + c0.4,0,0.7-0.1,1-0.2s0.3-0.4,0.3-0.7c0-0.3-0.1-0.5-0.3-0.6s-0.6-0.3-1.1-0.4c-0.8-0.2-1.3-0.4-1.7-0.7s-0.6-0.7-0.6-1.2 + c0-0.5,0.2-1,0.7-1.3s1-0.5,1.7-0.5c0.5,0,0.9,0.1,1.3,0.2s0.7,0.3,1,0.5L609,50.1z"/> + <path class="st42" d="M615.1,50.1h-0.9l-0.2-0.8c-0.1-0.1-0.3-0.2-0.5-0.3s-0.5-0.1-0.7-0.1c-0.4,0-0.7,0.1-0.9,0.3 + s-0.3,0.4-0.3,0.7c0,0.2,0.1,0.4,0.3,0.6s0.5,0.3,1.1,0.4c0.8,0.2,1.4,0.4,1.8,0.7s0.6,0.7,0.6,1.2c0,0.6-0.2,1-0.7,1.4 + s-1,0.5-1.8,0.5c-0.5,0-0.9-0.1-1.3-0.2s-0.7-0.3-1-0.5l0-1.4h0.9l0.2,0.8c0.1,0.1,0.3,0.2,0.5,0.3s0.5,0.1,0.7,0.1 + c0.4,0,0.7-0.1,1-0.2s0.3-0.4,0.3-0.7c0-0.3-0.1-0.5-0.3-0.6s-0.6-0.3-1.1-0.4c-0.8-0.2-1.3-0.4-1.7-0.7s-0.6-0.7-0.6-1.2 + c0-0.5,0.2-1,0.7-1.3s1-0.5,1.7-0.5c0.5,0,0.9,0.1,1.3,0.2s0.7,0.3,1,0.5L615.1,50.1z"/> + </g> + <line class="st61" x1="554.8" y1="52.1" x2="440.6" y2="52.1"/> +</g> +<g id="Layer_14"> +</g> +</svg> diff --git a/static/images/k3s_start/requests.gif b/static/images/k3s_start/requests.gif new file mode 100644 index 0000000000000000000000000000000000000000..aa989f78022ffaf1a3ac4e0f9f48f57da39c222b Binary files /dev/null and b/static/images/k3s_start/requests.gif differ diff --git a/static/images/k3s_start/service overview.png b/static/images/k3s_start/service overview.png new file mode 100644 index 0000000000000000000000000000000000000000..4dabcc06d299534309ce7370cd2652431c9d3598 Binary files /dev/null and b/static/images/k3s_start/service overview.png differ