1. Disk Handling
1.1 Inspect Disks
Disk /dev/nvme1n1: 3.91 TiB, 4294967296000 bytes, 8388608000 sectors
1.2 Build a RAID0
If you have several small disks, a better approach is to build a RAID0 — this gives you not only a larger storage directory but also higher speed.
1
| mdadm --create --verbose /dev/md0 --level=0 --raid-devices=3 /dev/nvme1n1 /dev/nvme2n1 /dev/nvme3n1
|
1
| mdadm --detail /dev/md0
|
1.3 Mount the Disk
1
| mkfs.xfs -f /dev/nvme1n1
|
or
mkfs.ext4 /dev/nvme1n1
xfs is suited to large-file workloads, ext4 to small and medium files.
For a RAID0 you can run mkfs.xfs -f /dev/md0 .
- Create the mount directory
1
2
| UUID=$(blkid -s UUID -o value /dev/nvme1n1)
echo $UUID
|
1
| grep -q "$UUID" /etc/fstab || echo "UUID=$UUID /data xfs defaults,nofail 0 2" >> /etc/fstab
|
or
1
| grep -q "$UUID" /etc/fstab || echo "UUID=$UUID /data ext4 defaults,nofail 0 2" >> /etc/fstab
|
1
2
3
| df -h |grep data
/dev/nvme1n1 4.0T 28G 3.9T 1% /data
|
2. Drivers and Configuration
2.1 Check Whether the System Recognizes the NPU
1
| 18:00.0 Processing accelerators: Huawei Technologies Co., Ltd. Device d802 (rev 20)
|
The device is identified as a Huawei Ascend NPU.
2.2 Install the Driver
- Create the HwHiAiUser user
1
2
| groupadd -g 1000 HwHiAiUser
useradd -g HwHiAiUser -u 1000 -d /home/HwHiAiUser -m HwHiAiUser -s /bin/bash
|
- Add directory permissions
1
2
| chown -R HwHiAiUser /usr/local/Ascend
chmod -R 755 /usr/local/Ascend
|
- Download the driver and firmware
Go to https://www.hiascend.com/hardware/firmware-drivers/community?product=4&model=26&cann=9.0.0-beta.1&driver=Ascend+HDK+25.5.1 to find the matching driver and firmware.
1
| bash ./Ascend-hdk-910b-npu-driver_25.5.1_linux-x86-64.run --full --install-for-all
|
1
| bash ./Ascend-hdk-910b-npu-firmware_7.8.0.6.201.run --full
|
- Verify that the installation succeeded
2.3 Disable TLS
1
| for i in {0..15};do hccn_tool -i $i -tls -s enable 0;done
|
1
| for i in {0..15};do hccn_tool -i $i -tls -g| grep 'switch';done
|
2.4 Check the IP
1
| for i in {0..15};do hccn_tool -i $i -ip -g;done
|
1
| for i in {0..15};do hccn_tool -i $i -gateway -g;done
|
2.5 NIC Health Status
1
| for i in {0..15};do npu-smi info -t health -i $i -c 0| grep 'Health Status';done
|
To see the specific reason: npu-smi info -t health -i -c 0
1
| for i in {0..15};do hccn_tool -i $i -link -g;done
|
1
| for i in {0..15};do hccn_tool -i $i -net_health -g;done
|
1
| for i in {0..15};do npu-smi info -t ecc -i $i;done
|
ECC counts cause program error 0x80E18005.
3. Installing ascend-docker-runtime
3.1 Install ascend-docker-runtime
- Download ascend-docker-runtime
Go to https://gitcode.com/Ascend/mind-cluster/releases to find the download link for the matching architecture.
1
| wget https://gitcode.com/Ascend/mind-cluster/releases/download/v26.1.0.beta.2/Ascend-docker-runtime_26.1.0.beta.2_linux-x86_64.run
|
- Install ascend-docker-runtime
1
| bash ./Ascend-docker-runtime_26.1.0.beta.2_linux-x86_64.run --install
|
3.2 Install Containerd
1
2
| apt-get update
apt-get install -y ca-certificates curl gnupg lsb-release
|
In China:
1
2
| mkdir -p /etc/apt/keyrings
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
1
2
3
4
| echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/ \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
1
2
| apt update
apt install containerd.io=1.6.31-1
|
- Generate the containerd config file (toml)
1
2
| mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
|
- Modify the containerd config file
1
2
3
4
| sed -i 's#root = "/var/lib/containerd"#root = "/data/containerd"#g' /etc/containerd/config.toml
sed -i 's#state = "/run/containerd"#state = "/data/run/containerd"#g' /etc/containerd/config.toml
sed -i 's#sandbox_image = "registry.k8s.io/pause:[^"]*"#sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"#g' /etc/containerd/config.toml
sed -i 's#SystemdCgroup = false#SystemdCgroup = true#g' /etc/containerd/config.toml
|
- Change the runtime to ascend
1
| sed -i 's#runtime = "runc"#runtime = "/usr/local/Ascend/Ascend-Docker-Runtime/ascend-docker-runtime"#g' /etc/containerd/config.toml
|
1
2
| systemctl daemon-reload
systemctl restart containerd
|
3.3 Docker Configuration [Optional]
Choose either Docker or Containerd.
- Update the Docker configuration
1
| vim /etc/docker/daemon.json
|
Add the following:
1
2
3
4
5
6
7
8
9
10
| {
"default-runtime": "ascend",
"data-root": "/data/docker",
"runtimes": {
"ascend": {
"path": "/usr/local/Ascend/Ascend-Docker-Runtime/ascend-docker-runtime",
"runtimeArgs": []
}
}
}
|
1
2
| systemctl daemon-reload
systemctl restart docker
|
3.4 Verifying with hccl_test
1
| export IMAGE=shaowenchen/demo:hccl-test-8.0.RC2-ubuntu22.04
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| nerdctl run --security-opt apparmor=unconfined --security-opt seccomp=unconfined --rm -it --ipc=host \
--device=/dev/davinci0 \
--device=/dev/davinci1 \
--device=/dev/davinci2 \
--device=/dev/davinci3 \
--device=/dev/davinci4 \
--device=/dev/davinci5 \
--device=/dev/davinci6 \
--device=/dev/davinci7 \
--device=/dev/davinci8 \
--device=/dev/davinci9 \
--device=/dev/davinci10 \
--device=/dev/davinci11 \
--device=/dev/davinci12 \
--device=/dev/davinci13 \
--device=/dev/davinci14 \
--device=/dev/davinci15 \
--device=/dev/davinci_manager \
--device=/dev/devmm_svm \
--device=/dev/hisi_hdc \
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
-v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \
-v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
-v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \
-v /var/log/npu/slog/:/var/log/npu/slog \
-v /var/log/npu/profiling/:/var/log/npu/profiling \
-v /var/log/npu/dump/:/var/log/npu/dump \
-v /var/log/npu/:/usr/slog \
${IMAGE} \
/bin/bash
|
1
2
3
4
5
| export HCCL_RDMA_TC=100
export HCCL_RDMA_SL=3
export HCCL_BUFFSIZE=2048
export HCCL_PROC=16
mpirun -n ${HCCL_PROC} /usr/local/Ascend/ascend-toolkit/latest/tools/hccl_test/bin/all_reduce_test -b 8K -e 64M -f 2 -d fp32 -o sum -p ${HCCL_PROC}
|
4. Joining the K8s Cluster
4.1 Change the Hostname
1
| export HOSTNAME=k8s-worker-npu-01
|
1
| hostnamectl set-hostname ${HOSTNAME}
|
Create the working directory for the device management plugin
1
| mkdir -p /var/log/mindx-dl/devicePlugin
|
4.2 Initialize Kernel Parameters
1
| opscli task -f ~/.ops/tasks/set-host.yaml
|
4.3 Install the Base K8s Components
https://developer.aliyun.com/mirror/kubernetes/ — add this for versions below 1.28
1
| curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/kubernetes-aliyun.gpg
|
1
2
3
| cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
|
- Symlink the kubelet directory
1
2
| mkdir -p /data/kubelet
ln -s /data/kubelet /var/lib/kubelet
|
- Install the base K8s components
1
| export K8S_VERSION=1.27.6
|
1
| apt-get install kubeadm=${K8S_VERSION}-00 kubelet=${K8S_VERSION}-00 kubectl=${K8S_VERSION}-00 -y
|
1
| vim /var/lib/kubelet/kubeadm-flags.env
|
Add the following:
1
| --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9 --resolv-conf=/etc/resolv.conf --authentication-token-webhook=true --authorization-mode=Webhook --system-reserved=cpu=1,memory=2Gi --kube-reserved=cpu=1,memory=2Gi --cpu-manager-policy=static
|
1
| --topology-manager-policy=best-effort --topology-manager-scope=container --feature-gates=TopologyManager=true,CPUManager=true,MemoryManager=true
|
topology-manager-policy can be best-effort (satisfy if possible), restricted (one resource does not cross nodes), or single-numa-node (no resource crosses nodes).
topology-manager-scope can be container (satisfied at the container level) or all containers within the pod.
feature-gates can be TopologyManager=true,CPUManager=true,MemoryManager=true to enable topology management, CPU management, and memory management.
In the kubelet configuration above, add the --node-ip= parameter to specify the node IP address and the --hostname-override= parameter to specify the node Hostname.
1
| --node-ip=x.x.x.x --hostname-override=my-hostname
|
With Flannel, you need to add the --iface= parameter to the DeamonSet to specify the NIC.
1
2
3
4
5
6
7
| containers:
- args:
- --ip-masq
- --kube-subnet-mgr
- --iface-regex=^10\.0\.
command:
- /opt/bin/flanneld
|
1
2
3
4
| systemctl enable kubelet
systemctl daemon-reload
systemctl restart kubelet
systemctl status kubelet
|
4.4 Join the Cluster
Generate the token on the master node
1
| kubeadm token create --print-join-command
|
1
2
| kubeadm join x.x.x.x:6443 --token xxx \
--discovery-token-ca-cert-hash sha256:xxx
|
In a Docker environment, you need to pass the --cri-socket parameter.
1
| --cri-socket unix:///var/run/cri-dockerd.sock
|
In a Containerd environment:
1
| --cri-socket unix:///run/containerd/containerd.sock -v5
|
If you get the error [ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables does not exist, run this.
1
2
3
| modprobe br_netfilter
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
echo 1 > /proc/sys/net/ipv4/ip_forward
|
6. Deploying k8s Plugins
6.1 Install the device-plugin to register huawei.com/Ascend910
1
| kubectl apply -f https://raw.githubusercontent.com/shaowenchen/ops-hub/master/ascend/v7.1.RC1-device-plugin-910.yaml
|
1
| kubectl -n kube-system edit ds ascend-device-plugin-daemonset-910
|
1
| -useAscendDocker=false -volcanoType=false
|
The plugin contains runtime- and volcano-related configuration that needs to be adjusted for your environment
6.2 Install rdma-shared-dev-plugin to register rdma/ib
To let Kubernetes discover RDMA devices such as InfiniBand and share them among multiple Pods, you need to install k8s-rdma-shared-dev-plugin.
- Install k8s-rdma-shared-dev-plugin
1
| kubectl apply -f https://raw.githubusercontent.com/shaowenchen/ops-hub/master/network/k8s-rdma-shared-dev-plugin.yaml
|
- Modify the configuration file
1
| kubectl -n kube-system edit cm rdma-devices
|
6.3 Create a Test Pod
1
| export IMAGE=shaowenchen/demo:hccl-test-8.0.RC2-ubuntu22.04
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| kubectl create -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
generateName: npu-demo-
labels:
app: npu-demo
spec:
nodeName: ${HOSTNAME}
hostIPC: true
containers:
- name: npu-demo
image: ${IMAGE}
command: ["/bin/bash", "-c", "sleep infinity"]
securityContext:
privileged: true
resources:
requests:
huawei.com/Ascend910: 4
limits:
huawei.com/Ascend910: 4
volumeMounts:
- mountPath: /usr/local/bin/npu-smi
name: npu-smi
readOnly: true
- mountPath: /usr/local/Ascend/driver
name: ascend-driver
readOnly: true
volumes:
- name: npu-smi
hostPath:
path: /usr/local/bin/npu-smi
- name: ascend-driver
hostPath:
path: /usr/local/Ascend/driver
EOF
|
1
| kubectl get pod -l app=npu-demo
|
1
| kubectl exec -it npu-demo-pm28m npu-smi info
|
1
| kubectl delete pod -l app=npu-demo
|
- Lock the CPU to the high-performance frequency mode; the downside is higher power consumption
Temporarily set the CPU to the locked high-performance mode
1
2
3
| for cpu in /sys/devices/system/cpu/cpu[0-9]*; do
echo performance | sudo tee $cpu/cpufreq/scaling_governor
done
|
Permanently set the CPU to the locked high-performance mode
1
| apt-get install tuned -y
|
1
| tuned-adm profile throughput-performance
|
Check the CPU operating mode
1
| cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
|
- System THP tuning; the downside is reduced memory utilization
Disable or tune THP (Transparent Huge Pages) automatic compaction to prevent kernel background defrag from causing latency stalls and periodic latency jitter.
Temporarily disable THP
1
2
| echo defer > /sys/kernel/mm/transparent_hugepage/defrag
echo 'defer+madvise' > /sys/kernel/mm/transparent_hugepage/defrag
|
Permanently disable THP
1
| echo never > /sys/kernel/mm/transparent_hugepage/defrag
|
Check the THP status
1
| cat /sys/kernel/mm/transparent_hugepage/defrag
|
- NIC ring buffer (packet loss issue); the downside is a larger buffer and increased network latency
The default value is usually 256 or 512, which is too small for high-speed 10G/100G NICs.
Temporarily set the NIC ring buffer
1
2
| ethtool -G eth0 rx 8192 tx 8192
ethtool -G eth1 rx 8192 tx 8192
|
Permanently set the NIC ring buffer
1
2
3
4
5
6
| cat >/etc/ethtool-ring.sh <<'EOF'
#!/bin/bash
ethtool -G eth0 rx 8192 tx 8192 || true
ethtool -G eth1 rx 8192 tx 8192 || true
EOF
chmod +x /etc/ethtool-ring.sh
|
Or configure bond0
1
2
3
4
5
6
7
8
9
| cat >/etc/ethtool-ring.sh <<'EOF'
#!/bin/bash
SLAVES=$(cat /sys/class/net/bond0/bonding/slaves 2>/dev/null)
for eth in $SLAVES; do
ethtool -G $eth rx 8192 tx 8192 || true
done
EOF
chmod +x /etc/ethtool-ring.sh
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| cat >/etc/systemd/system/ethtool-ring.service <<'EOF'
[Unit]
Description=Set NIC ring buffer size
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/etc/ethtool-ring.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable ethtool-ring.service
systemctl start ethtool-ring.service
|
Check the NIC ring buffer
1
2
| ethtool -g eth0
ethtool -g eth1
|
Check the bond0 NIC ring buffer
1
2
3
4
5
| SLAVES=$(cat /sys/class/net/bond0/bonding/slaves 2>/dev/null)
for eth in $SLAVES; do
ethtool -g $eth || true
done
|
- Change the machine clocksource from hpet to tsc; the downside is possible desynchronization on old CPUs or multi-CPU systems
TSC (Time Stamp Counter) is a CPU built-in timer with extremely fast access and low latency (nanosecond level)
Temporarily set the clocksource
1
| echo tsc | tee /sys/devices/system/clocksource/clocksource0/current_clocksource
|
Permanently set the clocksource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| cat >/etc/systemd/system/clocksource-tsc.service <<'EOF'
[Unit]
Description=Set clocksource to tsc
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo tsc > /sys/devices/system/clocksource/clocksource0/current_clocksource'
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable clocksource-tsc.service
systemctl start clocksource-tsc.service
|
Check the current clocksource
1
| cat /sys/devices/system/clocksource/clocksource0/current_clocksource
|
This is usually adjusted in the BMC (out-of-band management) or the BIOS.
- Kernel memory and scheduler tuning
Lower the swap tendency so training is not slowed down by swapping; disable automatic NUMA balancing to reduce the jitter caused by pages migrating across nodes.
Temporarily set
1
2
3
| sysctl -w vm.swappiness=0
sysctl -w kernel.numa_balancing=0
echo 50000 > /sys/kernel/debug/sched/migration_cost_ns
|
Permanently set vm.swappiness and kernel.numa_balancing
1
2
3
4
5
6
| cat >/etc/sysctl.d/99-npu-perf.conf <<'EOF'
vm.swappiness = 0
kernel.numa_balancing = 0
EOF
sysctl -p /etc/sysctl.d/99-npu-perf.conf
|
Permanently set migration_cost_ns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| cat >/etc/systemd/system/sched-migration-cost.service <<'EOF'
[Unit]
Description=Set sched migration_cost_ns
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo 50000 > /sys/kernel/debug/sched/migration_cost_ns'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable sched-migration-cost.service
systemctl start sched-migration-cost.service
|
Check the current configuration
1
2
| sysctl vm.swappiness kernel.numa_balancing
cat /sys/kernel/debug/sched/migration_cost_ns
|
8. References
- https://ascend.github.io/docs/sources/ascend/quick_install.html
- https://gitee.com/ascend/ascend-docker-runtime