软件/固件自动更新策略


9

我现在有一个中型项目,该项目已经接近“为客户演示提供草率咖啡因的原型”阶段的结尾,并过渡到“思考未来”阶段。该项目由具有软件和固件的基于Linux的设备以及中央管理Web服务器组成。目前存在10个原型,预计产量将低至1000左右。

我不熟悉自动更新技术,而且时间紧迫,所以我迅速制定了自己的软件部署/自动更新策略,坦率地说,它很糟糕。当前由以下各项组成:

  • 带有生产发行分支的托管git repo(GitLab)(请注意,Web服务器源也位于此相同的repo中,还有其他一些东西)。
  • Web界面上的“部署更新”按钮,该按钮:
    1. 从生产发行分支将最新版本拉到本地回购区域,并将其复制到临时软件包准备登台区域。
    2. 在登台区域中运行清理脚本(存储在仓库中)以删除不相关的源文件(例如服务器源,固件源等)和.git文件。
    3. 将当前git哈希写入更新包中的文件(目的将在下面变得清楚)。
    4. 如果一切顺利,它将用gzip压缩并准备好使用,方法是使用同名文件覆盖以前的gzip压缩包,然后删除暂存区。
    5. 请注意,服务器上现在有两个当前设备软件的副本,它们有望同步:最新生产分支上的完整本地git repo和一个现成的gzip压缩包,现在假定该软件包代表了以下内容:相同的版本。
  • 设备上的软件独立包含在名为的目录中/opt/example/current,该目录是该软件当前版本的符号链接。
  • 引导时设备上的自动更新功能:
    1. 检查do_not_update文件是否存在,如果文件存在,则不采取进一步措施(有关开发设备,请参见下文)。
    2. 从上述文本文件中读取当前提交哈希。
    3. 使用该哈希作为查询参数向服务器发出HTTP请求。服务器将以304(哈希为当前版本)响应,或者将提供压缩后的更新程序包。
    4. 如果收到更新包,则/opt/example通过以下方式安装:
      1. 提取更新的软件信息,将其命名为stage
      2. 从更新包运行安装后脚本,该脚本执行诸如对该更新进行必要的本地更改等操作。
      3. 将当前软件的根文件夹复制到previousprevious如果存在,则首先删除现有文件夹)。
      4. stage文件夹复制到latestlatest如果存在,则首先删除现有文件夹)。
      5. 确保current符号链接指向latest
      6. 重新引导设备(固件更新(如果存在)在重新引导时应用)。

在新建设备上也存在初始部署的问题。这些设备当前基于SD卡(存在其自身的问题集,不在本文范围内),因此此过程包括:

  1. 存在一个SD映像,上面带有该软件的某些稳定早期版本。
  2. 从该映像创建SD卡。
  3. 首次启动时,会进行各种首次特定于设备的(基于序列号)初始化,然后自动更新程序将照常获取并安装该软件的最新生产版本。

另外,我需要开发设备的支持。对于开发设备:

  • 完整的本地git repo会保留在设备上。
  • current符号链接指向开发目录。
  • do_not_update存在一个本地文件,该文件可防止自动更新程序随生产更新一起删除开发代码。

现在,从理论上讲,部署过程应为:

  1. 一旦准备好部署代码,就将其推送到发布分支。
  2. 按下服务器上的“部署更新”按钮。
  3. 该更新现已生效,设备在下次检查时将自动更新。

