Не только работой едины — ARK+K3S+MetalLB

от автора

Предыстория

Всем привет! Я работаю DevOps-MLops инженером и мне нравится постоянно что-то новое изучать и пытаться применять эти технологии везде где только можно.

Как-то играя в ark я захотел играть на своем сервере вместе с друзьями и как раз под это дело у меня есть свой домашний сервер и выделенный ip, характеристик сервера более чем достаточно, в моем случае это ryzen 7 1700x, 32Gb RAM и 1500Gb дисковой памяти.

Как основу я взял контейнернизацию lxc и настроил внутри ark сервер по первой инструкции что нашёл в интернете, настроил service для ark чтобы руками его не запускать все время и в целом месяца 3 все работало ок, потом по неизвестной причине мой ark сервер стал грузить всё что-то постоянно и вообще стал вести себя странно, сидеть изучать что не так у меня не было особо желания, да и времени, поэтому я подумал а не лучше мне попробовать перенести сервер в более что-то удобное для обслуживания нежели держать его где-то в отдельной среде куда нужно еще подключаться, делать кучу действий чтобы произвести анализ.

Приступим!

И так чтобы сделать красиво (по своему мнению), я взял:

  • k3s — скажем так это как ванильный k8s только из него вырезали около 1000 строчек кода как заявляют разработчики, кстати он построен на containerD.

  • mettllb — это инструмент позволяющий нам создать свой loadbalancer и использовать его, далее про него более подробно расскажу.

  • ubuntu 20.04 LTS — собственно то на чем всё будет крутится.

k3s

K3s (с офф сайт) — это сертифицированный дистрибутив Kubernetes с высокой доступностью, предназначенный для производственных рабочих нагрузок в автоматических, ограниченных по ресурсам, удаленных местах или внутри устройств IoT. (взято с офф сайт).

k3s (описание от меня) — это оркестратор контейнеров который может:

  • Запускать контейнеры (для контейнера мы можем также задать переменные, директории с нашего хоста или вообще с удаленного сервера, контейнер который будет запускаться до старта нашего основного контейнера, благодаря чему мы можем как пример подготовить какие либо файлы или выполнить скрипт для корректной работы нашего основного контейнера).

  • Ставить лимиты по ресурсам для контейнеров. (Как пример что приложение не сможет потреблять больше 2 Gb RAM или 2 CPU).

  • Задавать политики рестарта контейнеров.

  • Управлять доступностью к приложениям по сети.

  • Позволяет удобно читать логи.

  • Анализировать метрики.

  • Автомасштабированием контейнеров при повышении нагрузки ( к примеру если наше приложение в контейнере начинает грузится скажем под 80% по RAM или CPU оркестратор поднимет еще контейнеры и будет балансировать автоматическим сам нагрузку между ними).

  • И т.д.

  • И самое главное для нас мы можем описать это в манифесте один раз и потом переиспользовать и даже передавать кому угодно чтобы они могли запустить у себя или же наоборот мы можем запустить у себя чужой манифест.

И так я поставил чистую ubuntu 20.04 LTS, выделил ей 4 CPU 8 GB RAM, 50GB Disk и на неё первым делом мы будем ставить k3s.

  1. Открываем сайт https://k3s.io, на нем нам говорят чтобы это не займет много времени.

  1. Копируем команду и дописываем параметр который понадобится нам потом дальше, выполняем.

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --disable servicelb" sh -
  1. Далее всего менее 30 секунд и кластер готов.

  1. Прописываем sudo kubectl get nodes и видим что наш кластер готов!

  1. Далее, чтобы мы могли работать удобно из под своей УЗ нам требуется скопировать kubeconfig в свою домашнюю папку и выполнить пару команд:

Kubeconfig — это манифест в котором описано подключение к кластеру kubernetes. Вы можете его скопировать на любую машину у которой есть сетевой доступ до кластера и от туда им управлять.

