ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

在ODYSSEY-X86上部署Mender实现工业边缘设备OTA更新

2026/8/2 13:28:56 拓冰建站 浏览量
在ODYSSEY-X86上部署Mender实现工业边缘设备OTA更新

1. 项目缘起:为什么要在边缘设备上折腾OTA?

最近在折腾一个工业边缘计算的项目,客户现场部署了几十台基于ODYSSEY - X86的工控机,跑着定制的Linux应用。每次软件更新,都得派工程师带着U盘跑现场,一台一台手动刷机,效率低不说,还容易出错。客户提了个很实际的需求:能不能像手机更新系统一样,远程、安全、可靠地给这些设备推送固件和软件包?

这个需求直接指向了设备管理(Device Management)空中下载技术(OTA, Over-the-Air)。在物联网和边缘计算领域,OTA是刚需,它解决的不仅仅是“方便”的问题,更是运维成本、安全补丁、功能迭代和业务连续性的核心保障。想象一下,如果发现了一个安全漏洞,你需要紧急修复,难道要飞遍全国去插U盘吗?显然不现实。

于是我开始调研OTA解决方案。市面上有几种路径:一是用各大云厂商(如AWS IoT Greengrass, Azure IoT Edge)自带的设备管理服务,但往往绑定生态,不够灵活;二是自己从零搭建,用rsync加脚本,或者基于ostreeRAUC等底层技术封装,但这对稳定性和安全性要求极高,投入巨大;三是采用专业的开源或商业OTA框架。

Mender就是在这样的背景下进入视野的。它是一个开源的、以安全为设计核心的OTA更新管理器,专为嵌入式Linux设备打造。它的核心魅力在于采用了A/B分区双系统更新机制。简单来说,设备上有两套完整的系统分区(A和B)。更新时,新系统被完整地写入空闲分区(比如B分区),然后设备重启并从B分区启动。如果启动成功,B分区就被标记为“有效”;如果失败(比如启动超时或健康检查不通过),设备会自动回滚到已知良好的A分区。这种机制从根本上保证了更新的可靠性,避免了“变砖”的风险,非常适合无人值守的工业环境。

ODYSSEY - X86,是由Seeed Studio推出的一款x86架构的单板计算机(SBC)。它搭载了Intel Celeron J系列处理器,接口丰富,性能足以胜任许多边缘计算场景,价格也比许多ARM架构的工业网关更有优势。把它作为OTA管理的目标设备,既有代表性(x86架构在工业领域很常见),也有挑战性(其分区和启动方式与常见的树莓派等ARM设备不同)。

所以,这个项目的目标很明确:在一台标准的ODYSSEY - X86板卡上,成功部署Mender客户端,并将其接入一个Mender服务器(可以是开源的社区版,也可以是商业版),实现完整的OTA更新能力验证。这不仅仅是跑通一个安装流程,更是要理解在x86架构、UEFI启动、GPT分区表这一套现代PC标准下,Mender如何工作,以及我们会遇到哪些特有的“坑”。

2. 环境准备与核心概念澄清

在动手之前,我们必须把几个关键概念和前提条件理清楚,这能避免后面很多困惑。

2.1 硬件与基础系统选择

我使用的硬件是ODYSSEY - X86J4105。关键配置如下:

  • CPU: Intel Celeron J4105 (四核)
  • 内存: 8GB LPDDR4
  • 存储: 64GB eMMC(这是我们系统的主要载体)
  • 启动方式: UEFI
  • 磁盘分区表: GPT

对于基础操作系统,Mender官方对客户端系统有明确要求,它需要集成到Linux发行版的构建流程中。最主流、支持最好的方式是使用Yocto ProjectBuildroot来构建一个包含Mender客户端的完整系统镜像。这对于产品化部署是必经之路。

但对于我们当前的验证和评估阶段,从头搭建Yocto环境周期太长。更快捷的方式是使用一个已预集成Mender客户端的系统镜像。幸运的是,Mender社区为一些流行平台提供了这样的“演示镜像”(Demo Images)。

