LINUX.ORG.RU
ФорумTalks

Как я кубернетес поднимал

 ,


1

2

Точней начал. Может кому интересно будет. Гайдов вроде миллиард в интернете, но почему-то конкретно мои проблемы нигде не описаны были, пришлось курить, хотя там всё просто. А если вдруг корифеи расскажут, чего я сделал не так, будет совсем хорошо.

Вводная - имеется набор виртуальных серверов в одной частной сети 10.206.192.0/24. На них хочется поднять сабж.

Из нестандартного только load balancer. Он у моего провайдера к счастью есть. По сути это реверс прокси. Принимает соединения на 10.206.192.2:6443 и перенаправляет на 10.206.192.90:6443, 10.206.192.91:6443, 10.206.192.92:6443. Помимо прочего мониторит состояние и если какой-то сервер долго не принимает соединения на порту, то выключает его из этого пула.

На самих серверах я поставил ubuntu 20.04. Вообще я написал скрипты terraform и ansible, без них свихнуться можно, тыщу раз пересоздавал узлы.

В идеале надо 3 узла на control cерверы и 3+ worker-а. Конечно желательно, чтобы они крутились на физически разных серверах, иначе какой в этом всём толк. А так - если один сервер умрёт, то остальное вроде продолжит работать. На мастерах надо по 4GB / 2 cores, в крайнем случае до 2GB можно опустить, меньше уже нельзя. На рабочих нодах наверное можно и 1GB по сути сколько уже вашим приложениям нужно.

На всех серверах делается следующая конфигурация (помимо накатывания апдейтов):

echo br_netfilter > /etc/modules-load.d/br_netfilter.conf
modprobe br_netfilter
echo net.ipv4.ip_forward = 1 > /etc/sysctl.conf
sysctl net.ipv4.ip_forward = 1
apt install containerd
mkdir -p /etc/containerd
cat >/etc/containerd/config.toml <<EOF
version = 2
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = false
EOF
systemctl restart containerd
curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" >/etc/apt/sources.list.d/kubernetes.list
apt install kubelet=1.23.7-00 kubeadm=1.23.7-00 kubectl=1.23.7-00
apt-mark hold kubelet kubeadm kubectl

На этом вся подготовка закончилась. containerd из репозитория не очень новый, поэтому 1.24 кажется запустить не получится. Если нужно - там еще надо добавить репозитории докера и ставить последний containerd.

Далее на первом мастере

kubeadm init \
  --kubernetes-version=v1.23.7 \
  --control-plane-endpoint=10.206.192.2:6443 \
  --upload-certs \
  --pod-network-cidr=10.244.0.0/16

если тут какие-то проблемы будут, вероятно неправильно работает load balancer.

Он минут 5 попыхтит и родит кластер. Напечатает команды, их пока выполнять не надо. Еще напечатает команды для копирования admin.conf в ~/.kube, это сделать желательно.

Теперь ставим calico. Это некий плагин для сети. Вот тут я просидел два дня.

kubectl create -f https://projectcalico.docs.tigera.io/manifests/tigera-operator.yaml
curl -O 'https://projectcalico.docs.tigera.io/manifests/custom-resources.yaml'
vim custom-resources.yaml
// spec.calicoNetwork.ipPools[0].cidr: 10.244.0.0/16
// spec.calicoNetwork.ipPools[0].encapsulation: IPIP
kubectl create -f ./custom-resources.yaml
watch kubectl get pods -A

Вся суть в том, чтобы поменять значение поля encapsulation. По умолчанию оно пытается делать что-то странное, что у меня не работало и сеть не поднималась, причем без каких-то индикаторов проблем, на вид все нормально, а пакеты не ходят.

Потом ждем пока все поды запустятся. После этого (а может можно и сразу, но я предпочитаю не торопиться) добавляем все остальные ноды в кластер теми командами, которые написаны в выхлопе kubeadm init.

Альтернативно вмето calico можно поставить flannel. Он типа проще но настроек меньше. Я его пробовал, из коробки заработал без проблем.

В принципе всё, кластер работает. Я пока до этого этапа дошел. busybox запускается, пинги идут. Дальше буду со storage разбираться. Пока что всё довольно просто выглядит, не знаю, чего там этим кубернетесом все пугают. Какой-нибудь Оракл ставить было куда сложней.

★★★★

Последнее исправление: vbr (всего исправлений: 5)

не знаю, чего там этим кубернетесом все пугают.

3 года назад kubeadm отучили разваливать кластеры, а до него почти все конфиги для инициализации надо было писать ручками (читается как велосипедные шелл-скрипты).

