базовая настройка

main
laynholt 2 months ago
commit 311bf593b6

@ -0,0 +1,294 @@
## 🐳 Dockerfile
Если вы планируете использовать собственный `Dockerfile` для запуска `DeepSpeed` (или любого распределенного обучения через SSH), не забудьте добавить в образ настройку `pdsh`, `openssh` и `ca-certificates`. Также полезно сразу указать `sshd_config` с настройками, чтобы SSH соединения оставались активными и использовали нестандартный порт.
### 🔧 Минимальный пример для добавления SSH в ваш Dockerfile
```dockerfile
RUN apt-get update && \
apt-get install -y pdsh ca-certificates openssh-client openssh-server
# Поддержка keep-alive для ssh
RUN echo "ClientAliveInterval 30" >> /etc/ssh/sshd_config
# Настройка порта для SSH
ENV SSH_PORT=2229
RUN sed -i "0,/^#Port 22/s//Port ${SSH_PORT}/" /etc/ssh/sshd_config
# Создание необходимых директорий и запуск sshd
RUN mkdir -p /run/sshd
CMD ["/usr/sbin/sshd", "-D"]
```
---
### 🐋 Полный пример Dockerfile для CUDA + SSH + DeepSpeed
Если хотите, можете сразу использовать готовую основу, которая включает CUDA, cuDNN и SSH-сервер для распределенного обучения:
```bash
FROM nvidia/cuda:12.4.1-cudnn-devel-ubuntu20.04
ENV DEBIAN_FRONTEND noninteractive
##############################################################################
# Temporary Installation Directory
##############################################################################
ENV STAGE_DIR=/tmp
RUN mkdir -p ${STAGE_DIR}
##############################################################################
# Installation/Basic Utilities
##############################################################################
RUN apt-get update && \
apt-get install -y --no-install-recommends \
software-properties-common build-essential autotools-dev \
nfs-common pdsh \
cmake g++ gcc \
curl wget vim tmux emacs less unzip \
htop iftop iotop ca-certificates openssh-client openssh-server \
rsync iputils-ping net-tools sudo \
llvm-dev
##############################################################################
# Installation Latest Git
##############################################################################
RUN add-apt-repository ppa:git-core/ppa -y && \
apt-get update && \
apt-get install -y git && \
git --version
##############################################################################
# Client Liveness & Uncomment Port 22 for SSH Daemon
##############################################################################
# Keep SSH client alive from server side
RUN echo "ClientAliveInterval 30" >> /etc/ssh/sshd_config
RUN cp /etc/ssh/sshd_config ${STAGE_DIR}/sshd_config && \
sed "0,/^#Port 22/s//Port 22/" ${STAGE_DIR}/sshd_config > /etc/ssh/sshd_config
##############################################################################
# Mellanox OFED
##############################################################################
ENV MLNX_OFED_VERSION=4.9-7.1.0.0
RUN apt-get install -y libnuma-dev
RUN cd ${STAGE_DIR} && \
wget -q -O - http://www.mellanox.com/downloads/ofed/MLNX_OFED-${MLNX_OFED_VERSION}/MLNX_OFED_LINUX-${MLNX_OFED_VERSION}-ubuntu20.04-x86_64.tgz | tar xzf - && \
cd MLNX_OFED_LINUX-${MLNX_OFED_VERSION}-ubuntu20.04-x86_64 && \
./mlnxofedinstall --user-space-only --without-fw-update --all -q && \
cd ${STAGE_DIR} && \
rm -rf ${STAGE_DIR}/MLNX_OFED_LINUX-${MLNX_OFED_VERSION}-ubuntu20.04-x86_64*
##############################################################################
# nv_peer_mem
##############################################################################
ENV NV_PEER_MEM_VERSION=1.2
ENV NV_PEER_MEM_TAG=${NV_PEER_MEM_VERSION}-0
RUN mkdir -p ${STAGE_DIR} && \
git clone https://github.com/Mellanox/nv_peer_memory.git --branch ${NV_PEER_MEM_TAG} ${STAGE_DIR}/nv_peer_memory && \
cd ${STAGE_DIR}/nv_peer_memory && \
./build_module.sh && \
cd ${STAGE_DIR} && \
tar xzf ${STAGE_DIR}/nvidia-peer-memory_${NV_PEER_MEM_VERSION}.orig.tar.gz && \
cd ${STAGE_DIR}/nvidia-peer-memory-${NV_PEER_MEM_VERSION} && \
apt-get update && \
apt-get install -y dkms && \
dpkg-buildpackage -us -uc && \
dpkg -i ${STAGE_DIR}/nvidia-peer-memory_${NV_PEER_MEM_TAG}_all.deb
##############################################################################
# OPENMPI
##############################################################################
ENV OPENMPI_BASEVERSION=4.1
ENV OPENMPI_VERSION=${OPENMPI_BASEVERSION}.6
RUN cd ${STAGE_DIR} && \
wget -q -O - https://download.open-mpi.org/release/open-mpi/v${OPENMPI_BASEVERSION}/openmpi-${OPENMPI_VERSION}.tar.gz | tar xzf - && \
cd openmpi-${OPENMPI_VERSION} && \
./configure --prefix=/usr/local/openmpi-${OPENMPI_VERSION} && \
make -j"$(nproc)" install && \
ln -s /usr/local/openmpi-${OPENMPI_VERSION} /usr/local/mpi && \
# Sanity check:
test -f /usr/local/mpi/bin/mpic++ && \
cd ${STAGE_DIR} && \
rm -r ${STAGE_DIR}/openmpi-${OPENMPI_VERSION}
ENV PATH=/usr/local/mpi/bin:${PATH} \
LD_LIBRARY_PATH=/usr/local/lib:/usr/local/mpi/lib:/usr/local/mpi/lib64:${LD_LIBRARY_PATH}
# Create a wrapper for OpenMPI to allow running as root by default
RUN mv /usr/local/mpi/bin/mpirun /usr/local/mpi/bin/mpirun.real && \
echo '#!/bin/bash' > /usr/local/mpi/bin/mpirun && \
echo 'mpirun.real --allow-run-as-root --prefix /usr/local/mpi "$@"' >> /usr/local/mpi/bin/mpirun && \
chmod a+x /usr/local/mpi/bin/mpirun
##############################################################################
# Python
##############################################################################
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHON_VERSION=3
RUN apt-get install -y python3 python3-dev && \
rm -f /usr/bin/python && \
ln -s /usr/bin/python3 /usr/bin/python && \
curl -O https://bootstrap.pypa.io/pip/3.6/get-pip.py && \
python get-pip.py && \
rm get-pip.py && \
pip install --upgrade pip && \
# Print python an pip version
python -V && pip -V
RUN pip install pyyaml ipython build
##############################################################################
# Some Packages
##############################################################################
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libsndfile-dev \
libcupti-dev \
libjpeg-dev \
libpng-dev \
screen \
libaio-dev
RUN pip install psutil \
yappi \
cffi \
ipdb \
pandas \
matplotlib \
py3nvml \
pyarrow \
graphviz \
astor \
boto3 \
tqdm \
sentencepiece \
msgpack \
requests \
sphinx \
sphinx_rtd_theme \
scipy \
numpy \
scikit-learn \
nvidia-ml-py3 \
mpi4py
##############################################################################
## SSH daemon port inside container cannot conflict with host OS port
###############################################################################
ENV SSH_PORT=2229
RUN cat /etc/ssh/sshd_config > ${STAGE_DIR}/sshd_config && \
sed "0,/^Port 22/s//Port ${SSH_PORT}/" ${STAGE_DIR}/sshd_config > /etc/ssh/sshd_config
##############################################################################
# PyTorch
##############################################################################
RUN pip3 install torch==2.4.1+cu124 torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu124
##############################################################################
# PyYAML build issue
# https://stackoverflow.com/a/53926898
##############################################################################
RUN rm -rf /usr/lib/python3/dist-packages/yaml && \
rm -rf /usr/lib/python3/dist-packages/PyYAML-*
##############################################################################
# DeepSpeed
##############################################################################
RUN git clone https://github.com/deepspeedai/DeepSpeed.git ${STAGE_DIR}/DeepSpeed
RUN cd ${STAGE_DIR}/DeepSpeed && \
git checkout . && \
git checkout master && \
./install.sh --pip_sudo --allow_sudo
RUN rm -rf ${STAGE_DIR}/DeepSpeed
RUN python -c "import deepspeed; print(deepspeed.__version__)"
WORKDIR /workspace
# Launch ssh server
RUN mkdir -p /run/sshd
CMD ["/usr/sbin/sshd", "-D"]
```
---
## 🔨 build.sh
```bash
docker build -t deepspeed_image_cuda_12_4 .
```
---
## 🚀 launch.sh
Перед запуском контейнера необходимо:
* 📌 Настроить `ssh config` по [инструкции](ssh_setup.md).
* 📌 При необходимости [настроить интерфейсы](interface_setup.md).
Кроме того, создаём пустую папку `volume`, в которой будут храниться файлы для DeepSpeed:
```bash
mkdir /media/Data1/common/docker/deepspeed/volume
```
---
### 📝 Скрипт launch.sh
```bash
#!/bin/bash
# Путь к директории проекта
DEEPSPEED_DIR="/media/Data1/common/docker/deepspeed"
# Имя контейнера
CONTAINER_NAME="deepspeed_container"
# Имя Docker-образа
IMAGE_NAME="deepspeed_image_cuda_12_4"
# Запуск контейнера
docker run --rm -it -d \
-w /workspace \
--name "$CONTAINER_NAME" \
--network host \
--shm-size=32g \
--runtime nvidia --gpus '"device=1"' \
-v "${DEEPSPEED_DIR}/volume":/workspace \
-v "${DEEPSPEED_DIR}/ssh_docker":/root/.ssh \
-e NCCL_SOCKET_IFNAME=10gb0,10gb1 \
"$IMAGE_NAME"
```
---
### 🔍 Что здесь происходит
| Опция | Описание |
| ------------------------------------------- | ----------------------------------------------------------------- |
| `-w /workspace` | Рабочая директория внутри контейнера. |
| `--name "$CONTAINER_NAME"` | Имя контейнера для удобства управления. |
| `--network host` | Используем сеть хоста (важно для скорости и для NCCL). |
| `--shm-size=32g` | Размер памяти `shm` для PyTorch / NCCL. |
| `--runtime nvidia --gpus ...` | Указываем Docker использовать конкретный GPU (например device=1 или all). |
| `-v ${DEEPSPEED_DIR}/volume:/workspace` | Монтируем локальную папку для данных и логов в контейнер. |
| `-v ${DEEPSPEED_DIR}/ssh_docker:/root/.ssh` | Монтируем SSH-конфиг и ключи для запуска multinode через SSH. |
| `-e NCCL_SOCKET_IFNAME=10gb0,10gb1` | Указываем интерфейсы для NCCL (10Gb). |
---
## 🔌 connect.sh
```bash
docker exec -it deepspeed_container bash
```
---
> После создания этих скриптов, не забудь сделать их исполняемыми:
```bash
chmod +x *.sh
```
---

