Предыстория
Всем привет! Я работаю DevOps-MLops инженером и мне нравится постоянно что-то новое изучать и пытаться применять эти технологии везде где только можно.
Как-то играя в ark я захотел играть на своем сервере вместе с друзьями и как раз под это дело у меня есть свой домашний сервер и выделенный ip, характеристик сервера более чем достаточно, в моем случае это ryzen 7 1700x, 32Gb RAM и 1500Gb дисковой памяти.
Как основу я взял контейнернизацию lxc и настроил внутри ark сервер по первой инструкции что нашёл в интернете, настроил service для ark чтобы руками его не запускать все время и в целом месяца 3 все работало ок, потом по неизвестной причине мой ark сервер стал грузить всё что-то постоянно и вообще стал вести себя странно, сидеть изучать что не так у меня не было особо желания, да и времени, поэтому я подумал а не лучше мне попробовать перенести сервер в более что-то удобное для обслуживания нежели держать его где-то в отдельной среде куда нужно еще подключаться, делать кучу действий чтобы произвести анализ.
Приступим!
И так чтобы сделать красиво (по своему мнению), я взял:
k3s - скажем так это как ванильный k8s только из него вырезали около 1000 строчек кода как заявляют разработчики, кстати он построен на containerD.
metalLB - это инструмент позволяющий нам создать свой 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.
Открываем сайт https://k3s.io, на нем нам говорят чтобы это не займет много времени.
Копируем команду и дописываем параметр который понадобится нам потом дальше, выполняем.
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --disable servicelb" sh -
Далее всего менее 30 секунд и кластер готов.
Прописываем sudo kubectl get nodes и видим что наш кластер готов!
Далее, чтобы мы могли работать удобно из под своей УЗ нам требуется скопировать 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 - пространство в котором мы запускаем поды, загружаем конфиги и в общем ведем всю свою деятельность (удобно для разделения разных проектов/приложений в одном кластере).
Начнем с того что создадим namespace
kubectl create ns ark
Далее нам нужно составить манифесты PVC в которых мы будем хранить данные файлы сервера ARK, а это в районе 20 GB и файлы состоянии сервера не более 1 GB.
Всем манифесты для kubernetes описываются в виде yaml, требуется внимательно следить за пробелами.
И так откроем редактор.
vi ark-pvc.yaml
И впишем
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
Далее применим наш манифест
kubeclt apply -f ark-pvc.yaml
Кстати чтобы удалить то что мы создали через манифест необходимо выполнить
kubeclt delete -f ark-pvc.yaml
После того как мы подготовили PVC можем начинать подготовку и запуск нашего deployment.
Подготовим наш 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
Давайте тут тоже опишем дополнительные моменты:
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
После применим его командой.
kubeclt apply -f deployment.yaml
И так после того как мы применили все манифесты, kubectl должен ответить что все было создано и нет проблем
Кстати мы можем проверить что всё корректно создалось
kubectl get pvc -n ark
kubectl get deployment -n ark
Далее следует проверить что наш под запустился и не падает.
kubeclt get pods -n ark
Вывод должен быть примерно таким
Теперь проверим логи пода чтобы понять что нет проблем и идёт подготовка сервера.
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, пробросом портов и мы сможем сделать всё это красиво.
И так, шаг первый нужно установить 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/
Далее клонируем репозиторий и запускаем 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 применился и никаких ошибок нет.
Проверим что все поды metallb запустились и нет рестартов.
Теперь нужно добавить из какого пула адресов будет назначаться 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 - для нас сейчас достаточно просто запустить, чтобы более конкретно погрузиться что это и для чего стоит почитать на офф сайте.
Применим манифест.
kubectl apply -f metallb-IPAddressPool.yaml
Теперь нам нужно создать 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 сможет понять к какому поду подключить и перенаправлять трафик.
Применяем манифест
kubeclt apply -f service-ark.yaml
Проверим что наш service успешно создался.
kubeclt get svc -n ark
Отлично! Наш сервис создан и готов к работе.
Последние шаги.
Проверяем закончил ли подготовку сервера наш под (у меня заняло часа два, медленный HDD, может быть еще из за CPU).
Из вывода мы видим что сервер успешно запущен и готов принимать первых игроков.
Самое время подключиться! Добавляем в избранное через стим.
Вуаля!
Заходим на сервер (возможно ошибка при подключении, нужно через ark повторно подключиться просто).
Поздравляю! Теперь у вас есть свой сервер ark в kubernetes где вы может играть с друзьями! Или в одиночестве но с осознанием того что это ваш сервер =)
Итог
Я думал что это будет инструкция на одну страничку но вышло, длиннее.....
И так чем это лучше и проще чем просто взять ВМ и поставить туда сервер ark без всех эти надстроек?
Проще поднимать еще дополнительные серверы ark, достаточно просто поменять имена, ip в манифестах и применить.
Мы можем удобно отслеживать состояние pod в котором работает наше приложение и делать простую аналитику по потреблению памяти, цпу, сети, диска.
Удобно читать логи.
В случае сбоя работы приложения kubernetes просто перезапустит наш pod и никаких проблем не будет (почти не будет).
Наше приложение находится в изолированной среде, а это значит если мы будем делать какие либо изменения на хосте или внутри контейнера они не будут влиять друг на друга (почти не будут).
Всё что мы создаем, описывается декларативно в манифестах, то есть один раз написав, потом можно будет переиспользовать много раз или перенести на другой хост и поднять уже там.
-
Подход с декларативным описанием манифестов позволяет удобно менять настройки сервера, к примеру хотите поменять имя сервера, просто изменили его в манифесте и применили, даже не обязательно с того хоста где стоит наш kubernetes. В случае с ВМ нам нужно будет руками подключаться, менять значение, перезапускать скриптами или руками, в общем не очень удобно.
Всё что я описал это моя реализация, которая удобна мне. Может для других такие методы будут избыточны и бессмысленны.
Вообще мне очень нравится концепция контейнеров, ведь она нас освобождает от многих проблем, к примеру что мы минимизируем проблемы с зависимостями, так как каждое приложение живет в своём контейнере и не мешает другим, а так все это было бы в одном месте и создавало хаос, в котором сложно может быть найти виновника тормозов.
Спасибо что дочитали мой первый пост, надеюсь он будет вам полезен или просто интересен. Планирую в будущем еще писать всякие интересности, если дойду.
Комментарии (8)
scruff
05.12.2022 19:29Может, где-то упустил настройку ингреса? Ткните меня носом плиз)))
MasterChief
06.12.2022 10:52Для сервисов LoadBalancer не требуются ресурсы Ingress, потому что Ingress - "нативный" балансировщик только для приложений поверх HTTP. А тем, кому нужно балансировать любое приложение с протоколом поверх TCP/IP или UDP (в том числе и HTTP), остаётся использовать только LoadBalancer.
Olegun
05.12.2022 21:24+3Чувствуется, что это плотный и содержательный текст. Но либретто не помешало-бы.
maeris
07.12.2022 00:16curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --disable servicelb" sh -
Всегда волновал вопрос "а чё, реально есть люди, которые curl | sh исполняют, не моргнув глазом", и я нашёл на него ответ. Спасибо.
Предлагаю добавить ещё в девопсовый вунш-пунш sudo перед sh, чтобы было прямо по канону.
vainkop
07.12.2022 17:35Заходим на https://k3s.io и видим :)
curl -sfL https://get.k3s.io | sh -
# Check for Ready node, takes ~30 seconds
k3s kubectl get node
maeris
07.12.2022 23:18К сожалению, это не означает, что так вообще можно делать. Этот код не под контролем версий, без хешей, без подписей, без ревью, может поменяться в любую секунду. Там могут даже по юзерагенту отдавать разный код: один вам в браузер почитать, а другой курлу на исполнение.
Без задних мыслей предлагать делать такое в официальной документации могут только люди с нулевым пониманием инфобеза, и уж софт для контейнеров им доверять точно нельзя. Тема уже неоднократно обсуждалась.
vainkop
08.12.2022 00:08Ой да не будьте вы таким занудой.
За счёт максимальной простоты для новичков популяризировался как родительский проект Rancher, так и K3s. И я считаю, что это прекрасно, т.к. многие (к которым себя, кстати не отношу, т.к. прошёл всё the hard way) смогли пощупать кубер и создать что-то не имея возможности потратить на его освоение довольно значительное время.
Для тех, кто "подрос" можно уже и в GitHub заглянуть.
K3s вполне серьёзный и зрелый проект ( #1 кубер для iot уже несколько лет как) и с безопасностью у него всё хорошо.
Fox_exe
Тем временем обычные люди ставят винду в виртуалку и разворачивают сервера ARK через ARK Server Manager вообще не напрягая мозги (Ну почти).