226 lines
14 KiB
Markdown
226 lines
14 KiB
Markdown
# Установка 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.
|
||
|
||
Выполним в терминале:
|
||
```bash
|
||
sudo kubectl create namespace x-ui
|
||
```
|
||
|
||
Проверим, что пространство имён создано:
|
||
```bash
|
||
kubectl get namespaces
|
||
```
|
||
|
||
Увидим x-ui в списке:
|
||
```text
|
||
NAME STATUS AGE
|
||
... ... ...
|
||
... ... ...
|
||
x-ui Active 6s
|
||
```
|
||
|
||
## Простое развёртывание 3X-UI в поде
|
||
|
||
Cоздадим манифест развертывания пода (этого YAML-файл с инструкциями для K3s, что и как запустить). Мы будем
|
||
использовать SQLite как внутреннюю базу данных 3x-ui, и пока эта бызы будет храниться внутри пода. Позже сможем
|
||
переключиться на `Longhorn` (опционально).
|
||
|
||
Создадим `deployment.yaml` в каталоге `~/k3s/vpn/x-ui/` (см. [структуру каталогов для хранения конфигураций и манифестов](k3s-shadowsocks-client.md)
|
||
принятую в моем проекте):
|
||
```bash
|
||
mkdir -p ~/k3s/vpn/x-ui
|
||
nano ~/k3s/vpn/x-ui/deployment.yaml
|
||
```
|
||
|
||
Вставим в него следующий код:
|
||
```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.
|
||
|
||
|
||
Применим манифест:
|
||
```bash
|
||
sudo kubectl apply -f ~/k3s/vpn/x-ui/deployment.yaml
|
||
```
|
||
|
||
Проверим, что под запустился:
|
||
```bash
|
||
sudo k3s kubectl get pods -n x-ui -o wide
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
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
|
||
```
|
||
|
||
Увидим что-то вроде:
|
||
```text
|
||
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`.
|
||
|
||
<img src="../images/k3s--3x-ui-welcome.png" alt="3x-ui welcome page (RU)" width="70%" />
|
||
|
||
После первого логирования (по умолчанию логин и пароль `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`, включение его потребует компиляции ядра (если вы этого еще не сделали, [смотрите
|
||
инструкцию](../raspberry-and-orange-pi/opi5plus-rebuilding-linux-kernel-for-iscsi.md).
|
||
|
||
Если `Longhorn` уже установлен, создадим не его базе постоянное хранилище для -- _PersistentVolumeClaim_ (**PVC**).
|
||
Манифест PVC создадим в каталоге `~/k3s/vpn/x-ui/`, рядом с `deployment.yaml`:
|
||
```bash
|
||
nano ~/k3s/vpn/x-ui/pvc-db.yaml
|
||
```
|
||
|
||
Вставим в него следующий код:
|
||
```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-манифест:
|
||
```bash
|
||
sudo kubectl apply -f ~/k3s/vpn/x-ui/pvc-db.yaml
|
||
```
|
||
|
||
После этого Longhorn создаст том, который будет привязан к этому PVC.
|
||
|
||
Теперь нам нужно изменить манифест развертывания пода, и подключить к нему созданный PVC. Теперь наш
|
||
`~/k3s/vpn/x-ui/deployment.yaml` будет выглядеть так:
|
||
```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'
|
||
```
|
||
|
||
Применим обновлённый манифест:
|
||
```bash
|
||
sudo kubectl apply -f ~/k3s/vpn/x-ui/deployment.yaml
|
||
```
|
||
|
||
Под перезапустится, и теперь база данных будет храниться в постоянном хранилище Longhorn. При перезапуске пода или его
|
||
"переезде" на другой узел, база данных останется доступной и не потеряется. Следует отметить, что при сбое узла
|
||
процесс перемещения пода занимает некоторое время. В кластере на Orange Pi 5, где проверки связности не очень
|
||
агрессивные, это может занять до 5 минут. В общем, это нормально.
|
||
|
||
## Единая точка входа VPN-соединений через под 3x-ui
|
||
|
||
|
||
|
||
|