Hassio 启动详解及群晖运行方法

入坑智能家居三个月,学习了不少,发现很多人对 Hassio 存在一定的误解,所以这边先说明一下 hassio 到底是什么,和homeassistant 到底有什么的关系。

首先希望大家要清晰一点,Hassio 并不是一个操作系统,他仅仅是一个软件部署的架构,并不是一个系统,而官方文档上的 hassio 树莓派固件其实只是官方已经将 hassio 安装在 ResinOS 上面罢了,但是官方可能出于安全性和稳定性,不让用于拥有底层系统的 shell 权限,故此我并不推荐使用这个系统刷到树莓派来使用 hassio。

hassio 架构图

hassio

从架构图可以看出,hassio 是安装在操作系统层面上的一个软件,他本身是一个 Docker 容器,同时 hassio 也具有 Docker 的控制权限。

另系统层面上还有一个叫 hassio-hc 的脚本在运行,这个脚本会建立一个 sock 文件并建立 hassio 容器的时候用 -v 映射到 hassio 容器内部供容器使用。

Home-Assistant 则是跑在 Docker 下面的另一个容器,它享有与本机一样的网络状态,通过网络与 hassio 联系(应该是类似 Rest_api 的方式互通),而 Home-Assistant 则负责前端显示,hassio 角色像是作为 Home-Assistant 的一个插件那样存在。

Addons 是依赖于 Hassio 存在的,这些插件其实就是基于 Hassio 规范设计的 Docker 容器,发布到 Docker Hub、Github 方便 Hassio 调用。

hassio 启动分析

通过 hassio 启动分析,我们才能更好的了解 hassio 的角色和功能。

通过分析 hassio 一键安装脚本hassio_install,其实脚本就做了两件事。

1、检测本地系统内核类别,确定 hassio 的容器名称。

下面是代码片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
case $ARCH in
"i386" | "i686")
MACHINE=${MACHINE:=qemux86}
HOMEASSISTANT_DOCKER="$DOCKER_REPO/$MACHINE-homeassistant"
HASSIO_DOCKER="$DOCKER_REPO/i386-hassio-supervisor"
;;
"x86_64")
MACHINE=${MACHINE:=qemux86-64}
HOMEASSISTANT_DOCKER="$DOCKER_REPO/$MACHINE-homeassistant"
HASSIO_DOCKER="$DOCKER_REPO/amd64-hassio-supervisor"
;;
"arm" | "armv7l" | "armv6l")
if [ -z $MACHINE ]; then
echo "[ERROR] Please set machine for $ARCH"
exit 1
fi
HOMEASSISTANT_DOCKER="$DOCKER_REPO/$MACHINE-homeassistant"
HASSIO_DOCKER="$DOCKER_REPO/armhf-hassio-supervisor"
;;
"aarch64")
if [ -z $MACHINE ]; then
echo "[ERROR] Please set machine for $ARCH"
exit 1
fi
HOMEASSISTANT_DOCKER="$DOCKER_REPO/$MACHINE-homeassistant"
HASSIO_DOCKER="$DOCKER_REPO/aarch64-hassio-supervisor"
;;
*)
echo "[ERROR] $ARCH unknown!"
exit 1
;;
esac

这里就指明了什么平台下载什么 hassio 容器名称。

2、将 hassio-supervisor.servicehassio-hc.service 注册为服务。

那么这个 hassio-hc 是干什么的呢?我们可以到这里看看 hassio-hc 的代码。

上面的 hassio-hc.service 启动脚本之前会使用 socat 创建一个 hassio-hc.sock ,如果收到信息的话就执行 hassio-hc 脚本,见下面命令

1
/usr/bin/socat UNIX-LISTEN:/var/run/hassio-hc.sock,fork EXEC:%%BIN_DIR%%/hassio-hc

而 hassio-hc 则负责处理收到的信息,他有 info、reboot、shutdown、update 等参数控制,其实说白了就是 hassio 控制宿主用的一些命令,通过他们来控制系统的重启、更新、关机等操作。

接下来我们再看看 hassio-supervisor.service

1
2
3
ExecStartPre=-/usr/bin/docker stop hassio_supervisor
ExecStart=%%BIN_DIR%%/hassio-start
ExecStop=-/usr/bin/docker stop hassio_supervisor

懂 systemd 的人应该不难看出,hassio 注册为服务,启动的时候先用 docker 指令停掉 hassio_supervisor 再运行 hassio-start 脚本。接下来看下 hassio-start 脚本是做什么的。

学过 docker 的朋友一看就发现了这样一个东西。

1
2
3
4
5
6
7
8
9
10
11
12
runSupervisor() {
docker rm --force hassio_supervisor || true
docker run --name hassio_supervisor \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /var/run/hassio-hc.sock:/var/run/hassio-hc.sock \
-v /var/run/dbus:/var/run/dbus \
-v %%DATA_SHARE%%:/data \
-e SUPERVISOR_SHARE=%%DATA_SHARE%% \
-e SUPERVISOR_NAME=hassio_supervisor \
-e HOMEASSISTANT_REPOSITORY=%%HOMEASSISTANT_IMAGE%% \
%%SUPERVISOR_IMAGE%%
}

第一条 docker rm 就是删除 hassio_supervisor 容器

第二条 docker run 就是运行 hassio_supervisor 容器,而 %%SUPERVISOR_IMAGE%% 在一键安装脚本的时候就会根据平台的内核来命名。如果是x86_64的平台用一键脚本安装后应该是如下这样。

1
2
3
4
5
6
7
8
9
10
11
12
runSupervisor() {
docker rm --force hassio_supervisor || true #删除 hassio_supervisor 容器
docker run --name hassio_supervisor \ #运行 homeassistant/amd64-hassio-supervisor 容器命名为 hassio_supervisor
-v /var/run/docker.sock:/var/run/docker.sock \ #将 docker.sock 映射到容器内部
-v /var/run/hassio-hc.sock:/var/run/hassio-hc.sock \ #将 hassio-hc.sock 映射到容器内部
-v /usr/share/hassio:/data \ #将 /usr/share/hassio 映射到容器内部,这就是 hassio 的所有配置目录
-v /var/log/supervisor-log:/var/log \ #将日志文件夹映射到容器内部,为了持久化 hassio 日志
-e SUPERVISOR_SHARE=/usr/share/hassio \ #定义 hassio 的配置文件路径
-e SUPERVISOR_NAME=hassio_supervisor \ #定义 hassio docker 名称
-e HOMEASSISTANT_REPOSITORY=homeassistant/qemux86-64-homeassistant \ #定义homeassistant容器名称,想自定义自己的 homeassistant,可以将容器发布到 hub.docker.com 然后修改这里的容器名就好了。
homeassistant/amd64-hassio-supervisor
}

现在已经很清晰了,hassio 启动的时候,会获得 docker 的控制权,然后再向 hub.docker.com 拉取镜像,然后整个系统都是运行在 docker 里面。故此,hassio 仅仅需要 docker 就好了,其余官方脚本 install 中其余依赖,其实都是给 hassio-hc (也就是重启、更新、关闭操作系统)用的。故此,群晖运行 hassio,仅需以下步骤即可。

群晖运行 hassio 步骤

1. 创建 hassio 运行需要的文件夹

上文提到,运行 hassio 的容器的时候,需要两个路径,一个是 hassio 配置文件夹,一个是 hassio 日志文件夹。

我是这样设置的,大家可以按照自己的需求设置。

DSM-hassio-config-dir-01

DSM-hassio-config-dir-02

2. 在群晖 ssh 中使用 docker 命令运行 hassio

为什么一定要用 ssh 中的 docker 命令执行?

因为上面也说道,hassio 需要取得 docker 控制权,所以我们需要将系统内部的 docker.sock 映射到系统内部,而群晖的 docker 界面我没法找到映射 docker.sock 的方法,所以用命令执行是最方便的啦。

1
2
3
4
5
6
7
8
docker run -d --restart=always --name hassio_supervisor \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /volume1/docker/hassio:/data \
-v /volume1/docker/hassio/supervisor-log:/var/log \
-e SUPERVISOR_SHARE=/volume1/docker/hassio \
-e SUPERVISOR_NAME=hassio_supervisor \
-e HOMEASSISTANT_REPOSITORY=homeassistant/qemux86-64-homeassistant \
homeassistant/amd64-hassio-supervisor

运行命令后,我们会看到一个叫 homeassistant/qemux86-64-homeassistant:landingpage 的镜像在运行,这个其实就是那个 Preparing Hass.io 的页面而已,就是因为树莓派刷了 hassio 而没有修改 docker 的源,导致网络慢啦取镜像下来非常非常慢,而 qemux86-64-homeassistant 要300多兆,国内的网络状态,可想而知速度有多慢,我群晖更换了 docker 源,拉取下来也要几分钟时间,所以官方就做了一个 landingpage 的分支镜像,让刷了树莓派的人能够看到系统在干嘛,其实系统就是在 pull qemux86-64-homeassistant 镜像下来啦。