Вся суть в том, чтобы поменять значение поля encapsulation.

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

chupasaurus
()

А теперь посмотри в сторону kubespray - это готовый скрипт на Ansible, который не только поднимает kubernetes, но и ставит туда ingress controller, CSI драйвера для томов, и прочие вкусняшки.

Или в сторону курса от Slurm, базовый у них доступен бесплатно на youtube. Вот только для реального применения в production мегакурс тоже нужен, поскольку вопросы безопасности и stateful-приложения именно в нем.

AEP ★★★★★
()
Ответ на: комментарий от GoodRussian

На youtube, уже слегка протухший материал: https://www.youtube.com/watch?v=Jp866ltZBSk&list=PL8D2P0ruohOA4Y9LQoTttfSgsRwUGWpu6

Курс для разработчиков, с довольно большим пересечением: https://www.youtube.com/watch?v=Mw_rEH2pElw&list=PL8D2P0ruohOBSA_CDqJLflJ8FLJNe26K-

На сайте, платно с практикой на заранее заготовленных стендах: https://slurm.io/kubernetes-baza и https://slurm.io/kubernetes-megapotok (мегу проходить после базы)

AEP ★★★★★
()
Ответ на: комментарий от chupasaurus

3 года назад kubeadm отучили разваливать кластеры, а до него почти все конфиги для инициализации надо было писать ручками (читается как велосипедные шелл-скрипты).

Ну наверное не писать, а копипастить?

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

По-мне дефолт должен быть работающим на 100% везде. Или хотя бы в этих quickstart гайдах этот момент должен упоминаться. Тем более, что под популярные облака там отдельные quickstart-ы.

vbr ★★★★
() автор топика
Ответ на: комментарий от cobold

Почему? Это норма. Для подов выделяется отдельная «виртуальная» подсеть. По идее можно настроить роутер на её роутинг, но у меня не получилось, настроек там особо и нет. Поэтому идёт что-то вроде впна без шифрования. Из накладных расходов только несколько десятков байтов на инкапсуляцию одного IP пакета в другом.

vbr ★★★★
() автор топика
Ответ на: комментарий от vbr

Ну наверное не писать, а копипастить?

Дык неоткуда было. Вот вам дефолты, вот описание параметров, *битес.

По-мне дефолт должен быть работающим на 100% везде. Или хотя бы в этих quickstart гайдах этот момент должен упоминаться.

Там фишка в том, что 100% работающий метод (VXLAN везде) тормозной. В quickstart гайде для on-premise ссылочка про выбор обёртки имеется.

chupasaurus
()
Ответ на: комментарий от chupasaurus

В общем покурил, посидел с tcpdump. Без encapsulation пакеты идут в сеть с айпишниками подов: src и dest. Ну в целом так и ожидается. При этом судя по всему все маршруты анонсируются через BGP. И та сущность, которая роутит пакеты в моей виртуальной частной сети, должна бы эти BGP принимать и брать во внимание. По факту пакет уходит, но не приходит, то бишь на BGP оно не обращает внимание и просто выбрасывает пакеты, про которые не знает, куда роутить. Кажется надо в openstack включить некий dynamic routing, но это настройки на стороне провайдера, к которым у меня доступа нет. Поэтому без IPIP, видимо, не обойтись. Но исследование было познавательным.

vbr ★★★★
() автор топика
Ответ на: комментарий от etwrq

В любом месте, где есть почасовая оплата VPS-ок. Думаю, можно и на локалхосте с кучкой виртуалок, но я так не пробовал.

vbr ★★★★
() автор топика

Ты скажи лучше нажуя ты сам решил control plane поддерживать? Вся суть кубов для мелких - возможность свалить их на провайдера

upcFrost ★★★★★
()
Ответ на: комментарий от upcFrost

В моей стране нет такого провайдера, а проект требует локальное хранение данных.

vbr ★★★★
() автор топика

Я поднимал на firecracker + rancher. Вроде работало шустро и выполняло свои задачи. для Лоад Балансера я предпочитаю использовать Envoy Proxy (на базе haproxy).

Nurmukh ★★★
()

Уф, вроде nginx-ingress поднял. В целом всё просто, но информации примерно ноль, приходится рыться на задворках стековерфлу, чтобы нужные строчки выковырять. Для опытных кубернетесоводов видимо всё очевидно, а для неопытных не очевидно.

cat >ingress-nginx-values.yaml <<EOF
controller:
  config:
    use-forwarded-headers: true
  kind: DaemonSet
  service:
    type: NodePort
    enableHttps: false
    nodePorts:
      http: 30080
