
Всем привет. Меня зовут Путилин Дмитрий (Добрый Кот) Telegram.
От коллектива FR-Solutions : Продолжаем серию статей о K8S.
Наша команда получила запрос на оценку managed K8S от MTS Cloud и составление объективного обзора проделанной работы инженеров МТС. Хочу отметить, что данная статья не является заказной, поэтому мы сосредоточимся на объективном анализе плюсов и минусов этого решения.
Регистрация
Перед началом работы с облаком требуется пройти процесс регистрации. Замечательной особенностью является возможность входа по номеру телефона. Если у вас есть номер от МТС, вся ваша информация будет автоматически подтянута.

Первоначальная авторизация
При первом входе на страницу вы увидите следующую панель с доступными услугами.

Хотим отметить, что явно присутствует недоработка на данной странице. Проблема заключается в том, что при первом входе вероятно выполняется операция создания рабочей области, и до тех пор, пока она не будет создана, невозможно создать какой-либо ресурс. Поэтому при выборе любой услуги вы увидите пустое окно, как показано на скриншоте выше. Было бы логично отображать информацию о создании области и сообщать, что в ближайшее время вы сможете приступить к работе с ней.
Создание кластера K8S
Чтобы создать кластер K8S, вам необходимо выбрать услугу «Containerum Kubernetes» и нажать кнопку «Добавить».
Однако параметры модификации кластера оказываются довольно ограниченными:
-
имя кластера
-
зоны доступности (Москва/Владивосток)
-
сеть для нод
-
сеть для подов
-
версия кластера
-
single master / HA (вид отказоустойчивости)
-
описание группы нод (воркеры)
-
плагины
После выбора необходимой конфигурации вы нажимаете кнопку «Создать» и ожидаете создания кластера.
Сеть
Перед тем, как приступить к выполнению любых задач, вам потребуется настроить сеть. В МТС Облаке для этого доступны ресурсы: Виртуальная частная сеть (VPC) и подсети.