mkdir ~/.kube sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config sudo chown ark:ark .kube/config  echo "export KUBECONFIG=~/.kube/config" >> ~/.bashrc source ~/.bashrc kubectl get node
  • Cоздаем папку где будет хранится кубконфиг по умолчанию.

  • Копируем kubeconfig в ранее созданную папку.

  • Задаем права для kubeconfig на нашего пользователя и группу.

  • Загружаем в bashrc строчку которая будет задавать kubeconfig по умолчанию для kubectl при каждом входе в систему.

  • И смотрим готов ли наш кластер с одной нодой.

Все управление кластером осущетвляется через утилиту kubeclt

И так буквально пару действий и у нас есть есть готовый кластер k3s почти со всеми преимуществами kubernetes готовый к работе.

Запускаем ARK server

И так давайте для тех кто не сильно погружен в специфику kubernetes я обозначу четыре сущности с которыми мы будем работать:

Pods — Это абстрактный объект Kubernetes, представляющий собой «обертку» для одного или группы контейнеров. Контейнеры в поде запускаются и работают вместе, имеют общие сетевые ресурсы и хранилище. Kubernetes не управляет контейнерами напрямую, он собирает их в поды и работает с ими.

Deployments — Это ресурс предназначенный для для развертывания приложений и их обновления декларативным образом.

PVC — Это запрос на создание постоянного хранилища (Если по очень простому и для данной задачи нам этого понимания более чем достаточно. Вообще отмечу еще что PVC обращается к PV. В kubernetes все контейнеры что запускаются не имеют своего постоянного хранилища, то есть если он упадет всё данные пропадут, для этого нам и нужен будет PVC).

StorageClass — позволяет описать классы хранения, которые предлагают хранилища. (в k3s уже есть по умолчанию это rancher.io/local-path).

namespace — пространство в котором мы запускаем поды, загружаем конфиги и в общем ведем всю свою деятельность (удобно для разделения разных проектов/приложений в одном кластере).

  1. Начнем с того что создадим namespace

kubectl create ns ark
  1. Далее нам нужно составить манифесты PVC в которых мы будем хранить данные файлы сервера ARK, а это в районе 20 GB и файлы состоянии сервера не более 1 GB.

Всем манифесты для kubernetes описываются в виде yaml, требуется внимательно следить за пробелами.

  1. И так откроем редактор.

vi ark-pvc.yaml
  1. И впишем

apiVersion: v1 kind: PersistentVolumeClaim metadata:   name: ark-server   namespace: ark spec:   storageClassName: local-path   accessModes:     - ReadWriteOnce   resources:     requests:       storage: 30G  ---  apiVersion: v1 kind: PersistentVolumeClaim metadata:   name: ark-save   namespace: ark spec:   storageClassName: local-path   accessModes:     - ReadWriteOnce   resources:     requests:       storage: 10G

В данном манифесте мы описали сразу два PVC, для нас имеет значение сейчас такие значения как:

  • name — имя нашего PVC

  • kind — описание того что будем заводить в kubernetes

  • spec — под ним описываем более детально нашу сущность

  • namespace — наше пространство

  • storageClassName — local-path по умолчанию есть в k3s, если будете использовать не k3s то нужно будет заменить на тот что есть у вас (или можно смонтировать папку с хоста)

  • storage — размер PVC

  1. Далее применим наш манифест

kubeclt apply -f ark-pvc.yaml

Кстати чтобы удалить то что мы создали через манифест необходимо выполнить kubeclt delete -f ark-pvc.yaml

После того как мы подготовили PVC можем начинать подготовку и запуск нашего deployment.

  1. Подготовим наш yaml