但是,实践中存在大量问题:

  • Web服务器代码与设备代码位于相同的存储库中,并且服务器具有我要执行的本地git存储库。最新的Web服务器代码与最新的设备代码不在同一分支上。目录结构有问题。当“部署更新”按钮从生产分支中提取最新版本时,会将其提取到服务器代码的子目录中。这意味着当我从头开始部署到服务器时,我必须通过将设备生产分支捕获到该子目录中来手动“播种”该子目录,因为如果我不进行部署,则可能是由于git user错误造成的。从父目录的Web服务器分支中提取设备代码。我认为这可以解决,方法是使暂存区不是服务器本地git repo的子目录。
  • Web服务器当前不永久维护设备软件的git哈希。在服务器启动时,它会git rev-parse HEAD在其本地设备软件仓库中执行,以检索当前哈希。由于某些原因,我无法全神贯注,这还会导致大量逻辑错误,在此不再赘述,足以说明有时重新启动服务器会使事情搞砸,特别是如果服务器是全新的并且没有生产分支仓库已被撤消。如果需要的话,我很乐意分享该逻辑的源代码,但是这篇文章越来越长。
  • 如果清理脚本(服务器端)由于某种原因而失败,则服务器将拥有最新的存储库,但同步/丢失更新包不完整,因此git rev-parse HEAD将返回与实际不匹配的哈希服务于设备,并且必须在服务器命令行上手动更正此处的问题。即服务器不知道更新程序包是不正确的,它只是始终以纯属为前提。结合以上几点,使服务器在实践中极为脆弱。
  • 最大的问题之一是:设备上当前没有运行单独的updater守护程序。由于等待wifi上网的复杂性和最后一刻的黑客行为,它是检查和更新设备的主要设备控制软件。这意味着,如果某种程度上未经测试的版本将其投入生产,并且控制软件无法启动,则实际上存在的所有设备都是砖砌的,因为它不再能够自我更新。这将是生产中的绝对噩梦。如果单个设备在不幸的时间断电,则同样的处理方法。
  • 另一个主要问题是不支持增量更新。举例来说,如果设备一段时间没有打开,那么下次对其进行更新时,它会跳过一系列发行版本,因此它必须能够进行直接的版本跳过更新。更新部署的结果是确保任何给定更新都可以应用在任何给定过去版本之上的噩梦。此外,由于使用git散列来标识版本而不是版本号,因此目前尚无法对版本进行字典式比较以促进增量更新。
  • 我当前不支持的一个新要求是,将存在一些必须在管理服务器端配置的每设备配置选项(键/值对)。我不介意以某种方式将这些每设备选项以与软件更新相同的HTTP请求提供给设备(也许我可以将其封装在HTTP标头/ Cookie中),尽管我不太担心,因为我可以始终使其成为单独的HTTP请求。
  • 由于存在两个(将来会有更多)硬件版本,因此会有些复杂。当前硬件的当前版本实际上是作为环境变量存储在其初始SD映像上(它们无法自我识别),并且所有软件均设计为与设备的所有版本兼容。基于此环境变量选择固件更新,并且更新包包含所有硬件版本的固件。尽管有点笨拙,但我可以接受。
  • 当前还没有办法将更新手动上传到设备(长话短说,这些设备中有两个wifi适配器,一个可以连接到Internet,一个以AP模式供用户用来配置设备;将来我打算在设备的本地Web界面中添加“更新软件”功能。这不是什么大问题,但确实会对更新安装方法产生一些影响。
  • 一堆其他的挫败感和普遍的不安全感。

所以...很长。但是我的问题可以归结为:

如何正确,安全地执行此操作?我可以对现有流程进行一些小的调整吗?我是否可以使用经过时间考验的策略/现有系统,这样就不必推出自己糟糕的更新系统了?或者,如果我必须自己动手做,为了使部署/更新过程安全成功,必须做些什么?我还必须能够将开发设备包括在内。

我希望问题清楚。我意识到这有点模糊,但是我100%地确定这是一个之前已经解决并成功解决的问题,我只是不知道当前接受的策略是什么。


2
由于您的设备基于Linux,因此建议您使用其中一种Linux软件包管理器(apt,yum,rpm等)进行研究。首先,请检查您的Linux基本安装是否尚未随附。
Bart van Ingen Schenau'Mar

您能否提供有关系统大小的想法?我们在谈论MB还是GB?
lbenini '17

MB; 压缩后的更新程序包通常为1-2MB。
Jason C

Answers:


1

您能否提供有关正在使用的Linux发行版,引导程序和体系结构(x86,ARM,MIPS?)的更多信息?

我会尝试猜测任何一种方式,并希望将您引导到正确的方向。

如果这是带有U-Boot的基于Yocto的发行版,我建议您看一下mender.ioswupdate。这些项目似乎很符合标准。他们的主要目标是确保原子更新。

最大的问题之一是:设备上目前没有运行单独的updater守护程序。由于等待wifi上网的复杂性和最后一刻的黑客行为,其主要的设备控制软件本身会检查和更新设备。这意味着,如果某种程度上未经测试的版本将其投入生产,并且控制软件无法启动,则实际上存在的所有设备都是砖砌的,因为它无法自行更新。这将是生产中的绝对噩梦。如果单个设备在不幸的时间断电,则同样的处理方法。

Mender提供了很多工具,其中包括用Go编写的守护程序(和一堆systemd脚本),可以减轻您的负担。该项目非常容易与Yocto一起使用(它们为许多设备提供了一个元层,应该可以轻松地适应您的特定案例和分区布局。它们还为流行的SOC提供了许多现成的解决方案) 。如果您不使用Yocto,则可以查看这篇文章,该文章确切说明了将其与基于非Yocto的发行版一起使用时需要采取的步骤。

swupdate也很棒,但似乎是来自DENX(U-Boot背后的组织)的一个人的一次努力。似乎也很成熟。

还有Ubuntu Ubuntu Snappy,我没有任何经验,因此我无法对此发表评论(也许有人会参与其中)。想法是将您的应用程序以独立的“快照”形式交付。据我了解,尽管这不是系统范围的,但这几乎不能解决您的问题。

我希望问题清楚。我意识到这有点模糊,但是我100%确信这是一个之前已经解决并成功解决的问题,我只是不知道当前接受的策略是什么。

实际上,当今的趋势似乎是通过APT / YUM使用Docker(甚至在嵌入式系统中)和朋友。后期可能会很难确保一致性。


太好了,我不确定我怎么没注意到这个答案。我将尽快提供所需的信息,该项目被暂时推迟并于昨天恢复,所以我只是重新开始,这个特定问题现在是第一要务。
杰森C
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.