
Всем привет. Меня зовут Путилин Дмитрий (Добрый Кот) 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/fr_solution_ru
telegram me: https://t.me/Dobry_kot