然而,ODYSSEY - X86并没有官方的预集成镜像。因此,我们的路径需要变通:先在一个通用的x86-64系统上安装Mender客户端,然后针对ODYSSEY的硬件进行适配和测试。我选择了Ubuntu Server 20.04 LTS作为基础系统,因为它普及度高,文档丰富,且Mender提供了.deb安装包。

注意:生产环境强烈建议通过Yocto/Buildroot构建。本文的“安装”是指在现有发行版上部署客户端进行集成测试,这有助于快速理解Mender的工作流程和配置,为后续定制化构建打下基础。

2.2 Mender架构与组件

Mender的架构包含两个主要部分:

  1. Mender客户端(Mender Client): 运行在边缘设备(我们的ODYSSEY)上的守护进程。它负责与服务器通信、检查更新、下载更新包、执行更新(切换分区)和报告状态。
  2. Mender服务器(Mender Server): 提供设备管理后台的服务端。它负责设备认证、更新包管理、向设备派发更新任务、接收设备状态报告等。服务器又有两个版本:
    • Mender开源版(Mender Open Source): 包含核心的更新管理功能,可以自行部署。
    • Mender专业版/企业版(Mender Professional): 提供图形化UI、更细粒度的部署策略、审计日志等高级功能。

对于本次实验,为了简化,我将使用Mender提供的托管测试服务器(hosted.mender.io)。这是一个由Mender公司维护的免费沙箱环境,非常适合开发和功能验证。当然,你也可以在自己的服务器上部署开源版本。

2.3 理解A/B分区与数据持久化

这是Mender的核心,也是配置中最容易出错的地方。在ODYSSEY的eMMC上,我们需要规划出以下分区结构(示例):

分区挂载点文件系统大小作用
/dev/mmcblk0p1/boot/efivfat256MBUEFI启动分区,存放GRUB和内核。
/dev/mmcblk0p2(无)ext415GBRootfs A分区。存放当前运行的系统。
/dev/mmcblk0p3(无)ext415GBRootfs B分区。用于更新时写入新系统。
/dev/mmcblk0p4/dataext4剩余空间数据分区(Data Partition)。用于存放应用数据、配置等,在A/B切换时保持不变。

关键点解析:

  • A/B分区必须完全一致:大小、文件系统类型需相同。Mender更新时,会将整个新系统镜像写入空闲分区。
  • /boot分区:在UEFI+GPT体系中,通常是/boot/efi。内核和initramfs也在这里。Mender在更新时也会更新这个分区的内容(如内核),确保与rootfs匹配。
  • 数据分区(/data):这是实现“数据持久化”的关键。你的应用程序、数据库、用户配置等都应该放在这里,而不是rootfs里。这样无论系统从A还是B启动,都能访问到同一份数据,实现无缝切换。这是设计系统时就必须考虑的。

在标准的Ubuntu安装中,默认不会为你创建这样的A/B分区结构。因此,我们可能需要手动调整分区,或者在安装Ubuntu时就进行自定义分区。这是第一个实操难点。

3. 实操步骤:分区、安装与配置

假设我们已经通过Ubuntu安装器,采用“手动分区”模式,在ODYSSEY的eMMC上创建了类似于上表的分区结构,并成功将系统安装到了/dev/mmcblk0p2(Rootfs A)。

现在,我们开始在现有Ubuntu系统上安装和配置Mender客户端。

3.1 安装Mender客户端

首先,添加Mender的APT仓库并安装客户端软件包。

# 1. 信任Mender的GPG密钥 sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3EEF63F3E21D0944 # 2. 添加Mender APT源 (以Ubuntu 20.04为例) echo "deb [arch=amd64] https://downloads.mender.io/repos/debian stable main" | sudo tee /etc/apt/sources.list.d/mender.list # 3. 更新软件包列表并安装Mender客户端 sudo apt update sudo apt install mender-client -y

安装完成后,主要的配置文件位于/etc/mender目录下。

3.2 关键配置文件详解与修改

Mender客户端的行为几乎完全由配置文件驱动。以下几个文件至关重要:

1.mender.conf- 核心配置这是主配置文件。我们需要修改它以指向我们的测试服务器,并告知客户端设备的分区布局。

sudo nano /etc/mender/mender.conf

