在群晖的 Docker 环境中运行甜糖星愿服务

前段时间在网上看到了一个叫 “甜糖星愿计划” 的东西,声称可以通过贡献闲置带宽来获得积分。正好我有个 NAS,正好我的宽带一天从白天闲到黑夜,不如利用起来,少少挣一些零花钱。

需要注意的一点是,本文提到的镜像仅在我的群晖DS218+ 上测试过,虽然镜像中未使用任何群晖限定的依赖,理论上适用于任何 x86 架构的平台,但并不保证运行效果。而且本文目标平台是 x86,如果你拥有 ARM 平台的机器,那根本不需要废这个劲,你可以直接运行甜糖星愿的可执行程序。

本文提到的操作全部基于 Docker,故在按照本文操作前,请先确保你已经拥有足够的知识来使用 Dockerdocker-compose

我的网络环境

因为这个镜像相关的一些配置是以我的网络结构为基础的,所以我觉得有必要简单说一下我的网络结构是什么样的。

简单来说,我的网络就是这样子的。虽然网络里还有别的设备,但是因为与本文无关,我就略掉了。

1
[公网] -- [光猫] -- [群晖]

其中光猫负责拨号,所以它也是最外层的一个路由器,光猫的 IP 地址是 192.168.1.1,它下面有一个 192.168.1.0/24 的子网,群晖与光猫直连,有一个 192.168.1.0/24 子网下的 IP 地址。在群晖的 Docker 中,会有一个 macvlan 驱动的网络,与物理网卡共享同一个子网。甜糖星愿的容器将会接入到这个 macvlan 网络,在接入时我会手动为其分配一个 IP 地址。

安装 Docker 及配置网络

因为本文是通过 Docker 来实现的,所以第一步当然是安装 Docker。群晖嘛就从套件商店安装,其他平台就用自己平台的方法安装,总之装上 Docker 就行。安装好 Docker 之后,进入控制面板 -- 网络 -- 网络界面,选择连接公网的接口,如局域网1,点击管理 -- Open vSwitch设置,勾选启用 Open vSwitch

然后我们需要在 Docker 里面创建一个 macvlan 驱动的网络,命令如:

1
2
3
4
5
6
sudo docker network create \
-d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=ovs_eth0 \
macvlan

上面命令中 subnet 的值替换成群晖所在网络的子网,gateway 指向该子网的网关,parent 指向要绑定的物理网卡,最后面的 macvlan 是网络名,可以按需修改。

准备二进制翻译器

接下来,我们要借助 QEMU 的力量,放一个幻术。毕竟,甜糖星愿只给了 ARM 平台的可执行程序,直接在 x86 平台跑肯定是跑不起来的,所以我们要向内核注册一个翻译器,这样 Docker 在执行其他平台的机器码时就可以通过这个翻译器将其翻译成 x86 指令来执行了。是的,我知道这玩意效率不高,我已经体验过了。

首先,克隆这个镜像的源码仓库 [^2],找到 resources/qemu-aarch64-static,或者你直接从 GitHub 下载 qemu-aarch64-static也行,把这个文件放到 $PATH 指定的目录,赋予执行权限。

然后施法吟唱,很简单,就一句话:

1
sudo docker run --rm --privileged multiarch/qemu-user-static:register

但是,这个幻术在群晖重启之后就会消失,幻术没了,甜糖星愿就起不来。所以我们还得配一个开机后的自启动任务,让群晖帮我们自动吟唱。操作也很简单,首先将本仓库的 set_qemu_user_static.sh 放到一个合适的位置,比如我放到了 /var/services/homes/boris1993/scripts,然后前往控制面板 -- 任务计划,然后按照如下说明新增一个任务计划:

  • 任务名称:可自选
  • 用户账号:root
  • 事件:开机
  • 任务设置页面的运行命令:
    /var/services/homes/boris1993/scripts/set_qemu_user_static.sh

如果要看这个脚本的日志的话,在运行命令里面把脚本输出重定向到一个文件就可以了。

运行镜像

进入本仓库所在目录,或者下载 docker-compose.yml到一个合适的目录下,然后稍微编辑一下,以符合你的网络状况。主要要检查的就是 networks.macvlan.ipv4_address 的值,要确保它处在上面创建的那个 macvlan 网络的子网中。

确认无误后,执行 sudo docker-compose up -d,Docker 就会自动拉取镜像,并启动一个名为 tiantang 的容器。

容器内的甜糖星愿在首次启动时会自动退出,这是因为它在自我更新(我就不说这个操作一开始给了我多大的困扰了)。不要怕,容器里面有一个每分钟执行一次的定时任务,在没有发现甜糖星愿的进程时会自动将它启动。

除此之外,我会在容器启动两分钟后,检测甜糖星愿监听了哪些端口,然后通过脚本自动设置路由器上的 UPnP 规则,这样你就不需要将甜糖星愿容器的 IP 放到 DMZ 里,也不需要手动配置端口转发了。当然这个操作的前提是,你的路由器支持 UPnP,并且你启用了 UPnP,如果没有的话,那你只能手动操作了。或者,如果你不想让脚本自动配置 UPnP,或者客观条件下不允许你这么做,那么你可以把 docker-compose.ymlSKIP_UPNP_AUTOCONFIG 这一环境变量置为 true,这样脚本就不会执行了。

在甜糖星愿稳定运行,且端口转发规则也配置成功后,就可以通过手机客户端绑定这个节点了。但是这里有个问题,就是手机与甜糖星愿必须处在同一个子网里才能自动发现,如果因为各种原因没能自动发现,那么你可以在 tiantang 这个容器中打开一个 bash 终端,执行 ttnode_168 -p /data,在输出中会打印出这个节点的 UID,将其复制到任意二维码生成工具中生成一个二维码,然后用手机端扫描这个二维码,即可完成绑定。

在这之后,就没什么我们能做的了。我们就慢慢等着甜糖星愿给你分配任务吧。我是等了大概有两三天才开始跑流量的。如果在配置好 UPnP 后,手机端仍提示 “未配置网络”,那有可能是在配置 UPnP 的脚本启动时,甜糖星愿尚未打开所有端口,导致 UPnP 规则不完整。你可以前往路由器的 UPnP 页面,将页面显示结果与 netstat -nlp | grep qemu 命令的输出做对比,如果不一致的话,重新手动运行 set-port-forwarding.sh 脚本即可。

深入了解

如果你不止满足于把它跑起来,还想要了解这个镜像背后的运作方式,那么你可以前往这个镜像的 GitHub 仓库 [^3] 阅读该镜像相关的源码。在源码中我也写了注释,可以方便你理解我的想法。

我的邀请码

如果我的镜像帮到了你,或者我的这篇文章帮到了你,那么如果你愿意的话,你可以在手机客户端的填写邀请码处,填上我的邀请码 **804744**,这样你可以获得 15 张加成卡,当然我也会得到一些加成。反正互利互惠,我的加成不会从你的身上扣掉,何乐而不为呢?

[^2]: tiantang-x86-docker - Docker Hub
[^3]: tiantang-x86-docker - GitHub