Выражаем свое беспокойство относительно полосы пропускания в 100 Мбит на выходе (не проводили тестирование скорости между узлами).
Созданную подсеть можем указать базовой для наших будущих узлов кластера. Адресация будет выдана по DHCP.
Если речь идет о нодах, то ситуация в целом понятна. Однако, когда дело касается подов, возникают некоторые проблемы. Все решение рассчитано на использование оверлейной сети для контейнеров, что может привести к задержкам (летенси) и уменьшает гибкость доступа от контейнеров до внешних узлов.
Использование SNAT на адрес ноды может затруднить проведение аудита сетевой безопасности, так как необходимо иметь возможность четко отслеживать, какие конкретно запросы отправляются и откуда, так же может затруднить идентификацию точного отправителя в определенный момент времени. Это может создавать проблемы при анализе и мониторинге сетевых активностей для целей безопасности.
Masters
Поскольку мы не имеем доступа к конфигурации кластера из-за ограничений в инфраструктуре, мы можем полагаться на дедукцию и внешние факторы для нашей оценки.
-
Мастер-ноды Kubernetes разворачиваются в виртуальной частной сети (VPC) пользователя (*проверяется через
kubectl get endpoints -n default kubernetesтам будет отображен список IP от мастер нод) -
При создании кластера пользователь указывает базовую подсеть нод, в которой будут развернуты мастер-ноды.
-
Балансировщик нагрузки кластера ведет на мастера и может иметь либо внутреннюю адресацию, либо внешнюю.
Догадки:
-
OC Flatcar
-
Для control-plane и data-plane нод не создаются предварительно настроенные образы (Golden Images) — вся настройка производится через cloud-init.
-
Для выдачи сертификатов вероятно используется инструмент, подобный Vault или аналогичная центральная служба аутентификации (ЦА).
-
На борту системы имеется три пользователя, которые могут получить доступ к системе через SSH:
-
core (не используется, пароля нет, ssh ключа нет)
-
root (не используется, пароля нет, ssh ключа нет)
-
admin — с доступом по ssh через ключи типа ssh-ed25519
-
через него подключается containerum@config-manager
-
-
-
Вся конфигурация передается с использованием файлов Ignition config:
-
сертификаты (private/public ключи)
-
конфигурационные файлы
-
для скачивания необходимых бинарных файлов в систему используются триггер-сервисы, которые управляются через зависимости systemd services.
-
Догадки строятся основываясь на устройстве нод от data-plane.
Workers
При создании группы узлов в кластере, добавляются новые узлы с определенными метаданными:
-
OS IMAGE: Flatcar Container Linux by Kinvolk 3374.2.0 (Oklo)
-
KERNEL-VERSION: 5.15.74-flatcar
-
CONTAINER-RUNTIME: containerd://1.6.8
В официальной документации отмечается, что доступ к узлам для пользователей ограничен. Тем не менее, возникает желание ознакомиться с процессом создания воркер-узлов и изучить, какие компоненты добавляются и как они настраиваются.
Для получения доступа к узлу можно создать контейнер в привилегированном режиме и использовать механизм hostPath с монтированием директории /host. Затем можно выполнить команду chroot /host внутри контейнера, чтобы перейти в корневую файловую систему узла и получить доступ к его содержимому.
--- apiVersion: v1 kind: Pod metadata: name: chroot-pod spec: hostNetwork: true containers: - name: chroot-container image: nginx:stable securityContext: privileged: true volumeMounts: - name: host-root mountPath: /host volumes: - name: host-root hostPath: path: /
Этим способом мы сможем получить доступ к содержимому узла и взаимодействовать с ним.
Давайте рассмотрим процесс бутстрапа нашего хоста. Для этого выполним следующую команду:
journalctl --identifier=ignition --all
список созданных файлов
writing file "/etc/environment" writing file "/etc/hostname" writing file "/etc/coredns.conf" writing file "/etc/hosts" writing link "/etc/resolv.conf" -> "/run/systemd/resolve/stub-resolv.conf" writing file "/etc/flatcar/update.conf" writing file "/etc/kubernetes/kube-proxy.yaml" writing file "/etc/kubernetes/node.kubeconfig" writing file "/etc/kubernetes/kube-proxy.kubeconfig" writing file "/etc/kubernetes/kubelet.yaml" writing file "/opt/kubelet/config.json" writing file "/etc/sysctl.d/k8s.conf" writing file "/etc/sysctl.d/80-swappiness.conf" writing file "/etc/modules-load.d/k8s.conf" writing file "/etc/logrotate.d/overrides.conf" writing file "/etc/systemd/resolved.conf" writing file "/etc/containerd/config.toml" writing file "/etc/kubernetes/pki/node.key" writing file "/etc/kubernetes/pki/ca.crt" writing file "/etc/systemd/system/vmtoolsd.service"
Далее приведен результат, содержащий список записанных файлов.
environment
/# cat /etc/environment export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/opt/bin/:/opt/cni/bin # For crictl export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock
Возникает вопрос, почему было необходимо передавать переменную окружения
CONTAINER_RUNTIME_ENDPOINT, если имеется опция --config, указывающая на
файл /etc/crictl.yaml.
MDNS
В системе используется плагин COREDNS — MDNS, который обеспечивает поддержку мультисервисного обнаружения (mDNS). Этот плагин позволяет устройствам и сервисам в сети обнаруживать и взаимодействовать друг с другом без необходимости во внешних DNS-серверах.
coredns-mdns bootstrap
####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/systemd/system-preset/20-ignition.preset | grep coredns enable coredns.service enable coredns-download.service ####################################################### set-thrush-bce3f9-233564 /home/admin # systemctl status coredns.service ● coredns.service - CoreDNS DNS server Loaded: loaded (/etc/systemd/system/coredns.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2023-06-10 18:26:18 UTC; 21h ago Docs: https://coredns.io Main PID: 934 (mdns-coredns) Tasks: 8 (limit: 15420) Memory: 33.4M CPU: 46.814s CGroup: /system.slice/coredns.service └─934 /opt/bin/mdns-coredns -conf=/etc/coredns.conf ####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/systemd/system/coredns-download.service [Unit] Description=downloading coredns Wants=network-online.target network.target After=network-online.target ConditionFileNotEmpty=|/opt/coredns64.tgz ConditionFileNotEmpty=|!/opt/bin/mdns-coredns [Service] Type=oneshot Environment="URL=https://nexus.dev.cloud.mts.ru/repository/golang-raw/containers/mdns-coredns/mdns-coredns-v1.10.0-3.tgz" Environment="FILE=/opt/coredns64.tgz" ExecStart=/usr/bin/wget -c --retry-connrefused --tries 50 -O $FILE $URL ExecStartPost=tar -xvf $FILE -C /opt/ [Install] WantedBy=multi-user.target ####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/coredns.conf .:5000 { log . "[global] {combined}"{ class denial error } debug bind lo cache 30 forward . 10.99.43.154 { policy sequential expire 60s # expire (cached) connections after this time } } containerum:5000 { debug bind lo log . "[mdns] {combined}" mdns containerum 3 }
Используют плагин COREDNS — MDNS
KUBE-PROXY
kube-proxy bootstrap
####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/systemd/system-preset/20-ignition.preset | grep proxy enable kube-proxy.service enable kube-proxy-download.service ####################################################### set-thrush-bce3f9-233564 /home/admin # systemctl status kube-proxy.service ● kube-proxy.service - kube-proxy Loaded: loaded (/etc/systemd/system/kube-proxy.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2023-06-10 21:47:16 UTC; 18h ago Main PID: 142352 (kube-proxy) Tasks: 5 (limit: 15420) Memory: 39.9M CPU: 4min 7.100s CGroup: /system.slice/kube-proxy.service └─142352 /opt/bin/kube-proxy --config=/etc/kubernetes/kube-proxy.yaml ####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/kubernetes/kube-proxy.yaml --- apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration clientConnection: kubeconfig: "/etc/kubernetes/kube-proxy.kubeconfig" mode: "ipvs" clusterCIDR: 100.70.0.0/16 ####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/systemd/system/kube-proxy-download.service [Unit] Description=downloading kube-proxy Wants=network-online.target network.target After=network-online.target ConditionFileNotEmpty=|!/opt/bin/kube-proxy ConditionFileIsExecutable=|!/opt/bin/kube-proxy [Service] Type=oneshot # Environment="URL=https://storage.googleapis.com/kubernetes-release/release/v1.24.6/bin/linux/amd64/kube-proxy" Environment="URL=https://nexus.dev.cloud.mts.ru/repository/containerum-binaries/kube-proxy/kube-proxy-v1.24.6" Environment="FILE=/opt/bin/kube-proxy" ExecStart=/usr/bin/wget -c --retry-connrefused --tries 50 -O $FILE $URL ExecStartPost=/usr/bin/chmod 755 $FILE [Install] WantedBy=multi-user.target
KUBELET BOOT
kubelet-bootstrap
####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/systemd/system-preset/20-ignition.preset | grep kubelet enable kubelet.service enable kubelet-download.service ####################################################### set-thrush-bce3f9-233564 /home/admin # systemctl status kubelet.service ● kubelet.service - Kubernetes Kubelet Loaded: loaded (/etc/systemd/system/kubelet.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2023-06-11 00:04:06 UTC; 16h ago Main PID: 206921 (kubelet) Tasks: 0 (limit: 15420) Memory: 53.1M CPU: 226ms CGroup: /system.slice/kubelet.service ‣ 206921 /opt/bin/kubelet \ --config=/etc/kubernetes/kubelet.yaml \ --kubeconfig=/etc/kubernetes/node.kubeconfig \ --container-runtime=${KUBELET_RUNTIME} \ --container-runtime-endpoint=${KUBELET_RUNTIME_ENDPOINT} \ --cloud-provider=external \ --runtime-cgroups=/systemd/system.slice \ --root-dir=/opt/kubelet \ --v=2 ####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/systemd/system/kubelet-download.service [Unit] Description=downloading kubelet Wants=network-online.target network.target After=network-online.target ConditionFileNotEmpty=|!/opt/bin/kubelet ConditionFileIsExecutable=|!/opt/bin/kubelet [Service] Type=oneshot # Environment="URL=https://storage.googleapis.com/kubernetes-release/release/v1.24.6/bin/linux/amd64/kubelet" Environment="URL= https://nexus.dev.cloud.mts.ru/repository/containerum-binaries/kubelet/kubelet-v1.24.6" Environment="FILE=/opt/bin/kubelet" ExecStart=/usr/bin/wget -c --retry-connrefused --tries 50 -O $FILE $URL ExecStartPost=/usr/bin/chmod 755 $FILE [Install] WantedBy=multi-user.target ####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/kubernetes/kubelet.yaml kind: KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 authentication: anonymous: enabled: false webhook: enabled: true x509: clientCAFile: "/etc/kubernetes/pki/ca.crt" authorization: mode: Webhook clusterDomain: "cluster.local" clusterDNS: - 100.71.0.10 podCIDR: 100.70.0.0/16 runtimeRequestTimeout: "15m" cgroupDriver: systemd kubeletCgroups: "/systemd/system.slice" systemCgroups: "" tlsCertFile: "/etc/kubernetes/pki/node.crt" tlsPrivateKeyFile: "/etc/kubernetes/pki/node.key" staticPodPath: /etc/kubernetes/manifests volumePluginDir: "/opt/kubelet/libexec/kubernetes/kubelet-plugins/volume/exec/" ####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/kubernetes/node.kubeconfig apiVersion: v1 kind: Config current-context: default contexts: - context: cluster: set-thrush-bce3f9 user: system:node:set-thrush-bce3f9-233564 name: default clusters: - cluster: certificate-authority-data: *** server: https://ExternalIP:6443 tls-server-name: set-thrush-bce3f9 name: set-thrush-bce3f9 users: - user: client-certificate-data: ***== client-key-data: *** name: system:node:set-thrush-bce3f9-233564
Хочется обратить внимание на конфигурационный файл kubelet, kubeconfig и файл /opt/kubelet/config.json
KUBELET-CONFIG
mts-kubelet-config
--- kind: KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 authentication: anonymous: enabled: false webhook: enabled: true x509: clientCAFile: "/etc/kubernetes/pki/ca.crt" authorization: mode: Webhook clusterDomain: "cluster.local" clusterDNS: - 100.71.0.10 podCIDR: 100.70.0.0/16 runtimeRequestTimeout: "15m" cgroupDriver: systemd kubeletCgroups: "/systemd/system.slice" systemCgroups: "" tlsCertFile: "/etc/kubernetes/pki/node.crt" tlsPrivateKeyFile: "/etc/kubernetes/pki/node.key" staticPodPath: /etc/kubernetes/manifests volumePluginDir: "/opt/kubelet/libexec/kubernetes/kubelet-plugins/volume/exec/"
С точки зрения готовности к использованию в продакшн-среде, мы считаем, что данная конфигурация требует доработок и улучшений.
fr-solutions-kubelet-config
registerNode: true cgroupDriver: "systemd" clusterDomain: "cluster.local" cpuManagerReconcilePeriod: "0s" fileCheckFrequency: "0s" healthzBindAddress: "127.0.0.1" httpCheckFrequency: "0s" imageMinimumGCAge: "0s" memorySwap: {} nodeStatusReportFrequency: "1s" nodeStatusUpdateFrequency: "1s" resolvConf: "/run/systemd/resolve/resolv.conf" runtimeRequestTimeout: "0s" shutdownGracePeriod: "15s" shutdownGracePeriodCriticalPods: "5s" streamingConnectionIdleTimeout: "0s" syncFrequency: "0s" volumeStatsAggPeriod: "0s" containerLogMaxSize: "50Mi" maxPods: 250 kubeAPIQPS: 50 kubeAPIBurst: 100 podPidsLimit: 4096 serializeImagePulls: false rotateCertificates: false serverTLSBootstrap: true tlsMinVersion: "VersionTLS12" evictionPressureTransitionPeriod: "5s" imageGCHighThresholdPercent: 55 imageGCLowThresholdPercent: 50 authentication: anonymous: enabled: false webhook: cacheTTL: "0s" enabled: true authorization: mode: "Webhook" webhook: cacheAuthorizedTTL: "0s" cacheUnauthorizedTTL: "0s" logging: flushFrequency: 0 options: json: infoBufferSize: 0 verbosity: 0 systemReserved: ephemeral-storage: "1Gi" featureGates: RotateKubeletServerCertificate: true APIPriorityAndFairness: true DownwardAPIHugePages: true PodSecurity: true CSIMigrationAWS: false CSIMigrationAzureFile: false CSIMigrationGCE: false CSIMigrationvSphere: false tlsCipherSuites: - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" allowedUnsafeSysctls: - "net.core.somaxconn" evictionSoft: "memory.available": "3Gi" "nodefs.available": "25%" "nodefs.inodesFree": "15%" "imagefs.available": "30%" "imagefs.inodesFree": "25%" evictionSoftGracePeriod: "memory.available": "2m30s" "nodefs.available": "2m30s" "nodefs.inodesFree": "2m30s" "imagefs.available": "2m30s" "imagefs.inodesFree": "2m30s" evictionHard: "memory.available": "2Gi" "nodefs.available": "20%" "nodefs.inodesFree": "10%" "imagefs.available": "25%" "imagefs.inodesFree": "15%"
Кроме указанного примера, существует ряд дополнительных мер, которые могут быть применены для повышения отказоустойчивости и безопасности. Однако конкретные значения и настройки будут зависеть от требований и характеристик инфраструктуры каждой организации.
Из нашего опыта, рекомендуется указывать все значения в конфигурационном файле, даже если они соответствуют базовым значениям. Это обеспечивает ясность и недвусмысленность для инженера, а также гарантирует однозначное поведение, даже если значения по умолчанию изменятся при обновлении.
KUBELET-KUBECONFIG
node-kubeconfig
####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/kubernetes/node.kubeconfig apiVersion: v1 kind: Config current-context: default contexts: - context: cluster: set-thrush-bce3f9 user: system:node:set-thrush-bce3f9-233564 name: default clusters: - cluster: certificate-authority-data: *** server: https://ExternalIP:6443 tls-server-name: set-thrush-bce3f9 name: set-thrush-bce3f9 users: - user: client-certificate-data: ***== client-key-data: *** name: system:node:set-thrush-bce3f9-233564
Данный конфигурационный файл дает пищу для размышления.
-
Сертификаты передаются в открытом и нешифрованном виде через ignition config
-
В MTS Cloud, основанной на виртуализации VMWARE, конфигурационные файлы
ignition хранятся в метаданных виртуализации в виде параметра kwargs, к
которому могут иметь доступ инженеры-
*Мы очень надеемся, что приватные ключи Центра Аутентификации (ЦА) не
передаются вместе с бутстрап-конфигурацией кластера таким образом
-
-
Поскольку механизм bootstrap-kubeconfig не используется, можно предположить, что инженеры:
-
Используют внешний
PKIиз-за чегоkube-controller-managerне обладает приватным ключом Центра Аутентификации (ЦА) и, следовательно, не может выписывать сертификаты узлам через стандартный механизмCSR APPROVE -
Не используют данный механизм и разработали собственный метод обновления сертификатов, через ssh под пользователем admin — сервисом containerum@config-manager
-
-
Сертификаты выписываются на 1год, что по нашему мнению слишком много:
-
В нашей практике мы придерживаемся использования срока действия сертификатов не более одного месяца и регулярно обновляем их каждые две недели
-
В любом случае, есть куда расти и оптимизировать, так как многие best practice базируются на том, что в мультитенантных окружениях провайдер обеспечивает только стабильность своей области и не пересекает периметр клиента, где может размещаться критическая информация. Для реализации такого подхода рекомендуется использовать pull-модель и четко разделять ответственность между владельцами control-plane и data-plane.
/opt/kubelet/config.json
{"auths":{"registry.resources.cloud.mts.ru":{"username":"containerum-registry-guest","password":"cxqZrnmCy7LK7AQ","auth":"Y29udGFpbmVydW0tcmVnaXN0cnktZ3Vlc3Q6Y3hxWnJubUN5N0xLN0FR"}}}
Предположим, что эта учетная запись не имеет критического значения для безопасности системы, но ее можно получить, тогда как доступ к registry можно получить только с узлов K8S.
CONTAINERD
Данный инструмент сконфигурирован интересным образом.
containerd bootstrap
####################################################### set-thrush-bce3f9-233564 /home/admin # systemctl status containerd ● containerd.service - containerd container runtime Loaded: loaded (/run/systemd/system/containerd.service; enabled-runtime; vendor preset: disabled) Drop-In: /etc/systemd/system/containerd.service.d └─10-use-custom-config.conf Active: active (running) since Sat 2023-06-10 18:26:17 UTC; 22h ago Docs: https://containerd.io Process: 852 ExecStartPre=mkdir -p /run/docker/libcontainerd (code=exited, status=0/SUCCESS) Process: 856 ExecStartPre=ln -fs /run/containerd/containerd.sock /run/docker/libcontainerd/docker-containerd.sock (code=exited, status=0/SUCCESS) Main PID: 857 (containerd) Tasks: 29 Memory: 142.6M CPU: 25min 14.223s CGroup: /system.slice/containerd.service ####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/systemd/system/containerd.service.d/10-use-custom-config.conf [Service] ExecStart= ExecStart=/usr/bin/containerd --config /etc/containerd/config.toml ####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/containerd/config.toml version = 2 # persistent data location root = "/var/lib/containerd" # runtime state information state = "/run/containerd" # set containerd as a subreaper on linux when it is not running as PID 1 subreaper = true # set containerd's OOM score oom_score = -999 disabled_plugins = [] # grpc configuration [grpc] address = "/run/containerd/containerd.sock" # socket uid uid = 0 # socket gid gid = 0 [plugins."containerd.runtime.v1.linux"] # shim binary name/path shim = "containerd-shim" # runtime binary name/path runtime = "runc" # do not use a shim when starting containers, saves on memory but # live restore is not supported no_shim = false [plugins."io.containerd.grpc.v1.cri"] # enable SELinux labeling enable_selinux = true [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] # setting runc.options unsets parent settings runtime_type = "io.containerd.runc.v2" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true [plugins."io.containerd.grpc.v1.cri".registry] # registries mirrors path config_path = "/etc/containerd/certs.d" ####################################################### set-thrush-bce3f9-233564 /home/admin # ls -al /etc/containerd/certs.d total 36 drwxr-xr-x. 9 root root 4096 Jun 10 17:35 . drwxr-xr-x. 3 root root 4096 Jun 10 17:35 .. drwxr-xr-x. 2 root root 4096 Jun 10 17:35 docker.io drwxr-xr-x. 2 root root 4096 Jun 10 17:35 gcr.io drwxr-xr-x. 2 root root 4096 Jun 10 17:35 ghcr.io drwxr-xr-x. 2 root root 4096 Jun 10 17:35 k8s.gcr.io drwxr-xr-x. 2 root root 4096 Jun 10 17:35 quay.io drwxr-xr-x. 2 root root 4096 Jun 10 17:35 registry-1.docker.io drwxr-xr-x. 2 root root 4096 Jun 10 17:35 registry.k8s.io ####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/containerd/certs.d/k8s.gcr.io/hosts.toml server = "https://k8s.gcr.io" [host."https://registry.resources.cloud.mts.ru/v2/k8s-gcr-io-proxy"] override_path = true capabilities = ["pull", "resolve"]
####################################################### set-thrush-bce3f9-233564 /home/admin # cat /etc/containerd/certs.d/k8s.gcr.io/hosts.toml server = "https://k8s.gcr.io" [host."https://registry.resources.cloud.mts.ru/v2/k8s-gcr-io-proxy"] override_path = true capabilities = ["pull", "resolve"]
В данной конфигурации осуществляется проксирование основных репозиториев через Nexus-registry от MTS Cloud. Это позволяет получать полезную информацию о используемых образах, их уязвимостях и других статистических данных при правильной настройке и подходе. Однако, в случае недоступности реестра МТS, сборки клиентов станут недоступными.
Как говорится два стула.
MTS cloud-controller
Cloud-controller имеет ряд контроллеров:
-
Node controller
-
Маркировка и аннотирование узла
-
Обогощение ресурса Node информацией полученной из MTS Cloud
-
Проверка работоспособности узла
-
Получение Internal и external ip адресов
-
-
Route controller
-
Отвечает за правильную настройку маршрутов в облаке
-
-
Service controller
-
Создание K8S сервиса type=LoadBalancer
-
Сразу вопросы:
-
Node controller:
-
Почему internal и external ip адреса совпадают?
-
INTERNAL-IP EXTERNAL-IP
10.0.10.5 10.0.10.5
-
-
Какие availability-zones еще существуют в регионе Москва?
-
-
Route controller:
-
Предположим, что данный контроллер не описан, поскольку для оверлейных сетей не требуется его использование или настройка
-
-
Service controller:
-
В данном случае все в порядке, однако некоторое беспокойство вызывает время создания сервиса типа LoadBalancer, которое иногда достигает 15-20 секунд
-
MTS csi-controller
Поскольку все окружение основано на стеке VMware, рекомендуется использовать нативный провайдер дисков для VMware, что и сделали инженеры MTS.
По умолчанию в MTS K8S имеется 4 класса хранилищ (storage class):
dk@dobry-kot-system:~/$ kubectl get storageclass NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE mts-ssd-basic csi.vsphere.vmware.com Delete Immediate false 2d23h mts-ssd-fast (default) csi.vsphere.vmware.com Delete Immediate false 2d23h mts-ssd-ultra csi.vsphere.vmware.com Delete Immediate false 2d23h mts-ssd-ultra-plus csi.vsphere.vmware.com Delete Immediate false 2d23h
Эта статья является обзорной и не содержит результатов нагрузочного тестирования выделяемых дисковых пространств.
IAM
MTS обладает значительным опытом в области управления идентификацией и аутентификацией (IAM), однако на данный момент не предоставлены интеграции с Kubernetes (K8S). Мы ожидаем, что в будущем будут предоставлены возможности интеграции для предоставления доступа командам с использованием нативного механизма управления доступом на основе ролей (RBAC), аналогичного тому, что предоставляет Yandex Cloud.
*Т.К не предоставляется возможным изменять конфигурацию kube-apiserver то сделать интеграцию со своим IDP не получится.
IAC
К сожалению, в настоящий момент отсутствует поддержка инструментов IaC, таких как Terraform и Pulumi. Это означает, что всю конфигурацию придется настраивать вручную, без возможности автоматизировать этот процесс.
Reconciliation loop
На момент создания кластера MTS разворачивает базовое окружение внутри K8S кластера:
-
calico
-
kube-state-metrics
-
coredns
-
etc..
Заострять внимание на компонентах не будем, так как неясно, для чего они там существуют. Клиент в любой момент может их удалить, исправить или сломать, и нет никакого механизма защиты от этого со стороны MTS. Если защита отсутствует, то скорее всего MTS не отвечают за эти компоненты и не помогут, если они сломаются. По моему мнению, лучше предоставить пустой кластер или написать собственный контроллер, который будет поддерживать актуальное состояние управляемых компонентов и их конфигурационных файлов.
Вывод
После проведения первичного анализа, мы хотим отметить значительную работу, проделанную командой инженеров MTS при разработке своего продукта. Несмотря на то, что данный продукт является относительно новым и требует некоторой доработки, он уже функционирует и закрывает базовые потребности.
Лично нам продукт не подходит т.к отсутствуют необходимые инструменты взаимодействия, такие как поддержка terraform providers, механизмы изменения Feature Gates или хотя бы чтения установленных. Кроме того, в перспективе мы надеемся на наличие модифицированной конфигурации kubelet, так как при определенных нагрузках на узлы клиенты могут столкнуться с проблемами при использовании текущей конфигурации.
В целом, продукт MTS представляет собой перспективное решение, требующее дальнейшей доработки, но уже доступное для клиентов. Так же у MTS достаточно ресурсов и клиентской базы, что бы довести свое решение до нужного уровня и стать полноценным конкурентом того же Yandex Cloud.
В перспективе проведем анализ managed kubernetes от еще нескольких российских вендоров и постараемся собрать сравнительную базу, что бы показать плюсы и минусы каждого.
Контакты
Благодарим вас за прочтение статьи до конца, надеемся, что она оказалась для вас полезной. Мы будем рады, если вы подключитесь к нашему телеграм-каналу и зададите нам вопросы.
telegram community: https://t.me/fraima_ru
telegram me: https://t.me/Dobry_kot
ссылка на оригинал статьи https://habr.com/ru/articles/741178/
Добавить комментарий