Привет, меня зовут Руслан, я энтузиаст одного отдела искусственного интеллекта, занимаюсь автоматизацией процесса разработки и контролем за инфраструктурой внутри Kubernetes. Хочу детально рассмотреть развёртку Kubernetes-кластера, показать решения на возможные ошибки, ответы на которые пришлось довольно долго поискать. После окончания статьи вы будете знать, как создать кластер, который подойдет почти под любые задачи.
Используемый стек
-
3x VM Ubuntu 20.04 (cloud).
-
Kube* == 1.23.3.
-
Docker, containerd.
-
Flannel — интерфейс сети контейнеров, назначает Pod-ам IP-адреса для их взаимодействия между друг другом.
-
MetalLB — LoadBalancer, который будет использоваться для выдачи внешних IP-адресов из заданного нами пула.
-
Ingress NGINX Controller — контроллер для Ingress записей, используемый NGINX в качестве обратного прокси (reverse proxy) и балансировщика нагрузки.
-
Helm — средство для установки/обновления даже самого сложного приложения в Kubernetes в один клик.
-
NFS Subdir External Provisioner — средство устанавливаемое в Kubernetes, как обычный Deployment, которое использует существующий и уже настроенный NFS сервер для динамического создания и централизованного хранения PersistentVolume.
Первоначальная настройка
Для начала подготовим систему к установке Kubernetes, отключим swap, чтобы избежать неконтролируемых последствий. Большинство интерфейсов сети контейнеров (Container Network Interface), в том числе Flannel, работают напрямую с iptables, поэтому включим параметры, отвечающие за отправку пакетов из моста прямо в iptables с целью обработки.
sudo su; ufw disable; swapoff -a; sed -i '/swap/d' /etc/fstab; cat >>/etc/sysctl.d/kubernetes.conf<<EOF net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl --system
Установка Docker и Kubernetes
{ apt install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" apt update apt install -y docker-ce containerd.io } { curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list apt update && apt install -y kubeadm=1.23.3-00 kubelet=1.23.3-00 kubectl=1.23.3-00 }
Важно знать
Перед тем, как начнём создавать кластер, хочу предостеречь от возможных проблем, держим в голове, что Flannel использует сеть для назначения Pod’ам 10.244.0.0/16
, поэтому при создании будет добавлен параметр --pod-network-cidr=10.244.0.0/16
.
Если по какой-то причине необходимо изменить сеть для Pod’ов, то используйте свою, но не забудьте изменить сеть и в самой конфигурации Flannel, решение будет в «Нюансы в Flannel».
Чтобы избежать ошибки curl -sSL http://localhost:10248/healthz' failed with error: Get http://localhost:10248/healthz: dial tcp [::1]:10248: connect: connection refused.
, связанной из-за разных cgroupdriver используемых Kubelet и Docker пропишем это.
sudo mkdir -p /etc/docker cat <<EOF | sudo tee /etc/docker/daemon.json { "exec-opts": ["native.cgroupdriver=systemd"] } EOF sudo systemctl daemon-reload sudo systemctl restart docker sudo systemctl restart kubelet
Создание кластера
На машине, которая будет являться master-нодой прописываем команду на создание кластера.
kubeadm init --pod-network-cidr=10.244.0.0/16
Для доступа к команде kubectl
прописываем команды по перемещению конфига в домашнюю директорию.
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
Для добавление других VM, прописываем команду на создание токена. Вывод с команды вводим на остальных машинах.
kubeadm token create --print-join-command #Примерный вывод - kubeadm join --discovery-token abcdef.1234567890abcdef --discovery-token-ca-cert-hash sha256:1234..cdef 1.2.3.4:6443
Так как master-нода имеет по умолчанию метку NoSchedule, которая не позволяет запускать Pod’ы без этой метки, что помешает нам в развёртке дальнейших DaemonSet’ов, поэтому уберём метку с ноды.
kubectl get nodes # Узнаем название master ноды kubectl taint nodes <nodename> node-role.kubernetes.io/master:NoSchedule-
Установка Flannel и MetalLB
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml
Далее необходимо задать пул IP-адресов, MetalLB будет использовать их для сервисов, которым необходим External-IP. Копируем код снизу, заменяем адрес и применяем командой kubectl apply -f <название файла>.yaml
.
apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: first-pool namespace: metallb-system spec: addresses: - 10.119.0.15/32 # Локальный адрес одной из нод
P.S. Я указываю локальный адрес одной из своих worker-нод, интерфейс на котором назначен этот адрес является и выходом в интернет, после можно создать DNS-запись и подключаться по домену.
Нюансы в Flannel
Вернёмся к тому, как изменить пул адресов у Flannel. Для этого нужно скачать конфиг Flannel, зайти в него, найти net-conf.json, заменить на свой адрес, далее можно применять.
wget https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
Если вы решили сделать это уже после установки, то даже после ресета кластера Flannel не позволит поменять адрес интерфейсов, вероятно вы столкнулись с ошибкой NetworkPlugin cni failed to set up pod "xxxxx" network: failed to set bridge addr: "cni0" already has an IP address different from10.x.x.x
, произошло это, потому что старые интерфейсы всё ещё остались, чтобы исправить это, удаляем интерфейсы на всех нодах.
sudo su ip link set cni0 down && ip link set flannel.1 down ip link delete cni0 && ip link delete flannel.1 systemctl restart docker && systemctl restart kubelet
Установка Helm
Самая простая установка из всей статьи.
P.S. Всегда проверяйте скрипты.
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh
Установка Ingress NGINX Controller
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update helm show values ingress-nginx/ingress-nginx > values.yaml kubectl create ns ingress-nginx
В values.yaml меняем параметры hostNetwork, hostPort на true, kind на DaemonSet и применяем.
helm install ingress ingress-nginx/ingress-nginx -n ingress-nginx --values values.yaml
Установка NFS Subdir External Provisioner
Для установки понадобится развёрнутый NFS-сервер, в моём случае он находится на одной из worker-нод. На данный сервер будут сохраняться данные из PersistentVolume, советую задуматься о бэкапах.
Входные данные: 10.119.0.17
— IP-адрес NFS-сервера, /opt/kube/data
— директория сетевого хранилища. На остальных машинах (не NFS-сервере) необходимо скачать пакет nfs-common
для возможности доступа к хранилищу.
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/ helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \ --set nfs.server=10.119.0.17 \ --set nfs.path=/opt/kube/data
Делаем StorageClass NFS Provisioner’а, как класс по умолчанию, для удобного создания PersistentVolumeClaim без указания StorageClassName.
kubectl patch storageclass nfs-client -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
Проверяем работоспособность NFS Provisioner создав базовый PersistentVolumeClaim, применяем.
cat <<EOF | sudo tee testpvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 500Mi EOF
kubectl apply -f testpvc.yaml kubectl get pv
Если в поле Status написано Bound, и на NFS-сервере в директории хранилища появилась новая папка, то всё прошло успешно.
Дополнительно. Проброс TCP/UDP сервисов с помощью Ingress NGINX Controller
Обычный Ingress не поддерживает TCP или UDP для проброса сервисов наружу. По этой причине в Ingress NGINX Controller есть флаги --tcp-services-configmap
и --udp-services-configmap
, которые помогут пробросить целый сервис с помощью описанного ConfigMap. Пример снизу показывает как пробросить TCP сервис, где 1111
— проброшенный порт; prod
— название namespace; lhello
— название сервиса; 8080
— порт сервиса.
apiVersion: v1 kind: ConfigMap metadata: name: tcp-services namespace: ingress-nginx data: 1111: "prod/lhello:8080"
Если используется проброс TCP/UDP, то эти порты должны быть открыты и в службе ingress-ingress-nginx-controller, для этого прописываем команду на редактирование сервиса.
kubectl edit service/ingress-ingress-nginx-controller -n ingress-nginx
Добавляем свой новый порт, который хотим открыть и сохраняем.
###...значения опущены... spec: type: LoadBalancer ports: - name: proxied-tcp-1111 port: 1111 targetPort: 1111 protocol: TCP
И последнее, что нужно для проброса, так это указать ConfigMap, который будет использоваться, для этого добавим флаг в DaemonSet контроллера.
kubectl edit daemonset.apps/ingress-ingress-nginx-controller -n ingress-nginx
--tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
Итоги
На этом кластер готов к работе, вы можете развернуть всё, что угодно, не хватает только сертификатов для сайтов, но решение уже есть. Только не забудьте поставить в Ingress записи аннотациюkubernetes.io/ingress.class: "nginx"
для работы контроллера в Ingress. Буду рад любому фидбеку и советам, как улучшить инфраструктуру. Всем пока!
ссылка на оригинал статьи https://habr.com/ru/post/713520/
Добавить комментарий