vi deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata:   name: ark-deploy   namespace: ark   labels:     app: ARK spec:   replicas: 1   selector:     matchLabels:       app: ARK   template:     metadata:       labels:         app: ARK     spec:       containers:       - name: ark-server         image: hermsi/ark-server         resources:           requests:             memory: "500Mi"             cpu: "250m"           limits:             memory: "5000i"             cpu: "2000m"         volumeMounts:           - mountPath: /home/steam/ARK-Backups             name: ark-save           - mountPath: /app             name: ark-server         env:         - name: SESSION_NAME           value: ark_world         - name: SERVER_MAP           value: TheIsland         - name: SERVER_PASSWORD           value: iAmSuperman         - name: ADMIN_PASSWORD           value: iAmSuperman         - name: MAX_PLAYERS           value: "20"         ports:           - name: server-list             containerPort: 27015             protocol: UDP           - name: game-client             containerPort: 7777             protocol: UDP           - name: udp-socket             containerPort: 7778             protocol: UDP           - name: rcon             containerPort: 27020             protocol: UDP       volumes:       - name: ark-save         persistentVolumeClaim:           claimName: ark-save       - name: ark-server         persistentVolumeClaim:           claimName: ark-server
  1. Давайте тут тоже опишем дополнительные моменты:

  • spec — под первым мы описываем параметры deployment, по втором мы описываем работу нашего pod.

  • containers — описываем с какими параметрами будет подниматься наш контейнер.

  • image — какой образ нужно будет использовать.

  • selector — задаем по ним лейбл который нам понадобится дальше.

  • resources — описываем сколько выделяем фиксированно ресурсов для пода и сколько максимум он может забрать, то есть его лимиты и реквесты.

  • volumeMounts — прописываем куда монтировать наши PVC.

  • volumes — объявляем наши PVC.

  • env — тут задаем переменные для нашего приложения (сервера ark), в нашем случае это пароли, карты, имя сервера.

  • port — указываем какие порты открыть из контейнеры.

Замечу что ark server весьма прожорливый, когда мы запускаем в первый раз он потребляет в районе 3 GB. Мой сервер с 1800 днями уже 7 GB

Вот что пишут в интернете:

8GB RAM
20GB Disk Space Minimum (50-75GB Recommended)
2 CPU Cores @ 3.0GHz+ (For 10-15 players)
64 Bit Windows or Linux OS (CentOS Linux Recommended for a standalone server)
A reliable network connection, 100Mbps+ recommended

  1. После применим его командой.

kubeclt apply -f deployment.yaml

И так после того как мы применили все манифесты, kubectl должен ответить что все было создано и нет проблем

Кстати мы можем проверить что всё корректно создалось

kubectl get pvc -n ark

kubectl get deployment -n ark

  1. Далее следует проверить что наш под запустился и не падает.

kubeclt get pods -n ark

Вывод должен быть примерно таким

  1. Теперь проверим логи пода чтобы понять что нет проблем и идёт подготовка сервера.

kubeclt logs <<name-pod>> -n ark

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

metalLB

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

Собственно он так и называется service, через него мы и можем перенаправить трафик наружу, и так service бывает:

ClusterIP — это тип службы по умолчанию в Kubernetes. Он создает службу внутри кластера Kubernetes, к которой могут обращаться другие приложения в кластере, не разрешая внешний доступ.

NodePort — открывает определенный порт на всех узлах в кластере, и любой трафик, отправляемый на этот порт, перенаправляется в службу. Доступ к службе невозможен с IP-адреса кластера. 

LoadBalancer — это стандартный способ предоставления службы Kubernetes извне, чтобы к ней можно было получить доступ через Интернет. Если вы используете Google Kubernetes Engine (GKE), это создает балансировщик сетевой нагрузки с одним IP-адресом, к которому могут получить доступ внешние пользователи, а затем они перенаправляются на соответствующий узел в вашем кластере Kubernetes. Доступ к LoadBalancer можно получить так же, как к ClusterIP или NodePort.

То есть получается нам тут подходит только два варианты NodePort и LoadBalancer, но NodePort ввиду того что может использовать порты только c 30,000 по 32,767 не очень удобен в эксплуатации, остается только LoadBalancer, однако данная услуга поставляется обычно в облаке.

И тут на помощь приходит metalLB! Мы развернем дома свой LoadBalancer, направим его на наш домашний роутер и наш под будет прям с него получать свой IP. Нам не придется мучаться с NodePort, пробросом портов и мы сможем сделать всё это красиво.

  1. И так, шаг первый нужно установить helm:

Helm — это средство упаковки с открытым исходным кодом, которое помогает установить приложения Kubernetes и управлять их жизненным циклом.

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

Кстати если на первом шаге не был отключен встроенный servicelb то будет конфликт и MetalLB не будет работать, тут описано как его отключить если вы не отключили его ранее.

Ставим helm

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

Взято отсюда https://helm.sh/docs/intro/install/

  1. Далее клонируем репозиторий и запускаем helm с metalLB и запускаем.

