基于Unraid的高成本自建网盘及私有云服务:(二)Docker

本章节适合喜欢折腾多功能NAS,但又像我一样缺乏计算机方面的系统培训、非科班、一知半解的同学。

一、Docker极简介绍

Docker与虚拟机(VM)

首先二者都是为了能够充分发挥物理机性能而设计的,目的是在一台物理机上同时运行多个应用程序,并期待有一定程度的相互隔离来保证安全。

解释一下应用程序的意思,也就是“application”(国外简称“app”,国内简称“A-批-批”),平时用的微软Office、WPS、手机淘宝、抖音等等的便是应用程序。另外不是有图形界面的才是应用程序,命令行的也可以是,比如服务器上常见的mysql、nginx等等也是。应用程序是依附于操作系统的。实际上docker和VM都是提供了隔离的操作系统环境,然后我们才可以在环境里运行应用程序,因为仅有隔离的操作系统缺乏实际意义,所以这里就不提操作系统了。

docker的宗旨就是轻量化、可迁移化,docker可以快速启动(秒级)、快速部署、快速上线,一个docker容器只运行一个关键应用程序,缺点就是隔离度没有VM高,安全性相应也较VM低,另外目前缺乏对于图形界面的良好支持。

假如我想部署nextcloud、jellyfin、nginx这三个程序,原始的办法就是在物理机上先安装Linux系统,然后手动安装这些程序、手动配置,并且期待中间不要出岔子,过程是比较惊险的。日后要升级程序,那就得祈盼不会出现软件冲突和各种error。运行过程中,如果一个程序奔溃了,祈祷灾难不要扩大到整机……现在有docker之后,只需要下载别人制作好的docker镜像,轻松拉起容器运行,无需担心各种依赖和相互冲突(因为docker提供了隔离的环境),即可快速上线服务。只要性能够,你想同时运行100个nextcloud也是可以的!

2. Docker的不足以及VM的必要性

docker提供了家用环境下充足的隔离度和灵活度,但是涉及到图形界面的,比如要在unraid里运行win10虚拟机,那docker就无能无力了,这个时候还是得要传统的VM出手解决。

VM就是完完全全地虚拟化一台主机出来了。虚拟机有自己的一切,包括虚拟CPU、内存、虚拟主板、虚拟网卡、显卡等等。docker虽说也是提供了隔离的环境,但实际上是依附于主机系统的,并没有完全剥离。

如果说docker是多人宿舍,那VM就是带卫浴的独立单间了;往多人宿舍增员比安排一个独立单间显然要来得快和轻便,但功能性和私密性就差了。

3. Docker基础术语解释

Docker是一套主机虚拟化解决方案,里面包含了众多组件:

docker engine - 运行在服务器的掌管资源的主程序。docker image(docker镜像)- 由他人制作打包好的系统以及应用程序模板。docker container(docker容器)- 自己基于image创建的实际运行的系统以及应用程序的实例。mirror - 分布在全球的docker官方image资源库的拷贝,也就是DockerHub的拷贝,可以加速拉取下载过程。docker registry(docker仓库)- 可以用来存放和分享制作好的docker image。

二、Docker的安装和运行

安装Docker

Unraid系统里面已经集成了最新版的docker,不需要自己安装,需要自己动手操作的,就是下载docker镜像和配置运行docker容器了。

网络条件好的同学,在App下,选择自己喜欢的,点点鼠标即可在unraid里运行自己的各种基于docker的服务。没错,unraid就是这么便利!

找不到 App 标签?参考unraid官方wiki安装“Community Applications”这款插件就有了。可以看到,甚至上线了利用大众的闲置计算资源,分布式云计算来帮助研究新冠肺炎病毒的公益docker

显然,网络条件好是不可能的!家庭光纤宽带条件下,要直接从dockerhub上拉取docker镜像,速度几乎为零,偶有狗屎运可以成功一下……我个人加速docker镜像下载的解决方案是配置docker mirrors。移动光纤宽带网络下实测,用ustc的mirror可以有显著的加速效果。

2. 配置USTC的docker mirror

2.1. 添加配置文件

点击unraid后台管理页面右上角的那个命令行:

nano /etc/docker/daemon.json

复制后右键粘贴后,ctrl+o保存,ctrl+x退出编辑器:

{ "registry-mirrors":[""] }

2.2. 重载 docker

Settings > Docker 下面:“Enable Docker”选“No”后“Apply”,然后选回“Yes”再“Apply”即可。

这个时候在 Apps 下,安装别人打包好的 docker 应该就有下载速度了(但不是所有包都有效果)。

注意:unraid主机重启后,上述的配置文件将消失,需要重复操作一遍。通过配置 Flash 里的 /config/go 文件可以使得重启自动生效,具体可以搜索网上教程。

三、Docker容器模板及启动参数

多数情况下,通过Community Applications的方式运行docker,不需要更改启动参数,按照默认的模板拉起容器即可部署各类服务。

Docker容器的配置页面,默认显示基础配置,可以通过点击右上角的“Basic/Advanced View”切换

这里简要说明一下个别参数。

1. PUID和PGID

UID(user id)、GID(group id)涉及到Linux系统的用户和权限管理相关知识。使用默认模板的情况下,PUID=99、PGID=100。

在Linux中,0~99是系统保留的专用用户id段,其中root的UID为0,nobody的UID为99。users组的GID为100。

默认状态下,docker容器是以root身份运行的,这样存在安全隐患,因为如果docker容器被入侵,容易威胁到主机安全。通过在容器启动参数中指定UID和GID,可以一定程度上提升安全性。

这里有个问题,主机映射到docker容器的目录,其本身在主机的所属用户和所属用户组跟启动docker容器时传入的PUID和PGID不一致的话,通过smb共享直接访问主机这个目录,会遇到禁止读写等权限问题。比如,映射主机里的“/mnt/user/docs”这个smb共享目录到Nextcloud的docker容器里,unraid主机里的归属是 william / users,但是docker容器的权限是 nobody / users(对应着PUID=99、PGID=100),那么将来通过各种客户端上传到Nextcloud网盘里的文件,通过smb共享直连unraid主机访问时(\\server-ip-or-hostname\docs),将处于只读状态,无法修改和上传文件。其实unraid提供了贴心的归属重置功能,在Tools > New Permissions 里,阅读相关说明后,选好目标目录或磁盘,点击 Start 即可重置主机里相关目录或文件的归属为 nobody / users 。接下来通过smb共享访问主机里docker容器的映射目录,就不会遇到权限问题了。

2. 映射目录(数据持久化)

Docker容器不是一定要映射目录才可以拉起运行的。默认的配置类的映射目录是“/mnt/user/appdata/name-of-the-docker-container”,默认的数据类的映射目录根据docker 镜像的实际需求会各有不同。

新人会问,为什么需要映射主机目录?默认情况下,docker容器并不能直接访问主机目录。我们经常会遇到一种情况,比如运行Jellyfin容器,这是一款多媒体服务程序,我希望它能直接访问unraid主机里保存在“/mnt/user/movies”下的所有电影文件,这个时候就需要把主机的目录映射到容器里去了。另外一种情况就是数据持久化的需求,比如运行MariaDB这款数据库容器,如果不映射目录,那么数据文件将直接保存在容器内部这个封闭空间里,以后无论是要备份,还是要直接访问,都极为不便。特别是当删除容器的时候,所有的数据文件也跟着一起烟消云散了。Docker这套解决方案的特色就是轻量化,所以推荐应用和数据分离,通过映射主机目录到容器内部的方式,可以让数据更好地生存下来,也方便多个容器共享一个主机目录。

默认使用模板的情况下是不需要操心这个的,别人都已经贴心地为你设置好了映射目录。当然,喜欢折腾的人怎么可能一切都按照默认进行,只要首次创建容器的时候,或者在 Docker标签页下点击容器图标或名称,进入编辑模式即可。

注意,编辑docker容器启动参数并apply后,容器将经历先删除,再自动用新的参数创建的过程。这个时候,原来容器及其内部包含的数据就泯灭。当然主机映射目录不会受影响,新的容器将会访问“/mnt/user/appdata/name-of-the-docker-container”里面已泯灭的容器留下的配置文件,你会发现除了新添加的启动参数外,一切又恢复如初,这也是我喜欢docker的一点。

如果你还是不理解,那不妨这么比喻:映射的目录 = U盘,电脑A + 运行的微软Powerpoint = 容器A,电脑B + 运行的金山WPS = 容器B。你在A电脑上用Powerpoint做了PPT并保存在U盘上,这个时候相当于程序和数据已然分离。PPT因为保存了U盘上,不会因为A电脑全盘格式化重装就消失了。只要把U盘插在B电脑上,照样是可以读取PPT文件的。另外你也可以靠着这个U盘,在很多不同的电脑上读取到这个PPT文件。

3. 端口映射

咱就不说TCP/IP的复杂东西了。实际上,ip对应的是主机在网络上的位置(万达广场),端口对应的是主机上不同的服务(A奶茶店)。比如主机A的ip是192.168.1.100,主机A可以在不同的端口提供不同的服务,比如22端口提供ssh服务,80端口提供web服务,同时一个端口仅能被一个服务占用,通过“ip:端口”访问(万达广场:A奶茶店)。

默认的“Network Type”为“Bridge”,大多数情况下这个就够了,这个时候如果没有冲突或者其他需要的话,按照模板默认的来就可以了。

以上图为例,Syncthing容器的8384端口(Container Port)将映射到主机的8384端口(Host Port)上,那么网络上通过连接“unraid主机ip:8384”就可访问到Syncthing。现在如果我改动主机端口号为12323,那么要连接“unraid主机ip:12323”,才可以到访问Syncthing。

可能有人好奇如果我把所有的端口映射都remove了会怎么样?并不会怎么样,容器照样可以运行,只不过无法访问到其提供的服务罢了。Bridge模式下,容器内部照样可以连接外网,但外网无法直接访问到容器提供的服务(等于说奶茶店开在了严密的万达广场管理办公室内部,里面的人可以外出采购原料,但是外面的人不能进来买奶茶)。其实将Bridge模式理解为一个虚拟路由器即可,相当于不同的容器都接在了路由器的LAN,如果想在WAN上访问容器服务,那么就要在路由器里配置端口转发。

4. 通过命令行进入docker容器内部

有时候,比如重建Nextcloud数据表,必须要进入容器内部,通过命令行操作。

非常简单,点击容器的图标,点击“Console”即可进入。默认是Shell,可以自行修改为Bash。

这部分属于高级内容了,对于新手来说有点复杂了,需要掌握一定的Linux知识,所以暂时不说了。

关于docker,新手需要了解和折腾的就是以上内容了。以后看情况逐步添加内容,比如管理docker的神器Portainer、搭建私有仓库DockerRegistry等。