初始内容可能很简单。我们需要将其修改为类似以下结构:

{ "InventoryPollIntervalSeconds": 300, "RetryPollIntervalSeconds": 30, "RootfsPartA": "/dev/mmcblk0p2", "RootfsPartB": "/dev/mmcblk0p3", "ServerCertificate": "/etc/mender/server.crt", "ServerURL": "https://hosted.mender.io", "TenantToken": "你的租户Token", "UpdatePollIntervalSeconds": 1800 }
  • ServerURL: 我们使用托管测试服务器。
  • TenantToken: 这是连接服务器的“钥匙”。你需要去 hosted.mender.io 注册一个账户,创建一个“租户”(Tenant),然后在设置中找到这个Token。没有它,设备无法认证。
  • RootfsPartA/B: 这就是我们之前规划的A/B分区。必须准确填写,否则Mender不知道往哪里写系统。
  • ServerCertificate: 服务器证书路径。对于hosted服务器,我们可以下载其证书,也可以暂时跳过TLS验证(不推荐生产环境)。可以先放一个空文件或使用系统证书。

2.device_type- 设备类型文件这个文件告诉Mender服务器“这是一台什么设备”。服务器可以根据设备类型筛选并推送不同的更新包。

echo "odyssey-x86j4105" | sudo tee /etc/mender/device_type

你可以自定义这个字符串,例如custom-iot-gateway-v1

3.artifact_info- 制品信息文件(可选但重要)这个文件描述了当前设备上运行的“系统制品”的名称和版本。在通过Yocto构建时,它会自动生成。在手动安装场景下,我们可以手动创建,这对于服务器识别设备状态很有帮助。

echo "artifact_name=odyssey-base-image" | sudo tee /etc/mender/artifact_info echo "artifact_version=1.0" | sudo tee -a /etc/mender/artifact_info

3.3 配置数据持久化(/data分区)

如前所述,我们需要确保/data分区被正确挂载,并且我们的应用程序使用它。

  1. 首先,确保/data分区存在并已格式化(如果在安装时没做):

    sudo mkfs.ext4 /dev/mmcblk0p4
  2. 编辑/etc/fstab文件,添加自动挂载

    sudo nano /etc/fstab

    添加一行:

    /dev/mmcblk0p4 /data ext4 defaults 0 2
  3. 创建挂载点并挂载

    sudo mkdir -p /data sudo mount -a

    现在,df -h命令应该能看到/data分区。

  4. 迁移应用数据:将你的服务数据目录(如/var/lib/yourapp)通过符号链接或直接修改配置指向/data下的目录。

3.4 处理UEFI启动与GRUB

这是x86设备与许多ARM设备不同的关键点。Mender在切换根文件系统分区(从A到B)后,需要确保GRUB引导菜单也能正确指向新的分区。

Mender提供了一个mender-grubenv工具来管理UEFI启动变量。但我们需要检查GRUB配置是否支持。

  1. 检查GRUB配置:查看/etc/grub.d/10_linux/boot/grub/grub.cfg,看其中根文件系统是如何指定的。通常,Ubuntu会使用root=UUID=<分区UUID>的方式。
  2. Mender的应对:Mender客户端在更新过程中,会计算新rootfs分区的UUID,并更新UEFI启动管理器(efibootmgr)中的相关变量,或者更新GRUB环境块(grubenv),以确保下次启动时加载正确的内核和initramfs,并传递正确的root=参数。
  3. 一个常见问题:如果你的系统使用/dev/mmcblk0p2这样的设备节点直接指定root,在分区切换后肯定会失败。必须使用UUID或PARTUUID。幸运的是,现代Ubuntu安装默认就使用UUID。

你可以通过以下命令检查当前内核的启动参数:

cat /proc/cmdline

输出中应该包含类似root=UUID=5e7a7b8e-...的信息。只要Mender能正确更新指向新分区UUID的引导配置,UEFI启动就能正常工作。

4. 连接服务器与首次部署测试

完成客户端配置后,重启Mender服务并尝试连接服务器。

sudo systemctl restart mender-client sudo journalctl -u mender-client -f