@ -0,0 +1,227 @@
## ⚙️ Требования
* Для работы по текущему гайду необходим **драйвер NVIDIA**, поддерживающий **CUDA 12.4**.
* Кроме того, для работы DeepSpeed необходимо, чтобы **пути к файлам совпадали на всех машинах**.
В данном гайде основной путь будет:
```
/media/Data1/common/docker/deepspeed
```
и все манипуляции будут происходить относительно него.
---
## 🐳 Docker и скрипты
[Создаем Dockerfile и соответствующие скрипты для работы с образом](Dockerfile_and_scripts.md).
---
## 🌐 Hostfile для DeepSpeed
Для работы DeepSpeed на нескольких машинах необходимо создать `hostfile` и положить его в `volume` папку (чтобы был доступ из контейнеров):
```
mlnode1_ds slots=1 env="PDSH_RCMD_TYPE=ssh,NCCL_DEBUG=INFO,NCCL_CROSS_NIC=0"
mlnode2_ds slots=1 env="PDSH_RCMD_TYPE=ssh,NCCL_DEBUG=INFO,NCCL_CROSS_NIC=0"
```
Здесь:
* `mlnode1_ds` и `mlnode2_ds` — это хосты, определённые в нашем `ssh config`.
* `slots=1` — число GPU, выделяемых для этой ноды.
* `env=...` — дополнительные переменные для DeepSpeed и NCCL.
---
## 🚀 Запуск
При запуске мы должны передавать:
* `hostfile`
* файл скрипта (например, `train.py`)
* и `deepspeed_config.json`
Пример скрипта запуска — `run.sh`:
```bash
#!/bin/bash
deepspeed --hostfile hostfile train.py --deepspeed --deepspeed_config deepspeed_config.json
```
---
## 🛠 Рекомендуемые настройки перед запуском
Перед запуском рекомендуется выполнить [следующие действия](additional_settings.md), чтобы избежать ошибок.
---
## 🧪 Примеры для теста
Ниже приведены два минимальных примера для проверки работоспособности кластера:
* Легковесный (`batch_size=4`, `hidden_dim=16`).
* Потяжелее (`batch_size=64`, `hidden_dim≈1024`).
---
### ⚡ Пример 1: Лёгкий тест
#### `deepspeed_config.json`
```json
{
"train_batch_size": 4,
"gradient_accumulation_steps": 1,
"fp16": {
"enabled": false
},
"zero_optimization": {
"stage": 0
},
"optimizer": {
"type": "Adam",
"params": {
"lr": 0.001
}
}
}
```
#### `train.py`
```python
import torch
import torch.nn as nn
from torch.utils.data import Dataset
import deepspeed
import argparse
class RandomDataset(Dataset):
def __init__(self, num_samples=16, in_dim=10):
self.x = torch.randn(num_samples, in_dim)
self.y = torch.randn(num_samples, 1)
def __getitem__(self, idx):
return self.x[idx], self.y[idx]
def __len__(self):
return len(self.x)
class SimpleModel(nn.Module):
def __init__(self, hidden_dim=16):
super().__init__()
self.linear = nn.Linear(10, hidden_dim)
self.relu = nn.ReLU()
self.output = nn.Linear(hidden_dim, 1)
def forward(self, x):
return self.output(self.relu(self.linear(x)))
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--local_rank', type=int, default=-1)
parser = deepspeed.add_config_arguments(parser)
args = parser.parse_args()
model = SimpleModel()
model, _, trainloader, _ = deepspeed.initialize(
args=args,
model=model,
training_data=RandomDataset(num_samples=20)
)
for epoch in range(10):
for x, y in trainloader:
inputs = x.to(model.device)
targets = y.to(model.device)
outputs = model(inputs)
loss = nn.MSELoss()(outputs, targets)
model.backward(loss)
model.step()
if model.global_rank == 0:
print(f"Epoch {epoch:02d} - Loss: {loss.item():.4f}")
if __name__ == "__main__":
main()
```
---
### 🚀 Пример 2: Более тяжёлый тест
#### `deepspeed_config.json`
```json
{
"train_batch_size": 64,
"train_micro_batch_size_per_gpu": 32,
"steps_per_print": 10,
"optimizer": {
"type": "AdamW",
"params": {
"lr": 1e-3
}
},
"fp16": {
"enabled": false
}
}
```
#### `train.py`
```python
#!/usr/bin/env python3
import torch, torch.nn as nn
from torch.utils.data import DataLoader, Dataset
import deepspeed
import argparse
class RandomDataset(Dataset):
def __init__(self, num_samples=1024, in_dim=128):
self.x = torch.randn(num_samples, in_dim)
self.y = torch.randint(0, 2, (num_samples,))
def __getitem__(self, idx):
return self.x[idx], self.y[idx]
def __len__(self):
return len(self.x)
class TinyNet(nn.Module):
def __init__(self, in_dim=128, n_classes=2):
super().__init__()
hidden_dim = 1024
self.layers = nn.Sequential(
nn.Linear(in_dim, hidden_dim),
*[nn.Linear(hidden_dim, hidden_dim) for _ in range(8)],
nn.Linear(hidden_dim, n_classes)
)
def forward(self, x):
return self.layers(x)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--num_epochs", type=int, default=30)
parser.add_argument('--local_rank', type=int, default=-1)
parser = deepspeed.add_config_arguments(parser)
args = parser.parse_args()
model_engine, _, trainloader, _ = deepspeed.initialize(
args=args,
model=TinyNet(),
training_data=RandomDataset(num_samples=2048)
)
loss_fn = nn.CrossEntropyLoss()
for epoch in range(args.num_epochs):
for x, y in trainloader:
x, y = x.to(model_engine.device), y.to(model_engine.device)
y_hat = model_engine(x)
loss = loss_fn(y_hat, y)
model_engine.backward(loss)
model_engine.step()
if model_engine.global_rank == 0:
print(f"Epoch {epoch:02d}: loss={loss.item():.4f}")
```
---

