doc_memo/kubernetes/k3s-3xui-pod.md
2025-03-29 13:58:59 +03:00

14 KiB
Raw Blame History

Установка 3X-UI как под в K3s (Kubernetes)

3x-ui — это симпатичный веб-интерфейс для управления VPN-серверами, такими как WireGuard, Shadowsocks, Xray, V2Ray и тому подобное. Он позволяет настраивать и мониторить VPN-соединения и клиентов через браузер. Мы будем запускать его как контейнер (под) внутри K3s кластера на Orange Pi 5.

Мне нужен 3x-ui, для безопасного доступа к домашней сети из любой точки мира, а также для безопасного доступа к интернету через домашний сервер.

Создание namespace (не обязательно)

Для удобства организации рекомендую создать отдельное пространство имён (namespace) для 3x-ui. Пространство имен -- это способ организовать ресурсы в кластере. Оно работает как виртуальная "папка", которая помогает разделять (изолировать) и управлять объектами, такими как поды, сервисы, конфигурации и т.д. Объекты в одном namespace не видят объекты из другого namespace (если не настроено обратное), что помогает избежать путаницы. Несколько приложений с одинаковыми именами могут без проблем существовать в разных пространствах имен. Кроме того, можно настроить права доступа (RBAC) отдельно для каждого namespace.

Выполним в терминале:

sudo kubectl create namespace x-ui

Проверим, что пространство имён создано:

kubectl get namespaces

Увидим x-ui в списке:

NAME              STATUS   AGE
...               ...      ...
...               ...      ...
x-ui              Active   6s

Простое развёртывание 3X-UI в поде

Cоздадим манифест развертывания пода (этого YAML-файл с инструкциями для K3s, что и как запустить). Мы будем использовать SQLite как внутреннюю базу данных 3x-ui, и пока эта бызы будет храниться внутри пода. Позже сможем переключиться на Longhorn (опционально).

Создадим deployment.yaml в каталоге ~/k3s/vpn/x-ui/ (см. структуру каталогов для хранения конфигураций и манифестов принятую в моем проекте):

mkdir -p ~/k3s/vpn/x-ui
nano ~/k3s/vpn/x-ui/deployment.yaml

Вставим в него следующий код:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: x-ui        # имя развертывания (имя пода)
  namespace: x-ui   # пространство имён, в котором будет создан под
spec:
  replicas: 1
  selector:
    matchLabels:
      app: x-ui
  template:
    metadata:
      labels:
        app: x-ui
    spec:
      hostNetwork: true   # использовать сетевой стек хоста
      containers:
      - name: x-ui        # имя контейнера
        image: ghcr.io/mhsanaei/3x-ui:latest
        # image: enwaiax/x-ui:latest    # альтернативный облегчённый: меньше способов шифрования и китайский интерфейс

В этом манифесте примечательно следующее:

  • hostNetwork: true — позволяет контейнеру использовать сетевой стек хоста и значит работать с сетевыми интерфейсами и портами хоста напрямую. Это полезно для приложений, которые требуют прямого доступа к сети, например, VPN-серверы.
  • spec.replicas: 1 — количество реплик (экземпляров) пода, которые будут запущены. В данном случае -- оин под.
  • spec.selector — селектор, который используется для выбора подов, которые будут управляться этим развертыванием. Он определяет, какие поды будут обновлены или удалены при изменении конфигурации развертывания.
  • matchLabels — метки, которые должны совпадать с метками подов, чтобы они были выбраны селектором. В данном случае мы используем метку app: x-ui, чтобы выбрать поды, которые относятся к приложению x-ui.

Применим манифест:

sudo kubectl apply -f ~/k3s/vpn/x-ui/deployment.yaml

Проверим, что под запустился:

sudo k3s kubectl get pods -n x-ui -o wide

Увидим что-то вроде:

NAME                   READY   STATUS    RESTARTS   AGE   IP           NODE         NOMINATED NODE   READINESS GATES
x-ui-bb97f6894-h7zj8   1/1     Running   0          11s   10.42.1.50   opi5plus-3   <none>           <none>

