家庭统一多媒体服务器的架构设计与部署
打造一台All-in-One设备的想法很久了,一直懒得实施。家里有一台初代外星人Alpha虽仍7x24工作,却也随着入手X1X,利用率降低很多,只是挂挂PT、看看电影。既然新机器装不起,新发布的HPE ProLiant MicroServer Gen10也不给力,Mac Mini产品线还迟迟不更新,不如改造一下这台Alpha,让它继续发光发热,变身一台“家庭统一多媒体服务器”。
需求规划
既然是自己打造,那么当然按照我自己的需求来,把能想到的,不管能不能实现,先都列出来吧。
网络设备管理(UNMS, UniFi Controller)
智能家居网关(Home Assistant, Homebridge)
多媒体回放(网络音视频、次世代/原盘)
媒体资料库管理
下载(http, ftp, bt, magnet, ed2k, pt)
现阶段的需求,主要就这些了,也是按优先级从上往下排的。
网络设备管理
家里有UAP设备,需要有UniFi Controller进行管理,因为有来宾Portal认证的需求,UniFi得一直在线。目前是将一个树莓派刷了UniFiPi的系统在管理,这次将一起整合。
还有一个EdgeMAX ER-X-SFP路由器,通过UNMS进行管理。
智能家居网关
各种智能设备的接入和场景配置,Home Assistant + Homebridge标准搭配,无需多言。
多媒体回放
多媒体回放涵盖多种类型格式,Kodi(原XBMC)是不二之选。我倾向使用Windows版本的Kodi,因为安装方便,兼容性好;Linux版本的需要解决显卡、声卡驱动等各种问题,不然无法正常使用GPU解码,或无法正常实现次世代源码输出等;X1版本还有当然还有硬解的问题没有解决。当然,还有一些Kodi能力范围以外的东西,比如说3D原盘,Kodi至今都没法在快门式系统下正常输出,需要借助其他播放工具;再比如像一些网络流媒体优酷、爱奇艺、网易云音乐等等,必须借助浏览器或单独的应用。
媒体库资料库管理
虽说Kodi也能进行媒体管理,但是有专门的媒体库服务看起来似乎更酷一些,开源的Emby还能够免费支持串流点播转码,实现多终端无缝追剧,或轻松与朋友一同分享。
下载
下载是最基本的需求了,实现起来也相对容易,只要覆盖HTTP/FTP、ed2k、BT(Magnet)、PT即可,实现的方式有很多。最常见的如Windows下的迅雷 + utorrent,Linux下的aria2c + transmission。
方案设计
确定了具体需求及大体要部署的应用,接下来就该设计具体的方案了。首先可以确定的是,这些应用里既有Windows平台的应用又有Linux平台的应用,势必要借助虚拟化才能在一台设备上实现了(古老的Linux + Wine这种就不提了,会暴露年龄
)。
时下主流的虚拟化产品有VMWare(Workstation、vSphere)、Virtualbox、KVM、Hyper-V、Xen等,如何来选择呢?先来分分类,这些产品里Virtualbox、KVM、Xen是开源的,其他则是商业软件,对我们来说不花钱最重要!那么仔细看一下,VMWare vSphere Hypervisor(ESXi)是免费的,而Hyper-V随Windows专业版/企业版或Windows Server附带,也算是没有额外的成本。
关于虚拟化技术,Type I类、II类虚拟化的技术差异,这里就不赘述了,大概意思就是,II类的虚拟机并不能直接访问硬件资源,而是是要依托于宿主操作系统,就像VMWare Workstation、VirtualBox、Parallels这类产品;而I类的虚拟机则是直接运行在硬件之上,同时需要底层硬件支持虚拟化,就像Xen、vSphere、Hyper-V、KVM(关于KVM到底是Type I还是II的争论,从未停止过,我认为他是I类)。从系统性能方面考量,肯定首选Type I类无疑了。
那么到底采用哪种Type I类的技术?再来看看我的需求,Linux端执行的是以B/S架构的应用为主,Windows端执行的图形化界面应用为主。那么如果Windows作为虚拟机出现,必须要借助GPU虚拟化或者GPU设备直通来输出图像;而Linux作为虚拟机,不需要输出图像也没有任何影响。
是时候来看看我手头的设备了,仅仅是一台15年的初代Dell Alienware Alpha,配置:CPU Intel i5-4590T, Mem 8GB, SSD 256GB, GTX860m GPU,外加一个双盘位硬盘盒做存储。
这样的配置,很容易就可以做出决定了——Windows系统作为物理机,Linux作为虚拟机,那么最简便也成本最低的当然是Windows 10 Pro + Hyper-V了,OEM桌面版系统没有任何成本,且较服务器版更适合日常应用。(这里补充一下,其实Hyper-V是一种Type I类混合型虚拟化技术,当Windows启用Hyper-V功能后,系统架构已经发生了转变,先前的Windows系统在此时其实也变成了首台虚机,称之为父分区,运行在hypervisor层之上,负责管理子分区和I/O,而新创建的虚机则是在子分区里。但为了方便理解,我们暂时还是将Windows称为物理机,Linux称为虚拟机)
好了,只剩下一个问题,选择哪个Linux发行版?再来看看需求吧,其中UNMS这个应用,官方只提供了一种部署方式——Docker。那么不如我们将所有的应用都采用Docker容器方式来部署,选择最适合部署Docker容器的CoreOS吧。
等等!虚机里面再做一层虚拟化,会不会效率很低?Docker不是有for Windows的版本吗?是不是可以一个Windows全搞定了呢?好吧,这个大坑其实我已经踩过了,答案就是暂不推荐。简单说一下原因:
Docker for Windows有两种容器可以采用,一种是真正在Windows上实现的容器Windows Container,另一种则是在Hyper-V上部署了一台微软精简过的包含Docker的MobyLinux镜像来实现。
前者的这种容器很多应用都还无法支持,而后者这种其实与现在的方案基本一样,在效率上就算有提升也应该差别不大。而且Hyper-V上的这个镜像,正常情况是拿不到控制台的。我们只能使用Powershell来使用Docker,或安装一个Windows Subsystem for Linux(WSL),通过tcp来连接Docker引擎。并非完全不能用,但就从本文即将部署的UNMS来看,官方提供了Linux下的安装脚本,要将其改写能够在Windows下部署还是有不小的困难的(我没有尝试,官方论坛有人尝试没有成功)。而且,这种方式部署出来的容器应用如何访问宿主的文件系统?恐怕要改造每个需要访问的容器应用了。
确定方案,Windows 10 Pro + Hyper-V + CoreOS + Docker。CoreOS官网提供了Hyper-V的镜像vhd文件,如此看来兼容性应该不会太糟糕。而CoreOS上,完全采用Docker容器部署应用,来降低维护更新的复杂度和降低试错成本。架构图如下:
部署实施
准备环境
终于进入正题开始部署了,首先准备环境,进入CoreOS官网。
下载适用Hyper-V的磁盘镜像vhd文件,我选择的是Stable分支的最新版本。当然也可以下载iso livecd自行安装,另外页面上同时提供了其他的虚机镜像文件。
在下载的同时,打开Hyper-V管理器,新建一台虚拟交换机,并设置将交换机连接到外部网络,其实就是桥接到连接外网的端口上,最好用千兆有线。我们即将部署的CoreOS会连接到这个虚拟交换机上,便于我们后续的管理和使用。
部署虚机
vhd文件下载并校验完成后,在Hyper-V中使用快速创建,并选择这个镜像文件。在更多选项中可以设定虚机的名称,这里设置为CoreOS,并将网络设定为我们刚刚建立的虚拟交换机,我这里叫bridge。
创建后很快就生成了一台虚机,不急着启动,先调整一下配置。默认的配置给了2个CPU核心,2GB内存,不到5GB的硬盘空间。稍作调整,内存启用动态内存,最多允许占用4GB。硬盘调整到16GB,避免不够用,再大一点也没关系,因为vhdx文件在物理磁盘中是会动态扩展的,并不会把磁盘空间先都占上。
好了,现在可以连接到控制台并启动CoreOS了。瞬间就到了登录界面,然而并不知道登陆的口令。。。
CoreOS官网没有找到ssh key,那么就用单机模式登陆并更改口令吧。重新引导系统,在GRUB选单上按下键盘上的‘e’,要快,稍纵即逝。然后在最后加上“coreos.autologin”。
按下键盘上的‘F10’,就引导进入单机模式了,赶紧修改密码。CoreOS默认管理员用户名是core,连同root口令一起改了,顺便创建一个没有sudo权限的用户。
sudo passwd core //修改core用户口令
sudo passwd //修改root口令
sudo useradd -G docker huzheyi //创建用户huzheyi,并添加到附属组docker
sudo passwd huzheyi //修改huzheyi用户口令
id huzheyi //查看huzheyi用户信息
再将主机名改为CoreOS:
sudo hostnamectl set-hostname CoreOS
OK,系统部署基本完成,重启一下。不必再盯着无法复制粘贴和回滚屏幕的控制台了,记下屏幕上的IP,用ssh登陆来操作吧!(补充一句,现在Windows也自带ssh客户端了喔,直接在cmd或PowerShell下就可以使用
)
应用部署
CoreOS具备完整的Docker环境,真正开箱即用,开始部署应用吧!
UNMS
先来部署UNMS,参考官网的安装文档。
一句话部署:
curl -fsSL https://unms.com/install > /tmp/unms_inst.sh && sudo bash /tmp/unms_inst.sh
没一会儿就报错了,什么原因呢?原来是UNMS的系统相对复杂,为了支持企业环境的分布式部署,并没有将redis、nginx、prostre这些放在一个容器里。这种情况下就需要Docker Compose进行编排了,而报错正是在Docker Compose的安装。
这里要提到CoreOS的一个特性,也是我选择CoreOS的一个原因。
CoreOS采用双系统分区 (Dual Root Partition) 设计。两个分区分别被设置成主动模式和被动模式并在系统运行期间各司其职。主动分区负责系统运行,被动分区负责系统升级。一旦新版本的操作系统被发布,一个完整的系统文件将被下载至被动分区,并在系统下一次重启时从新版本分区启动,原来的被动分区将切换为主动分区,而之前的主动分区则被切换为被动分区,两个分区扮演的角色将相互对调。同时在系统运行期间系统分区被设置成只读状态,这样也确保了 CoreOS 的安全性。CoreOS 的升级过程在默认条件下将自动完成,并且通过 cgroup 对升级过程中使用到的网络和磁盘资源进行限制,将系统升级所带来的影响降至最低。
没错,就像Android 8.0一样,正是这种设计,/usr分区是以只读形式挂载的。所以刚才在安装Docker Compose到默认的/usr/bin时发生了错误。知道了原因就好办了,我们来手动安装Docker Compose,/opt/bin在环境变量里,那就装在这吧。
su
curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` > /opt/bin/docker-compose
chmod +x docker-compose
装完Docker Compose,再执行前面的安装UNMS的命令,就可以了!看一下效果:
UniFi Controller
UBNT官方没有提供UniFi Controller的Docker的部署方式,Docker Hub上下载最多的镜像有两个,分别是jacobalberty/unifi和linuxserver/unifi。前者是自动构建的,跟UBNT官方同步到了最新的5.8版本,而后者只有5.6 LTS版本。后者的维护者linuxserver.io团队也是挺有意思,维护了好多Docker镜像,就选择他的版本吧。参照https://hub.docker.com/r/linuxserver/unifi/,自己调整了一下启动参数如下:
docker run -d
--name=unifi
-v /home/huzheyi/unifi:/config
-e PGID=1000 -e PUID=1000
-p 3478:3478/udp
-p 10001:10001/udp
-p 8080:8080
-p 8081:8081
-p 8443:8443
-p 8843:8843
-p 8880:8880
-p 6789:6789
--restart=always
--memory=1024M
linuxserver/unifi
增加了自动启动和内存限制的参数,以uid为1000的用户——也就是前面建立的huzheyi用户来运行容器,配置文件放在了/home/huzheyi/unifi下。部署成功后,在浏览器试一下:
Home Assistant
Home Assistant官方提供了Docker的部署方式,自己调整了一下启动参数:
docker run -d
--name=hass
-v /home/huzheyi/hass:/config
-v /etc/localtime:/etc/localtime:ro
-e PGID=1000 -e PUID=1000
--net=host
--restart=always
--memory=512M
homeassistant/home-assistant
跟上面一样,增加了自动启动和内存限制的参数,用huzheyi来运行,配置文件放在/home/huzheyi/hass下。部署成功后,在浏览器试一下:
Homebridge
Homebridge是基于NodeJS的项目,项目拥有者nfarina只提供了NPM一种部署方式。好在有oznu维护了一个docker-homebridge项目(https://hub.docker.com/r/oznu/homebridge/),自己调整了一下启动参数:
docker run -d
--net=host
--name=homebridge
-e PUID=1000 -e PGID=1000
-e TZ=Asia/Shanghai
-v /home/huzheyi/hb:/homebridge
--restart=always
--memory=512M
oznu/homebridge
Emby
Emby官方支持Docker方式部署(https://hub.docker.com/r/emby/embyserver/),然而我却在试过之后就删掉了,什么原因呢?如果仅仅把Emby当作媒体库来用,给Kodi提供媒体元数据,那没有什么问题。但点播视频串流的时候,就有点不忍心了,因为容器下的Emby无法支持任何硬件层面的优化加速转码(CoreOS下也没有VAAPI的驱动),CPU占用直奔100%,风扇呼啸;而如果在Windows下部署Emby,可以利用Nvidia NVENC加速编码,CPU几乎无负载。
尽管如此,还是将部署方法写在这里:
docker run -d
--volume /home/huzheyi/emby:/config
--volume /media/Storage:/mnt/share1
--publish 8096:8096
--publish 8920:8920
--env UID=1000
--env GID=1000
--restart=always
--memory=1024M
emby/embyserver:latest
可以看到,这里我把/media/Storage传进了容器,作为我的媒体源。而这个/media/Storage节点实际是挂载了我Windows下的一个共享文件夹,这部分的实现稍后再讲。
rtorrent、Aria2
rtorrent和Aria2是两个下载工具,轻便易用,且都没有Windows版本。反正容器应用即插即用,那就随手部上吧。
rtorrent的镜像同样是采用linuxserver.io团队维护的版本,包含了rutorrent前端,启动参数如下:
docker run -d
--name=rutorrent
-v /home/huzheyi/rtorrent:/config
-v /media/Storage:/downloads
-e PGID=1000 -e PUID=1000
-e TZ=Asia/Shanghai
-p 8000:80
-p 5000:5000
-p 51413:51413
-p 6881:6881/udp
--restart=always
--memory=256M
linuxserver/rutorrent
Aria2采用的是abcminiuser维护的版本,集成了Aria2-NG的前端,个人认为比YAAW和Aria2-WebUI要好看,启动参数如下:
docker run -d
--name aria2
-p 6800:6800 -p 6880:80
-v /media/Storage:/data
-v /home/huzheyi/aria2:/conf
-e PGID=1000 -e PUID=1000
-e TZ=Asia/Shanghai
--restart=always
--memory=256M
abcminiuser/docker-aria2-with-webui:latest-ng
在这两个容器中,同样传入了/media/Storage目录,作为下载目的目录。
部署成功后,在浏览器试一下:
其他容器
为了方便日常监控,我们可以引入一些图形化工具来管理容器。CoreOS官方提供的Tectonic(其实是原生的Kubernetes,Google的开源项目),开源的Shipyard、Rancher等,都可以选择。为了方便,同时也更轻量化,我就用国内的DaoCloud吧。注册DaoCloud账户后,可以添加主机,页面上也给出了添加的方法,其实也是部署一个容器,但是CoreOS还是略有不同,按照下面的命令来执行吧:
sudo mkdir -p /opt/bin
sudo mkdir -p /usr/share/oem/bin
curl -sSL https://get.daocloud.io/daomonit/install.sh | sed -e s//usr/local/bin//opt/bin/g | sed -e s//usr/bin//usr/share/oem/bin/g | sh -s a...z
最后这个AccessKey填页面上给的这个喔。执行完之后就可以看到主机添加成功了,便于我们日后随时随地监控。
说到DaoCloud,那么就顺便说下Docker加速器吧,归功于GFW,Docker Hub在国内的访问速度不理想,Docker加速器能帮我们解决不少问题,DaoCloud就是国内最早提供镜像服务的厂家。当然像阿里、163等也提供了这项服务。就以DaoCloud为例,登陆后点击加速器,就显示了个人的加速器连接,和启用方法。然而官方提供的这个脚本并没有适配我们的CoreOS,手动来改吧。
查看一下CoreOS的Docker启动服务配置文件/run/systemd/system/docker.service。
可以看到启动参数定义在了/run/flannel/flannel_docker_opts.env,而这个文件不存在,需要手动创建。
sudo mkdir -p /run/flannel/
sudo vi /run/flannel/flannel_docker_opts.env
输入内容:
DOCKER_OPTS="--registry-mirror=http://********.m.daocloud.io"
星号部分是自己的用户代码替代,然后重启一下Docker服务。
sudo systemctl daemon-reload
sudo systemctl restart docker
当然你会发现这种修改并不是永久的,因为/run节点挂载的是个临时文件系统,里面的内容重启后就没有了。在CoreOS里要持久化有点麻烦,因为这个/run/systemd/system/docker.service也是临时的,至于是从哪里生成的,我也暂时不知道,不过就算知道了,可能也改不了,因为前面提到过CoreOS的启动分区是只读的。所以如果要永久使用加速器的化,只能将这个flannel_docker_opts.env文件保存到别的地方,比如用户目录,然后在Docker服务器之前增加一个启动服务,用来创建一个软连接到/run/flannel/下。(启动服务怎么写后面讲共享的时候会提到)。 着实有点麻烦,好在不会天天重启,也不会经常部署容器。再说,其实我也不需要加速,因为在路由器上做了手脚
。
Windows平台应用部署
这部分就没什么好说的了,有UWP应用的首选,例如网易云音乐。除此之外,我部署了Kodi、Emby、utorrent和迅雷。
Windows下的Kodi可以轻松实现GPU硬解和次世代源码输出,3D视频也可以,只是3D原盘会有问题,另外Emby为Kodi提供了插件,可以直接启动时获取资料库。
Windows下的Emby也支持了多种硬件加速转码的方式,对比下来Nvidia NVENC的效率大于Intel Quick Sync,那就用GPU来加速转码吧。
由于共享文件夹存在着一定程度的不稳定性,所以还是在Windows下安装了utorrent和迅雷,用来支持pt和其他的下载(比如aria2不支持的ed2k)。现在的utorrent满屏幕广告,不过也习惯了;迅雷更是懒得吐槽,而且迅雷停止了xware的开发维护。
共享文件夹
容器中的应用,如何与Windows系统共享文件呢?前面我提到了/media/Storage这个目录,这个节点实际上挂载了Windows上的一个共享文件夹。这个文件夹存放了我现在所有的资料库,位于一个外置的USB多盘位硬盘盒中,并且用Windows提供的存储池功能虚拟成了一个存储设备。但这其实只是个过渡的办法,并不完美。原因有:
Linux系统虽支持SMB/CIFS协议访问Windows共享文件夹,但不太稳定,随便google一下关键字“cifs vfs error”就能找到无数反应类似问题的,从十年前到现在;
通过这种方式挂载的存储设备不能支持fast allocation技术,也就是意味着当通过Linux系统下载大文件的时候,要么忍受漫长的prealloc时间,要么承担产生碎片的风险干脆关闭预分配磁盘空间;
这种方式的数据传输基于网络,由于虚机CoreOS与宿主机Windows的网络是桥接的,于是传输效率又跟虚拟网桥的效率有关。
但不管怎样,先将CoreOS挂载Windows共享文件夹的方法写出来,后续再来改进他。
首先,Windows下开启一个共享文件夹,比如我的共享文件夹名为“Storage“;
然后,在CoreOS下测试看能否挂载:
mkdir /media/Storage
mount -t cifs -o username=用户名,password=密码,uid=1000,gid=1000,vers=3.0 //192.168.1.164/Storage /media/Storage
如果成功了,就说明配置没有问题,但这种挂载是临时的,重启就会失效,需要将它加入系统开机启动服务中。
CoreOS通过systemd来控制系统启动关闭的所有服务,我们也来写一个这样的服务:
su
vi ~/mountcifs.service
输入内容:
[Unit]
Description=Mount CIFS
Before=docker.service
After=network-online.target
[Service]
RemainAfterExit=yes
TimeoutStartSec=0
ExecStartPre=/usr/bin/mkdir -p /media/Storage
ExecStart=/usr/bin/mount -t cifs -o username=用户名,password=密码,uid=1000,gid=1000,vers=3.0 //192.168.1.164/Storage /media/Storage
ExecStop=/usr/bin/umount /media/Storage
[Install]
WantedBy=docker.service
保存退出vi,通过systemctl在/etc/systemd中创建软连接:
systemctl enable /root/mountcifs.service
顺便让docker也随机启动吧:
systemctl enable docker
重启测试一下,看能否访问到共享文件夹。
收尾工作
至此家庭统一多媒体服务器的部署基本完成,记得在Hyper-V管理器中,为CoreOS创建一份快照(检查点),以便在系统出现意外时能够快速恢复。
后续改进
主要的问题还是在于共享文件夹这块,并不完美。相对完美的方式,应该是将存储设备通过Hyper-V直通给CoreOS,由CoreOS直接管理整个物理设备。但由于我现在的存储设备是Windows存储池,这种设备并不能被Linux所识别。正好近期准备调整扩容存储,到时候再来研究调整方案。是搞个盘阵直通进去,采用btrfs文件系统?还是干脆买个成品NAS,把存储下载都剥离出来?
当然在新存储还没有到位前,其实也可以用NFS共享的方式来取代SMB/CIFS,以提高稳定性(并未测试)。只不过微软没有在Windows 10中提供NFS服务端的功能(Server中有),需要借助第三方工具。
总结
洋洋洒洒写了这么多,对新手来说可能着实有点折腾。但对我来说,提高了旧设备的利用率,还是比较欣慰的。而且,虚拟化技术和容器技术的发展,着实为我们带来了极大的灵活性和便利性!
最后,文中如有错误,还请大家多多指教,对于技术理解和选择上的偏见,也希望大家包涵!


















丢了丢丢
校验提示文案
阿伏伽德Luo
校验提示文案
买青椒也用券
校验提示文案
橘子宝宝大大叔
校验提示文案
oO小林子Oo
校验提示文案
oO小林子Oo
校验提示文案
3006kane
校验提示文案
QFSSonline
校验提示文案
change520
校验提示文案
Babyii
校验提示文案
心蓝无為
校验提示文案
黎_浩
校验提示文案
MarvinYang
校验提示文案
东门张
校验提示文案
idlesun
校验提示文案
贝格菲斯
校验提示文案
youer
我自己的痛点是a、源太多杂乱无章需要一个索引工具(KODI);b、资源分散需要集中管理(FTP或SMB挂载存储);那么集装箱那堆应用我不需要,请问全部割除会有什么影响(包括HyperV及下面部署的linux)?
我现在是一台旧机跑ESXI,有3个VM,一个WIN2019,一个黑群晖,一个爱快软路由,现在是打算WIN下部署KODI,挂载所有存储
校验提示文案
茶走
校验提示文案
OluMel7
校验提示文案
神马玩意
校验提示文案
jhdss
校验提示文案
吃土豆多长肉
校验提示文案
[已注销]
校验提示文案
youer
我自己的痛点是a、源太多杂乱无章需要一个索引工具(KODI);b、资源分散需要集中管理(FTP或SMB挂载存储);那么集装箱那堆应用我不需要,请问全部割除会有什么影响(包括HyperV及下面部署的linux)?
我现在是一台旧机跑ESXI,有3个VM,一个WIN2019,一个黑群晖,一个爱快软路由,现在是打算WIN下部署KODI,挂载所有存储
校验提示文案
DerekChia
校验提示文案
贝格菲斯
校验提示文案
橘子宝宝大大叔
校验提示文案
值友9683084444
校验提示文案
大轰趴
校验提示文案
idlesun
校验提示文案
天河
校验提示文案
东门张
校验提示文案
丢了丢丢
校验提示文案
始终在奔跑
校验提示文案
OluMel7
校验提示文案
语烨
校验提示文案
LANGOO
校验提示文案
miaoxin
校验提示文案
MarvinYang
校验提示文案
漫天星光繁星点点
校验提示文案