@ -0,0 +1,128 @@
## 🚫 Отключение IPv6
Если у сетевых интерфейсов настроены IPv6-адреса, `DeepSpeed` и `NCCL` могут пытаться использовать их для межнодового обмена, что часто приводит к ошибкам соединения или подвисаниям, особенно если IPv6 на вашей сети фактически не используется. Чтобы этого избежать, рекомендуется полностью отключить IPv6 на всех машинах.
### Как отключить IPv6 на Ubuntu
Откройте (или создайте) файл `/etc/sysctl.conf`:
```bash
sudo vim /etc/sysctl.conf
```
Добавьте в конец файла:
```ini
# Disable IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
```
Примените изменения:
```bash
sudo sysctl -p
```
После этого проверьте, что IPv6 отключён:
```bash
ip a | grep inet6
```
Ничего не должно выводиться.
---
## 🔥 Разрешение портов в файрволе
Если после настройки SSH и передачи интерфейсов через `-e NCCL_SOCKET_IFNAME=10gb0,10gb1` связь между машинами всё равно не устанавливается, причиной может быть блокировка портов файрволом. Для работы `NCCL` и `DeepSpeed` требуются открытые диапазоны TCP и UDP портов (по умолчанию в пределах `~1024-65535`).
### Проверяем и настраиваем UFW
Смотрим статус:
```bash
sudo ufw status verbose
```
Если включён, то разрешаем весь трафик на интерфейсе `10gb0`:
```bash
sudo ufw allow in on 10gb0
sudo ufw allow out on 10gb0
```
И аналогично для `10gb1`:
```bash
sudo ufw allow in on 10gb1
sudo ufw allow out on 10gb1
```
После чего перезагружаем UFW:
```bash
sudo ufw reload
```
---
### Проверяем и настраиваем iptables
Посмотреть текущие правила:
```bash
sudo iptables -L -v -n
```
Открыть весь трафик для интерфейсов:
```bash
sudo iptables -A INPUT -i 10gb0 -j ACCEPT
sudo iptables -A OUTPUT -o 10gb0 -j ACCEPT
sudo iptables -A INPUT -i 10gb1 -j ACCEPT
sudo iptables -A OUTPUT -o 10gb1 -j ACCEPT
```
Сохранить правила (Ubuntu):
```bash
sudo iptables-save | sudo tee /etc/iptables/rules.v4
```
---
### Проверяем и настраиваем nftables
Если у вас используется `nftables`, посмотреть таблицы можно так:
```bash
sudo nft list ruleset
```
Добавить разрешающие правила:
```bash
sudo nft add rule inet filter input iifname "10gb0" accept
sudo nft add rule inet filter output oifname "10gb0" accept
sudo nft add rule inet filter input iifname "10gb1" accept
sudo nft add rule inet filter output oifname "10gb1" accept
```
Либо только для определенных портов для Docker:
```bash
sudo nft add rule ip filter DOCKER tcp dport 48000-48031 ip saddr 172.16.45.0/24 accept
sudo nft add rule ip filter DOCKER tcp sport 48000-48031 ip saddr 172.16.45.0/24 accept
```
После чего сохранить:
```bash
sudo nft list ruleset > /etc/nftables.conf
sudo systemctl restart nftables
```
---
После всех этих действий повторите запуск `DeepSpeed` / `torchrun` и проверьте обмен между нодами.

