@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: Разделение докера на среды.
|
title: Разделение докера на среды.
|
||||||
description: Как работать с несколькими docker-compose.
|
description: Как работать с несколькими docker-compose.
|
||||||
position: 3
|
position: 2
|
||||||
category: DevOps
|
category: DevOps
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: Makefiles для чайников.
|
title: Makefiles для чайников.
|
||||||
description: Автоматизируем по старинке.
|
description: Автоматизируем по старинке.
|
||||||
position: 1
|
position: 3
|
||||||
category: 'DevOps'
|
category: 'DevOps'
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
multi_line_output = 3
|
||||||
include_trailing_comma = true
|
|
||||||
use_parentheses = true
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
`.flake8` - конфигурация линтинга. Тут довольно много. Это игнорирование ненужных кодов ошибок, которые не особо-то и ошибки.
|
`.flake8` - конфигурация линтинга. Тут довольно много. Это игнорирование ненужных кодов ошибок, которые не особо-то и ошибки.
|
||||||
@ -416,13 +422,6 @@ repos:
|
|||||||
entry: yesqa
|
entry: yesqa
|
||||||
language: system
|
language: system
|
||||||
types: [ python ]
|
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).
|
И не забываем про `.gitignore`. Его можно найти [тут](https://github.com/github/gitignore/blob/master/Python.gitignore).
|
||||||
|
753
content/ru/start-with-k8s.md
Normal file
@ -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 удалит все описанные ресурсы из вашего кластера.
|
||||||
|
|
||||||
|
До новых встреч.
|
@ -7,7 +7,6 @@ category: DevOps
|
|||||||
|
|
||||||
# Traefik - роутинг просто
|
# Traefik - роутинг просто
|
||||||
|
|
||||||
|
|
||||||
Сегодня я бы хотел рассказать о такой клёвой штуке, как [Traefik](https://traefik.io/traefik/). Не так давно я перевёл все сервисы своего сервера на traefik и это буквально сделало жизнь проще. Сегодня я расскажу вам зачем он нужен, как его настроить, и покажу на примере, как именно он помогает. По факту, это nginx на стероидах, в плане конфигурации, потому что в traefik за тебя сделано гораздо больше.
|
Сегодня я бы хотел рассказать о такой клёвой штуке, как [Traefik](https://traefik.io/traefik/). Не так давно я перевёл все сервисы своего сервера на traefik и это буквально сделало жизнь проще. Сегодня я расскажу вам зачем он нужен, как его настроить, и покажу на примере, как именно он помогает. По факту, это nginx на стероидах, в плане конфигурации, потому что в traefik за тебя сделано гораздо больше.
|
||||||
|
|
||||||
# Что такое traefik
|
# Что такое traefik
|
||||||
@ -33,6 +32,7 @@ Traefik - это система, которая позволяет настро
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Архитектура
|
## Архитектура
|
||||||
|
|
||||||
В официальной документации зарисована следующая схема работы traefik:
|
В официальной документации зарисована следующая схема работы traefik:
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@ -43,21 +43,24 @@ Traefik - это система, которая позволяет настро
|
|||||||
|
|
||||||
Как можно видеть по данному изображению, есть 5 основных составляющих traefik, а именно:
|
Как можно видеть по данному изображению, есть 5 основных составляющих traefik, а именно:
|
||||||
|
|
||||||
* entrypoints
|
- entrypoints
|
||||||
* routers
|
- routers
|
||||||
* rules (часть routers)
|
- rules (часть routers)
|
||||||
* middlewares (чать routers)
|
- middlewares (чать routers)
|
||||||
* services
|
- services
|
||||||
|
|
||||||
### Entrypoint
|
### Entrypoint
|
||||||
|
|
||||||
Являются основными слушателями входящих соединений. Через них проходит весь трафик. Если попробовать объяснить в двух словах: "Порт, на который должно прийти входящее соединение", - вполне себе неплохое объяснение. В данном туториале я создам 2 `entrypoint`, которые будут слушать на http и https.
|
Являются основными слушателями входящих соединений. Через них проходит весь трафик. Если попробовать объяснить в двух словах: "Порт, на который должно прийти входящее соединение", - вполне себе неплохое объяснение. В данном туториале я создам 2 `entrypoint`, которые будут слушать на http и https.
|
||||||
|
|
||||||
### Routers, Rules и Middlewares
|
### Routers, Rules и Middlewares
|
||||||
|
|
||||||
Роутер - связующее звено между `entrypoint` и сервисом, куда нужно направить трафик. Роутер хранит в себе информацию, куда направить входящий трафик, и
|
Роутер - связующее звено между `entrypoint` и сервисом, куда нужно направить трафик. Роутер хранит в себе информацию, куда направить входящий трафик, и
|
||||||
правила, по которым можно определить, пускать ли трафик дальше.
|
правила, по которым можно определить, пускать ли трафик дальше.
|
||||||
|
|
||||||
Rules - это и есть те самые правила, которые определяют, через какой роутер пустить трафик.
|
Rules - это и есть те самые правила, которые определяют, через какой роутер пустить трафик.
|
||||||
Допустим, у вас в конфиге есть следующие правила:
|
Допустим, у вас в конфиге есть следующие правила:
|
||||||
|
|
||||||
```
|
```
|
||||||
Host(`myapp.com`) && (PathPrefix(`/api`) || PathPrefix(`/memes`))
|
Host(`myapp.com`) && (PathPrefix(`/api`) || PathPrefix(`/memes`))
|
||||||
```
|
```
|
||||||
@ -75,7 +78,6 @@ Host(`myapp.com`) && (PathPrefix(`/api`) || PathPrefix(`/memes`))
|
|||||||
Вы, конечно же, можете использовать локально установленную версию, всё будет работать, как часы.
|
Вы, конечно же, можете использовать локально установленную версию, всё будет работать, как часы.
|
||||||
</b-message>
|
</b-message>
|
||||||
|
|
||||||
|
|
||||||
Для нашего основного traefik на сервере мы создадим небольшой docker-compose.yml, файл конфига и папочку с сертификатами.
|
Для нашего основного traefik на сервере мы создадим небольшой docker-compose.yml, файл конфига и папочку с сертификатами.
|
||||||
Структура будет следующая:
|
Структура будет следующая:
|
||||||
|
|
||||||
@ -101,12 +103,19 @@ services:
|
|||||||
image: traefik:v2.4.8
|
image: traefik:v2.4.8
|
||||||
container_name: traefik_main
|
container_name: traefik_main
|
||||||
command:
|
command:
|
||||||
|
# Включает прослушивание докера на новые события и следит за лейблами контейнеров.
|
||||||
- --providers.docker=true
|
- --providers.docker=true
|
||||||
|
# Отключает автоматическое создание роутеров ко всем контейнерам на сервере.
|
||||||
- --providers.docker.exposedbydefault=false
|
- --providers.docker.exposedbydefault=false
|
||||||
|
# Сеть докера, по которой будет выполнятся подключение к контейнерам.
|
||||||
- --providers.docker.network=traefik-shared
|
- --providers.docker.network=traefik-shared
|
||||||
|
# Папка с конфигурационным файлом.
|
||||||
- --providers.file.directory=/etc/traefik/dynamic
|
- --providers.file.directory=/etc/traefik/dynamic
|
||||||
|
# Включает отслеживание изменений файла конфигурации.
|
||||||
- --providers.file.watch=true
|
- --providers.file.watch=true
|
||||||
|
# Создаёт entrypoint с названием http и слушает 80 порт.
|
||||||
- --entrypoints.http.address=:80
|
- --entrypoints.http.address=:80
|
||||||
|
# Создаёт entrypoint с названием https и слушает 443 порт.
|
||||||
- --entrypoints.https.address=:443
|
- --entrypoints.https.address=:443
|
||||||
ports:
|
ports:
|
||||||
# The HTTP port
|
# The HTTP port
|
||||||
@ -119,12 +128,16 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
MAIN_HOST: 192.168.1.89
|
MAIN_HOST: 192.168.1.89
|
||||||
volumes:
|
volumes:
|
||||||
# So that Traefik can listen to the Docker events
|
# Обязательный вольюм. Так траефик может слушать
|
||||||
|
# события происходящие в демоне докера.
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
# Вольюм с файлом конфигурации.
|
||||||
- ./config.toml:/etc/traefik/dynamic/traefik.toml
|
- ./config.toml:/etc/traefik/dynamic/traefik.toml
|
||||||
|
# Папка сертификатов.
|
||||||
- ./certs:/etc/certs/
|
- ./certs:/etc/certs/
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
|
# Сетка, внутри которой будут находится приложения.
|
||||||
traefik-shared:
|
traefik-shared:
|
||||||
name: traefik-shared
|
name: traefik-shared
|
||||||
|
|
||||||
@ -132,16 +145,6 @@ networks:
|
|||||||
|
|
||||||
Вот какие параметры я передаю в `traefik-cli`.
|
Вот какие параметры я передаю в `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` и подобрать себе желаемые параметры.
|
Конечно, вы всегда можете глянуть `traefik --help` и подобрать себе желаемые параметры.
|
||||||
|
|
||||||
Также из docker-compose файла видно, что я создал докер сеть `traefik-shared`, которую в дальнейшем буду использовать на всех контейнерах, которым требуется свой домен.
|
Также из docker-compose файла видно, что я создал докер сеть `traefik-shared`, которую в дальнейшем буду использовать на всех контейнерах, которым требуется свой домен.
|
||||||
@ -153,16 +156,19 @@ networks:
|
|||||||
Для генерации локальных сертификатов я использую тулу [mkcert](https://github.com/FiloSottile/mkcert).
|
Для генерации локальных сертификатов я использую тулу [mkcert](https://github.com/FiloSottile/mkcert).
|
||||||
|
|
||||||
Для любого локального домена я делаю что-то типа:
|
Для любого локального домена я делаю что-то типа:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkcert "*.local"
|
mkcert "*.local"
|
||||||
mv _wildcard.local-key.pem local.key
|
mv _wildcard.local-key.pem local.key
|
||||||
mv _wildcard.local.pem local.pem
|
mv _wildcard.local.pem local.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
И помещаю это в папочку `certs` рядом с `docker-compose.yml`.
|
И помещаю это в папочку `certs` рядом с `docker-compose.yml`.
|
||||||
|
|
||||||
После того как я создал все нужные сертефикаты для всех доменов, их надо указать в файле `config.toml` в папочке traefik.
|
После того как я создал все нужные сертефикаты для всех доменов, их надо указать в файле `config.toml` в папочке traefik.
|
||||||
|
|
||||||
Вот пример:
|
Вот пример:
|
||||||
|
|
||||||
```toml{}[config.toml]
|
```toml{}[config.toml]
|
||||||
[tls.options]
|
[tls.options]
|
||||||
[tls.options.default]
|
[tls.options.default]
|
||||||
@ -190,9 +196,11 @@ mv _wildcard.local.pem local.pem
|
|||||||
После этого вы можете запускать traefik и наслаждаться доменами для ваших контейнеров.
|
После этого вы можете запускать traefik и наслаждаться доменами для ваших контейнеров.
|
||||||
|
|
||||||
# Запуск приложений
|
# Запуск приложений
|
||||||
|
|
||||||
Теперь сконфигурируем приложение таким образом, чтобы к нему можно было обращаться через доменное имя.
|
Теперь сконфигурируем приложение таким образом, чтобы к нему можно было обращаться через доменное имя.
|
||||||
|
|
||||||
Для примера возьмем мелкое приложение на nodejs со следующей структурой проекта:
|
Для примера возьмем мелкое приложение на nodejs со следующей структурой проекта:
|
||||||
|
|
||||||
```
|
```
|
||||||
.
|
.
|
||||||
├── docker-compose.yml
|
├── docker-compose.yml
|
||||||
@ -260,10 +268,15 @@ services:
|
|||||||
server:
|
server:
|
||||||
build: .
|
build: .
|
||||||
labels:
|
labels:
|
||||||
|
# Включить поддержку роутинга через traefik.
|
||||||
- traefik.enable=true
|
- traefik.enable=true
|
||||||
|
# Поставить правило роутинга, если Host запроса равен test_node.local.
|
||||||
- traefik.http.routers.test_node.rule=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
|
- traefik.http.routers.test_node.entrypoints=http
|
||||||
|
# Сервис, связанный с роутером test_node.
|
||||||
- traefik.http.routers.test_node.service=node_test
|
- traefik.http.routers.test_node.service=node_test
|
||||||
|
# Порт, куда направлять запросы в сервис node_test.
|
||||||
- traefik.http.services.node_test.loadbalancer.server.port=3000
|
- traefik.http.services.node_test.loadbalancer.server.port=3000
|
||||||
command: runserver
|
command: runserver
|
||||||
networks:
|
networks:
|
||||||
@ -271,6 +284,7 @@ services:
|
|||||||
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
|
# Докер сеть, в которой находится traefik.
|
||||||
traefik-shared:
|
traefik-shared:
|
||||||
name: traefik-shared
|
name: traefik-shared
|
||||||
external: true
|
external: true
|
||||||
@ -282,14 +296,6 @@ networks:
|
|||||||
|
|
||||||
Как вы видите, приложение слушает на порт `3000` и отвечает свим hostname и количеством обработанных запросов. А в docker-compose.yml, в отличие от обычного проекта, появились labels.
|
Как вы видите, приложение слушает на порт `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/>
|
<hr/>
|
||||||
<b-message type="is-danger" has-icon>
|
<b-message type="is-danger" has-icon>
|
||||||
|
|
||||||
@ -308,6 +314,7 @@ networks:
|
|||||||
Также можно видеть, что я подключил контейнер к сети, которую мы указывали в контейнере traefik. Здесь она помечена как external.
|
Также можно видеть, что я подключил контейнер к сети, которую мы указывали в контейнере traefik. Здесь она помечена как external.
|
||||||
|
|
||||||
Теперь мы можем спокойно запустить наш сервис. Для этого воспользуемся следующей командой:
|
Теперь мы можем спокойно запустить наш сервис. Для этого воспользуемся следующей командой:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose up --build --scale server=3
|
docker-compose up --build --scale server=3
|
||||||
```
|
```
|
||||||
@ -328,6 +335,7 @@ $ curl -H "Host: test_node.local" "http://localhost"
|
|||||||
Как вы видите, traefik балансирует между контейнерами за нас. И я считаю, что это - победа.
|
Как вы видите, traefik балансирует между контейнерами за нас. И я считаю, что это - победа.
|
||||||
|
|
||||||
## Подключение TLS и сертификатов
|
## Подключение TLS и сертификатов
|
||||||
|
|
||||||
Тут всё не намного сложнее. Давайте немного поменяем лейблы нашего контейнера.
|
Тут всё не намного сложнее. Давайте немного поменяем лейблы нашего контейнера.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@ -347,6 +355,7 @@ services:
|
|||||||
На данном этапе вам потребуется добавить свой хост в `/etc/hosts`, если вы используете нормальную систему. Но если вы всё же на windows, то вам потребуется добавить правило в `C:\Windows\System32\drivers\etc\hosts`.
|
На данном этапе вам потребуется добавить свой хост в `/etc/hosts`, если вы используете нормальную систему. Но если вы всё же на windows, то вам потребуется добавить правило в `C:\Windows\System32\drivers\etc\hosts`.
|
||||||
|
|
||||||
И добавляем в конец файла запись:
|
И добавляем в конец файла запись:
|
||||||
|
|
||||||
```
|
```
|
||||||
127.0.0.1 test_node.local
|
127.0.0.1 test_node.local
|
||||||
```
|
```
|
||||||
@ -365,12 +374,12 @@ $ curl --insecure https://test_node.local
|
|||||||
{"request_num":0,"host":"7417ac8fda92"}
|
{"request_num":0,"host":"7417ac8fda92"}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Добавление локальных сервисов не из докера
|
## Добавление локальных сервисов не из докера
|
||||||
|
|
||||||
Все те флаги, которые мы указываем в labels, вы также можете указать в файле конфигурации рядом с docker-compose.yml, указав конкретный ip адрес.
|
Все те флаги, которые мы указываем в labels, вы также можете указать в файле конфигурации рядом с docker-compose.yml, указав конкретный ip адрес.
|
||||||
|
|
||||||
Например:
|
Например:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[http.routers]
|
[http.routers]
|
||||||
# Define a connection between requests and services
|
# Define a connection between requests and services
|
||||||
@ -387,8 +396,8 @@ $ curl --insecure https://test_node.local
|
|||||||
url = "http://192.168.1.89:8100"
|
url = "http://192.168.1.89:8100"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
# Создание локального DNS
|
# Создание локального DNS
|
||||||
|
|
||||||
В данном пункте я бы хотел рассказать, как настроить свой DNS-сервер, чтобы ваши домены были доступны всем устройствам в локальной сети. Для этого я буду использовать dnsmasq. Пользователям винды он недоступен, поэтому советую развернуть маленький домашний сервер на линуксе.
|
В данном пункте я бы хотел рассказать, как настроить свой DNS-сервер, чтобы ваши домены были доступны всем устройствам в локальной сети. Для этого я буду использовать dnsmasq. Пользователям винды он недоступен, поэтому советую развернуть маленький домашний сервер на линуксе.
|
||||||
|
|
||||||
Для этого установите `dnsmasq` и найдите и раскомментируйте, либо добавьте следующие строчки в файл `/etc/dnsmasq.conf`:
|
Для этого установите `dnsmasq` и найдите и раскомментируйте, либо добавьте следующие строчки в файл `/etc/dnsmasq.conf`:
|
||||||
@ -406,6 +415,7 @@ address=/.<other_domain>/<your_local_ip>
|
|||||||
Чтобы это узнать, посмотрите свой ip через роутер или выполните `ip addr`.
|
Чтобы это узнать, посмотрите свой ip через роутер или выполните `ip addr`.
|
||||||
|
|
||||||
Вообще, `dnsmasq` парсит файл `/etc/hosts` и вы можете туда добавлять записи, типа:
|
Вообще, `dnsmasq` парсит файл `/etc/hosts` и вы можете туда добавлять записи, типа:
|
||||||
|
|
||||||
```
|
```
|
||||||
192.168.1.1 mydomain.local
|
192.168.1.1 mydomain.local
|
||||||
```
|
```
|
||||||
@ -413,6 +423,7 @@ address=/.<other_domain>/<your_local_ip>
|
|||||||
Но так как я указал `address`, то это необязательно. `dnsmasq` и без явного указания поддоменов должен будет работать отлично.
|
Но так как я указал `address`, то это необязательно. `dnsmasq` и без явного указания поддоменов должен будет работать отлично.
|
||||||
|
|
||||||
Запустите `dnsmasq` в режиме сревиса:
|
Запустите `dnsmasq` в режиме сревиса:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo systemctl enable dnsmasq.service
|
sudo systemctl enable dnsmasq.service
|
||||||
sudo systemctl start dnsmasq.service
|
sudo systemctl start dnsmasq.service
|
||||||
@ -457,5 +468,4 @@ services:
|
|||||||
|
|
||||||
[](/images/traefik_imgs/traefik_web.png)
|
[](/images/traefik_imgs/traefik_web.png)
|
||||||
|
|
||||||
|
|
||||||
Разве это не круто?
|
Разве это не круто?
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<b-navbar type="is-primary w-100">
|
<b-navbar type="is-primary w-100" :fixed-top="true">
|
||||||
<template #brand>
|
<template #brand>
|
||||||
<NuxtLink to="/" class="navbar-item">
|
<NuxtLink to="/" class="navbar-item">
|
||||||
<img src="/icon.png" alt="Logo" /> S3rius' dev blog
|
<img src="/icon.png" alt="Logo" /> Dev blog
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</template>
|
</template>
|
||||||
<template #end>
|
<template #end>
|
||||||
@ -24,7 +24,7 @@
|
|||||||
:key="category"
|
:key="category"
|
||||||
class="is-hidden-desktop"
|
class="is-hidden-desktop"
|
||||||
>
|
>
|
||||||
<p class="navbar-item is-inactive divider">
|
<p class="navbar-item is-inactive category">
|
||||||
<span>{{ category }}</span>
|
<span>{{ category }}</span>
|
||||||
</p>
|
</p>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
@ -73,7 +73,8 @@ export default defineComponent({
|
|||||||
const categories = ref([])
|
const categories = ref([])
|
||||||
$content({ deep: true })
|
$content({ deep: true })
|
||||||
.only(['category', 'slug', 'title', 'position'])
|
.only(['category', 'slug', 'title', 'position'])
|
||||||
.sortBy('createdAt', 'asc')
|
.sortBy('category', 'asc')
|
||||||
|
.sortBy('position', 'asc')
|
||||||
.fetch()
|
.fetch()
|
||||||
.then((pages) => {
|
.then((pages) => {
|
||||||
let cats = new Map()
|
let cats = new Map()
|
||||||
@ -94,12 +95,11 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.divider {
|
.category {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-bottom: 1px solid #000;
|
|
||||||
line-height: 0.1em;
|
|
||||||
margin: 10px 0 20px;
|
margin: 10px 0 20px;
|
||||||
|
color: gray;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
@ -70,7 +70,7 @@ export default {
|
|||||||
short_name: 'Dev blog',
|
short_name: 'Dev blog',
|
||||||
lang: 'ru',
|
lang: 'ru',
|
||||||
background_color: '#fafdff',
|
background_color: '#fafdff',
|
||||||
theme_color: '#fafdff',
|
theme_color: '#687cec',
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
fileName: 'icon.png',
|
fileName: 'icon.png',
|
||||||
|
@ -44,10 +44,16 @@ export default defineComponent({
|
|||||||
]
|
]
|
||||||
if (doc.image) {
|
if (doc.image) {
|
||||||
meta_data.push({
|
meta_data.push({
|
||||||
hid: 'og:description',
|
hid: 'og:image',
|
||||||
name: 'og:description',
|
name: 'og:image',
|
||||||
content: doc.image,
|
content: doc.image,
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
meta_data.push({
|
||||||
|
hid: 'og:image',
|
||||||
|
name: 'og:image',
|
||||||
|
content: 'https://s3rius.blog/logo.png',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
meta.value = meta_data
|
meta.value = meta_data
|
||||||
})
|
})
|
||||||
@ -83,7 +89,7 @@ export default defineComponent({
|
|||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
letter-spacing: -0.01em;
|
letter-spacing: -0.01em;
|
||||||
color: rgba(0, 0, 0, 0.54);
|
color: rgba(0, 0, 0, 0.54);
|
||||||
margin: 1em 0.5em;
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@ -139,5 +145,10 @@ export default defineComponent({
|
|||||||
margin-bottom: 0.5em !important;
|
margin-bottom: 0.5em !important;
|
||||||
margin-left: 1.25em !important;
|
margin-left: 1.25em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
display: inline-block;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
BIN
static/images/k3s_start/ingress-overview.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
static/images/k3s_start/kube_intro.jpg
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
static/images/k3s_start/kubectl-apply.png
Normal file
After Width: | Height: | Size: 840 KiB |
BIN
static/images/k3s_start/lens-deployed.png
Normal file
After Width: | Height: | Size: 134 KiB |
BIN
static/images/k3s_start/lens-example.png
Normal file
After Width: | Height: | Size: 208 KiB |
484
static/images/k3s_start/pods.svg
Normal file
@ -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>
|
After Width: | Height: | Size: 37 KiB |
BIN
static/images/k3s_start/requests.gif
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
static/images/k3s_start/service overview.png
Normal file
After Width: | Height: | Size: 15 KiB |