我们可以看 hassio_supervisor 的日志看到下面这一行。

1
18-01-24 12:47:01 INFO (SyncWorker_0) [hassio.docker.interface] Pull image homeassistant/qemux86-64-homeassistant tag 0.61.1.

这样就只有等了,等 pull 完,就会出现 homeassistant 的界面了。

值得注意的是,如果不小心写错路径,又执行了上面的 docker run 命令,那么需要将 hassio_supervisor 删掉再重新执行命令,否则会报名字已存在,导致 docker run 命令出错。

1
docker rm -f hassio_supervisor

3. 想在 hassio 中修复历史转圈的问题?

那么可以将上面的启动 hassio 命令改成下面的样子。

1
2
3
4
5
6
7
8
docker run -d --restart=always --name hassio_supervisor \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /volume1/docker/hassio:/data \
-v /volume1/docker/hassio/supervisor-log:/var/log \
-e SUPERVISOR_SHARE=/volume1/docker/hassio \
-e SUPERVISOR_NAME=hassio_supervisor \
-e HOMEASSISTANT_REPOSITORY=neroxps/qemux86-64-homeassistant \
homeassistant/amd64-hassio-supervisor

如果已经运行过 hassio 的话,那么可以先在群晖下删除原来的 hassio 镜像,再运行咯。

对比上面的命令会发现 neroxps/qemux86-64-homeassistant 这个容器其实是我根据 homeassistant/qemux86-64-homeassistant 容器修改的,详情可以看这个帖子发布 hassio 的 homeassistant 镜像(仅支持amd64)

4. 启动后没有 hassio 怎么办?

当 homeassistant 启动之后,进去发现没有 hassio 菜单,查日志发现是无法连通 hassio api,查了下 hassio.py 这个插件,发现建立 homeassistant 容器的时候传递了一个 $HASSIO 的变量给homeassistant,这个变量记录了 hassio 的ip地址,而这个ip地址就是 hassio bridge 里面的 ip。

原来当 hassio 运行时候,会初始化一个 hassio bridge,用于分配给所有 hassio addons 的容器,但是当这个 bridge 建立好后,route 里面却没有记录 hassio 网络接口的本地路由条目,导致网络无法连通,具体为什么连不通,可能是群晖的 docker 问题,也可能是群晖网络问题,对 ip bridge 不太熟悉,所以就不知其原因了。

最后我发现一个解决方案,可以通过重启 hassio 网络接口来修复这个问题。

1
2
ifconfig hassio down
ifconfig hassio up

运行后重启 homeassistant 即可。

我写了个脚本,将这个脚本放到群晖一个目录里面(什么目录都可以自己喜欢),然后利用群晖的计划任务来启动脚本,达到修复 hassio 网路不运作的问题。

如果重启后发现 homeassistant 依然无法找到 hassio,请使用 root 账号登陆群晖 ssh,找到 /var/log/hassio-network.log 贴出来回帖吧。

群晖 hassio 下已知问题

  • homebridge 有时候重启群晖会启动失败,建议使用 marcoraddatz/homebridge 代替,不是用 addons 的 homebridge 就没问题了。

  • FTP 重启后启动失败,具体为什么启动失败我还没查到,但是只要在 hassio 中启动 FTP 就修复了。

最后给新手的忠告

hassio 的确方便,但方便的代价是排错困难,当你不了解 homeassistant 的配置文档,不了解 homeassistant 的架构,先从 hassio 入手的话,出错了自己会一脸茫然,然后就出现各种 hassio
为何不稳定啊,hassio 封闭的说法。

其实 hassio 是集成了 docker 的所有优点,docker 是什么,就是一个集装箱,他将所有的环境都封装好,不需要你管环境的问题,开发者已经将所有的环境问题解决了。

我这里建议,先学 homeassistant 的尽量看看论坛置顶帖的手动部署文档,先让 homeassistant 跑起来,等坑填的差不多了,再学习下 docker 的基本使用方法,对要学习 docker,因为 hassio 的所有插件都是跑在 docker 下,如果学会 docker 你将受用终身。

我推荐的部署环境是 debian(ubuntu等) + docker + hassio。树莓派的用户也适用,homeassistant 这种开源系统,不要想他能有多简单,即使出了 UI 配置,也需要底层运维支持。千万不要刷官方的那个 hassio(即使开了 SSH) ,因为你不懂 linux 系统,而且还要从一个非常少资料查询的系统开始学起,无疑是开启了困难模式。

祝大家好运。