@ -0,0 +1,260 @@
# 🚀 Полный гайд по настройке 10Gb интерфейсов и статических IP
---
## 🔄 Шаг 1. Переименовать интерфейсы на лету (без ребута)
### 1.1 На первой машине (node1)
```bash
sudo ip link set enp37s0f1 down
sudo ip link set enp37s0f1 name 10gb0
sudo ip link set 10gb0 up
```
---
### 4.2 На второй машине (node2)
```bash
sudo ip link set enp37s0f0 down
sudo ip link set enp37s0f0 name 10gb1
sudo ip link set 10gb1 up
```
---
### 4.3 Проверить
```bash
ip a
```
Ты должен увидеть:
На node1:
```
3: 10gb0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 7c:10:c9:47:05:71 brd ff:ff:ff:ff:ff:ff
```
На node2:
```
3: 10gb1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 7c:10:c9:47:05:03 brd ff:ff:ff:ff:ff:ff
```
---
**Важно:**
* IP останется привязан к интерфейсу, только имя сменится.
* Если интерфейс сейчас используется для SSH, есть риск обрыва. Делай через локальную консоль или другой интерфейс.
---
## 🔧 Шаг 2. Сохранить новое имя интерфейса после перезагрузки через `.link`
---
### 2.1 Создать `.link` файл на node1
```bash
sudo vim /etc/systemd/network/10gb0.link
```
И вставить:
```ini
[Match]
MACAddress=7c:10:c9:47:05:71
[Link]
Name=10gb0
```
---
### 2.2 Аналогично на node2
```bash
sudo vim /etc/systemd/network/10gb1.link
```
И вставить:
```ini
[Match]
MACAddress=7c:10:c9:47:05:03
[Link]
Name=10gb1
```
---
## 📝 Шаг 3. Назначить IPv4 на интерфейсы
### На первой машине (node1)
```bash
sudo ip addr add 172.16.45.5/24 dev 10gb0
```
### На второй машине (node2)
```bash
sudo ip addr add 172.16.45.3/24 dev 10gb1
```
✅ Теперь:
* Сеть `172.16.45.0/24` будет видна через эти интерфейсы.
* Трафик между `172.16.45.5` и `172.16.45.3` пойдёт **напрямую**, минуя роутер — через твой 10Gb линк.
---
## 🛠 Шаг 4. Проверить соединение
С первой машины:
```bash
ping 172.16.45.3
```
Или наоборот — со второй.
---
Конечно! Вот твой пункт **расширенный и приведённый в общий вид для двух разных систем**, включая твой случай с NetworkManager на **node1** и классический netplan на **node2**.
---
## 🗄 Шаг 5. Сделать IP-адреса постоянными
---
### ⚙ Для node1 (NetworkManager)
Тут ты используешь Ubuntu Desktop (или Server c включённым NM), где сетями рулит NetworkManager. Так что статический IP для интерфейса нужно настроить с помощью `nmcli`.
#### 5.1 Создать профиль для интерфейса 10gb0
```bash
sudo nmcli con add type ethernet ifname 10gb0 con-name 10gb0-static \
ipv4.method manual ipv4.addresses 172.16.45.5/24 \
ipv4.dns "8.8.8.8 8.8.4.4" autoconnect yes
```
> Если для этой сети **не нужен gateway**, задай явно пустой:
```bash
sudo nmcli con mod 10gb0-static ipv4.gateway ""
```
---
#### 5.2 Подключить профиль
```bash
sudo nmcli con up 10gb0-static
```
---
#### 5.3 Проверить состояние интерфейса
```bash
nmcli device show 10gb0
```
Там должно появиться:
```
GENERAL.CONNECTION: 10gb0-static
IP4.ADDRESS[1]: 172.16.45.5/24
...
```
---
### ⚙ Для node2 (Netplan, Ubuntu 20.04+)
---
Для конскольной версии Ubuntu будем использовать `netplan`.
#### 5.4 Найти netplan конфиг
Посмотри список файлов:
```bash
ls /etc/netplan/
```
Например:
```
00-installer-config.yaml
```
---
#### 5.5 Отредактировать конфиг
Открой файл в редакторе:
```bash
sudo vim /etc/netplan/00-installer-config.yaml
```
---
#### 5.6 Добавить настройки интерфейса 10gb1
Добавь блок с настройками для `10gb1`:
```yaml
network:
version: 2
ethernets:
enp37s0f0:
dhcp4: true
enp37s0f1:
dhcp4: true
enx82ac094db1f5:
dhcp4: true
10gb1:
dhcp4: no
addresses:
- 172.16.45.3/24
nameservers:
addresses: [8.8.8.8, 8.8.4.4]
```
> ⚠ Если для этой подсети **шлюз не нужен**, можешь не добавлять `gateway4`.
---
#### 5.7 Применить конфигурацию
```bash
sudo netplan apply
```
---
#### 5.8 Проверить интерфейс
```bash
ip a s 10gb1
```
---
Теперь у тебя **node1 управляется через NetworkManager**, а **node2 через Netplan**, и на обоих IP-адреса будут сохраняться после перезагрузки.
---