git clone https://github.com/general-rj45/helm-ark-survival-evolved.git helm install metallb helm-ark-survival-evolved/charts/metallb/ --create-namespace --namespace metallb

После выполнения команды мы увидим что helm применился и никаких ошибок нет.

  1. Проверим что все поды metallb запустились и нет рестартов.

  1. Теперь нужно добавить из какого пула адресов будет назначаться ip для наших подов и добавить еще один конфиг для MetalLB.

vi metallb-IPAddressPool.yaml
apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata:   name: first-pool   namespace: metallb spec:   addresses:   - 192.168.1.100-192.168.1.200  ---  apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata:   name: example   namespace: metallb
  • IPAddressPool — задаем диапазон ip для подов.

  • addresses — указываем диапазон ip.

  • L2Advertisement — для нас сейчас достаточно просто запустить, чтобы более конкретно погрузиться что это и для чего стоит почитать на офф сайте.

  1. Применим манифест.

kubectl apply -f metallb-IPAddressPool.yaml
  1. Теперь нам нужно создать service типа loadbalancer.

vi service-ark.yaml
apiVersion: v1 kind: Service metadata:   name: ark-service   namespace: ark spec:   type: LoadBalancer   loadBalancerIP: 192.168.1.183   selector:     app: ARK   ports:     - port: 27015       targetPort: 27015       protocol: UDP       name: server-list       # Port for connections from ARK game client     - port: 7777       targetPort: 7777       protocol: UDP       name: game-client       # Raw UDP socket port (always Game client port +1)     - port: 7778       targetPort: 7778       protocol: UDP       name: always-game-client       # RCON management port     - port: 27020       targetPort: 27020       protocol: UDP       name: rcon-management-port
  • type — тут задается тип service.

  • port — порт который будет выведен наружу.

  • targetPort — порт пода который будет перенаправляться.

  • protocol — задаем протокол tcp или udp

  • selector — тут указывается лейб по которому service сможет понять к какому поду подключить и перенаправлять трафик.

  1. Применяем манифест

kubeclt apply -f service-ark.yaml
  1. Проверим что наш service успешно создался.

kubeclt get svc -n ark

Отлично! Наш сервис создан и готов к работе.

Последние шаги.

  1. Проверяем закончил ли подготовку сервера наш под (у меня заняло часа два, медленный HDD, может быть еще из за CPU).

Из вывода мы видим что сервер успешно запущен и готов принимать первых игроков.

Самое время подключиться! Добавляем в избранное через стим.

Вуаля!

Заходим на сервер (возможно ошибка при подключении, нужно через ark повторно подключиться просто).

Поздравляю! Теперь у вас есть свой сервер ark в kubernetes где вы может играть с друзьями! Или в одиночестве но с осознанием того что это ваш сервер =)

Итог

Я думал что это будет инструкция на одну страничку но вышло, длиннее…..

И так чем это лучше и проще чем просто взять ВМ и поставить туда сервер ark без всех эти надстроек?

  • Проще поднимать еще дополнительные серверы ark, достаточно просто поменять имена, ip в манифестах и применить.

  • Мы можем удобно отслеживать состояние pod в котором работает наше приложение и делать простую аналитику по потреблению памяти, цпу, сети, диска.

  • Удобно читать логи.

  • В случае сбоя работы приложения kubernetes просто перезапустит наш pod и никаких проблем не будет (почти не будет).

  • Наше приложение находится в изолированной среде, а это значит если мы будем делать какие либо изменения на хосте или внутри контейнера они не будут влиять друг на друга (почти не будут).

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

  • Подход с декларативным описанием манифестов позволяет удобно менять настройки сервера, к примеру хотите поменять имя сервера, просто изменили его в манифесте и применили, даже не обязательно с того хоста где стоит наш kubernetes. В случае с ВМ нам нужно будет руками подключаться, менять значение, перезапускать скриптами или руками, в общем не очень удобно.

Всё что я описал это моя реализация, которая удобна мне. Может для других такие методы будут избыточны и бессмысленны.

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

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


ссылка на оригинал статьи https://habr.com/ru/post/703624/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *