前言
最近刚好有将stable-difussion服务运行在服务器的需求,首先考虑的是amazon,但最便宜的那款一小时都要1美元多,偶然间发现腾讯云有活动高性能应用服务HAI_GPU云服务器_腾讯云,价格如下
- GPU 基础型算力套餐
- 显存大小:16 GB
- 算力大小:8+TFlops SP
- CPU:8 核,内存:32GB
- 1.2元每h
- 学生特惠,150元买250 小时 GPU基础型算力套餐
- 这参数其实就是NVIDIA T4 Tensor Core GPU for AI Inference | NVIDIA Data Center
这价格快比电费还便宜了,于是买了一张150元的现金券来体验下。
需求
我想使用该服务器跑一个被我魔改后的stable-difussion-webui,而它提供了一键部署Stable Difussion WebUI的选项。
如果能使用这装好的python环境,那我能省事很多。而且我也好奇这是怎么做的。以下是我的过程。
ssh连接
第一步肯定是得连接上去。
但在腾讯云 - 控制台并不能找到连接的按钮,还以为不提供,找文档找到了高性能应用服务 连接 Linux 算力-操作指南-文档中心-腾讯云。
看到方式一,很熟悉啊,于是就去做了。
(写这篇文章的时候我又看了遍这个文档,发现还有方式二:通过 Terminal 连接算力),然后我才发现它提供的JupyterLab有项目的基础介绍。所以其实我下面写的这些很大一部分其实人都写得很明白了,╮(╯-╰)╭ )
找到python依赖的安装位置
一进去先ls
,发现有个miniconda3,答案就呼之欲出了,请ChatGPT写了个简单的cheatsheet:
# 创建一个新的 Conda 环境
conda create --name myenv python=3.8
# 激活环境
conda activate myenv
# 停用环境
conda deactivate
# 列出所有 Conda 环境
conda env list
node运行装在conda的python
我需要用node去调用python,可以这样做
const workDir = "/root/my-stable-diffusion-webui";
let webUIProcess;
const url = process.env.URL;
const initWebGUI = _ => {
return new Promise(resolve => {
console.log('initWebGUI start');
process.chdir(workDir);
webUIProcess = spawn('/root/miniconda3/bin/python', ['launch.py', '--xformers', '--api','--nobrowser']);
webUIProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
return resolve();
});
webUIProcess.stderr.on('data', (data) => {
const errorMessage = data.toString();
console.error(`stderr: ${errorMessage}`);
// Check for errors, assuming warnings do not contain 'error'
if (/error/i.test(errorMessage)) {
console.log('Kill process...', webUIProcess.pid);
webUIProcess.kill(); // Kill the current process
console.log('Process', webUIProcess.pid, ' killed.');
}
});
});
}
值得一提的是,因为该服务器将依赖将依赖全安装在了base这个环境下,所以路径就是/root/miniconda3/bin/python
基础环境配置
- nvm安装
- nvm-sh/nvm: Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash
- redis安装:
apt-get install redis
下载所需的底模和lora文件
- 因为我本地已经有相应的文件,于是我首先想的是上传。先是用的Cyberduck,但连接失败,检查了下端口,也有开放,不知道啥原因,于是放弃
- 尝试直接使用sftp,
sftp username@your_server_ip
,确实可行,于是请请ChatGPT写了个简单的cheatsheet:
# 连接到服务器
sftp username@your_server_ip
# 切换到远程目录
cd /home/root/
# 使用 lpwd 查看本地工作目录,lcd 切换本地目录:
# 上传本地文件
put C:\path\to\example.txt
# 使用 get 命令从远程服务器下载文件到本地:
get remotefile.txt
# 退出 sftp 会话
exit
但发现速度不尽如人意,于是放弃
这时候就可以将思维逆转过来。既然不能上传,那我就下载啊。我需要的底模文件是在【SDXL】 Pixel Art | Base - v1.0 | Stable Diffusion Checkpoint | Civitai,当我直接复制下载链接,使用wget会报错,需要认证。查文档查到了Civitai’s Guide to Downloading via API - Civitai Education。最终能运行的命令类似于:
curl -L -H "Content-Type: application/json" -H "Authorization: Bearer your_token" https://civitai.com/api/download/models/311399 -o SDXLPixelArtBase_v10.safetensors
lora文件我则将上传到了s3上。它有个
share with presigned URL
,于是我想当然地使用,但发现还是报错。最后还是直接用的Object URL
后来发现文档中推荐的下载是这样写的:
- 建议将基础模型文件转存至与HAI实例同地域的COS桶中,再在HAI实例中拉取COS文件,速度最快
- 国内地域HAI实例可能存在网络不稳定情况,推荐启用“学术加速”;国外地域HAI实例下载模型、插件速度更快
好一个“学术加速”
运行时报错
import - no module named ‘dotenv’ python 3.8 - Stack Overflow
pip install python-dotenv
pm2使用
再再请ChatGPT写了个简单的cheatsheet:
# 安装
npm install pm2 -g
# 指定env文件
pm2 start "node --env-file=.env app.js"
# 查看 PM2 中正在运行的进程
pm2 list
# 查看应用程序日志
pm2 logs my-app
# 停止应用程序:
pm2 stop my-app
# 重启应用程序:
pm2 restart my-app
# 删除应用程序:
pm2 delete my-app
# 检查日志
pm2 logs app
# 实时监控
pm2 monit
怎么开机自启的
服务跑着跑着爆显存了,感觉问题可能出在这个服务器运行了两个stable-difussion-webui,重启后发现还是有,那么它是怎么做到开机自启的呢?
我先后检查了以下几处(还是请ChatGPT帮的忙):
- systemctl
systemctl list-unit-files --type=service --state=enabled
systemctl list-units --type=service --state=running
这个命令将列出所有在系统启动时启用的服务。
- 检查
/etc/init.d/
在一些较旧的系统或特定的服务中,可以通过检查/etc/init.d/
目录来查看初始化脚本:
ls /etc/init.d/
这些脚本通常用于传统的 init
系统,在启动时运行。
- cron
sudo crontab -l
sudo crontab -u <username> -l
cat /etc/crontab
cat /etc/cron.*/*
5. 检查 rc.local
sudo vim /etc/rc.local
以上检查都无果后,我想起了查看当前进程:
# 显示当前终端中的所有进程:
ps -ef
# 比较可疑的包括
root 1 0 0 12:35 ? 00:00:00 /usr/bin/dumb-init -- /usr/local/bin/application_init.s
root 7 1 0 12:35 pts/0 00:00:00 /bin/bash /usr/local/bin/application_init.sh
root 16 7 0 12:35 pts/0 00:00:00 /usr/bin/python3 /usr/bin/supervisord -c /etc/superviso
root 18 16 0 12:35 pts/0 00:00:00 /bin/bash /usr/local/bin/launch_jupyter.sh
root 19 16 0 12:35 pts/0 00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root 20 16 0 12:35 pts/0 00:00:00 /bin/bash /usr/local/bin/launch_stable_diffusion_webui.
root 21 18 0 12:35 pts/0 00:00:04 /root/miniconda3/bin/python3 /root/miniconda3/bin/jupyt
root 22 18 0 12:35 pts/0 00:00:00 tee -a /var/log/jupyter_service.log
root 23 20 1 12:35 pts/0 00:01:03 python3 -u launch.py --skip-prepare-environment --xform
root 24 20 0 12:35 pts/0 00:00:00 tee -a /var/log/sd_service.log
root 1225 68 0 12:50 pts/1 00:00:00 vim /etc/systemd/system/supervisord.service
root 1994 21 0 13:29 ? 00:00:00 /root/miniconda3/bin/python3 -m ipykernel_launcher -f /
于是找到了supervisord
supervisord的使用
- 请ChatGPT写了个简单的介绍:
supervisord 是一个流行的进程控制系统,用于管理和监控 Unix-like 操作系统上的进程。它提供了一种简单的方式来启动、停止、重启和监控进程。supervisord 是 supervisor 的守护进程,而 supervisor 是用于管理进程的客户端工具。
- 用
whereis supervisord
找到了配置文件的位置,是在/etc/supervisord.conf
,[program:stable_diffusion_webui] command=/usr/local/bin/launch_stable_diffusion_webui.sh autostart=true autorestart=false numprocs=1 redirect_stderr=true startretries=1 startsecs=300 stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stdout_events_enabled=true stderr_events_enabled=true stopasgroup=true killasgroup=true
- 那么刚才的问题得到了解答,开机自启的是
supervisor.service
,然后supervisor将stable_diffusion_webui
给启动了 /usr/local/bin/launch_stable_diffusion_webui.sh
这个文件内容是#!/bin/bash source /mnt/application_env.txt cd /root/stable-diffusion-webui/ && python3 -u launch.py --skip-prepare-environment --xformers --listen --enable-insecure-extension-access --port=$STABLE_DIFFUSION_WEBUI_PORT 2>&1 | tee -a /var/log/sd_service.log`
开机自启
找到了它开机自启动服务的办法,那么就可以利用它来实现我想要的开机自启。
- 先写了个脚本
/usr/local/bin/check_and_start_pm2.sh
:
#!/bin/bash
# 进入程序目录
cd /path/to/SD-server/stable-difussion-server/
# 检查 pm2 中是否已有名为 "app" 的程序
if ! pm2 list | grep -q 'app'; then
# 如果没有,启动 pm2 进程
pm2 start "node --env-file=.env app.js" --name app
else
echo "PM2 process 'app' is already running."
fi
- 给权限
chmod +x /usr/local/bin/check_and_start_pm2.sh
- 改
/etc/supervisord.conf
[program:stable_diffusion_webui] command=/usr/local/bin/check_and_start_pm2.sh autostart=true autorestart=true numprocs=1 redirect_stderr=true startretries=1 startsecs=300 stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stdout_events_enabled=true stderr_events_enabled=true stopasgroup=true killasgroup=true
- 重新加载 supervisord 配置
supervisorctl reread supervisorctl update
- 这里我还踩到了自己挖的一个坑,
/usr/local/bin/check_and_start_pm2.sh
文件首行我是写#!/bin/bash
,但我nvm是在zsh上装的,于是pm2在bash环境下就识别不到,再加上就行了。export PATH=$PATH:/root/.nvm/versions/node/v20.16.0/bin
体验
之前用过好几家国内的云服务器,最大的感受是ui很糟糕,然后就是费劲折腾的网络。
但这次体验却着实不赖,因为有了“学术加速”,呵呵。
特别鸣谢
感谢ChatGPT! 它省去了不少我查文档的功夫。