add: minor.

This commit is contained in:
2025-03-25 16:04:39 +03:00
parent 0a90d4a444
commit c7a5241d33
5 changed files with 114 additions and 86 deletions
+28
View File
@@ -0,0 +1,28 @@
# Установка 3X-UI как под в K3s (Kubernetes)
3X-UI — это симпатичный веб-интерфейс для управления VPN-серверами, такими как WireGuard, Shadowsocks, Xray, V2Ray
и тому подобное. Он позволяет настраивать и мониторить VPN-соединения и клиентов через браузер. Мы будем запускать
его как контейнер (под) внутри K3s кластера на Orange Pi 5.
### Создание namespace (не обязательно)
Для удобства организации рекомендую создать отдельное пространство имён (`namespace`) для 3X-UI. Это как папка для
ресурсов, чтобы они не смешивались с другими приложениями.
Выполним в терминале:
```bash
sudo kubectl create namespace x-ui
```
Проверим, что пространство имён создано:
```bash
kubectl get namespaces
```
Увидим x-ui в списке:
```text
NAME STATUS AGE
... ... ...
... ... ...
x-ui Active 6s
```
+19 -19
View File
@@ -23,8 +23,8 @@
│ └── cclient-shadowsocks--izmir/ # Локация Измир
│ ├── config.yaml
│ └── deployment.yaml
├── ...
└── ...
├── …
└── …
```
Создаем файл `config.yaml` для первого Shadowsocks-клиента (Москва):
@@ -61,7 +61,7 @@ data:
- `data:` — данные конфигурации.
- `config.json:` — имя файла, в который будет записан конфиг.
- `|` — говорит, что дальше будет многострочный текст.
- `{...}` — Собственно JSON-конфигурация нашего Shadowsocks-клиента.
- `{…}` — Собственно JSON-конфигурация нашего Shadowsocks-клиента.
- `server` и `server_port` — адрес и порт нашего VPS.
- `local_address` и `local_port` — где будет SOCKS5 внутри кластера.
- `password` и `method` — пароль и метод шифрования. Метод шифрования `chacha20-ietf-poly1305` -- используется,
@@ -150,10 +150,10 @@ sudo k3s kubectl get pods -n kube-system
Увидим что-то типа:
```text
NAME READY STATUS RESTARTS AGE
...
...
…
…
shadowsocks-client-moscow-54d64bf5f4-trb6p 1/1 Running 0 24m
...
…
```
Можно проверь логи:
@@ -232,10 +232,10 @@ sudo k3s ctr images ls | grep shadowsocks
Увидим что-то типа:
```text
...
docker.io/library/shadowsocks-with-tools:latest application/vnd.oci.image.manifest.v1+json sha256:... 22.5 MiB linux/arm64 io.cri-containerd.image=managed
...
...
…
docker.io/library/shadowsocks-with-tools:latest application/vnd.oci.image.manifest.v1+json sha256:… 22.5 MiB linux/arm64 io.cri-containerd.image=managed
…
…
```
Теперь нам нужно передать образ контейнера на другие ноды кластера. Как это сделать есть заметка "[Развертывание
@@ -246,15 +246,15 @@ docker.io/library/shadowsocks-with-tools:latest application/vnd.oci.image.ma
новый образ. Закомментируем строку `image: shadowsocks/shadowsocks-libev:latest` и вставим две строки после неё
(обратите внимание на заметки):
```yaml
...
…
spec:
containers:
- name: shadowsocks-client
# image: shadowsocks/shadowsocks-libev:latest
image: shadowsocks-with-tools # Без :latest, чтобы k3s не "ходил" за контейнером в реестр (например, DockerHub)
imagePullPolicy: Never # Только локальный образ, не тянуть из реестра
...
...
…
…
```
Уберём старый под из deployment и удалим сам под из k3s:
@@ -276,9 +276,9 @@ sudo k3s kubectl get pods -n kube-system
Увидим что-то типа:
```text
NAME READY STATUS RESTARTS AGE
...
…
shadowsocks-client-moscow-6cf7b956b8-mtsg4 1/1 Running 0 9s
...
…
```
#### Проверка работы Shadowsocks
@@ -344,12 +344,12 @@ sudo k3s kubectl logs -n kube-system shadowsocks-client-moscow-<hash>
Для этого нужно изменить _local_address_ в конфиге shadowsocks-клиента `config.yaml`:
```yaml
...
…
"server_port": <ПОРТ>,
# "local_address": "127.0.0.1",
"local_address": "0.0.0.0",
"local_port": 1081,
...
…
```
Применим конфиг:
@@ -437,9 +437,9 @@ sudo k3s kubectl get service -n kube-system
Увидим что-то типа:
```text
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
...
…
ss-moscow-service ClusterIP 10.43.236.81 <none> 1081/TCP,1081/UDP 5m5s
...
…
```
Теперь другие поды могут обращаться к `ss-moscow-service.kube-system.svc.cluster.local:1081` как к SOCKS5-прокси.
+38 -38
View File
@@ -20,7 +20,7 @@ IoT-устройства, edge-серверы и т.п.). Для кластер
контейнеры всё равно запускаются runtime’ом (это containerd в k3s). И Docker все равно еще нужен для создания
образов, и если при установке k3s не указать `--docker` то k3s будет использовать его как runtime._
Но, есть у k3s и минус для конкретно моего случая -- распределенная база **etcd**, в которой хранится состояния
Но, есть у k3s и минус для конкретно моего случая — распределенная база **etcd**, в которой хранится состояния
кластера, нод и подов, в нем заменена SQLite. Это круто для маленьких компьютеров: экономно по памяти и другим ресурсам,
и, что главное, никак не сказывается на производительности (пока узлов меньше 50-80), но означает, что в кластере k3s
может быть только одна мастер-нода. Если мастер-нода упадет, её некому будет заменить и весь кластер умрет.
@@ -29,7 +29,7 @@ IoT-устройства, edge-серверы и т.п.). Для кластер
### Важное предупреждение
k3s -- это не упрощенная мини-версия Kubernetes, здесь все компоненты упакованы в один бинарник, а значит намного
k3s — это не упрощенная мини-версия Kubernetes, здесь все компоненты упакованы в один бинарник, а значит намного
проще не только добавлять узлы, но и удалять их. Так что если что-то пойдет не так с настройкой узла, просто удалите
и начните заново. Удаление k3s с узла:
```bash
@@ -51,14 +51,14 @@ curl -sfL https://get.k3s.io | sh -s - server --cluster-init --tls-san=192.168.1
```
Здесь:
* `server` -- значение по умолчанию, устанавливает узел k3s в режиме *мастер* (control-plane). В этом режиме узел
* `server` — значение по умолчанию, устанавливает узел k3s в режиме *мастер* (control-plane). В этом режиме узел
будет запускать все компоненты управления Kubernetes: API-сервер, контроллер-менеджер, планировщик (scheduler).
Такой узел отвечает за управление кластером и может также выполнять рабочие нагрузки (workloads), если
не настроены ограничения (taints). Если бы мы указали `agent` -- был бы установлен узел k3s в режиме *воркер*-узла.
* `--cluster-init` -- добавляет поддержку высокой доступности (HA -- High Availability) через встроенный `etcd`. Это
не настроены ограничения (taints). Если бы мы указали `agent` — был бы установлен узел k3s в режиме *воркер*-узла.
* `--cluster-init` — добавляет поддержку высокой доступности (HA — High Availability) через встроенный `etcd`. Это
значит, что узел инициализирует новый кластер и готов к тому, чтобы другие мастер-узлы могли к нему подключиться
(для создания HA-конфигурации).
* `--tls-san=192.168.1.27` -- добавляет IP 192.168.1.27 в сертификаты API-сервера, чтобы другие узлы и клиенты
* `--tls-san=192.168.1.27` — добавляет IP 192.168.1.27 в сертификаты API-сервера, чтобы другие узлы и клиенты
могли обращаться к нему по этому адресу.
Проверим, что все k3s запущен:
@@ -70,9 +70,9 @@ sudo service k3s status
```text
● k3s.service - Lightweight Kubernetes
Loaded: loaded (/etc/systemd/system/k3s.service; enabled; vendor preset: enabled)
Active: active (running) since ...
...
...
Active: active (running) since …
…
…
```
Посмотрим сколько нод в кластере:
@@ -113,16 +113,16 @@ kube-system traefik-5d45fc8cc9-t5d58 1/1 Running 0
Представлены следующие поды:
1. `coredns` — это DNS-сервер для кластера. Он отвечает за разрешение имен внутри Kubernetes (например, чтобы поды
могли обращаться друг к другу по именам сервисов вроде my-service.default.svc.cluster.local).
2. `helm-install-traefik-crd` -- это временный под (Job), который устанавливает Custom Resource Definitions (CRD)
2. `helm-install-traefik-crd` — это временный под (Job), который устанавливает Custom Resource Definitions (CRD)
для *Traefik* — ingress-контроллера, встроенного в k3s. CRD нужны для управления ingress-ресурсами
(маршрутизацией HTTP/HTTPS). Этот под — одноразовая задача (Job), а не постоянный сервис. Он запустился, выполнил
работу (установил CRD) и завершился. Статус "*Completed*" значит, что он больше не работает.
3. `helm-install-traefik` -- ещё один Job, который устанавливает сам Traefik через Helm-чарт. Этот под развернул
3. `helm-install-traefik` — ещё один Job, который устанавливает сам Traefik через Helm-чарт. Этот под развернул
основной Traefik-под и завершился.
4. `local-path-provisioner` -- компонент для автоматического создания локальных Persistent Volumes (PV) на узлах. Он
4. `local-path-provisioner` — компонент для автоматического создания локальных Persistent Volumes (PV) на узлах. Он
позволяет подам запрашивать хранилище (например, через PersistentVolumeClaim) без сложной настройки NFS или внешних
хранилищ. В k3s это встроено для простоты.
5. `metrics-server` -- собирает данные об использовании ресурсов (CPU, память) подов и узлов. Это нужно для команд
5. `metrics-server` — собирает данные об использовании ресурсов (CPU, память) подов и узлов. Это нужно для команд
вроде `kubectl top` или для Horizontal Pod Autoscaler (HPA). Установку метрик можно отключить при запуске k3s
флагом `--disable=metrics-server`.
6. `svclb-traefik` - это под для балансировки нагрузки (Service Load Balancer) для Traefik. В k3s нет встроенного
@@ -131,14 +131,14 @@ kube-system traefik-5d45fc8cc9-t5d58 1/1 Running 0
* один для самой логики балансировки;
* другой для мониторинга или дополнительной функциональности (например, *keepalived* или аналога) и это зависит
от реализации в k3s.
7. `traefik` -- сам Traefik, ingress-контроллер, который обрабатывает HTTP/HTTPS трафик кластера и маршрутизирует
7. `traefik` — сам Traefik, ingress-контроллер, который обрабатывает HTTP/HTTPS трафик кластера и маршрутизирует
его к соответствующим подам (с динамической конфигурацией нашим) и сервисам по правилам Ingress. Traefik в k3s
установлен по умолчанию, но его можно отключить при запуске k3s флагом `--disable=traefik` (не будет ни *traefik*,
ни *svclb*, ни связанных *Helm Jobs*).
Обратите внимание, что, например, под `coredns` получил имя `coredns-ccb96694c-tfjwj`. Имена подов (Pod Names)
в Kubernetes генерируются автоматически на основе правил, чтобы каждый под в кластере имел уникальное имя.
Структура имени -- `<имя-приложения>-<хеш-ревизии>-<случайный-суффикс>`. Впрочем, `<хеш-ревизии>` может отсутствовать,
Структура имени — `<имя-приложения>-<хеш-ревизии>-<случайный-суффикс>`. Впрочем, `<хеш-ревизии>` может отсутствовать,
если под не имеет контроллера репликации (например, Job или CronJob).
Можно проверить, что API нашего узла (кластера) отвечает:
@@ -168,7 +168,7 @@ Unauthorized JSON-ответ от API. Что-то вроде:
sudo cat /var/lib/rancher/k3s/server/node-token
```
Вывод будет что-то вроде `K10...::server:longrandomstring`. Это и есть токен, который нужно будет использовать.
Вывод будет что-то вроде `K10…::server:longrandomstring`. Это и есть токен, который нужно будет использовать.
Теперь на втором Orange Pi (например, с IP 192.168.1.28) можно запустить второй мастер-узел (вставим токен
из предыдущего шага):
@@ -176,9 +176,9 @@ sudo cat /var/lib/rancher/k3s/server/node-token
curl -sfL https://get.k3s.io | sh -s - server --server https://192.168.1.27:6443 --token <ТОКЕН> --tls-san=192.168.1.28
```
Здесь ключи:
* `--server https://192.168.1.27:6443` -- указывает на API мастер-узла, чтобы наш новый узел мог подключиться к кластеру.
* `--server https://192.168.1.27:6443` — указывает на API мастер-узла, чтобы наш новый узел мог подключиться к кластеру.
* `--token` — токен аутентификации из предыдущего шага.
* `--tls-san=192.168.1.28` -- добавляет IP нашего второго мастера в сертификаты (для будущих подключений).
* `--tls-san=192.168.1.28` — добавляет IP нашего второго мастера в сертификаты (для будущих подключений).
Проверим какие теперь ноды в кластере:
```bash
@@ -210,7 +210,7 @@ kube-system svclb-traefik-4f8c2580-xzt5d 2/2 Running 0
kube-system traefik-5d45fc8cc9-t5d58 1/1 Running 0 2h 10.42.0.8 opi5plus-2 <none> <none>
```
Как видим, у нас появился еще один `svclb-traefik` на второй ноде. Это под -- Service Load Balancer (SLB) для Traefik.
Как видим, у нас появился еще один `svclb-traefik` на второй ноде. Это под — Service Load Balancer (SLB) для Traefik.
Он эмулирует облачный балансировщик нагрузки (типа AWS ELB), которого нет в локальном окружении вроде Orange Pi.
SLB перенаправляет внешний трафик (например, на порты 80/443) к сервисам типа LoadBalancer внутри кластера.
@@ -226,7 +226,7 @@ curl -sfL https://get.k3s.io | sh -s - agent --server https://192.168.1.10:6443
```
Здесь ключ:
* `agent` -- устанавливает узел в режиме воркера (worker). Это значит, что узел будет выполнять рабочие нагрузки
* `agent` — устанавливает узел в режиме воркера (worker). Это значит, что узел будет выполнять рабочие нагрузки
(поды), но не будет управлять кластером (без *control-plane*, *master* и на нем нет реплики *etcd*).
Посмотрим на ноды (команда выполняется на одном из мастер-узлов):
@@ -301,7 +301,7 @@ traefik LoadBalancer 10.43.164.48 192.168.1.26,192.168.1.27,192.16
им не нужен доступ к etcd в реальном времени.
В чем может быть смысл иметь два мастера? Это обеспечивает репликацию данных (второй хранит копию etcd), но не
даёт отказоустойчивости -- когда один мастер упал, кластер становится неуправляемым (нет управления через kubectl),
даёт отказоустойчивости — когда один мастер упал, кластер становится неуправляемым (нет управления через kubectl),
рабочие нагрузки (поды) могут продолжать работать, пока жив хотя бы один узел, но новые изменения (развертывание
подов и обновления) невозможны.
@@ -399,7 +399,7 @@ traefik-6c979cd89d-z6wwm 1/1 Running 0 2
```
Хотя, в целом, кластер остается рабочим, и сам чинится при отключении и восстановлении узлов, но если отключается нода
на которой исполняется под с `coredns` -- то временно будет затруднен перезапуска и создание новых подов, а значит
на которой исполняется под с `coredns` — то временно будет затруднен перезапуска и создание новых подов, а значит
и "переезд" подов с погашенного узла, до восстановления `coredns` тоже будет замедлен. Кроме того, если сценарий
приложения(ий) развернутых внутри k3s предполагает переподключение с использованием имен подов или обнаружение подов,
то это тоже перестанет работать.
@@ -410,12 +410,12 @@ sudo k3s kubectl edit deployment coredns -n kube-system
```
Здесь:
* `kubectl edit` -- Открывает редактор (по умолчанию *vim*) для изменения ресурса Kubernetes напрямую в кластере.
* `kubectl edit` — Открывает редактор (по умолчанию *vim*) для изменения ресурса Kubernetes напрямую в кластере.
Вместо создания локального YAML-файла и применения его через `kubectl apply`, мы сразу редактируем "живой" конфиг.
* `deployment coredns` -- Указывает, что редактируем объект типа *deployment* с именем `coredns`. Deployment — это
* `deployment coredns` — Указывает, что редактируем объект типа *deployment* с именем `coredns`. Deployment — это
контроллер, который управляет набором подов (в данном случае coredns), обеспечивая их количество (реплики),
перезапуск и обновления.
* `-n kube-system` -- Указывает пространство имён (namespace), где находится *coredns8. В k3s системные компоненты,
* `-n kube-system` — Указывает пространство имён (namespace), где находится *coredns8. В k3s системные компоненты,
к которым относится *coredns(, обычно живут в kube-system.
В открывшемся окне найдем строку `replicas: 1` и заменим её на `replicas: 2`.
@@ -431,7 +431,7 @@ spec:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-ccb96694c-n4qsp 0/1 ContainerCreating 0 5s <none> opi5plus-1 <none> <none>
coredns-ccb96694c-wzh96 1/1 Running 0 3h10m 10.42.1.8 opi5plus-3 <none> <none>
...
…
```
А затем:
@@ -439,7 +439,7 @@ coredns-ccb96694c-wzh96 1/1 Running 0
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-ccb96694c-n4qsp 1/1 Running 0 15s 10.42.2.6 opi5plus-1 <none> <none>
coredns-ccb96694c-wzh96 1/1 Running 0 3h10m 10.42.1.8 opi5plus-3 <none> <none>
...
…
```
**Как это будет работать?** Обе реплики `coredns` привязаны к сервису `kube-dns` в пространстве имён `kube-system`.
@@ -455,10 +455,10 @@ sudo k3s kubectl get endpoints kube-dns -n kube-system
гасили при экспериментах с устойчивостью кластера:
```text
NAME ENDPOINTS AGE
kube-dns 10.42.1.8:53,10.42.2.6:53,10.42.1.8:53 + 3 more... 5d23h
kube-dns 10.42.1.8:53,10.42.2.6:53,10.42.1.8:53 + 3 more… 5d23h
```
Каждый под `coredns` -- самостоятельный DNS-сервер. Они не взаимодействуют друг с другом и не обмениваются данными. Это
Каждый под `coredns` — самостоятельный DNS-сервер. Они не взаимодействуют друг с другом и не обмениваются данными. Это
просто экземпляры одного и того же сервиса, работающие параллельно. Они независимы, получают данные из API Kubernetes
и отвечают на запросы параллельно. В каждом поде кластера в качестве DNS настроен `kube-dns` (задаётся в файле
`/etc/resolv.conf` внутри пода). Когда под отправляет DNS-запрос, его получит `kube-dns` и перенаправит запрос
@@ -518,7 +518,7 @@ sudo apt install keepalived
sudo nano /etc/keepalived/keepalived.conf
```
На первом мастер-узле (хост -- `opi5plus-1`, IP -- `192.168.1.26`):
На первом мастер-узле (хост — `opi5plus-1`, IP — `192.168.1.26`):
```text
vrrp_instance VI_1 {
state MASTER # ЭТО ГЛАВНЫЙ ХОСТ. ПО УМОЛЧАНИЮ ТРАФИК С VIP БУДЕТ ПЕРЕНАПРАВЛЯТЬСЯ НА ЭТОТ ХОСТ
@@ -537,7 +537,7 @@ vrrp_instance VI_1 {
}
```
На втором мастер-узле (хост -- `opi5plus-2`, IP -- `192.168.1.27`):
На втором мастер-узле (хост — `opi5plus-2`, IP — `192.168.1.27`):
```text
vrrp_instance VI_1 {
state BACKUP # ЭТО ВТОРОЙ ХОСТ. ОН БУДЕТ ПОЛУЧАТЬ ТРАФИК С VIP, ЕСЛИ ГЛАВНЫЙ ХОСТ УПАДЕТ
@@ -556,7 +556,7 @@ vrrp_instance VI_1 {
}
```
И, наконец, на третьем мастер-узле (хост -- `opi5plus-3`, IP -- `192.168.1.28`):
И, наконец, на третьем мастер-узле (хост — `opi5plus-3`, IP — `192.168.1.28`):
```text
vrrp_instance VI_1 {
state BACKUP # ЭТО ТРЕТИЙ ХОСТ. ОН БУДЕТ ПОЛУЧАТЬ ТРАФИК С VIP, ЕСЛИ ГЛАВНЫЙ- И БЭКАП-ХОСТ УПАДЕТ
@@ -588,15 +588,15 @@ ip addr show
то увидим:
```text
...
...
…
…
2: enP4p65s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether c0:74:2b:fd:42:3c brd ff:ff:ff:ff:ff:ff
inet 192.168.1.26/24 brd 192.168.1.255 scope global dynamic noprefixroute enP4p65s0
valid_lft 68779sec preferred_lft 68779sec
inet 192.168.1.200/32 scope global enP4p65s0
valid_lft forever preferred_lft forever
...
…
```
Обратите внимание на виртуальный IP-адрес `192.168.1.200` находится в другой подсети (CIDR) и имеет маску `/32` (то
есть с маской подсети `255.255.255.255`). Это "точечная" подсеть, содержащая только один адрес, не привязан к основной
@@ -652,9 +652,9 @@ vps-sw-eye Ready <none> 35m v1.31.6+k3s1
Таким образом, для управления удаленным узлом нужно чтобы он имел локальный IP-адрес в домашней сети, а не внешний.
SSH-тоннель с помощью `autossh` и упаковкой UDP-трафика в TCP через `socat` не сработает (а я надеялся). Таким образом
"пробросить" Flannel для полноценного подключения удаленного k3s-узла -- VPN-туннель между каждой мастер-нодой на
удаленный узел. Это вполне рабочия вариант, если удаленные узлы -- полноценные и произвольные хосты. Но в моём
случае удаленный узел -- хост на 1 ядро и 1 ГБ ОЗУ. К тому же он на платформе x86_64, а не ARM, а значит ради одного
"пробросить" Flannel для полноценного подключения удаленного k3s-узла — VPN-туннель между каждой мастер-нодой на
удаленный узел. Это вполне рабочия вариант, если удаленные узлы — полноценные и произвольные хосты. Но в моём
случае удаленный узел — хост на 1 ядро и 1 ГБ ОЗУ. К тому же он на платформе x86_64, а не ARM, а значит ради одного
узла не стоит заморачиваться с VPN.
Другим вариантом является подключение внутри самих подов на удаленном узле к необходимым сервисам напрямую. Но таким
@@ -9,14 +9,14 @@ SSD NVMe, и для eMMC. Но, как и всякая магия, она мож
## Установка накопителей
Выключим Orange Pi 5 Plus и установим в него eMMC-носитель...
Выключим Orange Pi 5 Plus и установим в него eMMC-носитель…
| Фото до и после установки eMMC. Внимание, устанавливайте до щелчка с обоих сторон! |
|:-------------------------------------------------------------------------------------|
| ![Orange Pi 5 Plus без eMMC](../images/orange-pi--photo--without-emmc.webp) |
| ![Orange Pi 5 Plus c установленным eMMC](../images/orange-pi--photo--with-emmc.webp) |
...и/или SSD-накопитель NVMe
…и/или SSD-накопитель NVMe
| Фото до и после установки NVMe. Более просто в установке. Для надёжности закрепить винтиком. |
|:---------------------------------------------------------------------------------------------------|
@@ -61,8 +61,8 @@ ls -al /tmp/boot-backup.tar.gz
Теперь нам нужно скопировать его на какой-нибудь внешний хост (или носитель, но я буду копировать на хост другого
компьютера). Если что-то пойдёт не так (например, после обновления ядра система не загрузится) можно будет восстановить
файлы из этого архива. Мой Orange Pi 5 Plus, на котором я буду компилировать ядро имеет хост -- `opi5plus-3` (замени
на свой хост), а имя пользователя от которого я работаю -- `opi` (замени на свой). На рабочем компьютере, с которого
файлы из этого архива. Мой Orange Pi 5 Plus, на котором я буду компилировать ядро имеет хост — `opi5plus-3` (замени
на свой хост), а имя пользователя от которого я работаю — `opi` (замени на свой). На рабочем компьютере, с которого
я захожу по SSH на Orange, у меня есть папка `~/backup/` (`mkdir -p ~/backup`). Скачиваю в неё архив:
```bash
scp opi@opi5plus-3.local:/tmp/boot-backup.tar.gz ~/backup/opi5plus-3-boot-backup.tar.gz
@@ -93,38 +93,38 @@ drwxr-xr-x 3 root root 4096 ноя 21 09:55 dtb-6.1.43-rockchip-rk3588/
```
Ключевые файлы:
* `Image` -- собственно ядро Linux (в данном случае версия 6.1.43 для Rockchip RK3588). При старте компьютера загрузчик
* `Image` — собственно ядро Linux (в данном случае версия 6.1.43 для Rockchip RK3588). При старте компьютера загрузчик
U-Boot загрузит его в память и передаст ему управление. Без этого файла система не запустится.
* `vmlinuz-6.1.43-rockchip-rk3588` -- копия ядра (в системе уже есть резервная копия).
* `dtb/` -- Каталог файлами **Device Tree Blob** (`DTB`). Это бинарные файлы, описывающие аппаратное обеспечение устройства.
* `vmlinuz-6.1.43-rockchip-rk3588` — копия ядра (в системе уже есть резервная копия).
* `dtb/` — Каталог файлами **Device Tree Blob** (`DTB`). Это бинарные файлы, описывающие аппаратное обеспечение устройства.
Для Orange Pi 5 Plus используется файл вроде `rk3588-orangepi-5-plus.dtb` (находится в подкаталоге `dtb/rockchip/`).
DTB передаётся ядру, чтобы оно знало, как работать с процессором (количество ядер, частоты), памятью (RAM, её объём
и адреса), периферией (UART, I2C, SPI, Ethernet, USB, GPIO, прерывания и тому подобное). На ARM-устройствах
(в отличие от x86, где есть ACPI) нет стандартного способа обнаружения оборудования. DTB решает эту проблему,
предоставляя ядру "карту" железа. U-Boot загружает DTB из `/boot/dtb/ `и передаёт его ядру при старте. Кстати,
в подкаталоге dtb/rockchip/ есть `overlay/` -- это дополнительные файлы, которые могут использоваться для добавления
в подкаталоге dtb/rockchip/ есть `overlay/` — это дополнительные файлы, которые могут использоваться для добавления
и/или изменения функциональности устройства. Например, можно добавить поддержку новых периферийных устройств (камеру,
дисплей и т.п.).
* `uInitrd` -- Начальный RAM-диск (initrd), адаптированный для U-Boot. Содержит модули и скрипты, необходимые для
* `uInitrd` — Начальный RAM-диск (initrd), адаптированный для U-Boot. Содержит модули и скрипты, необходимые для
пред-загрузки (выбор накопителя, монтирование корневой файловой системы и т.п.). Если он повреждён или несовместим
с ядром, загрузка может упасть на этапе инициализации.
* `orangepiEnv.txt` -- Конфигурационный файл для U-Boot. Здесь задаются параметры загрузки, такие как путь расположение
дерева DTB, UUID корневой файловой системы, тип файловой системы... Без правильных настроек в этом файле U-Boot не
* `orangepiEnv.txt` — Конфигурационный файл для U-Boot. Здесь задаются параметры загрузки, такие как путь расположение
дерева DTB, UUID корневой файловой системы, тип файловой системы… Без правильных настроек в этом файле U-Boot не
найдёт нужные для загрузки файлы.
* `boot.scr` -- Скрипт загрузки для U-Boot. Содержит команды для загрузки ядра, initrd и DTB. U-Boot выполняет его
* `boot.scr` — Скрипт загрузки для U-Boot. Содержит команды для загрузки ядра, initrd и DTB. U-Boot выполняет его
при старте системы. Этот файл создаётся из `boot.cmd` с помощью утилиты `mkimage`. Если он повреждён или отсутствует,
U-Boot не сможет загрузить систему.
* `dtb-6.1.43-rockchip-rk3588/` -- Копия каталога `dtb/`, обычно появляется, когда ядро устанавливается или обновляется
* `dtb-6.1.43-rockchip-rk3588/` — Копия каталога `dtb/`, обычно появляется, когда ядро устанавливается или обновляется
через пакетный менеджер (например, `apt`). Она привязана к конкретной версии ядра — в данном случае
`6.1.43-rockchip-rk3588`, для того, чтобы: Хранить DTB-файлы, соответствующие этой версии ядра и избегать конфликты
между DTB от разных версий ядра (если используется несколько ядер на одной системе).
Менее критичные, но полезные файлы:
* `config-6.1.43-rockchip-rk3588` -- Конфигурация ядра, использованная при его сборке (он нам понадобится, чтобы
* `config-6.1.43-rockchip-rk3588` — Конфигурация ядра, использованная при его сборке (он нам понадобится, чтобы
пересобрать ядро с iSCSI).
* `System.map-6.1.43-rockchip-rk3588` -- Карта меток (символов) ядра, полезна для отладки.
* `initrd.img-6.1.43-rockchip-rk3588` -- Обычный initrd, из которого генерируется uInitrd.
* `boot.bmp` и `logo.bmp` -- Изображения для экрана загрузки (не влияют на работу системы).
* `System.map-6.1.43-rockchip-rk3588` — Карта меток (символов) ядра, полезна для отладки.
* `initrd.img-6.1.43-rockchip-rk3588` — Обычный initrd, из которого генерируется uInitrd.
* `boot.bmp` и `logo.bmp` — Изображения для экрана загрузки (не влияют на работу системы).
## Устанавливать инструменты для сборки ядра
@@ -136,13 +136,13 @@ sudo apt install -y build-essential bc flex bison libssl-dev libncurses-dev git
Нам понадобятся следующие пакеты:
* `build-essential` -- Включает `gcc` (для ARM64, make и другие базовые инструменты компиляции.
* `bc` -- Утилита для точных математических вычислений в командной строке. Используется для вычислений в скриптах сборки ядра.
* `flex` и `bison` -- генератор лексических анализаторов и парсер. Нужны для обработки конфигурационных файлов ядра.
* `libssl-dev` -- Для поддержки криптографии в ядре и `OpenSSL`.
* `libncurses-dev` -- Библиотека для создания текстовых интерфейсов в терминале. Необходимо для работы интерфейса
* `build-essential` — Включает `gcc` (для ARM64, make и другие базовые инструменты компиляции.
* `bc` — Утилита для точных математических вычислений в командной строке. Используется для вычислений в скриптах сборки ядра.
* `flex` и `bison` — генератор лексических анализаторов и парсер. Нужны для обработки конфигурационных файлов ядра.
* `libssl-dev` — Для поддержки криптографии в ядре и `OpenSSL`.
* `libncurses-dev` — Библиотека для создания текстовых интерфейсов в терминале. Необходимо для работы интерфейса
`menuconfig` при настройке параметров ядра.
* `git` -- Для клонирования исходного кода ядра из репозитория Xunlong.
* `git` — Для клонирования исходного кода ядра из репозитория Xunlong.
> **Примечание:** Если вы хотите собрать ядро на x86-системе, установите кросс-компилятор `gcc-aarch64-linux-gnu` (`sudo apt install gcc-aarch64-linux-gnu`) и используйте его вместо обычного gcc в командах сборки. Он позволит собрать ядро для ARM64-архитектуры на x86-системе.
@@ -314,10 +314,10 @@ sudo reboot
Если вы все делали правильно, то такого быть не должно. Но, тем не менее, если загрузка не произошла, то это может
выглядеть двумя способами:
* Система зависает на этапе загрузки: синенький огонек на Orange Pi не загорается и Ethernet тоже не мигает --
_вы неправильно собрали ядро или испортили загрузчик_.
* Система, вроде как, грузится, но все никак... огоньки весело мигают, но не получается подключиться ни по SSH, ни
другим способом, пинги на IP-адрес не проходят -- _вы забыли подключить модули, накосячили с конфигом или с `.dtb`_.
* Система зависает на этапе загрузки: синенький огонек на Orange Pi не загорается и Ethernet тоже не мигает —
_вы неправильно собрали ядро или испортили загрузчик.
* Система, вроде как, грузится, но все никак… огоньки весело мигают, но не получается подключиться ни по SSH, ни
другим способом, пинги на IP-адрес не проходят — вы забыли подключить модули, накосячили с конфигом или с `.dtb`_.
Чтобы починить, загружайтесь с MicroSD-карты (не забудьте отключить питание перед тем как вставить MicroSD-карту).
Затем смонтируйте, в зависимости где у вас система, eMMC:
@@ -327,7 +327,7 @@ mount /dev/mmcblk2p1 /mnt/emmc
cd /mnt/emmc
```
...или NVMe:
…или NVMe:
```bash
mkdir -p /mnt/nvme
mount /dev/nvme0n1p1 /mnt/nvme