项目简介
背景
随着国家政策的导向,互联网基础设施的普及,工业、能源行业的智能化改造已经进行的如火如荼,传统行业的特点是信息化、智能化水平严重落后于其他行业,在进行信息化、智能化改造的过程中,首先第一步,就是要获取底层系统的全方位的数据。
为此,需要部署大量的边缘设备来采集数据、分析数据,通过这些数据进行建模,大量的边缘设备一般离散的分布在不同机房、厂区、甚至是不同的地理区域,这对运维人员来讲是令人恐惧的事情,维护这些设备,管理其上运行的应用变得极其困难。
我们公司是国内第一批投身于工业互联网改革浪潮中一员,因此上面提到的问题,也是我们面临的问题。
公司从一开始就采用了微服务化的开发模式,除了平台框架核心应用之外,所有应用都是可插拔的微服务。
与业务平台不同的是,边缘设备具有下面的特点:
数量大,动辄有数十台、数百台设备;
单点故障影响小,一个设备只负责一小块区域的数据采集、分析与计算,因此单台设备的故障导致的局部数据的缺失,数据分析层面也进行了数据清洗,因此,单点故障对全局业务影响不大。
需求
对于运维角色来讲:
管理这些边缘设备,保持边缘设备上运行的服务的高可用性;
快速的上线、升级
配置的快速更改与应用
逻辑拓扑图
下面的图形简单描述了项目基础设施层的拓扑:
其中,每一个边缘侧设备上运行的业务会和中枢业务系统通讯,边缘侧所有设备在单独的一个网络平面中。
运维方案选型
在决定运维方式时,考虑过下面的几种方式:
Ansible
我们在边缘侧设备上运行的应用大部分都是纯 Java 应用,再加上一部分 Python 应用,因此部署和启动非常简单,外加上 supervisord 应用实现了应用的基本高可用方案。在公司还没有进行容器化转型之前,我们采用传统的部署形式部署微服务,就是配置好宿主机的系统环境,直接将应用部署在宿主机系统上,在这种情况下,我们只需要解决的问题是大批量设备部署和维护的问题,因为不管是部署还是更新升级、配置,所有边缘侧使用 Ansible 可以较好的满足这一条件。
但是这种方法也有缺点,需要维护一套甚至多套 ansible playbook,边缘侧设备所在的网络条件比较差,异常状况也比较差,经常掉电重启或者断网,使用 ansible 容易造成各个节点的配置不同步。
kubeedge
kubeedge 是由华为基于 kubernetes 开发并开源,专门用于边缘容器编排的运维方案,其基本架构如下:
从上面的架构图中可以看到,kubeedge 实现了一个边缘侧完整的框架,对我们公司来讲,我们自行实现了例如“DeviceTwin”、“EventBus”、“ServiceBus”以及基于 MQTT 收发消息。因此:
一部分组件与 kubeedge 重叠了;
部署不方便,kubeedge 要求在各个节点上以 kubeadmin 部署 kubernetes 集群(0.6 版本,现在已经更新至 1.1 版本,不知道现在是否有更简便快捷的形式),对网络环境不好的边缘侧设备有较大难度;
kubeedge 组件与 kubernetes 组件基本一致,对于边缘设备寸土寸金的资源来说,不太友好。
通过实践,第 2 点和第 3 点原因直接打消了我采用 kubeedge 的念头。
k3s 简介
什么是 k3s?
k3s is 5 less then k8s,直接翻译过来就是 k3s 比 k8s 少了 5 个字符,引申一下就是 k3s 就是 k8s 的简化版。可以看做 k8s 的一个衍生版,特点就是轻量。
k3s 的特点有哪些?
apiserver、controller manager、scheduler、kubelet、flannel 等组件这到一个进程中(通过指定是 server 或者 agent 选项来控制节点上需要启动哪些组件,server 相当于 k8s 的 master 节点,agent 相当于 worker 节点),占用的内存更少了,整个 k3s server 进程需要的内存在 500MB 以下。
从上面看出 k3s server 进程当前占用的内存是 210MB。
去除了 k8s 中的一些实验特性、非必须的组件,例如云厂商的驱动、存储插件,k3s 在默认状态下只会启动除自身进程之外的两个应用:
coredns:提供集群内部的 DNS 解析服务。
traefik:ingress controller 的角色。
通讯效率高:k3s server 默认使用本地(已集成)的 sqllite 作为后端数据存储,通讯效率更高一些。
占用资源少:k3s 默认使用 containerd(server 节点,不可更改)作为容器运行时,不在需要中间层的 docker engine,占用资源更少。
部署简单:对环境依赖少,可离线也可在线部署(不过国内的网络环境不推荐在线部署。),离线部署时,只需要下载一个大约 40MB 的二进制文件和一个 200MB 不到的离线镜像包,启动 k3s 节点几乎是秒级的。
上手无代价:
使用 k3s 与 kubernetes 习惯完全一致,对于使用 kubernetes 的人来讲使用 k3s 没有任何代价;
支持部署 helm tiller 服务端(尽管 tiller 端会在 helm 3.x 版本中被干掉),直接使用原有 charts 部署应用无障碍;
扩缩容方便:增删节点极其方便,几乎是分钟以内就可以完成;
兼容 arm 架构设备:对于部分有此种类型的设备的集群友好。
下面是 k3s 的架构图:
k3s 集群的所有数据存储在 server(master)节点本地的 SQLite 数据库中,当然也支持存储在诸如 MySQL、etcd 中,都是支持按照需求在部署节点时选择配置的。server 节点与 agent 节点之间采用 tunnel 隧道通信,增强了安全性,同时也提升了效率。agent 与 server 节点即使断开网络连接,也不影响相互各自的业务。
因此通过上面的对比和实践验证,我们决定采用 k3s 来管理边缘设备集群。
运维架构简介
下面是一张完整的运维架构图:
部署 k3s 集群
由于集群节点一般存在多个,一台台手工安装部署会占用大量的时间,吃力不讨好,因此,我写成了 ansible playbook 来完成 k3s 集群的多节点快速自动化部署,如有需要,可以联系 yj.zeng@aliyun.com。
各个组件版本信息:
k3s: v0.9.1
docker: 18.09.9
helm: v2.14.3
OS:CentOS Linux release 7.6.1810 (Core)
Ansible: 2.8.3(在多节点下,用来快速批量部署集群节点)
本次实践在 Centos 7 上完成,由于部署 k3s 节点需要 root 用户权限,因此本实践中所有操作均直接使用 root 用户登录后进行。
获取 k3s 以及离线镜像包
k3s GitHub 主页:
https://github.com/rancher/k3s/releases
由于国内访问 GitHub 的速度很慢,在线安装耗时很长,因此推荐采用离线部署方式部署。
以 v0.8.1 版本为例,下载下面的两个文件:
k3s
k3s-airgap-images-amd64.tar
准备工作
假定下载到的文件已经上传到服务器节点的~/packages 目录下面。
将 k3s 二进制文件放置到/usr/local/bin 目录下,并赋予可执行权限:
将离线镜像包放置到指定的位置:
需要在 k3s 集群所有节点上都放置上面的离线文件。
在部署 k3s 集群之前,需要对所有节点做如下的基础配置。
如果没有专门的域名服务器提供主机名解析服务,那么在每一台节点的/etc/hosts 文件中。写入本节点的 IP 与主机名映射。
给所有节点安装并配置相同的 NTP 服务器,保证服务器时间的正确性。
为了方便我们直接关闭防火墙服务:
至此,准备工作完成。
部署 k3s server 节点
提醒:
截止目前,k3s server 节点并不支持 HA。
k3s server 节点安装时,可以选在同时在本地安装一个 k3s agent 节点用以承载工作负载,如果选择不在 server 节点上安装 agent 节点,则除了 k3s 集成的 kuberntes 组件(如 kubelet、api server)之外,其余的插件、应用均不会被调度到 server 节点上。
k3s 支持使用多种容器运行时环境,server 默认以 containerd 作为运行时,不支持更改。agent 节点可以使用 contained 也可以使用 docker,推荐使用 docker,因为 docker 人机更友好,可以方便的管理镜像和容器以及查错。所以如果选择 agent 节点以 docker 作为容器运行时,那么必须要提前安装并配置好 docker 服务。
现在,我们可以启动 k3s server 节点:
参数说明:
–docker: k3s server 组件以 containerd 作为容器运行时。可以顺便在 k3s server 节点上启动一个 agent 节点,agent 节点可以使用 docker 作为容器运行时,这样 k3s server 节点也可以当做工作节点用。当然也可以不在 server 节点上启动 agent 节点(添加参数–disable-agent 即可)。
–bind-address:k3s 监听的 IP 地址,非必选,默认是 localhost。
–cluster-cidr:与 kubernetes 一样,也就是 pod 所在网络平面,非必选,默认是 10.42.0.0/16.
–service-cidr:与 kubernetes 一样,服务所在的网络平面,非必选,默认是 10.43.0.0/16.
–kube-apiserver-arg:额外的 api server 配置参数,具体可以参考 kuberntes 官方网站了解支持的配置选项,非必选。
–write-kubeconfig:安装时顺便写一个 kubeconfig 文件,方便使用 kubectl 工具直接访问。如果不加此参数,则默认的配置文件路径为/etc/rancher/k3s/k3s.yaml,默认只有 root 用户能读。
–write-kubeconfig-mode:与–write-kubeconfig 一起使用,指定 kubeconfig 文件的权限。
–node-label:顺便给节点打上一个 asrole=worker 的 label,非必选。
k3s 支持众多的安装参数和选型,详细请参考官方文档。
完成之后,检查集群状态:
可见节点已经呈就绪状态。
检查 pod 的状态:
可以看到,系统命名空间下所有的应用都已经启动了,server 节点已经就绪,接下来可以部署 k3s agent 工作节点了。
在上面的命令中,我们均是以 k3s kubectl 开头的命令,是否可以直接使用 kubectl 客户端呢?当然可以,只需要下载一个对应版本的 kubectl 二进制文件放到系统的 path 中,赋予可执行权限即可,使用起来与使用 kubernetes 集群一模一样!
由于上面的命令是在前台执行的,一旦断开 SSH 链接或者终止 shell 进程,k3s server 就停止运行了,因此我们给他配置一个 systemd 服务,用以像管理系统服务一样管理 k3s server 节点。
创建文件/usr/lib/systemd/system/k3s-server.service,内容为:
然后设置服务开机自启:
CTRL+C 结束在前台执行的命令,我们看到服务文件中引用了一个环境变量文件/etc/systemd/system/k3s.service.env,这个文件并不存在需要先创建一个然后才能启动服务:
查看服务状态:
提醒:如果出现错误,可以通过 journalctl -u k3s-server 查看日志。
部署 k3s agent 节点
在 server 节点部署完成之后,在 server 节点的/var/lib/rancher/k3s/server/目录下面生成一个 node-token 文件,该文件存储了 k3s agent 节点加入集群时所需的 token。
在 server 节点上,获取 token:
在作为 k3s agent 节点的系统中,以 root 用户执行下面的命令启动 k3s agent 节点,但是,因为我们采用了 docker 作为 agent 节点的容器运行时,所以我们先将离线镜像导入到 docker 中:
然后执行下面的命令安装 k3s-agent 节点
参数说明:
–docker:k3s agent 以 docker 作为容器运行时。
–server:k3s server 节点监听的 url,必选参数。
–token:k3s server 安装时生成的 token,必选参数。
–node-ip:k3s agent 节点的 IP 地址,非必选参数。
–node-label:同样给 k3s agent 节点打上一个 asrole=worker 的标签,非必选参数。
稍等一会儿,在 server 节点上查看 agent 节点是否已经加入到了集群中:
可以看到节点已经成功加入到了集群中。
同样给 agent 节点配置成 systemd 可以管理的系统服务,创建/usr/lib/systemd/system/k3s-agent.service,内容如下:
我们终止前台执行的命令,执行下面的命令通过 systemd 重新启动服务:
可以看到 k3s agent 节点已经成功启动了。
如果还需要加入新的 agent 节点到集群中,可以按照上述方式配置启动新节点,完成后,新节点自动加入到集群中。
部署应用
通过 helm 部署应用
一般情况下,我们会通过 helm chart 安装应用和升级应用,在 k3s 集群中,同样可以采用 helm 来安装部署应用。
下载 helm 的客户端二进制文件后,放置到/usr/local/bin 目录下并赋予可执行权限。执行下面的命令初始化 helm 客户端:
查看 helm 信息:
可见 helm 的服务端已经在集群中创建成功了,下面就可以使用 helm chart 安装应用了。在此我们进行演示:
查看 pod 的情况:
可见应用已经创建成功。
使用 Rancher 管理 k3s 集群
在 Rancher 上添加一个集群,然后按照步骤将该集群导入到 Rancher 平台中,可以使用 Rancher 管理和维护集群:
FAQ
1、在边缘计算中,往往涉及到访问硬件资源,如何从容器内部访问硬件资源?
Linux 系统中,所有的硬件资源都体现为/dev/目录下面的一个设备,因此只要能够访问/dev/目录下面的设备文件即可,有的同学会说,那是不是将/dev/目录挂载到容器里面就可以了呢?经过我的实践证明不行,因为挂载到容器里面,即便容器里面是以 root 用户运行,然是仍旧有可能无法访问一些特殊资源文件,也就是说容器中的“root”用户与宿主机的 root 用户在访问权限上还是有差别。只需要将容器的运行模式设置为“privileged”即可,如下:
2、如何备份集群数据?
k3s 集群数据全部存储在/var/lib/rancher 下面,在/etc/rancher、/etc/kubernetes 下面会存储一些配置文件和证书,因此我们可以周期性备份这几个目录的数据即可。也可以给 k3s server 节点挂载一个高可靠性的存储设备。
3、节点宕机怎么恢复?
对于 agent 节点,边缘节点只负责一个小区域的业务,单个节点宕机对整个集群业务影响很有限,只需要重新启动将节点加入集群中即可恢复业务运行。对于 server 节点,如果有数据备份,可以用数据备份进行恢复(将备份数据放置到对应的目录重新按照原有参数启动 server 节点服务即可),如果没有备份,那么重新安装一个 server 节点,更改 agent 节点的启动参数中的 token,重新将 agent 注册到新的 server 节点,但是因为集群数据丢失,可能需要重新安装应用,因此尽可能对 server 节点的数据进行周期性备份并妥善存储保管。
4、k3s 是否可以外部存储系统?
当然是可以的,如果涉及到应用必须要访问持久化存储,那么也可以像 kubernetes 一样给其接入外部存储系统,但是不推荐这么做,因为边缘设备一般比较分散,网络环境也不稳定,外接存储系统会导致性能打折扣,因此建议:
对于必须将数据存储在外部存储上的应用,可以通过 nodeSelector 限制其到某几个特定的比较可靠稳定的节点上,然后接入外部存储系统;
对于 daemonset 类型的应用,非关键核心数据可以通过 hostPath 存储在宿主机系统上
社区 QA
Q1:一台阿里云杭州服务器,一台阿里云美国服务器,都有公网 IP,如何方便、快捷(并且不购买网络带宽费用)地搭建一个 2 台服务器的 K3S 集群?
A:这主要是你自己的路由的问题,pod 网络和 service 网络的一个拉平的问题,涉及到这个路由的跳转是需要你自己去配置的。
Q2:边缘节点的 K3S 集群可以很方便的被中心节点的 K8S 集群来管理吗?如何管理?数据如何同步?中心节点需要存放边缘节点的数据吗?边缘节点挂了之后中心节点能拉起或管理吗?现在我们也计划做这方面的工作。我们有多个分公司,想在分公司部署集群,但没有维护人员。还有一个问题就是,现在集群联邦不成熟,也不能很好纳管多个集群做资源调度,这该如何解决?
A:k3s 集群和 k8s 集群是平级的关系,属于多个集群。如果要管理多个集群,我们可以采用像 Rancher 这样的集群管理平台去管理它,我们公司现在就是这么做的:在阿里云上有一个 Rancher 的平台,然后管着我们在阿里云平台的业务集群和我们的多个边缘集群。
你的第二个问题是中心节点会存储我整个集群的所有的数据,因此我们应该周期性地对这个中心节点的数据进行备份,而且在未来的版本当中,k3s 会支持 HA,它是通过实现后端存储,如 postgresql、MySQL 的一个高可用性保证我们的集群的可靠性的,这个现在已经是实验的特性了,估计在未来很快就会发布了。工作节点挂了的话,可能分两种情况,一种是你这个节点直接不能工作了,还有一种情况点跟我的 master 节点网络不通了。如果是前一种情况,业务肯定也不能正常工作了;后一种情况的话,其实业务还在正常运行,只不过是不能通过主节点去调度了,但是一旦它恢复通信,所有的都会自动恢复,因为边缘设备的网络不稳定有点难以避免。我们这个集群已经跑了两三个月了,表现一直是很好的。
Q3:k3s 可以去哪获取资料?
A:k3s 的官网是:https://k3s.io,GitHub 的主页是:https://github.com/rancher/k3s,最新开始运营的官方微信公众号是:
Q4:K3s 的 list-watch 请求没有走 tunel-proxy 吗?
A:k3s 的主节点和 agent 节点之间通信都是走的 tunnel 通道的。
Q5:除了占用较少资源之外,k3s 在使用上和 k8s 相比还有什么限制和优势?
A:对,因为边缘设备的话都是很小的工,一般都是公用的,工业用的工控机,工控机一般都是一个低压的 CPU 啊,然后还有一个就是内存比较小。实际上来讲的话我目前没有发现根 k8s 有太大的区别,基本上在我 k8s 上部署的应用全部可以部署在我的边缘端。
k3s 开发人员补充:
除了占用资源较少外,还支持:
极致简化的安装体验,对比 k8s 和 k3s 安装部署就会体会到 k3s 的安装体验上的优化。
除了 etcd 外,还是支持 sqlite/mysql/pg 等数据库,最小可以做两节点的 HA。
Q6:k3s 的主节点和 agent 节点之间通信都是走的 tunnel 通道的。List-watch 请求也走 tunnel 通道的吗,据我看源码,并没有走 tunnel,只有 logs 和 exec 接口走了 tunnel。
A:list-watch 就是直接访问 kube-apiserver 的端口。
Q7:k3s 集群直接更改设备 IP 是否可用,如果不支持更改 IP,对于更改 IP 的需求有什么应对方案?
A:这里分两种情况,在集群部署完成后,如果要更改 server 节点的 IP,那么我们需要重新去将所有的 agent 节点重新加入到集群中,如果更改 agent 的节点 IP,那么可能导致 agent 节点对应存储在 server 节点中的身份凭证失效,也就是需要移除失效的节点,将修改后的节点重新加入,当然这种情况是在同一个子网内的情况,如果跨网段的话,那就会更复杂一些了。
Q8:Rancher 管理 k3s 集群,k3s 的 master 要暴露公网 IP 吗?
A:server 节点不需要暴露公网 IP,只需要能从 server 节点内部访问 rancher 即可。通过 import 的形式将 k3s 集群导入到 Rancher 中即可管理起来,也可以管理应用和配置。
Q9:k3s server 也支持 docker 吧?
A:是的,agent 节点提供了–docker 参数,可以指定它的容器运行时为 docker。
Q10:Rancher 可以自己部署、管理自己的 k3s?
A:是的,我们的 Rancher 是部署在阿里云端,同时管理了我们的中枢业务 k8s 集群和多个客户的 k3s 边缘集群。
Q11:运行单个 Docker 容器来安装 Rancher,可以满足管理吗?
A:可以,但是这样可靠性会不好,推荐还是多实例通过负载均衡的形式来部署。
Q12:k3s 支持 master 高可用吗?
A:暂时还未 GA 支持,但是已经发布了实验性的版本,通过对 k3s 集群数据存储的高可用来实现的,我们可以部署高可用的 postgresql 作为 k3s 集群的管理节点的数据存储。这个特性应该不久就会 GA 了。
Q13:边缘资源充足,是否可以直接用 k8s?
A:如果边缘设备资源充足的情况下,也可以使用 k8s 来维护,但是需要考虑的是边缘设备网络的复杂性和不稳定性。
Q14:k3s 启动 helm 的时候,由于众所周知的原因,经常下载不到镜像,怎么解决呢?
A:官方提供了离线镜像包,大约 200MB 不到,这个镜像包包含了我们启动 server 和 agent 节点所需的所有镜像,能够保证集群自身功能正常。helm 我们可以使用国内的 charts 源来代替,例如 azure 的源。
Q15:containerd 可以配置 morror 么?
A:可以配置,但是比较麻烦,docker 提供了比较好的人际接口,所以推荐使用 docker。
Q16:备份 k3s 的集群数据,为什么是备份那几个目录而不是备份 sqlite 的 db 文件?k3s 的 server 支持类似 rke 对 etcd 定期自动备份配置吗?
A:因为还涉及到一些认证文件,譬如 agent 节点在 server 端存储有一个身份标记,agent 节点的恢复是会判断这些身份的。一旦丢失,重新注册相当于是一个新的节点了。
Q17:不管是基于 containerd 还是 docker,它们都是共享内核的,那么如何做到安全隔离呢?
A:在底层的资源隔离上,还是依赖于系统的各种命名空间,这块建议可以详细研究一下 pod 的安全策略。
Q18:离线镜像文件是否只要放在 images 目录即可,文件名并不重要,都可以被识别出来?
A:是的,使用 containerd 作为 runtime 时,不需要手动导入,启动时会自动从这里获取镜像,如果使用 docker 作为运行时,需要手动 load 镜像,因为国内直接访问不了 gcr.io 下面的镜像。
Q19:单机版 K3S,容器内访问本机的一个服务端口,无法访问,这个问题官方测试过吗?
A:这个可能有很多种情形了,看是否是主机安全策略限制。例如 selinux 或者 iptables 规则限制了。
k3s 开发人员补充:
简单验证了从容器内访问主机的 ssh 端口并没有问题。应该是自身的应用有其特殊性,你可以尝试在 k8s 中确实可以 work 后,在 k3s 中部署。
Q20:centos 在边缘设备小内存设备上能装吗?也是有内存限制的吧,最小支持多少?
A:k3s server 官方给的需求是 512MB 就能满足,在我们公司的实际观察中,一般情况下用到 200 多 MB,剩下的就看你部署的应用的资源需求了。另外我们需要保证应用不能把系统资源全部抢占了。
Q21:k8s 与 k3s 在 api 上使用上有啥具体差别?比如是否支持 crd?另外 k8s 的网络组网方案有 flannel 和 calico,k3 是怎么组网的?
A:K3s 默认使用的是 flannel 网络,也支持手动指定其他的 CNI,都是比较灵活的配置。
Q22:IoT client 设备没有固定公网 ip 下如何进行部署?需要自行组网吗?
A:这里是一个大家都会遇到的问题,一般来说,IOT 设备都是客户内网的,不可能给你在防火墙上打洞,我们现在是自己开发了一套系统,只用来偶尔维护边缘设备的后台,类似 ssh 反向代理就可以实现。
Q23:边缘设备是怎么被监控的,有的什么方案呢?是否也有监控的实时界面?
A:我们可以考虑采取 prometheus pushgateway 的形式来在边缘内网部署监控代理,然后再介入到统一的监控平台。
Q24:内网环境(可通过代理上网),需要为 containerd 配制代理吗?还是 containerd 可以识别主机的代理配制?如果需要配制的话应该如何配制?
A:如果是全局代理的话,应该是支持的。
Q25:k3s 跟 k8s 的迭代关系是什么,每发布新版 k8s,k3s 都要修剪出相应的版本,还是增量开发?用 k3s 需不需要定期升级?
A:我们一直在持续关注相关 release notes,当有重大新特性和安全问题、功能 Bug 修复时我们会考虑升级版本。
k3s 开发人员补充:
每次 k8s 发版后都会修建对应的 k3s 版本。你如果很在意 k8s 的安全更新,你可以升级 k3s,否则如果业务已经稳定适用,可不必太过频繁升级。
Q26:我尝试给 containerd 配了代理,单独安装的 containerd 可以拉镜像,但是 k3s 内嵌的 containerd 确一直没法拉镜像。这个应该怎么解决?
A:不确定你在 k3s 的 containerd 中如何配置的,k3s 的 containerd 中的配置文件会被重置,你需要以模版方式配置
https://rancher.com/docs/k3s/latest/en/configuration/#containerd-and-docker。
详细问题可以提 issue 到 k3s 来讨论:
https://github.com/rancher/k3s
评论