EOF

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace \
  --values ingress-nginx-values.yaml

Вот эти строчки запускают нгинкс на каждой worker node. Далее нужно внешний load balancer настроить так, чтобы он перекидывал :80 -> worker-ip:30080. С HTTPS пока не начинал. Тут стандартные решения тоже не подойдут. Мой load balancer не умеет в PROXY. Поэтому мне нужна терминация на load balancer-е и передача source ip/port/proto через x-forwarder-* заголовки. Ну да ладно, разберемся.

vbr ★★★★
() автор топика
Последнее исправление: vbr (всего исправлений: 1)

Оптимизировал сеть. Настроил через ebpf. Обещают, что будет быстрей. Ох и долго же я команды рожал.

sudo kubeadm init \
        --control-plane-endpoint="10.206.192.99:6443" \
        --kubernetes-version="1.23.8" \
        --pod-network-cidr="10.244.0.0/16" \
        --skip-phases="addon/kube-proxy"
    || exit $?

kubectl create namespace "tigera-operator" \
    || exit $?

kubectl create configmap \
        --namespace="tigera-operator" "kubernetes-services-endpoint" \
        --from-literal="KUBERNETES_SERVICE_HOST=10.206.192.99" \
        --from-literal="KUBERNETES_SERVICE_PORT=6443" \
    || exit $?

helm upgrade --install "calico" "tigera-operator" \
        --repo="https://projectcalico.docs.tigera.io/charts" \
        --namespace="tigera-operator" --create-namespace \
        --set="installation.calicoNetwork.linuxDataplane=BPF" \
        --set="installation.calicoNetwork.ipPools[0].cidr=10.244.0.0/16" \
        --set="installation.calicoNetwork.ipPools[0].encapsulation=VXLAN" \
    || exit $?

Как ни странно, но всё заработало с первого раза. По крайней мере простые пинги идут между подами на разных узлах. Вот так вот.

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

vbr ★★★★
() автор топика

В общем ладно, писать сюда уже больше не буду, всё расползлось по куче скриптов и конфигов, в одном месте это всё вываливать уже геморно.

Общая схема, к которой я в итоге пришёл.

  1. Создаётся отдельный внутренний лоад-балансер, слушающий на 10.206.192.99:6443, в пуле которого 10.206.192.9x:6443 (это control planes).

  2. kubeadm init –control-plane-endpoint «10.206.192.99:6443» …

  3. Всё без исключения устанавливается через helm. Все (нужные мне) пакеты поддерживают его из коробки.

  4. Некоторые пакеты требуют секреты. Хотя обычно можно через хельм их создать, я создаю отдельно, чтобы единообразно создавать/обновлять пакеты и не вбивать секреты каждый раз.

  5. Устанавливаем calico, единственный конфиг это { cidr: "10.244.0.0/16", encapsulation: VXLAN }. Убрал ebpf, плохо понимаю, как он работает, не думаю, что замечу разницу.

  6. Добавляем worker-ов или убираем taint с control plane.

  7. Устанавливаем openstack cinder csi. Это потому, что у меня openstack. Кто-нибудь просит persistent volume claim, этот csi создаёт persistent volume. Очень удобно. Сначала создаём секрет, потом устанавливаем хельмом. Приведу полную схему, всё остальное устанавливается так же.

#!/bin/sh

bin="$(dirname "$0")"
conf="$bin/../conf"

. "$conf/versions.sh"

if [ -z "$OS_APPLICATION_CREDENTIAL_ID" ] || [ -z "$OS_APPLICATION_CREDENTIAL_SECRET" ]
then
    echo >&2 "OS_APPLICATION_CREDENTIAL_ID and OS_APPLICATION_CREDENTIAL_SECRET must be set"
    exit $?
fi

cat "$conf/secret-cinder-csi-system-cloud-config.yaml" \
    | envsubst '$OS_APPLICATION_CREDENTIAL_ID $OS_APPLICATION_CREDENTIAL_SECRET' \
    | kubectl apply --filename=- \
    || exit $?

echo "success: apply secret-cinder-csi-system-cloud-config.yaml"

helm repo add "cloud-provider-openstack" "https://kubernetes.github.io/cloud-provider-openstack" \
    || exit $?

"$bin/upgrade-cinder-csi.sh" || exit $?
apiVersion: v1
kind: Namespace
metadata:
  name: "cinder-csi-system"
---
apiVersion: v1
kind: Secret
metadata:
  namespace: "cinder-csi-system"
  name: "cloud-config"
