commit 311bf593b64a31f72428994e5fc60b71323f8728 Author: laynholt Date: Wed Jul 2 15:35:29 2025 +0000 базовая настройка diff --git a/Dockerfile_and_scripts.md b/Dockerfile_and_scripts.md new file mode 100644 index 0000000..52672f1 --- /dev/null +++ b/Dockerfile_and_scripts.md @@ -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 +``` + +--- \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..77408fd --- /dev/null +++ b/README.md @@ -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}") +``` + +--- + diff --git a/additional_settings.md b/additional_settings.md new file mode 100644 index 0000000..83ca48b --- /dev/null +++ b/additional_settings.md @@ -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` и проверьте обмен между нодами. \ No newline at end of file diff --git a/interface_setup.md b/interface_setup.md new file mode 100644 index 0000000..7f12d8a --- /dev/null +++ b/interface_setup.md @@ -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: 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: 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-адреса будут сохраняться после перезагрузки. + +--- + + diff --git a/ssh_setup.md b/ssh_setup.md new file mode 100644 index 0000000..d007171 --- /dev/null +++ b/ssh_setup.md @@ -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 +``` + +--- +