通过journalctl日志,你可以看到客户端启动、尝试连接服务器、进行身份认证的过程。如果TenantToken正确,网络通畅,几分钟后你应该能在 hosted.mender.io 的设备列表中看到你的ODYSSEY设备,状态为“pending”(等待接受)。

在服务器管理界面,你需要“授权”这台设备。授权后,状态变为“accepted”

4.1 制作一个简单的更新“制品”

在服务器上创建一个更新,你需要一个Mender“制品”文件(.mender后缀)。这是一个包含完整根文件系统镜像、版本信息和校验信息的压缩包。在Yocto构建流程中,bitbake命令会直接生成它。

对于我们手动安装的场景,为了快速测试,我们可以创建一个“空更新”“脚本更新”。Menter支持一种rootfs-image类型的更新,也支持module类型的更新(如执行脚本)。

更简单的方法是使用Mender提供的示例脚本和工具来生成一个仅修改版本号的小更新包,用于测试流程。但这涉及mender-artifact工具的使用,步骤稍复杂。对于首次测试,核心目标是验证“客户端能收到更新指令、下载、并尝试切换分区”这个流程。

你可以在服务器界面创建一个部署(Deployment),选择一个虚拟的或非常小的测试制品(有时托管服务器会提供示例制品),将其分配给“odyssey-x86j4105”设备类型。

4.2 观察更新流程与关键日志

当部署创建后,你的ODYSSEY设备会在下一次轮询(或你手动重启mender-client服务)时获取到更新任务。

关键日志节点:

  1. 下载Downloading artifact...->Artifact downloaded.
  2. 安装Installing artifact...->Artifact installed.这一步是将更新包写入到空闲的B分区。
  3. 重启Rebooting to new partition...客户端会尝试重启系统。
  4. 提交(Commit):重启后,从新分区(B)成功启动,Mender客户端再次运行,会向服务器报告更新成功,并提交这次更新。提交意味着B分区被标记为有效的主分区。
  5. 回滚(Rollback):如果从新分区启动失败(例如,内核崩溃,或Mender的健康检查脚本返回失败),设备会在超时后自动重启回原来的A分区,并向服务器报告失败。

在ODYSSEY上的特别观察点:

  • 重启后,观察系统是从哪个分区挂载的根目录(mount | grep ‘on /‘)。
  • 检查/etc/mender/artifact_info文件中的版本号是否已更新。
  • 观察UEFI启动顺序或GRUB菜单是否有变化(通常Mender会处理,无需手动干预)。

5. 踩坑实录与进阶考量

在实际操作中,我遇到了几个典型问题,这里分享出来以供避坑。

5.1 分区表不兼容导致更新失败

问题现象:Mender日志显示安装成功,但重启后系统依然从旧分区启动,更新未生效。排查过程

  1. 检查/etc/mender/mender.conf,确认RootfsPartA/B设置正确。
  2. 重启后检查/proc/cmdline,发现root=参数指向的仍然是旧分区的UUID。
  3. 深入查看Mender日志,发现一条警告:Unable to find boot partition matching rootfs根因与解决:Mender需要识别出/boot分区所在的位置,以便更新引导程序。在UEFI系统中,它默认会寻找一个带有bootesp标志的GPT分区。我的/dev/mmcblk0p1分区虽然格式化为vfat并挂载在/boot/efi,但我可能没有在fdiskparted中为其正确设置esp标志。解决方案
sudo parted /dev/mmcblk0 (parted) set 1 esp on (parted) quit

设置标志后,Mender就能正确识别并更新引导配置了。

5.2 数据分区权限与SELinux/AppArmor

问题:更新后,从新分区启动,发现应用程序无法写入/data目录。原因:虽然/data分区是同一个物理分区,但新系统里的用户ID(UID)、组ID(GID)可能和之前有细微差别(特别是如果你不是用同一个镜像构建的A/B系统)。此外,如果开启了SELinux或AppArmor,新系统上下文或策略文件可能未正确配置,导致访问被拒绝。解决

  1. 确保UID/GID一致:在构建A/B系统时,确保关键系统用户(如www-data,mysql)的UID/GID固定。
  2. 检查文件权限:更新后,手动检查/data目录及其子目录的所有者和权限。
  3. 处理安全模块:对于评估环境,可以考虑暂时禁用SELinux或AppArmor。对于生产环境,必须在构建系统镜像时,就为/data下的路径预先配置好正确的安全上下文或策略。