@ -0,0 +1,112 @@
# 🚀 Гайд по созданию SSH-ключей и конфигов для DeepSpeed
Этот гайд помогает настроить SSH между двумя узлами для запуска DeepSpeed в Docker-контейнерах. Все шаги повторяются на обеих машинах (`mlnode1` и `mlnode2`).
---
## 1⃣ Создаем папки для SSH
Перейдите в директорию вашего проекта (например, `deepspeed`) и создайте структуру для хранения ключей и конфигов:
```bash
cd /media/Data1/common/docker/deepspeed
mkdir -p ssh_docker/keys
```
---
## 2⃣ Генерируем SSH-ключи
Создаем ключ по алгоритму `ed25519` с названием `deepspeed` и сохраняем его в `ssh_docker/keys`.
```bash
ssh-keygen -t ed25519 -f ssh_docker/keys/deepspeed -N ""
```
---
## 3⃣ Создаем SSH config
Создаем файл `ssh_docker/config` и записываем туда конфигурацию для ваших узлов.
**Пример:**
```bash
cat > ssh_docker/config << EOF
Host mlnode1_ds
HostName 172.16.45.5
User root
Port 2229
IdentityFile ~/.ssh/keys/deepspeed
StrictHostKeyChecking no
Host mlnode2_ds
HostName 172.16.45.3
User root
Port 2229
IdentityFile ~/.ssh/keys/deepspeed
StrictHostKeyChecking no
EOF
```
* `HostName` — IP-адрес интерфейса, по которому будет идти соединение. Узнать его можно через:
```bash
ip a
```
* `Port` — порт, который вы указывали в `Dockerfile` для SSH (например `2229`).
---
## 4⃣ Аналогично на второй машине
Повторите шаги **1-3** на второй машине.
Убедитесь, что IP-адреса в `HostName` соответствуют интерфейсам для связи между нодами.
---
## 5⃣ Обмениваемся публичными ключами
Создайте на обеих машинах файл `ssh_docker/authorized_keys` и добавьте туда публичный ключ второй машины.
* На `mlnode1` добавьте публичный ключ `mlnode2`:
* На `mlnode2` добавьте публичный ключ `mlnode1`:
```bash
cat ssh_docker/keys/deepspeed.pub
```
Для обмена можно использовать `scp` или просто скопировать содержимое `deepspeed.pub` вручную.
---
## 6⃣ Выставляем права и владельца
Чтобы SSH корректно работал, выставим права на папку и файлы:
```bash
sudo chmod 700 ssh_docker
sudo chmod 700 ssh_docker/keys
sudo chmod 600 ssh_docker/keys/deepspeed
sudo chmod 644 ssh_docker/keys/deepspeed.pub
sudo chmod 644 ssh_docker/config
sudo chmod 600 ssh_docker/authorized_keys
sudo chown -R root:root ssh_docker
```
---
## 7⃣ Использование в Docker
Эту папку можно монтировать в контейнер как volume для использования SSH.
Например:
```yaml
volumes:
- /media/Data1/common/docker/deepspeed/ssh_docker:/root/.ssh
```
---
Loading…
Cancel
Save