Как стать автором
Обновить

Managed K8S от MTS Cloud

Уровень сложностиПростой
Время на прочтение18 мин
Количество просмотров4.7K

Всем привет. Меня зовут Путилин Дмитрий (Добрый Кот) Telegram.

От коллектива FR-Solutions : Продолжаем серию статей о K8S.

Наша команда получила запрос на оценку managed K8S от MTS Cloud и составление объективного обзора проделанной работы инженеров МТС. Хочу отметить, что данная статья не является заказной, поэтому мы сосредоточимся на объективном анализе плюсов и минусов этого решения.

Регистрация

Перед началом работы с облаком требуется пройти процесс регистрации. Замечательной особенностью является возможность входа по номеру телефона. Если у вас есть номер от МТС, вся ваша информация будет автоматически подтянута.

Первоначальная авторизация

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

Хотим отметить, что явно присутствует недоработка на данной странице. Проблема заключается в том, что при первом входе вероятно выполняется операция создания рабочей области, и до тех пор, пока она не будет создана, невозможно создать какой-либо ресурс. Поэтому при выборе любой услуги вы увидите пустое окно, как показано на скриншоте выше. Было бы логично отображать информацию о создании области и сообщать, что в ближайшее время вы сможете приступить к работе с ней.

Создание кластера K8S

Чтобы создать кластер K8S, вам необходимо выбрать услугу "Containerum Kubernetes" и нажать кнопку "Добавить".

Однако параметры модификации кластера оказываются довольно ограниченными:

  • имя кластера

  • зоны доступности (Москва/Владивосток)

  • сеть для нод

  • сеть для подов

  • версия кластера

  • single master / HA (вид отказоустойчивости)

  • описание группы нод (воркеры)

  • плагины

После выбора необходимой конфигурации вы нажимаете кнопку "Создать" и ожидаете создания кластера.

Сеть

Перед тем, как приступить к выполнению любых задач, вам потребуется настроить сеть. В МТС Облаке для этого доступны ресурсы: Виртуальная частная сеть (VPC) и подсети.

Выражаем свое беспокойство относительно полосы пропускания в 100 Мбит на выходе (не проводили тестирование скорости между узлами).

Созданную подсеть можем указать базовой для наших будущих узлов кластера. Адресация будет выдана по DHCP.

Если речь идет о нодах, то ситуация в целом понятна. Однако, когда дело касается подов, возникают некоторые проблемы. Все решение рассчитано на использование оверлейной сети для контейнеров, что может привести к задержкам (летенси) и уменьшает гибкость доступа от контейнеров до внешних узлов.

Использование SNAT на адрес ноды может затруднить проведение аудита сетевой безопасности, так как необходимо иметь возможность четко отслеживать, какие конкретно запросы отправляются и откуда, так же может затруднить идентификацию точного отправителя в определенный момент времени. Это может создавать проблемы при анализе и мониторинге сетевых активностей для целей безопасности.

Masters

Поскольку мы не имеем доступа к конфигурации кластера из-за ограничений в инфраструктуре, мы можем полагаться на дедукцию и внешние факторы для нашей оценки.

  1. Мастер-ноды Kubernetes разворачиваются в виртуальной частной сети (VPC) пользователя (*проверяется через
    kubectl get endpoints -n default kubernetes
    там будет отображен список IP от мастер нод)

  2. При создании кластера пользователь указывает базовую подсеть нод, в которой будут развернуты мастер-ноды.

  3. Балансировщик нагрузки кластера ведет на мастера и может иметь либо внутреннюю адресацию, либо внешнюю.

Догадки:

  1. OC Flatcar

  2. Для control-plane и data-plane нод не создаются предварительно настроенные образы (Golden Images) - вся настройка производится через cloud-init.

  3. Для выдачи сертификатов вероятно используется инструмент, подобный Vault или аналогичная центральная служба аутентификации (ЦА).

  4. На борту системы имеется три пользователя, которые могут получить доступ к системе через SSH:

    1. core (не используется, пароля нет, ssh ключа нет)

    2. root (не используется, пароля нет, ssh ключа нет)

    3. admin - с доступом по ssh через ключи типа ssh-ed25519

      1. через него подключается containerum@config-manager

  5. Вся конфигурация передается с использованием файлов Ignition config:

    1. сертификаты (private/public ключи)

    2. конфигурационные файлы

    3. для скачивания необходимых бинарных файлов в систему используются триггер-сервисы, которые управляются через зависимости 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:

  • 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 mehttps://t.me/Dobry_kot

Теги:
Хабы:
Всего голосов 4: ↑3 и ↓1+4
Комментарии6

Публикации

Работа

Ближайшие события