Видим, что нода на которой запустился 3x-ui это `opi5plus-3`, а имя пода `x-ui-bb97f6894-h7zj8`. Проверим логи пода,
используя его имя:
```bash
sudo kubectl logs -n x-ui x-ui-bb97f6894-h7zj8

Увидим что-то вроде:

Server ready
(0x291e4e8,0x40001657b0)
2025/03/28 13:28:34 Starting x-ui 2.5.6
(0x291e4e8,0x40001658e0)
INFO - Web server running HTTP on [::]:2053
INFO - XRAY: infra/conf/serial: Reading config: &{Name:bin/config.json Format:json}
WARNING - XRAY: core: Xray 25.3.6 started

Теперь мы знаем порт, на котором работает 3x-ui (2053), и значит можем получить доступ к веб-интерфейсу через браузер по адресу http://opi5plus-3:2053 или http://<IP_адресашего_узла>:2053.

3x-ui welcome page (RU)

После первого логирования (по умолчанию логин и пароль admin/admin) можно настаивать VPN-подключения, создавать пользователей, менять логин и пароль на вход и т.д. Веб-интерфейс 3x-ui интуитивно понятен, так что разбираться не составит труда.

Развертывание Kubernetes пода 3x-ui с постоянным хранилищем (PVC)

Есть, конечно, у 3x-ui под k3s минусы. В частности, внутри пода (sudo kubectl exec -it -n x-ui x-ui-... -- /bin/sh) не будет работать командный интерфейс 3x-ui (x-ui admin). Поды k3s работают на Alpine, а там некоторые команды отличаются (например, нет bash, а только ash). Но web-панель работает как положено, и всё управление удобнее делать через веб-интерфейс, так что лезть в консоль подов не обязательно.

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

Чтобы этого избежать нужно использовать постоянное хранилище (Persistent Volume). Для его работы требуется установить Longhorn (или другой менеджер хранилищ). K3s поддерживает Longhorn из коробки, так как в операционной системе на Orange Pi 5 нет поддержки iSCSI, включение его потребует компиляции ядра (если вы этого еще не сделали, смотрите инструкцию.

Если Longhorn уже установлен, создадим не его базе постоянное хранилище для -- PersistentVolumeClaim (PVC). Манифест PVC создадим в каталоге ~/k3s/vpn/x-ui/, рядом с deployment.yaml:

nano ~/k3s/vpn/x-ui/pvc-db.yaml

Вставим в него следующий код:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: x-ui-db-pvc
  namespace: x-ui
spec:
  storageClassName: longhorn  # Указываем Longhorn как класс хранилища
  accessModes:
    - ReadWriteOnce           # Доступ для чтения и записи одним подом
  resources:
    requests:
      storage: 512Mi         # Запрашиваемое хранилище, размер можно увеличить, если нужно

Обратите внимание:

  • metadata.name и metadata.namespace — имя хранилища (и это имя мы должны использовать в манифесте развертывания пода, чтобы указать, какое хранилище использовать) и пространство имён, в котором оно будет создано.
  • spec.storageClassName — класс хранилища, который будет использоваться для создания постоянного хранилища. В данном случае -- longhorn.
  • spec.accessModes — режим доступа к хранилищу. ReadWriteOnce означает, что хранилище может быть смонтировано только одним подом для чтения и записи. У нас один под и база на SQLite, так что этого достаточно.
  • spec.resources.requests.storage — запрашиваемый размер хранилища. Мы запрашиваем 1 ГБ и не означает, что хранилище будет занимать 1 ГБ на диске. Это предельный размер, который сможет занять хранилище.

Применим pvc-манифест:

sudo kubectl apply -f ~/k3s/vpn/x-ui/pvc-db.yaml

После этого Longhorn создаст том, который будет привязан к этому PVC.

Теперь нам нужно изменить манифест развертывания пода, и подключить к нему созданный PVC. Теперь наш ~/k3s/vpn/x-ui/deployment.yaml будет выглядеть так:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: x-ui
  namespace: x-ui
spec:
  replicas: 1
  selector:
    matchLabels:
      app: x-ui
  template:
    metadata:
      labels:
        app: x-ui
    spec:
      hostNetwork: true
      containers:
      - name: x-ui
        image: ghcr.io/mhsanaei/3x-ui:latest
        # image: enwaiax/x-ui:latest    # альтернативный облегчённый: меньше способов шифрования и китайский интерфейс
        volumeMounts:
        - name: db-storage      # Имя тома, в который будет смонтирован...
          mountPath: /etc/x-ui  # ...в путь к базе данных внутри контейнера
      volumes:
      - name: db-storage          # Имя тома, которое...
        persistentVolumeClaim:    # ...должно быть постоянным хранилищем
          claimName: x-ui-db-pvc  # ...и размещаться в PVC с именем 'x-ui-db-pvc'

Применим обновлённый манифест:

sudo kubectl apply -f ~/k3s/vpn/x-ui/deployment.yaml

Под перезапустится, и теперь база данных будет храниться в постоянном хранилище Longhorn. При перезапуске пода или его "переезде" на другой узел, база данных останется доступной и не потеряется. Следует отметить, что при сбое узла процесс перемещения пода занимает некоторое время. В кластере на Orange Pi 5, где проверки связности не очень агрессивные, это может занять до 5 минут. В общем, это нормально.

Единая точка входа VPN-соединений через под 3x-ui