本文介绍了如何在树莓派(Ubuntu Server 22.04 on Raspberry Pi 4B 8G)上部署百度网盘,并通过脚本(Linux tc命令)的方式对docker容器进行带宽限制。
你也可以从这篇博文中了解如何使用Devv AI编写shell脚本。
找到合适的镜像
目标是使用百度网盘在树莓派上进行离线下载,因此需要找到合适的 arm64镜像,在DockerHub上找寻了一番,发现 johngong/baidunetdisk
这个镜像拉取次数也不少并且支持arm64。所以就采用这个镜像来部署容器。
容器部署
参考文档
- DockerHub: https://hub.docker.com/r/johngong/baidunetdisk
- Github: https://github.com/gshang2017/docker/tree/master/baidunetdisk
创建目录
- 工作目录
# mkdir -p /opt/docker_container/baidunetdisk && cd /opt/docker_container/baidunetdisk
# touch .env docker-compose.yml
- 下载目录
# mkdir -p /var/download/baidunetdisk/download
docker-compose.yml
/opt/docker_container/baidunetdisk/docker-compose.yml
version: '3.9'
services:
baidunetdisk:
container_name: baidunetdisk
image: johngong/baidunetdisk:v_4.14.6_arm64v8
user: root # 配置了其他用户启动时报错,配置成root简单粗暴,只有需要离线下载时才启动这个容器
restart: unless-stopped
env_file: ./.env
volumes:
- /var/download/baidunetdisk/download:/config/baidunetdiskdownload
- /var/download/baidunetdisk:/config
network_mode: bridge # 如果对网络有隔离要求,可以单独配置网络
ports:
- 5800:5800
- 5900:5900 #开启VNC端口,可以设置访问密码,增加安全性
环境变量配置
- 随机生成VNC密码
< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c 32 | xargs -I{} echo {}
/opt/docker_container/baidunetdisk/.env
VNC_PASSWORD=your_vnc_password
启动网盘容器
# docker compose up -d
配置Nginx反向代理(可选)
如果有公网访问需要,建议配置反向代理并且开启SSL。
以下Nginx配置供参考(假设域名是 pan.test.com)
server {
listen 80;
server_name pan.test.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name pan.test.com;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# Maximum secure cipher list from https://cipherli.st/. Not support some clients: IF6/XP, IE8/XP, Java 6u45, Java 7u25, OpenSSL 0.9.8y
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains; preload' always;
ssl_certificate /path/to/pan.test.com.pem; # 修改为实际证书文件路径
ssl_certificate_key /path/to/pan.test.com.key; # 修改为实际密钥文件路径
location / {
proxy_pass http://127.0.0.1:5800;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 以下配置开启Websocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_connect_timeout 3m;
proxy_send_timeout 3m;
proxy_read_timeout 3m;
client_max_body_size 0;
proxy_buffering off;
proxy_request_buffering off;
proxy_redirect off;
}
}
访问Web地址
- Web地址:
http://your_ip_address:5800
- 打开以上地址后输入之前配置的
VNC_PASSWORD
就进入了百度网盘的界面了
docker容器限制带宽
背景说明(可忽略)
百度网盘部署完成后,登录了百度网盘的账号后就可以开始让它静静的在后台下载了。
但是因为所安装版本的设置
内没有限制下载速度
的选项,这样在进行下载时占满了带宽就很糟糕了。
首先想到的是在路由器上限制树莓派的下行带宽
然后家里的其它设备就有充足的带宽正常上网了,但是树莓派上还部署了其他的服务,百度网盘不限速的话就把树莓派下行带宽全部占满影响了其他服务,因此就需要想办法把 docker 容器进行限速。
经过一番研究,找到几个方法来解决此问题:
1、使用docker-tc镜像作为sidecar来限制容器的带宽,但是该镜像没有arm64的版本,因此未尝试此方案。
2、将百度网盘容器的网络类型修改为 macvlan
, 单独分配一个与宿主机同网段的IP,然后在路由器的界面中限制带宽。(理论上这个方法是可行的,但是我的macvlan网络配置未成功,遂放弃...)
3、在宿主机上使用tc命令限制docker容器对应的veth虚拟网络设备的带宽,参考 stackoverflow: https://stackoverflow.com/a/71677515
最终在 Devv AI 的帮助下,我采用方案3
实现了对 docker容器的带宽限制,具体见以下shell脚本。
使用tc.sh脚本限制docker容器带宽
/opt/docker_container/baidunetdisk/tc.sh
#!/bin/bash
# 解析参数
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-c|--container)
CONTAINER_NAME="$2"
shift
shift
;;
-r|--rate)
RATE="$2"
shift
shift
;;
*)
shift
;;
esac
done
# 检查参数是否为空
if [ -z "$CONTAINER_NAME" ]; then
echo "缺少参数:容器名称,usage: -c <container_name> or --container <container_name>"
exit 1
fi
if [ -z "$RATE" ]; then
echo "缺少参数:宽带速率,usage: -r 24 or --rate 24,其中24代表 24 mbit,即3MB/s"
exit 1
fi
# 计算burst值
LATENCY=10
RATE_BIT_S=$(echo "scale=10; $RATE * 10^6" | bc -l)
LATENCY_S=$(echo "scale=10; $LATENCY * 10^-3" | bc -l)
BURST=$(echo "scale=0; ($RATE_BIT_S * $LATENCY_S) / (8 * 10^3)" | bc -l)
# 获取容器PID
PID=$(docker inspect -f '{{.State.Pid}}' $CONTAINER_NAME)
# 创建网络命名空间
mkdir -p /var/run/netns
ln -sfT /proc/$PID/ns/net /var/run/netns/$CONTAINER_NAME
# 获取veth名称
VETH_NAME=$(ip link show | grep "link-netns $CONTAINER_NAME" -B 1 | grep -o 'veth[0-9a-f]*')
echo "veth_name ${VETH_NAME}"
# 检查网络设备的规则状态
RULES=$(tc -s qdisc show dev $VETH_NAME 2>&1)
# 设置网络设备的限速规则
if [[ $RULES == *"Cannot find device"* || $RULES == *"qdisc noqueue"* ]]; then
sudo tc qdisc add dev $VETH_NAME root tbf rate ${RATE}mbit burst ${BURST%.*}kbit latency ${LATENCY}ms
else
sudo tc qdisc change dev $VETH_NAME root tbf rate ${RATE}mbit burst ${BURST%.*}kbit latency ${LATENCY}ms
fi
# 查看网络设备的队列规则
tc -s qdisc show dev $VETH_NAME
脚本使用方法
以限制百度网盘的docker容器
baidunetdisk
的带宽为例子, 脚本需要在对应的docker容器启动后执行
- 设置带宽为 8mbit,即 1MB/s
# sh ./tc.sh -c baidunetdisk -r 8
veth_name veth9a59fb4
qdisc tbf 800a: root refcnt 5 rate 8Mbit burst 1280b lat 10ms
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
- 设置带宽为 16mbit,即 2MB/s
# sh ./tc.sh -c baidunetdisk -r 16
veth_name veth9a59fb4
qdisc tbf 800a: root refcnt 5 rate 16Mbit burst 2560b lat 10ms
Sent 592 bytes 3 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
按照以上的配置,就可以安心的把它挂在后台下载了 :)。
等到不需要离线下载时,把容器
baidunetdisk
停掉,对应的虚拟网络设备veth9a59fb4
就自动删除了。
使用Devv AI生成tc.sh
附上通过AI来生成shell脚本的基本步骤:
1、做好背景知识调查,例如:
- 通过搜索引擎找到可行的方案 stackoverflow问题
- 学习 tc命令的基本参数使用方法
2、提供需求描述
3、调试AI反馈的脚本,修改需求描述,迭代完成脚本的编写
背景知识调查
需求描述
复制以下
需求描述内容
到 Devv AI 去试试提问吧~
现有以下脚本:
`脚本1`(通过容器名称获取容器`PID`):
```bash
# docker inspect -f '{{.State.Pid}}' <container_name>
```
`脚本2`(创建网络命名空间):
```bash
# mkdir -p /var/run/netns
# ln -sfT /proc/<PID>/ns/net /var/run/netns/<container_name>
```
`脚本3`(查看docker容器的网卡名称):
```bash
# ip link show | grep "link-netns <container_name>" -B 1
130172: veth6749ab5@if130171: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc tbf master docker0 state UP mode DEFAULT group default qlen 1000
link/ether 1e:e0:4d:31:30:fb brd ff:ff:ff:ff:ff:ff link-netns baidunetdisk
```
从以上脚本中最后一个命令的输出获取网卡名称: veth6749ab5
`脚本4`(查看网络设备队列规则): `tc -s qdisc show dev <veth_name>`
此脚本有两种执行结果:
1、未找到网络设备
```bash
Cannot find device "<veth_name>"
```
或者
```bash
qdisc noqueue ...
```
2、正常显示网络设备
```bash
qdisc tbf 8003: root refcnt 5 rate 24Mbit burst 4Kb lat 10ms
Sent 150219 bytes 1193 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
```
`脚本5`(增加网卡设备的限速规则)
```bash
# sudo tc qdisc add dev veth6749ab5 root tbf rate <rate> burst <burst> latency 10ms
```
`脚本6`(修改网卡设备的限速规则)
```bash
# sudo tc qdisc add dev veth6749ab5 root tbf rate <rate> burst <burst> latency 10ms
```
`公式1`: `burst = (rate_bit_s * latency_s) / 8`
举例说明:
假设: rate = 24 mbit, latency = 10 ms
将带宽转换为 ‘bit/s’,即 rate_bit_s = 24 * 10^6
延迟单位为 ‘秒’,即 latency_s = 10 * 10^-3
然后计算得到的burst值将以字节为 bit。
根据这个公式,计算出的burst值将是:burst = (24 * 10^6 * 10 * 10^-3) / (8 * 10^3) = 30 kbit
因此,对于24mbit的带宽和10ms的延迟,一个合理的burst值将是 30kbit。
---
编写shell脚本,根据以上提供的功能脚本实现以下功能:
1、输入参数:
-c 或 --container: docker容器名称
-r 或 --rate: 限制带宽(单位mbit)
2、计算参数 burst:
固定 latency = 10ms
通过`公式1` 计算burst参数值
3、由以上 第1步 和 第2步得到以下三个参数:
- rate: 单位 mbit,举例 24 mbit
- burst: 单位 kbit,举例 30 kbit
- latency: 单位 ms,值固定为 10 ms
4、设置该docker容器对应的veth网卡的网速,有以下几个要求:
4.1、基于 `脚本1` 获取容器PID
4.2、基于 `脚本2` 创建容器的网络命名空间
4.3、基于 `脚本3` 获取网卡名称 `veth_name`
4.4、执行 `脚本4` 获取网络设备的规则状态,分为两种 “未找到网络设备” 和 “网络设备已配置限速规则”
4.4.1、当4.4的执行结果为 “未找到网络设备” 时,执行`脚本5`
4.4.1、当4.4的执行结果为 “网络设备已配置限速规则” 时,执行`脚本6`
5、执行`脚本4` 查看网络设备的队列规则,并打印
评论区