2026-04-03 11:25:31
自己构建的 ceph 发现 mon 起不来,报错如下:
Apr 03 11:14:30 debian systemd[1]: Started Ceph cluster monitor daemon.
░░ Subject: A start job for unit [email protected] has finished successfully
░░ Defined-By: systemd
░░ Support: https://www.debian.org/support
░░
░░ A start job for unit [email protected] has finished successfully.
░░
░░ The job identifier is 6997.
Apr 03 11:14:31 debian ceph-mon[374601]: 2026-04-03T11:14:31.084+0800 ffffaf907040 -1 load: jerasure load: lrc load dlopen(/usr/lib/ceph/erasure-code/libec_isa.so): /usr/lib/ceph/erasure-code/libec_isa.so: cannot make segment writable for relocation: Operation not permitted
Apr 03 11:14:31 debian systemd[1]: [email protected]: Main process exited, code=exited, status=1/FAILURE
░░ Subject: Unit process exited
░░ Defined-By: systemd
░░ Support: https://www.debian.org/support
░░
░░ An ExecStart= process belonging to unit [email protected] has exited.
░░
░░ The process' exit code is 'exited' and its exit status is 1.
Apr 03 11:14:31 debian systemd[1]: [email protected]: Failed with result 'exit-code'.
░░ Subject: Unit failed
░░ Defined-By: systemd
░░ Support: https://www.debian.org/support
░░
░░ The unit [email protected] has entered the 'failed' state with result 'exit-code'.
根据 claude-sonnet 4.6 的说法:
现在最快能让服务跑起来的办法就是 systemd override,直接关掉那个内存保护:
bashmkdir -p /etc/systemd/system/[email protected]/
cat > /etc/systemd/system/[email protected]/override.conf << 'EOF'
[Service]
MemoryDenyWriteExecute=false
EOF
systemctl daemon-reload
systemctl restart ceph-mon@$(hostname)
systemctl status ceph-mon@$(hostname)
同样的问题也会出现在 ceph-osd 和 ceph-mds,可以一并处理。
for svc in ceph-mon ceph-osd ceph-mds; do
mkdir -p /etc/systemd/system/${svc}@.service.d/
cat > /etc/systemd/system/${svc}@.service.d/override.conf << 'EOF'
[Service]
MemoryDenyWriteExecute=false
EOF
done
systemctl daemon-reload
systemctl restart ceph-mon@$(hostname)
这个方法不需要重新编译,直接解决 Operation not permitted 的问题。
MemoryDenyWriteExecute=false 只是关闭了一个进程级别的内存安全加固选项,它的作用是:阻止进程将同一块内存页同时标记为"可写"和"可执行"。
唯一的代价是理论上轻微降低了安全加固等级,即如果 ceph-mon 进程被攻击者利用漏洞控制,攻击者稍微容易一点点注入可执行代码。对于内网存储集群这个风险几乎可以忽略。
这个办法可以临时解决,但不确定是否有风险,需要充分验证后再使用。
下面给出了一个彻底解决方案:
唯一正确的根本解法:编译时禁用 ISA 插件
在 debian/rules 里找到 cmake 参数,加入 -DWITH_EC_ISA_PLUGIN=OFF:
bashgrep -n "cmake\|CMAKE" ~/build-ceph/ceph/ceph-16.2.7/debian/rules | head -20
找到 cmake 调用的那行,加入该参数后重新编译。
永久解决方案暂未验证。
2026-04-01 22:26:36
[TOC]
[root@master1 ~]# kubectl -n kube-system describe pod ascend-device-plugin-ll46f
Name: ascend-device-plugin-ll46f
Namespace: kube-system
Priority: 2000001000
Priority Class Name: system-node-critical
Service Account: ascend-device-plugin-sa
Node: master1/10.17.30.131
Start Time: Mon, 30 Mar 2026 11:08:32 +0800
Labels: app.kubernetes.io/managed-by=npu-operator
controller-revision-hash=7df5dcb887
helm.sh/chart=npu-operator-0.15.0
name=ascend-device-plugin-ds
pod-template-generation=1
Annotations: cni.projectcalico.org/containerID: c1f2adcaeaaf2bdcf0a6e09730f68231a293074e31d58f61997f714dfb520878
cni.projectcalico.org/podIP: 192.168.137.118/32
cni.projectcalico.org/podIPs: 192.168.137.118/32
scheduler.alpha.kubernetes.io/critical-pod:
seccomp.security.alpha.kubernetes.io/pod: runtime/default
Status: Running
IP: 192.168.137.118
IPs:
IP: 192.168.137.118
Controlled By: DaemonSet/ascend-device-plugin
Init Containers:
init-permission:
Container ID: containerd://4406968a522bea48dfefebae81ec53644312762af4781c25de689952ed6c2d27
Image: cr.openfuyao.cn/openfuyao/busybox:1.36.1
Image ID: cr.openfuyao.cn/openfuyao/busybox@sha256:4b8407fadd8100c61b097d63efe992b2c033e7d371c9117f7a9462fe87e31176
Port: <none>
Host Port: <none>
Command:
sh
-c
chown 9000:9000 /var/log/mindx-dl /var/log/mindx-dl/devicePlugin
chmod 750 /var/log/mindx-dl/devicePlugin
State: Terminated
Reason: Completed
Exit Code: 0
Started: Mon, 30 Mar 2026 15:28:32 +0800
Finished: Mon, 30 Mar 2026 15:28:32 +0800
Ready: True
Restart Count: 1
Environment: <none>
Mounts:
/var/log/mindx-dl/devicePlugin from log-path (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-gfldg (ro)
Containers:
device-plugin-01:
Container ID: containerd://fcc0c4742285847e2621a9a9217502307fc7e28644fbf86b32f9c11d67a2c0ab
Image: cr.openfuyao.cn/openfuyao/ascend-image/ascend-k8sdeviceplugin:v6.0.0
Image ID: cr.openfuyao.cn/openfuyao/ascend-image/ascend-k8sdeviceplugin@sha256:a5b9612b21bcd35384f9f19a05b2d7915b865e7b2be6a30bfd7806a9b8a86f58
Port: <none>
Host Port: <none>
Command:
/bin/bash
-c
--
Args:
device-plugin -useAscendDocker=true -volcanoType=false -logFile=/var/log/mindx-dl/devicePlugin/devicePlugin.log -logLevel=0
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Tue, 31 Mar 2026 10:28:58 +0800
Finished: Tue, 31 Mar 2026 10:28:58 +0800
Ready: False
Restart Count: 274
Limits:
cpu: 500m
memory: 500Mi
Requests:
cpu: 500m
memory: 500Mi
Environment:
NODE_NAME: (v1:spec.nodeName)
Mounts:
/tmp from tmp (rw)
/usr/local/Ascend/driver from hiai-driver (ro)
/var/lib/kubelet/device-plugins from device-plugin (rw)
/var/lib/kubelet/pod-resources from pod-resource (rw)
/var/log/mindx-dl/devicePlugin from log-path (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-gfldg (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
device-plugin:
Type: HostPath (bare host directory volume)
Path: /var/lib/kubelet/device-plugins
HostPathType:
pod-resource:
Type: HostPath (bare host directory volume)
Path: /var/lib/kubelet/pod-resources
HostPathType:
hiai-driver:
Type: HostPath (bare host directory volume)
Path: /usr/local/Ascend/driver
HostPathType:
log-path:
Type: HostPath (bare host directory volume)
Path: /var/log/mindx-dl/devicePlugin
HostPathType: DirectoryOrCreate
tmp:
Type: HostPath (bare host directory volume)
Path: /tmp
HostPathType:
kube-api-access-gfldg:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
Optional: false
DownwardAPI: true
QoS Class: Burstable
Node-Selectors: openfuyao.com/npu.present=
Tolerations: CriticalAddonsOnly op=Exists
device-plugin=v2:NoSchedule
huawei.com/Ascend910:NoSchedule op=Exists
node-role.kubernetes.io/control-plane:NoSchedule
node-role.kubernetes.io/master:NoSchedule
node.kubernetes.io/disk-pressure:NoSchedule op=Exists
node.kubernetes.io/memory-pressure:NoSchedule op=Exists
node.kubernetes.io/not-ready:NoExecute op=Exists
node.kubernetes.io/pid-pressure:NoSchedule op=Exists
node.kubernetes.io/unreachable:NoExecute op=Exists
node.kubernetes.io/unschedulable:NoSchedule op=Exists
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pulled 16m (x205 over 18h) kubelet (combined from similar events): Successfully pulled image "cr.openfuyao.cn/openfuyao/ascend-image/ascend-k8sdeviceplugin:v6.0.0" in 403ms (403ms including waiting). Image size: 48017174 bytes.
Warning BackOff 2m47s (x5216 over 18h) kubelet Back-off restarting failed container device-plugin-01 in pod ascend-device-plugin-ll46f_kube-system(8edcd384-ab2d-4998-8077-5ac58801c79e)
Normal Pulling 66s (x227 over 19h) kubelet Pulling image "cr.openfuyao.cn/openfuyao/ascend-image/ascend-k8sdeviceplugin:v6.0.0"
[root@master1 fuyao-26.3-rc3]# kubectl -n kube-system exec -it daemonsets/ascend-device-plugin -- ls /dev
Defaulted container "device-plugin-01" out of: device-plugin-01, init-permission (init)
autofs null tty10 tty34 tty58 vcs5
bsg ppp tty11 tty35 tty59 vcs6
btrfs-control ptmx tty12 tty36 tty6 vcsa
bus pts tty13 tty37 tty60 vcsa1
core random tty14 tty38 tty61 vcsa2
cpu_dma_latency raw tty15 tty39 tty62 vcsa3
cuse relationship_ctrl tty16 tty4 tty63 vcsa4
davinci0 rfkill tty17 tty40 tty7 vcsa5
davinci_manager rtc0 tty18 tty41 tty8 vcsa6
devmm_svm sda tty19 tty42 tty9 vcsu
dri sda1 tty2 tty43 ttyAMA0 vcsu1
fb0 sda2 tty20 tty44 ttyS0 vcsu2
fd sg0 tty21 tty45 ttyS1 vcsu3
full sg1 tty22 tty46 ttyS2 vcsu4
fuse sg2 tty23 tty47 ttyS3 vcsu5
hidraw0 shm tty24 tty48 uhid vcsu6
hidraw1 snapshot tty25 tty49 uinput vfio
hisi_hdc sr0 tty26 tty5 urandom vga_arbiter
hwrng sr1 tty27 tty50 usbmon0 vhost-net
input stderr tty28 tty51 usbmon1 vhost-vsock
kmsg stdin tty29 tty52 usbmon2 vport2p1
loop-control stdout tty3 tty53 vcs zero
mapper termination-log tty30 tty54 vcs1
mem tty tty31 tty55 vcs2
mqueue tty0 tty32 tty56 vcs3
net tty1 tty33 tty57 vcs4
[root@master1 fuyao-26.3-rc3]# kubectl -n kube-system exec -it daemonsets/ascend-device-plugin -- ls -lha /usr/local/Ascend/driver
Defaulted container "device-plugin-01" out of: device-plugin-01, init-permission (init)
total 44K
drwxr-xr-x 8 root root 4.0K Mar 27 08:03 .
drwxr-xr-x 3 root root 4.0K Mar 31 02:34 ..
drwxr-xr-x 2 root root 4.0K Mar 27 08:01 bin
-r--r--r-- 1 root root 20 Mar 27 08:01 build.info
dr-xr-x--- 2 root root 4.0K Mar 27 08:01 device
dr-x------ 41 root root 4.0K Mar 27 08:01 kernel
drwxr-xr-x 6 root root 4.0K Mar 27 08:01 lib64
-r--r----- 1 root root 56 Mar 27 08:01 scene.info
dr-xr-x--- 2 root root 4.0K Mar 27 08:01 script
drwxr-xr-x 2 root root 4.0K Mar 27 08:01 tools
-r--r--r-- 1 root root 352 Mar 27 08:03 version.info
[root@master1 ~]# kubectl -n kube-system logs daemonsets/ascend-device-plugin --previous
Defaulted container "device-plugin-01" out of: device-plugin-01, init-permission (init)
[INFO] 2026/03/31 06:46:54.593254 1 hwlog/api.go:108 devicePlugin.log's logger init success
[INFO] 2026/03/31 06:46:54.593449 1 main.go:187 ascend device plugin starting and the version is v6.0.0_linux-aarch64
[INFO] 2026/03/31 06:46:54.593494 1 main.go:188 ascend device plugin starting scene is center
[INFO] 2026/03/31 06:46:54.787930 1 devmanager/devmanager.go:104 the dcmi version is 24.1.rc3
[ERROR] 2026/03/31 06:46:54.788019 1 devmanager/devmanager.go:211 get error card quantity: 0
[ERROR] 2026/03/31 06:46:54.788052 1 devmanager/devmanager.go:195 get card list failed for init
[ERROR] 2026/03/31 06:46:54.788101 1 main.go:203 init devmanager failed, err: auto init failed, err: get card list failed for init
[root@master1 ~]# kubectl -n kube-system exec -it daemonsets/ascend-device-plugin -- bash -c 'find /usr/local/Ascend/driver -name libdcmi.so 2>/dev/null; echo $LD_LIBRARY_PATH'
Defaulted container "device-plugin-01" out of: device-plugin-01, init-permission (init)
/usr/local/Ascend/driver/lib64/driver/libdcmi.so
command terminated with exit code 137
[root@master1 ~]# ps -ef | grep -E 'dmp_daemon|slogd' | grep -v grep
root 21578 1 0 Mar30 ? 00:00:19 /usr/sbin/rsyslogd -n -i/var/run/rsyslogd.pid
[root@master1 ~]# systemctl status ascend-dmi
Unit ascend-dmi.service could not be found.
[root@master1 ~]# systemctl status ascend-dkms
Unit ascend-dkms.service could not be found.
[root@master1 ~]# systemctl status npu-smi
Unit npu-smi.service could not be found.
[root@master1 ~]# find / -name dmp_daemon 2>/dev/null
[root@master1 ~]# find / -name slogd 2>/dev/null
[root@master1 ~]# ls -l /var/dmp_daemon /var/slogd 2>/dev/null
[root@master1 ~]#
dcmi 问题,需硬件排查
#include <stdlib.h>
#include <stdio.h>
#include "dcmi_interface_api.h"
int my_get_card_list();
int main(int argc,char *argv[])
{
my_get_card_list();
return 0;
}
int my_get_card_list()
{
printf("\n==================================card id info list=========================\n");
dcmi_init();
int card_num = 0;
int card_list[16] = {0};
int ret = dcmi_get_card_list(&card_num, card_list, 16);
if (ret != DCMI_OK) {
printf("dcmi get card list failed ret=%d\n", ret);
}
printf("card_num=%d, card_list:[",card_num);
for (int i = 0; i < card_num; i++) {
printf("%d ", card_list[i]);
}
}
cc ./test1.c -o test1 -I /usr/local/dcmi -L /usr/local/dcmi -ldcmi
-I头文件(.h)搜索路径
-L库文件(.so/.a)搜索路径
-l链接的库名(去掉 lib 前缀)
nerdctl run --rm \
-v /usr/local/Ascend:/usr/local/Ascend \
-v /usr/local/dcmi:/usr/local/dcmi \
-v $(pwd):/build \
ubuntu:18.04 bash -c "
sed -i -e 's@http*://ports.ubuntu.com/\? @http://10.17.31.217:8081/repository/mirror-ubuntu-ports/@g' \
-e 's@http*://ports.ubuntu.com@http://10.17.31.217:8081/repository/mirror-ubuntu-ports@g' \
/etc/apt/sources.list
apt update && apt install -y gcc
cd /build
cc ./test1.c -o test1 \
-I /usr/local/dcmi \
-L /usr/local/dcmi \
-L /usr/local/Ascend/driver/lib64/common \
-L /usr/local/Ascend/driver/lib64/driver \
-ldcmi \
-Wl,-rpath,/usr/local/Ascend/driver/lib64/common \
-Wl,-rpath,/usr/local/Ascend/driver/lib64/driver \
-Wl,-rpath,/usr/local/dcmi
"
分析二进制:
[root@master1 ascend_debug]# ldd ./test1 | grep -i dcmi
libdcmi.so => /usr/local/Ascend/driver/lib64/driver/libdcmi.so (0x0000ffffa6dd0000)
[root@master1 ascend_debug]# LD_DEBUG=libs ./test1 2>&1 | grep -i dcmi
284830: find library=libdcmi.so [0]; searching
284830: search path=/usr/local/Ascend/driver/lib64/common/tls/aarch64/atomics:/usr/local/Ascend/driver/lib64/common/tls/aarch64:/usr/local/Ascend/driver/lib64/common/tls/atomics:/usr/local/Ascend/driver/lib64/common/tls:/usr/local/Ascend/driver/lib64/common/aarch64/atomics:/usr/local/Ascend/driver/lib64/common/aarch64:/usr/local/Ascend/driver/lib64/common/atomics:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver/tls/aarch64/atomics:/usr/local/Ascend/driver/lib64/driver/tls/aarch64:/usr/local/Ascend/driver/lib64/driver/tls/atomics:/usr/local/Ascend/driver/lib64/driver/tls:/usr/local/Ascend/driver/lib64/driver/aarch64/atomics:/usr/local/Ascend/driver/lib64/driver/aarch64:/usr/local/Ascend/driver/lib64/driver/atomics:/usr/local/Ascend/driver/lib64/driver:/usr/local/dcmi/tls/aarch64/atomics:/usr/local/dcmi/tls/aarch64:/usr/local/dcmi/tls/atomics:/usr/local/dcmi/tls:/usr/local/dcmi/aarch64/atomics:/usr/local/dcmi/aarch64:/usr/local/dcmi/atomics:/usr/local/dcmi (RUNPATH from file ./test1)
284830: trying file=/usr/local/Ascend/driver/lib64/common/tls/aarch64/atomics/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/common/tls/aarch64/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/common/tls/atomics/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/common/tls/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/common/aarch64/atomics/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/common/aarch64/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/common/atomics/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/common/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/driver/tls/aarch64/atomics/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/driver/tls/aarch64/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/driver/tls/atomics/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/driver/tls/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/driver/aarch64/atomics/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/driver/aarch64/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/driver/atomics/libdcmi.so
284830: trying file=/usr/local/Ascend/driver/lib64/driver/libdcmi.so
284830: search path=/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver:/usr/local/dcmi/tls/aarch64/atomics:/usr/local/dcmi/tls/aarch64:/usr/local/dcmi/tls/atomics:/usr/local/dcmi/tls:/usr/local/dcmi/aarch64/atomics:/usr/local/dcmi/aarch64:/usr/local/dcmi/atomics:/usr/local/dcmi (RUNPATH from file ./test1)
284830: trying file=/usr/local/dcmi/tls/aarch64/atomics/libc.so.6
284830: trying file=/usr/local/dcmi/tls/aarch64/libc.so.6
284830: trying file=/usr/local/dcmi/tls/atomics/libc.so.6
284830: trying file=/usr/local/dcmi/tls/libc.so.6
284830: trying file=/usr/local/dcmi/aarch64/atomics/libc.so.6
284830: trying file=/usr/local/dcmi/aarch64/libc.so.6
284830: trying file=/usr/local/dcmi/atomics/libc.so.6
284830: trying file=/usr/local/dcmi/libc.so.6
284830: calling init: /usr/local/Ascend/driver/lib64/driver/libdcmi.so
284830: calling fini: /usr/local/Ascend/driver/lib64/driver/libdcmi.so [0]
[root@master1 ascend_debug]# readlink -f /usr/local/dcmi/libdcmi.so
/usr/local/dcmi/libdcmi.so
[root@master1 ascend_debug]# readlink -f /usr/local/Ascend/driver/lib64/driver/libdcmi.so
/usr/local/Ascend/driver/lib64/driver/libdcmi.so
[root@master1 ascend_debug]# sha256sum /usr/local/dcmi/libdcmi.so /usr/local/Ascend/driver/lib64/driver/libdcmi.so
13a38cae84bad0f06367ff9280016e372c0608ca16465b5ae5f000d3844ee401 /usr/local/dcmi/libdcmi.so
13a38cae84bad0f06367ff9280016e372c0608ca16465b5ae5f000d3844ee401 /usr/local/Ascend/driver/lib64/driver/libdcmi.so
宿主机跑
strace -f -o /tmp/host.strace -e trace=file,ioctl ./test1
容器里跑
strace -f -o /tmp/container.strace -e trace=file,ioctl ./test1
volumeMounts:
- name: hdc-basic
mountPath: /etc/hdcBasic.cfg
readOnly: true
- name: localtime
mountPath: /etc/localtime
readOnly: true
volumes:
- name: hdc-basic
hostPath:
path: /etc/hdcBasic.cfg
type: File
- name: localtime
hostPath:
path: /etc/localtime
type: File
kubectl -n kube-system exec -it ascend-device-plugin-69q5t -c device-plugin-01 -- bash
strace -f -o /tmp/container.strace -e trace=file,ioctl ./test1
root@ascend-device-plugin-69q5t:/tmp# strace -f -o /tmp/container.strace -e trace=file,ioctl ./test1
==================================card id info list=========================
card_num=0, card_list:[
root@ascend-device-plugin-69q5t:/tmp# cat /var/log/nputools_LOG_INFO.log > /tmp/nputools_LOG_INFO.log
root@ascend-device-plugin-69q5t:/tmp# cat /var/log/nputools_LOG_ERR.log > /tmp/nputools_LOG_ERR.log
cat: /var/log/nputools_LOG_ERR.log: No such file or directory
root@ascend-device-plugin-69q5t:/tmp# cat /tmp/nputools_LOG_INFO.log
[2026/04/01 11:18:12][0583][root][127.0.0.1][dcmi_api.c,dcmi_board_init,86]:dcmi board init success. device_count=1.
[2026/04/01 11:18:12][0583][root][127.0.0.1][dcmi_api.c,dcmi_init,119]:dcmi init all success.
#include <stdio.h>
#include <stdlib.h>
#include "dcmi_interface_api.h"
#ifndef DCMI_OK
#define DCMI_OK 0
#endif
/* 头文件里没看到这个声明,手动补一个 */
extern int dcmi_get_card_num_list(int *card_num, int *card_list, int list_length);
static void print_list(const char *name, int ret, int num, int *list) {
printf("%s ret=%d num=%d list=[", name, ret, num);
for (int i = 0; i < num; ++i) {
printf("%d ", list[i]);
}
printf("]\n");
}
int main(void) {
int ret = dcmi_init();
printf("dcmi_init ret=%d\n", ret);
if (ret != DCMI_OK) {
return 1;
}
int card_num = 0;
int card_list[16] = {0};
ret = dcmi_get_card_list(&card_num, card_list, 16);
print_list("dcmi_get_card_list", ret, card_num, card_list);
int card_num2 = 0;
int card_list2[16] = {0};
ret = dcmi_get_card_num_list(&card_num2, card_list2, 16);
print_list("dcmi_get_card_num_list", ret, card_num2, card_list2);
for (int i = 0; i < card_num && i < 16; ++i) {
int dev_num = -1;
ret = dcmi_get_device_num_in_card(card_list[i], &dev_num);
printf("dcmi_get_device_num_in_card card=%d ret=%d dev_num=%d\n",
card_list[i], ret, dev_num);
}
return 0;
}
主机编译
cc ./test2.c -o test2 -I /usr/local/dcmi -L /usr/local/dcmi -ldcmi
容器编译
nerdctl run --rm \
-v /usr/local/Ascend:/usr/local/Ascend \
-v /usr/local/dcmi:/usr/local/dcmi \
-v $(pwd):/build \
ubuntu:18.04 bash -c "
sed -i -e 's@http*://ports.ubuntu.com/\? @http://10.17.31.217:8081/repository/mirror-ubuntu-ports/@g' \
-e 's@http*://ports.ubuntu.com@http://10.17.31.217:8081/repository/mirror-ubuntu-ports@g' \
/etc/apt/sources.list
apt update && apt install -y gcc
cd /build
cc ./test2.c -o test2 \
-I /usr/local/dcmi \
-L /usr/local/dcmi \
-L /usr/local/Ascend/driver/lib64/common \
-L /usr/local/Ascend/driver/lib64/driver \
-ldcmi \
-Wl,-rpath,/usr/local/Ascend/driver/lib64/common \
-Wl,-rpath,/usr/local/Ascend/driver/lib64/driver \
-Wl,-rpath,/usr/local/dcmi
"
拷入容器运行
kubectl -n kube-system cp ./test2 ascend-device-plugin-69q5t:/tmp/
# 主机运行
[root@master1 ascend_debug]# ./test2
dcmi_init ret=0
dcmi_get_card_list ret=0 num=1 list=[176 ]
dcmi_get_card_num_list ret=0 num=1 list=[176 ]
dcmi_get_device_num_in_card card=176 ret=0 dev_num=1
# 容器运行
root@ascend-device-plugin-69q5t:/tmp# ./test2
dcmi_init ret=0
dcmi_get_card_list ret=0 num=0 list=[]
dcmi_get_card_num_list ret=0 num=0 list=[]
经过许老师认真定位,最终发现是因为非裸金属环境。虚拟机场景需要定制镜像。
根据官网文档:
如果在虚拟机场景下部署Ascend Device Plugin,需要在Ascend Device Plugin的镜像中安装systemd,推荐在Dockerfile中加入RUN apt-get update && apt-get install -y systemd命令进行安装。
为了使用 nerdctl 构建镜像首先安装 buildkit
wegt https://github.com/moby/buildkit/releases/download/v0.29.0/buildkit-v0.29.0.linux-arm64.tar.gz
tar zxvf buildkit-v0.29.0.linux-arm64.tar.gz
cp bin/* /usr/local/bin/
之后找一个新终端启动 buildkit ,这里是为了 nerdctl 构建 image, 如果不需要则不用启动。
buildkitd --oci-worker=false --containerd-worker=true --containerd-worker-namespace=k8s.io
Dockerfile 如下:
镜像源部分按需修改
FROM hub.oepkgs.net/openfuyao/ascendhub/ascend-k8sdeviceplugin:v6.0.0
# 替换 apt 镜像源
RUN sed -i \
-e 's@http*://ports.ubuntu.com/\? @http://10.17.31.217:8081/repository/mirror-ubuntu-ports/@g' \
-e 's@http*://ports.ubuntu.com@http://10.17.31.217:8081/repository/mirror-ubuntu-ports@g' \
/etc/apt/sources.list
# 安装 systemd
RUN apt-get update && \
apt-get install -y --no-install-recommends systemd systemd-sysv && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 设置 systemd 为 init
STOPSIGNAL SIGRTMIN+3
STOPSIGNAL SIGRTMIN+3 是告诉容器运行时(containerd/docker)停止这个容器时应该发送哪个信号。
如果你的容器里 不跑 systemd 作为主进程(比如 entrypoint 是业务程序),这行可以删掉,没有任何作用。
如果确实用 systemd 管理容器内服务,保留它能避免 kubectl delete pod 时等待 30 秒超时再强杀的问题。
构建命令如下:
nerdctl build \
--namespace k8s.io \
-t hub.oepkgs.net/openfuyao/ascendhub/ascend-k8sdeviceplugin:v6.0.0-systemd \
-f Dockerfile \
.
之后将出问题的镜像替换为新构建的镜像即可。
npu-operator 有同样的问题,一样修改即可。
最终在 node 中能看到 npu 资源即成功。
[root@master1 ~]# kubectl describe node master1
Name: master1
Roles: control-plane,master,node,worker
Labels: accelerator=huawei-Ascend310P
beta.kubernetes.io/arch=arm64
beta.kubernetes.io/os=linux
...
servertype=Ascend310P-8
workerselector=dls-worker-node
Annotations: baseDeviceInfos: {"Ascend310P-0":{"IP":"","SuperDeviceID":0}}
...
Capacity:
cpu: 16
ephemeral-storage: 129724184Ki
huawei.com/Ascend310P: 1
hugepages-1Gi: 0
hugepages-2Mi: 0
hugepages-32Mi: 0
hugepages-64Ki: 0
memory: 32595632Ki
pods: 110
Allocatable:
cpu: 16
ephemeral-storage: 119553807777
huawei.com/Ascend310P: 1
hugepages-1Gi: 0
hugepages-2Mi: 0
hugepages-32Mi: 0
hugepages-64Ki: 0
memory: 32493232Ki
pods: 110
...
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 15565m (97%) 16910m (105%)
memory 17492Mi (55%) 30900Mi (97%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-1Gi 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
hugepages-32Mi 0 (0%) 0 (0%)
hugepages-64Ki 0 (0%) 0 (0%)
huawei.com/Ascend310P 0 0
...
2026-04-01 13:55:30
不知道从什么时候开始,KDE Plasma 默认启用类似 macOS 的全局应用菜单。
即应用窗口标题栏下方不显示菜单,而是移动到顶部菜单栏中“全局菜单”小组件中。
但问题是,Linux 桌面生态生态复杂,X11 Wayland Qt GTK 等等技术太过复杂,很难保证常用软件都能够正常显示全局菜单。
比如我最近在使用 Joplin ,就发现除了菜单栏根本找不到任何入口。
于是搜索了一番后,终于找到了关闭全局菜单,恢复正常的应用菜单的方法。
第一步:移除“全局菜单组件”
Edit Mode > Add or Manage Widgets > Global Menu > Remove all instances (button in the top right corner of the widget)
进入编辑模式,添加或管理组件,删除“全局菜单”小组间

第二步:移除应用菜单
实测完成第一步即可,第二步按照自己实际情况决定是否要做。
Settings > Colors & Themes > Window Decorations > Configure Titlebar Buttons…
There remove the Application Menu (“Hamburger”) button from your titlebars.
进入设置,颜色与主题,窗口装饰元素,配置菜单栏按钮,将“应用菜单”按钮移除,点击应用,即可。

第三步:重启应用
此时应该就能看到应用菜单了,如果看不到再重启一下即可。

2026-01-29 20:00:15
2026 年初,一个名为 Moltbot(前身为 Clawbot)的开源 AI 代理(Agent)框架席卷了开发者社区。该框架允许用户将强大的 AI 模型(例如 OpenAI 的 GPT 系列、Anthropic 的 Claude 等)与 WhatsApp、Telegram、Discord 等日常通讯工具集成,从而通过聊天即可操控电脑、执行任务、获取信息。特斯拉前 AI 主管 Andrej Karpathy 的推荐更是使其迅速走红,其 GitHub 项目在短时间内获得了超过 60,000 个星标。
本指南将提供一份以安全为核心的详尽教程,旨在引导您逐步在 Linux 裸机服务器上安全地完成 Moltbot 的部署。
在开始之前,请确保你已具备以下条件:
| 项目 | 要求 | 说明 |
|---|---|---|
| Linux 服务器 | Ubuntu 22.04+ 或其他现代发行版 | 推荐至少 2GB RAM 和 2 核 CPU。 |
| 基础 Linux 知识 | 熟悉 SSH、命令行操作 | 本教程将提供所有需要的命令。 |
基于安全最佳实践,我们强烈建议不要直接使用 root 用户运行任何应用程序。因此,第一步是创建一个专用的非特权用户,并为其授予 sudo 权限。
root 用户 SSH 登录你的服务器:ssh root@your_server_ip
moltbot):adduser moltbot
系统会提示你为新用户设置密码和其他信息。
sudo 组,以便执行需要管理员权限的操作:usermod -aG sudo moltbot
su - moltbot
sudo apt update && sudo apt upgrade -y
此后,所有操作都应在该 moltbot 用户下进行。
Moltbot 的核心依赖是 Node.js (版本 ≥ 22)。官方提供了一个便捷的一键安装脚本,可自动处理相关依赖并完成 Moltbot 的安装。
curl -fsSL https://molt.bot/install.sh | bash
该脚本会自动检测您的操作系统,安装适配的 Node.js 版本,并部署 Moltbot 命令行工具(CLI)。
安装成功后,将自动进入交互式配置流程,如下图所示:

第一个选项是风险提示,输入 yes 确认已知晓。
第二步在模式选择中,建议选择 QuickStart 以进行快速配置。
在选择模型服务商时,本教程以阿里云的 Qwen(通义千问)为例,其提供充足的免费额度,非常适合初学者入门。待您熟悉系统后,可根据需求更换为其他模型。

选择 Qwen 模型后,终端会提供一个授权链接,请复制并在浏览器中打开。

打开链接后,您会看到授权页面。如果您尚未登录阿里云账户,请根据提示完成登录。

登录成功后,系统会提示您选择具体的 Qwen 模型版本。

此处选择默认模型即可。随后,安装向导会询问是否配置频道(Channel),建议暂时跳过,后续再进行配置。

接着,在技能(Skills)配置步骤中,同样选择 No。

等待安装流程结束,在最后的启动方式选择中,选择 TUI(文本用户界面)。

如果成功进入 TUI 聊天界面,说明 Moltbot 已正确安装。您可以输入 Hello 进行初步测试。

测试无误后,使用 Ctrl+C 组合键退出 TUI 界面,以便进行后续的后台服务配置。
安装向导会自动将 Gateway 配置为系统服务并在后台启动。
clawdbot gateway status
如果服务正常运行,您将看到 active (running) 的状态提示。

如果检查状态时发现服务异常(例如 inactive 或 failed),可以尝试使用内置的诊断工具进行修复:
clawdbot doctor --repair
修复后,再次检查状态,应可看到服务已恢复正常。

您可以根据需要编辑 Moltbot 的主配置文件。
使用文本编辑器(如 vim 或 nano)打开配置文件:
sudo vim ~/.clawdbot/clawdbot.json
每次修改配置文件后,需要重载服务以使更改生效。虽然某些版本的 Moltbot 支持自动重载,但手动重启是更可靠的方式。
systemctl --user daemon-reload
clawdbot gateway restart
至此,Moltbot Gateway 已在后台稳定运行,并监听本地端口,等待连接。
Moltbot 自带一个 Web UI 用于管理和测试。运行以下命令可获取访问方式:
clawdbot dashboard
命令会输出一段 SSH 端口转发指令,格式如下:

在您的本地电脑(而非服务器)上打开一个终端,并执行上述 SSH 命令。该命令会将服务器的 Web UI 端口 18789 映射到您本地的同名端口。
ssh -N -L 18789:127.0.0.1:18789 [email protected] -p xxx
命令运行后,在本地浏览器访问 http://127.0.0.1:18789 即可打开 Web UI 。
您可以发送一条 Hello 消息进行测试,如果收到回复,则说明一切正常。

首先,在服务器上为 Moltbot 安装飞书插件:
clawdbot plugins install @m1heng-clawd/feishu
接下来,登录飞书开放平台,进入「开发者后台」,点击「创建企业自建应用」。

填写应用名称和描述后,完成创建。

创建成功后,进入应用的「凭据与基础信息」页面,复制并妥善保存 App ID 和 App Secret,它们将在后续配置中用到。

然后添加机器人,如下操作

暂时停留在飞书后台,我们先返回服务器终端,完成 Moltbot 的飞书相关配置。

飞书的其他配置先暂停,回到服务器配置 Clawdbot 的飞书参数
clawdbot config set channels.feishu.appId "飞书 app id"
clawdbot config set channels.feishu.appSecret "飞书 app secret"
clawdbot config set channels.feishu.enabled true
# 推荐使用 websocket
clawdbot config set channels.feishu.connectionMode websocket
clawdbot config set channels.feishu.dmPolicy pairing
clawdbot config set channels.feishu.groupPolicy allowlist
clawdbot config set channels.feishu.requireMention true
配置完成之后,重启
clawdbot gateway restart
重启完成后回到飞书,找到「事件和回调」,选择长连接模式,如下图

如果配置成功,说明连接已建立。继续下面的配置,添加事件,选择「接收消息」事件

事件添加完成之后,还需要开通权限,有以下权限全部勾选
| 权限 | Scope(范围) | Description(说明) |
|---|---|---|
| contact:user.base:readonly | 用户信息 | 获取基础用户信息 |
| im:message | 消息 全部勾选 | 发送和接收消息 |
如下图


以上步骤全部完成后,即可与机器人对话。但在此之前需要先创建一个版本

注意:每次修改配置后都需要重新发布版本,建议全部配置完成后再统一发布。
发布完成后,回到飞书客户端,可以看到应用已上线,点击打开应用

向机器人发送 Hello,即可收到 Moltbot 的回复

恭喜您!至此,您已成功在 Linux 服务器上部署了 Moltbot,并将其与飞书集成。现在您可以开始探索其强大的功能,或根据官方文档进行更深度的定制。如果在部署过程中遇到任何问题,欢迎留言交流。
# 检查常见安全问题
clawdbot security audit
# 自动修复文件权限等问题
clawdbot security audit --fix
# 查看 Moltbot 日志
clawdbot logs --follow
2026-01-09 16:28:00
默认情况下 Windows 安装的 Claude Code 会从这个位置读取配置:
C:\Users\<YOUR_NAME>\.claude
其他系统则类似的找到 ~/.claude 路径。
官方流程在安装结束后就完成了,可以直接登录使用。如果需要修改配置将 Claude Code 接入第三方 API,就需要修改这里的 settings.json 配置文件,可以使用 CC-Switch 或是手动编写,但是修改后会发现不生效。
经过调研,发现是最新版的 Claude Code 修改了一个参数,导致启动时一定要登录,这里可以手动修改一下 C:\Users\<YOUR_NAME>\.claude.json 中的这个参数,即可正常使用:
hasCompletedOnboarding: true
将配置中的 false 改为 true ,再重新运行 Claude Code 即可。
这个问题卡了我两天,一度打算放弃回到其他 OS,最后终于在 这里 找到了答案,因此特别记录一下。
2026-01-09 16:22:00
今天终于跑通了 Windows 下运行 Claoude Code 的全流程,不借助 WSL ,原生运行。起因是自己需要一个可以长期运行任务的云桌面,这方面还是 Windows 最好用。不得不说相比于 Linux/macOS ,Windows 下运行 Claude Code 实在太多坑了。
感谢 LD 巨佬 哈雷彗星 的 《 Claude Code 终极版 FAQ 指南 》 ,在这份指南的指导下,还有开源社区朋友的帮助下,终于跑通了全流程,在这里记录一下,避免更多的朋友踩坑。

先说一下我的环境:
Windows 10 Enterprise LTSC 2021
PowerShell 5 -> PowerShell 7
我是在全新安装的 Windows 10 Enterprise LTSC 2021 系统中进行,使用系统自带的 PowerShell 5 开始 ,流程中会安装最新的 PoserShell 7 并使用 PS7 完成后续。根据论坛大佬的说法,PS7 很好用,自带的 PS5 不好用,因此下面的流程包含了安装 PS7 的流程,大家可以自己体验一下。
以下内容主要来自 《 Claude Code 终极版 FAQ 指南 》 和实践补充。
打开 PowerShell 5 并安装 WinGet:
$progressPreference = 'silentlyContinue'
Install-PackageProvider -Name NuGet -Force | Out-Null
Install-Module -Name Microsoft.WinGet.Client -Force -Repository PSGallery | Out-Null
Write-Host "Using Repair-WinGetPackageManager cmdlet to bootstrap WinGet..."
Repair-WinGetPackageManager -AllUsers
在 PoserShell 5 中使用 WinGet 安装 PoserShell 7
winget install Microsoft.PowerShell
打开 PoserShell 7 并使用 winget 安装其他依赖,后续全部在 PS7 中进行:
# 必须,安装 fnm 用于管理 node 环境,或使用现有环境
winget install Schniz.fnm
# 可选,安装 Git
winget install --id Git.Git -e --source winget
# 可选,安装 notepad4
winget install zufuliu.notepad4
# 可选,安装 Windows Terminal
winget install -e --id Microsoft.WindowsTerminal
# 可选,安装 Notepad++
winget install -e --id Notepad++.Notepad++
下面使用 fnm 安装特定版本的 node 运行环境,首先需要对 FNM 给予一个环境启动,否则安装的 node 无法使用,因此首先预配置环境:
New-Item –Path $Profile –Type File –Force
notepad $profile
之后将以下内容写入该文件并保存:
fnm env --use-on-cd --shell powershell | Out-String | Invoke-Expression
下面开始正式安装 nodejs:
fnm install lts/krypton
fnm use lts/krypton
全局安装 Claude Code:
npm install -g @anthropic-ai/claude-code
之后就可以愉快的使用 Claude Code 了。

settings.json 不生效默认情况下这样安装的 Claude Code 会从这个位置读取配置:
C:\Users\<YOUR_NAME>\.claude
官方流程在安装结束后就完成了,可以直接登录使用。如果你需要修改配置将 Claude Code 接入第三方 API,就需要修改这里的 settings.json 配置文件,可以使用 CC-Switch 或是手动编写,但是修改后会发现不生效。
经过调研,发现是最新版的 Claude Code 修改了一个参数,导致启动时一定要登录,这里可以手动修改一下 C:\Users\<YOUR_NAME>\.claude.json 中的这个参数,即可正常使用:
hasCompletedOnboarding: true
将配置中的 false 改为 true ,再重新运行 Claude Code 即可。
这个问题卡了我两天,一度打算放弃回到其他 OS,最后终于在 这里 找到了答案,因此特别记录一下。