type: Opaque
stringData:
  cloud.conf: |
    [Global]
    auth-url="https://auth.pscloud.io/v3/"
    application-credential-id="$OS_APPLICATION_CREDENTIAL_ID"
    application-credential-secret="$OS_APPLICATION_CREDENTIAL_SECRET"
    region="kz-ala-1"
    [Metadata]
    search-order="metadataService"
    [BlockStorage]
    rescan-on-resize=true
#!/bin/sh

bin="$(dirname "$0")"
conf="$bin/../conf"

. "$conf/versions.sh"

helm upgrade "cinder-csi" "cloud-provider-openstack/openstack-cinder-csi" \
        --install \
        --namespace="cinder-csi-system" \
        --version "$CINDER_CSI_VERSION" \
        --values "$conf/helm-values-cinder-csi.yaml" \
    || exit $?

echo "success: upgrade cinder-csi"
  1. Устанавливаем ingress-nginx. Ох и поломал я тут голову, как лучше это сделать. И openstack controller устанавливал, чтобы он создавал LoadBalancer-ы автоматом. И через hostNetwork пробовал. Все варианты рабочие.

Но в итоге остановился на самом тупом и топорном.

controller:
  config: { use-proxy-protocol: true }
  ingressClassResource: { default: true }
  replicaCount: 2
  service:
    type: NodePort
    nodePorts:
      http: 30080
      https: 30443

Соответственно создаём отдельно через терраформ второй лоад-балансер и настраиваем его на worker адреса, :80 -> 30080, :443 -> 30443. Также у меня настроен он через протокол PROXYV2, чтобы получать адрес клиента. Nginx его передаёт потом через заголовки X-Forwarder-*.

Вообще можно всё на один лоад балансер повесить (исходный). Но мне показалось правильней сделать несколько. В моём понимании самое важное это обеспечить непрерывность работы control нод. Остальное как-нибудь работать будет. А если, например, внешний дудос перегрузит load balancer, через который общаются все узлы с control plane, то кластер точно развалится нафиг. Правда стоит больше денег. В общем если будете делать - на ваше усмотрение.

Такая конфигурация вносит лишнюю задержку (микроскопическую), вносит лишнюю нагрузку (запрос приходит на load balancer, с него идёт на случайный worker, с него идет на случайный worker, в котором запущен nginx-controller, с него идёт уже на worker, где запущен целевой сервис. Но плюс в том, что всё работает просто и понятно.

Далее устанавливаем cert-manager. Для него нужен cloudflare token. Через DNS домены будет подтверждать.

apiVersion: v1
kind: Namespace
metadata:
  name: "cert-manager"
---
apiVersion: v1
kind: Secret
metadata:
  namespace: "cert-manager"
  name: "cloudflare-api-token"
type: Opaque
stringData:
  "api-token": "$CLOUDFLARE_API_TOKEN"
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: "default"
spec:
  acme:
    email: "me@example.com"
    server: "https://acme-v02.api.letsencrypt.org/directory"
    privateKeySecretRef:
      name: "default-issuer-account-key"
    solvers:
      - dns01:
          cloudflare:
            apiTokenSecretRef:
              name: "cloudflare-api-token"
              key: "api-token"

В принципе на этом настройку основных компонентов кластера считаю завершённой. Пользователь может запрашивать хранилище, пользователь может публиковать свои сервисы через ingress и автоматически получать рабочий https. Пока не разобрался с публикацией произвольных портов, в частности для gitlab нужно будет опубликовать 22 порт, но вроде через тот же ingress-nginx должно работать.

Дальше на очереди установка KeyCloak, настройка kubectl и Dashboard (а в будущем gitlab, grafana) для работы через логин-пароль, но это уже другая история.

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

vbr ★★★★
() автор топика
Последнее исправление: vbr (всего исправлений: 2)
Ответ на: комментарий от vbr

Может уже спрашивали, а почему не взять microk8s и просто начать использовать, ну или k3s, чтоб чуточку повозиться, но опять же быстро начать использовать?

Пользователь может запрашивать хранилище, пользователь может публиковать свои сервисы через ingress и автоматически получать рабочий https.

Или у вас что-то типа SaaS?

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 2)
Ответ на: комментарий от vvn_black

Может уже спрашивали, а почему не взять microk8s и просто начать использовать, ну или k3s, чтоб чуточку повозиться, но опять же быстро начать использовать?

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

Или у вас что-то типа SaaS?

Нет, обычная софтовая компания, директор которой решил, что хватит терпеть ограничения выделенных серверов и пора лететь в облака (:

vbr ★★★★
() автор топика
Последнее исправление: vbr (всего исправлений: 1)
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)