5.3 网络代理与客户端状态管理

在工业现场,设备可能通过企业代理访问互联网。Mender客户端默认不支持配置代理。你需要通过设置http_proxyhttps_proxy环境变量来让底层的HTTP库(如Go的net/http)使用代理。这需要修改Mender的systemd服务文件。

sudo systemctl edit mender-client

在打开的编辑器中添加:

[Service] Environment="http_proxy=http://your-proxy:port" Environment="https_proxy=http://your-proxy:port"

然后重启服务。

关于客户端状态:Mender客户端有多个状态(idle,downloading,installing,rebooting,failure等)。有时客户端会卡在某个状态。可以通过命令mender -show-artifactmender -commit进行手动干预,但需谨慎。最彻底的方法是清除客户端数据库(rm -rf /var/lib/mender/*)并重启服务,但这会使设备在服务器上“重新注册”,丢失之前的部署历史。

5.4 从“安装”到“生产”:Yocto集成之路

本文演示的在现有系统上“安装”Mender客户端,只是一个概念验证(PoC)。要用于生产,必须通过Yocto ProjectBuildroot进行系统集成。这样做的好处是:

  • 原子性:整个根文件系统作为一个镜像被更新,确保一致性。
  • 可重复性:通过配方(recipe)定义,每次构建出的镜像完全相同。
  • 深度集成:Mender的配置、引导更新、数据分区挂载等都在构建时完成,无需手动干预。
  • 签名与安全:可以方便地集成数字签名,确保更新包的完整性和来源可信。

集成过程主要涉及:

  1. conf/local.conf中添加INHERIT += "mender-full"
  2. 配置MENDER_STORAGE_DEVICE,MENDER_ROOTFS_PART_A/B等变量,匹配ODYSSEY的硬件。
  3. 为你的设备定制内核和引导加载程序(GRUB)配置。
  4. 构建镜像,生成可直接用于OTA的.mender制品。

这个过程的学习曲线较陡,但它是将ODYSSEY-X86这类设备推向规模化、可维护的物联网边缘节点的必由之路。

6. 总结与个人体会

在ODYSSEY - X86上成功跑通Mender客户端,远不止是输入几条命令那么简单。它迫使你去深入理解Linux系统的启动链条(UEFI、GRUB、内核参数)、磁盘分区管理(GPT、A/B布局)、系统服务集成(systemd、配置管理)以及网络通信安全。

最大的体会是:OTA不是一个功能,而是一个系统性的工程实践。客户端安装只是冰山一角,水面之下是系统镜像的构建流水线、更新制品的签名与分发策略、设备分组与部署的灰度发布、更新失败的回滚监控与告警等一系列环节。Mender提供了一个优秀的开源框架,但如何将其无缝、可靠地融入到你特定的硬件和业务系统中,需要大量的定制和测试。

对于ODYSSEY - X86这类性能不错的x86边缘设备,Mender是一个极具潜力的选择。它带来了企业级的更新可靠性。下一步,如果你打算深入,我的建议是:

  1. 立即搭建一个Yocto构建环境,哪怕只是用core-image-minimal来构建一个包含Mender的基础镜像,并烧录到ODYSSEY上。这会让你对整个流程有质的理解。
  2. 部署私有的Mender开源服务器。托管版方便测试,但私有化部署能让你掌控所有数据,并定制集成(如与内部CMDB系统对接)。
  3. 设计你的数据持久化方案。认真规划哪些数据放/data分区,并编写相应的迁移或初始化脚本。
  4. 编写健康检查脚本。Mender允许你定义更新后的健康检查命令。利用好这个功能,比如检查关键服务是否启动、网络是否连通、业务端口是否监听等,这能自动拦截有问题的更新,触发回滚。

折腾的过程虽然费时,但当你看到几十上百台设备在远程管理界面中整齐划一地完成静默更新时,那种运维效率的提升所带来的成就感,是对这些努力最好的回报。