前言

本文记录如何使用 Mender 建立一套“总部统一发布版本,各地区服务器主动获取并升级”的系统。

目标场景如下:

  • 总部维护一个 Mender Server;
  • 前端、后端等业务服务通过 Docker Compose 运行;
  • 每个地区有一台或多台 Linux 服务器;
  • 地区服务器只需要主动访问总部的 HTTPS 地址,不开放升级端口;
  • 总部可以按地区分组、灰度发布、查看结果并停止异常批次;
  • 发布制品必须经过签名,地区服务器拒绝未签名或被篡改的制品;
  • 应用升级失败时能够回退容器版本;
  • 涉及数据库变更时,由业务脚本完成备份、迁移和恢复。

本文重点介绍 Docker Compose 应用升级。Mender 的 A/B 根文件系统适合操作系统整体升级,但需要磁盘分区、bootloader 和系统镜像适配,不能通过安装一个客户端直接获得,文末会单独说明。

本文版本和环境

Mender 的软件仓库、Chart 和命令会继续变化。本文固定以下示例环境,实际部署前应再次检查官方 Supported releases 页面。

项目示例值部署位置
Mender Serverv4.1.0 评估环境总部测试服务器
Mender Helm Chart安装时选择稳定版本并固定版本号总部 Kubernetes
Mender Client6.x,使用 mender-client4 元包安装每台地区服务器
Docker Compose Update Module1.0.0每台地区服务器
地区服务器系统Ubuntu Server 24.04 amd64各地区
容器运行环境Docker Engine + Compose v2各地区
构建环境Ubuntu 24.04 amd64总部 CI/CD Runner
对外域名mender.example.com指向总部入口
设备类型region-server-amd64Artifact 与客户端保持一致

文中的域名、账号、Bucket、密钥、镜像地址和地区编号都是示例,不能原样用于生产。

Mender各组件分别做什么

先明确 Mender 中几个容易混淆的概念。

组件或概念作用
Mender Server保存设备、Release、Deployment 和执行状态,向设备提供更新指令
Mender Client周期性连接 Server,下载、验签、安装制品并上报结果
Mender Artifact后缀为 .mender 的发布制品,包含负载、兼容信息、版本和可选脚本
ReleaseMender Server 中可供发布的软件版本,可以包含适配不同设备类型的 Artifact
Deployment一次具体发布任务,定义把哪个 Release 发给哪些设备
Device Type设备兼容类型,Artifact 只会安装到匹配的设备上
Inventory设备上报的地区、环境、架构和当前版本等属性
Device Group设备集合,作为 Deployment 的发布目标
Update ModuleMender Client 的扩展,负责解释和安装某一种 Artifact 负载
State Script在下载、安装、提交、回滚等生命周期执行的自定义脚本
Mender Gateway企业版地区代理和 Artifact 缓存,不是独立发布中心
mender-artifact创建、读取、签名和验证 .mender 文件的命令行工具
mender-cli上传 Artifact、调用服务端能力的命令行工具

在本文场景中,每台地区服务器都作为一台 Mender Device。总部创建 Deployment 后,地区服务器在下一次轮询时收到任务。

推荐架构

Mender Client 主动发起所有通信,因此地区服务器只需要出站访问总部 443/TCP。总部不需要 SSH 到地区服务器,地区防火墙也不需要为 Mender Client 开放入站端口。

这里的“同步升级”是同一 Deployment 内的批量升级,不代表所有服务器在同一秒开始。设备何时拿到任务取决于自己的轮询周期。生产环境也不建议同时升级全部地区,而应该先试点再逐步扩大。

部署位置规划

位置必须部署可选部署
总部 KubernetesMender Server、IngressPrometheus、日志平台
总部基础设施MongoDB、Redis、NATS、对象存储KMS、Vault、企业 SSO
总部 CI/CD RunnerDocker、Skopeo、mender-artifact、mender-cli、Artifact 生成器HSM 或云 KMS 客户端
每台地区服务器Docker、Compose、Mender Client、Compose Update Module、验签公钥数据库备份工具、业务预检脚本
每个地区出口节点无Mender Gateway,适合设备多或出口受限的地区

如果使用 Hosted Mender,总部 Kubernetes、MongoDB、Redis、NATS 和对象存储都由 Mender 官方维护。企业只需要部署 CI/CD 工具、地区客户端和业务升级脚本。

从哪里下载

所有组件都应从官方地址获取。

内容官方地址
Hosted Mender 注册mender.io/signup
Mender 文档docs.mender.io
Mender Server 源码和评估 Composemendersoftware/mender-server
Mender Helm Chartmendersoftware/mender-helm
设备端 APT 仓库Device components
工作站 APT 仓库Workstation tools
Compose Update Modulemender-container-modules
CI/CD 工具镜像mendersoftware/mender-ci-tools
Helm Chart 仓库https://charts.mender.io

生产环境不要使用 experimental APT 源、main 镜像标签或不固定版本的安装脚本输出。应先在测试环境验证,再固定具体软件和 Chart 版本。

第一阶段:搭建Mender Server评估环境

第一次接触 Mender 时,建议先用 Docker Compose 搭建一次评估环境,熟悉设备接入、上传 Artifact 和创建 Deployment。这个环境配置简单,但证书、依赖和资源配置都不符合生产要求。

准备总部测试服务器

官方评估环境最低要求为:

  • x86_64 或 arm64;
  • 16 GiB 内存;
  • 2 个 vCPU;
  • 50 GiB 可用磁盘;
  • Docker Engine;
  • Docker Compose 2.23.1 或更新版本。

确认环境:

1
2
3
4
docker version
docker compose version
free -h
df -h

这一步的作用是确认容器运行环境和磁盘满足 Mender 多个微服务同时启动的要求。

配置评估域名

在测试服务器的 /etc/hosts 中增加:

1
2
127.0.0.1 docker.mender.io
127.0.0.1 s3.docker.mender.io

官方评估环境内置证书使用这两个域名。该配置只是让本机能够把域名解析到评估环境,不能作为生产 DNS 方案。

下载并启动评估服务器

1
2
3
4
5
6
7
git clone -b v4.1.0 \
https://github.com/mendersoftware/mender-server.git \
mender-server

cd mender-server
export MENDER_IMAGE_TAG=v4.1.0
docker compose up -d

每条命令的作用如下:

  • git clone -b v4.1.0:下载固定版本的官方 Compose 和配置;
  • MENDER_IMAGE_TAG:指定各个 Mender 服务使用的镜像版本;
  • docker compose up -d:后台启动 API Gateway、UI、设备认证、部署、库存和存储等服务。

检查容器:

1
2
docker compose ps
docker compose logs --tail=100

只有所有关键容器都正常运行后,才继续创建管理员。

创建管理员

1
2
3
4
5
6
export MENDER_USERNAME='admin@docker.mender.io'
export MENDER_PASSWORD='Replace-With-A-Strong-Password'

docker compose run --name create-user useradm create-user \
--username "$MENDER_USERNAME" \
--password "$MENDER_PASSWORD"

useradm 是 Mender 的用户管理服务。这条命令直接在服务端创建第一个管理用户。

浏览器访问:

1
https://localhost

评估环境使用自签名证书,浏览器会提示不受信任。这个警告只能在隔离测试环境临时接受,生产环境必须配置有效证书。

停止和清理评估环境

只停止容器并保留数据:

1
docker compose stop

删除容器、Volume 和全部测试数据:

1
docker compose down -v --remove-orphans

第二条命令会删除设备、用户、Artifact、Deployment 和日志,不能在需要保留数据的环境执行。

第二阶段:生产部署Mender Server

生产环境官方推荐使用 Kubernetes + Helm。经过官方验证和支持的 Kubernetes 环境主要是 EKS、AKS 和 GKE;本地 k3s 可以用于 PoC,但不能因为 Helm 安装成功就视为完整生产集群。

生产依赖

Mender Server 生产环境至少需要:

依赖作用生产建议
Kubernetes运行 Mender 微服务多节点、独立维护、定期升级
MongoDB保存用户、设备、认证、库存和发布元数据使用副本集并建立备份
Redis临时数据和缓存使用高可用实例
NATSMender 服务间消息通信高可用场景启用 JetStream 副本
S3 兼容对象存储保存 .mender Artifact开启版本化、备份和生命周期策略
Ingress 或 Load Balancer对外提供 HTTPS API 和 UI只开放 HTTPS,HTTP 跳转 HTTPS
DNS 和 TLS让客户端验证总部服务器身份使用企业 CA 或公开可信 CA

官方 Chart 内可以带 MongoDB、Redis 和 NATS 子 Chart,但这些更适合测试或 PoC。生产环境应使用独立维护的服务。

Mender Server 本身的参考资源为:

设备规模Mender 服务资源,不含数据库和对象存储
100 台以内8 GiB RAM、4 vCPU
1 万台以内16 GiB RAM、8 vCPU
10 万台以内24 GiB RAM、16 vCPU

准备Kubernetes和Helm

如果只是验证 Helm 流程,可以在 Ubuntu 测试机安装 k3s:

1
2
3
4
5
curl -sfL https://get.k3s.io -o install-k3s.sh
less install-k3s.sh
sudo sh install-k3s.sh --write-kubeconfig-mode 644
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl get nodes

先下载并审查脚本,再以 root 执行。kubectl get nodes 出现 Ready 表示控制面可用。

安装 Helm:

1
2
3
4
5
6
curl -fsSL \
https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 \
-o get-helm-3.sh
less get-helm-3.sh
bash get-helm-3.sh
helm version

生产环境应使用企业已经维护的 Kubernetes 集群,不应照搬单节点 k3s。

准备域名和TLS

将以下域名解析到 Kubernetes Ingress 或 Load Balancer:

1
mender.example.com

Ingress 必须满足:

  • HTTP 自动跳转 HTTPS;
  • 对 mender.example.com 提供有效 TLS 证书;
  • 大文件上传超时足够长;
  • 如果负载均衡器要求健康检查,使用 /ui;
  • Artifact 上传大小不能被 Ingress 默认限制拦截。

可以使用 cert-manager 自动申请证书:

1
2
3
4
5
6
7
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm upgrade --install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.16.1 \
--set crds.enabled=true

这一步的作用是让 Kubernetes 自动申请、保存和续期 X.509 证书。实际使用 Let’s Encrypt 还是企业 CA,应由网络和安全策略决定。

准备对象存储

生产环境建议使用 AWS S3、Cloudflare R2、Google Cloud Storage 的 S3 兼容接口或 Azure Blob Storage。对象存储负责保存真正体积较大的 .mender 文件,MongoDB 只保存元数据。

准备以下信息:

1
2
3
4
5
export STORAGE_BUCKET='mender-artifacts-prod'
export STORAGE_ENDPOINT='https://s3.example.com'
export AWS_REGION='us-east-1'
export AWS_ACCESS_KEY_ID='Replace-With-Access-Key'
export AWS_SECRET_ACCESS_KEY='Replace-With-Secret-Key'

生产中不要把密钥写进 Shell 历史或提交到 Git,应放在 Kubernetes Secret、Vault 或云 Secret Manager 中。示例使用环境变量只是为了说明 Chart 需要哪些值。

准备Mender Helm配置

先添加 Mender Chart 仓库并查看可用版本:

1
2
3
helm repo add mender https://charts.mender.io
helm repo update
helm search repo mender/mender --versions

创建 mender-values.yml:

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
ingress:
enabled: true
ingressClassName: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "7200"
nginx.ingress.kubernetes.io/proxy-send-timeout: "7200"
path: /
hosts:
- mender.example.com
tls:
- secretName: mender-ingress-tls
hosts:
- mender.example.com

global:
url: https://mender.example.com
s3:
AWS_URI: https://s3.example.com
AWS_BUCKET: mender-artifacts-prod
AWS_REGION: us-east-1
AWS_ACCESS_KEY_ID: Replace-With-Access-Key
AWS_SECRET_ACCESS_KEY: Replace-With-Secret-Key

api_gateway:
storage_proxy:
enabled: true
url: https://s3.example.com
customRule: "PathRegexp(`^/mender-artifacts-prod`)"

这份配置完成三件事:

  1. 通过 Ingress 暴露 Mender UI 和 API;
  2. 告诉 Mender 自己的外部访问地址;
  3. 指定 Artifact 保存到哪个对象存储。

不同云厂商、Ingress Controller 和对象存储的配置不完全相同。上面的文件是结构示例,生产部署应按实际服务修改,并将凭据改为 Secret 引用。

使用外部MongoDB

创建保存连接串的 Secret:

1
2
3
4
5
kubectl create namespace mender

kubectl -n mender create secret generic mender-mongo \
--from-literal=MONGO='mongodb://mender-user:Replace-With-Password@mongo-1.example.com:27017,mongo-2.example.com:27017,mongo-3.example.com:27017/mender?replicaSet=rs0' \
--from-literal=MONGO_URL='mongodb://mender-user:Replace-With-Password@mongo-1.example.com:27017,mongo-2.example.com:27017,mongo-3.example.com:27017/mender?replicaSet=rs0'

在 mender-values.yml 中增加以下内容;如果文件已经存在 global,必须把 mongodb 合并到原有 global 下,不能再创建一个同级重复键:

1
2
3
4
5
6
global:
mongodb:
existingSecret: mender-mongo

mongodb:
enabled: false

existingSecret 让 Mender 服务读取外部 MongoDB 连接;mongodb.enabled: false 禁用 Chart 内置的评估数据库。

Redis、NATS 和对象存储也应采用同样原则:连接企业维护的外部服务,并关闭对应的测试子 Chart。具体字段随 Chart 版本变化,应以安装版本的 values.yaml 为准:

1
helm show values mender/mender > mender-default-values.yml

安装Mender Server

前面已经添加过 Mender Chart 仓库。先确认列表,从中选择经过测试的版本,然后固定 Chart:

1
2
3
4
5
6
7
8
9
export MENDER_CHART_VERSION='Replace-With-Verified-Chart-Version'

helm upgrade --install mender mender/mender \
--namespace mender \
--create-namespace \
--version "$MENDER_CHART_VERSION" \
--wait \
--timeout 20m \
-f mender-values.yml

不要在生产中省略 --version。固定 Chart 可以避免某次重新部署时自动拿到不兼容的新版本。

检查部署:

1
2
3
kubectl -n mender get pods
kubectl -n mender get ingress
kubectl -n mender get events --sort-by=.lastTimestamp

所有核心 Pod 应为 Running 或完成预期 Job,Ingress 应显示正确域名和地址。

创建第一个管理员

1
2
3
4
5
6
7
8
USERADM_POD=$(kubectl -n mender get pod \
-l 'app.kubernetes.io/component=useradm' \
-o name | head -1)

kubectl -n mender exec "$USERADM_POD" -- \
useradm create-user \
--username 'admin@example.com' \
--password 'Replace-With-A-Strong-Password'

浏览器访问:

1
https://mender.example.com

如果页面打不开,依次检查 DNS、Ingress 地址、TLS Secret、Ingress 日志和 Mender Pod 状态。

生产备份

Mender Server 至少需要分别备份:

  • MongoDB:设备身份、用户、库存、Deployment 和发布元数据;
  • 对象存储:全部 .mender Artifact;
  • Kubernetes Secret:服务连接串、证书和部署配置;
  • Helm values:去除明文密钥后纳入配置版本管理。

只备份 MongoDB 不能恢复 Artifact 文件,只备份对象存储也不能恢复设备和发布记录。恢复演练必须验证 UI 登录、设备认证、Artifact 下载和历史 Deployment 查询。

第三阶段:安装地区服务器Mender Client

下面的操作在每一台地区服务器执行。

检查网络和时间

1
2
3
getent hosts mender.example.com
curl -I https://mender.example.com/ui
timedatectl status

这一步验证三个前提:

  • DNS 能解析总部域名;
  • 出站 HTTPS 可用;
  • 系统时间正确,TLS 和 Artifact 有效期判断不会出错。

地区服务器无需开放 Mender 入站端口。

安装Docker和Compose

按照 Docker 官方 Ubuntu 安装文档安装 Docker Engine 和 Compose 插件,然后验证:

1
2
3
docker version
docker compose version
sudo systemctl enable --now docker

Compose Update Module 会调用本机 Docker,因此 Docker 必须由 systemd 正常管理。

安装Mender Client

下面两种方式二选一。最快的方式是官方便利脚本,适合 PoC;先下载、审查,再执行:

1
2
3
curl -fLsS https://get.mender.io -o get-mender.sh
less get-mender.sh
sudo bash get-mender.sh mender-client4

只传入 mender-client4,可以避免便利脚本额外安装 Remote Terminal 和 Configure 插件。

生产环境更推荐显式配置官方 device-components APT 仓库并固定软件版本。Ubuntu 24.04 可以执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sudo apt-get update
sudo apt-get install --assume-yes --no-install-recommends \
apt-transport-https ca-certificates curl gnupg jq

curl -fsSL https://downloads.mender.io/repos/debian/gpg \
| sudo tee /etc/apt/trusted.gpg.d/mender.asc >/dev/null

gpg --show-keys --with-fingerprint \
/etc/apt/trusted.gpg.d/mender.asc

echo "deb [arch=$(dpkg --print-architecture)] https://downloads.mender.io/repos/device-components ubuntu/noble/stable main" \
| sudo tee /etc/apt/sources.list.d/mender-device-components.list

sudo apt-get update
apt-cache madison mender-client4

从 apt-cache 输出中选定经过测试的版本。首次验证时可以安装仓库当前稳定版:

1
sudo apt-get install --assume-yes mender-client4

完成兼容性验证后,应在自动化安装清单中记录实际包版本,并通过 APT preference 或版本参数锁定,避免地区服务器在不同日期安装到不同客户端版本。

官方仓库签名密钥指纹应核对为:

1
E6C8 5734 5575 F921 8396 5662 2407 2B80 A1B2 9B00

安装后检查:

1
2
3
4
mender-update --version
mender-auth --version
mender-setup --help
systemctl status mender-authd mender-updated

mender-authd 负责设备认证和令牌,mender-updated 负责轮询、下载和安装更新。

配置连接总部

定义设备类型和服务器地址:

1
2
3
4
5
6
export DEVICE_TYPE='region-server-amd64'
export MENDER_SERVER_URL='https://mender.example.com'

sudo mender-setup \
--device-type "$DEVICE_TYPE" \
--server-url "$MENDER_SERVER_URL"

device-type 必须和后面生成 Artifact 时的兼容类型完全一致。不同 CPU 架构或部署形态应使用不同类型,例如:

1
2
3
region-server-amd64
region-server-arm64
factory-edge-amd64

生产环境不要使用 --demo-polling,它会产生比默认值更频繁的请求。

如果使用 Hosted Mender,不传 --server-url,而是从 Organization 设置中取得 Tenant Token:

1
2
3
4
5
6
7
export DEVICE_TYPE='region-server-amd64'
export TENANT_TOKEN='Replace-With-Tenant-Token'

sudo mender-setup \
--device-type "$DEVICE_TYPE" \
--hosted-mender \
--tenant-token "$TENANT_TOKEN"

Tenant Token 能让新设备向组织申请接入,必须作为 Secret 管理,不能写入镜像、Git 或日志。Hosted 和自建 Server 两种配置方式同样是二选一。

配置轮询和证书

Mender Client 主配置位于:

1
/etc/mender/mender.conf

默认更新轮询周期是 1800 秒,Inventory 上报周期是 28800 秒。可以调整为:

1
2
3
4
5
{
"ServerURL": "https://mender.example.com",
"UpdatePollIntervalSeconds": 300,
"InventoryPollIntervalSeconds": 3600
}

这只是最小结构示例。编辑时要保留 mender-setup 已写入的其他字段,不能直接覆盖整份配置。

  • UpdatePollIntervalSeconds: 300:设备最多约 5 分钟发现新任务;
  • InventoryPollIntervalSeconds: 3600:每小时上报一次地区和版本信息;
  • 轮询越频繁,总部服务端压力越大。

如果总部使用公开可信 CA,客户端使用系统 CA 即可。如果使用企业私有 CA,应把 CA 证书放到客户端,例如:

1
/etc/mender/server.crt

然后在配置中增加:

1
2
3
{
"ServerCertificate": "/etc/mender/server.crt"
}

不要在生产环境启用跳过 TLS 验证。

重新启动客户端:

1
2
3
sudo systemctl restart mender-authd mender-updated
sudo journalctl -u mender-authd -n 100 --no-pager
sudo journalctl -u mender-updated -n 100 --no-pager

在服务端接纳设备

客户端第一次运行时会生成自己的密钥:

1
/var/lib/mender/mender-agent.pem

然后向 Server 提交认证请求。在 Mender UI 中进入 Devices,找到 Pending 设备,核对设备 ID、公钥和主机信息后选择 Accept。

只有 Accepted 设备才能进入 Deployment。生产环境设备多时,可以使用预授权 API 或企业版 mTLS 自动接纳,但不能在没有身份校验的情况下自动接受任意设备。

第四阶段:上报地区Inventory并建立分组

Mender 会执行 /usr/share/mender/inventory 中所有以 mender-inventory- 开头的可执行文件,并把脚本标准输出解析为 Inventory。

在华东服务器创建:

1
2
3
4
5
6
7
8
9
10
sudo tee /usr/share/mender/inventory/mender-inventory-region >/dev/null <<'EOF'
#!/bin/sh
printf '%s\n' \
'region=east-china' \
'environment=production' \
'site_id=site-001' \
'service_type=factory-compose'
EOF

sudo chmod 700 /usr/share/mender/inventory/mender-inventory-region

手工检查脚本输出:

1
sudo /usr/share/mender/inventory/mender-inventory-region

这些属性用于搜索、筛选和分组,不用于唯一识别设备。site_id 也不应代替 Mender Device ID。

等待 Inventory 上报后,在 UI 中可以:

  1. 建立静态组 pilot,手工加入试点服务器;
  2. 建立静态组 production-east、production-south 等地区组;
  3. 企业版可根据 region 和 environment 建立动态组。

静态组在创建 Deployment 时会固化设备列表。Deployment 创建后再向组里增加设备,不会把新设备自动加入正在执行的任务。

第五阶段:安装Docker Compose Update Module

只安装 Mender Client 还不能理解 docker-compose Artifact。需要在每台地区服务器安装对应 Update Module。

下载并安装模块

1
2
3
4
5
6
7
8
9
sudo apt-get update
sudo apt-get install --assume-yes git make m4

git clone --branch 1.0.0 --depth 1 \
https://github.com/mendersoftware/mender-container-modules.git

cd mender-container-modules
make
sudo make install-docker-compose

这些命令的作用分别是:

  • 下载固定版本的官方容器更新模块;
  • make 将模板和公共 Shell 逻辑生成可执行模块;
  • make install-docker-compose 安装到 Mender 的 Update Module 目录。

验证:

1
2
test -x /usr/share/mender/modules/v3/docker-compose
ls -l /usr/share/mender/modules/v3/docker-compose

Update Module 的文件名就是 Artifact payload type。客户端收到 docker-compose 类型负载时,会调用这个文件完成安装、提交或回滚。

规划Docker持久化目录

如果未来还要做 A/B 操作系统升级,Docker 镜像和业务数据不能留在会被整体替换的根分区。应把 Docker data-root 放到持久化数据分区,例如:

1
2
3
{
"data-root": "/data/docker"
}

文件位置:

1
/etc/docker/daemon.json

修改后需要重启 Docker:

1
2
sudo systemctl restart docker
docker info | grep 'Docker Root Dir'

只做应用更新时也建议将数据库、上传文件、运行时配置和备份放在明确的持久化目录,不能依赖容器可写层。

第六阶段:在构建机安装Mender工具

下面的操作在总部 CI/CD Runner 或独立签名机构执行,不是在地区服务器执行。

配置工作站APT仓库

安装依赖并导入官方签名密钥:

1
2
3
4
5
6
7
8
9
sudo apt-get update
sudo apt-get install --assume-yes \
apt-transport-https ca-certificates curl gnupg jq skopeo

curl -fsSL https://downloads.mender.io/repos/debian/gpg \
| sudo tee /etc/apt/trusted.gpg.d/mender.asc >/dev/null

gpg --show-keys --with-fingerprint \
/etc/apt/trusted.gpg.d/mender.asc

确认指纹为官方公布的:

1
E6C8 5734 5575 F921 8396 5662 2407 2B80 A1B2 9B00

Ubuntu 24.04 添加工作站工具源:

1
2
3
4
5
echo "deb [arch=$(dpkg --print-architecture)] https://downloads.mender.io/repos/workstation-tools ubuntu/noble/stable main" \
| sudo tee /etc/apt/sources.list.d/mender-workstation-tools.list

sudo apt-get update
sudo apt-get install --assume-yes mender-artifact mender-cli

验证:

1
2
3
mender-artifact --version
mender-cli --version
skopeo --version

mender-artifact 处理 .mender 文件,mender-cli 与 Mender Server API 通信,skopeo 在不运行容器的情况下下载不同架构的镜像。

也可以直接使用官方 CI 工具镜像:

1
docker pull mendersoftware/mender-ci-tools:1.0.0

下载Compose Artifact生成器

1
2
3
4
5
6
sudo curl -fL \
https://raw.githubusercontent.com/mendersoftware/mender-container-modules/1.0.0/src/gen_docker-compose \
-o /usr/local/bin/gen_docker-compose

sudo chmod 755 /usr/local/bin/gen_docker-compose
gen_docker-compose --help

生成器负责解析 Compose、通过 Skopeo 下载镜像,再把 Compose 和镜像归档成 Mender Artifact。

第七阶段:准备业务Compose发布包

创建发布目录:

1
2
mkdir -p release/manifests release/output
cd release

示例 manifests/compose.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
services:
frontend:
image: registry.example.com/factory/frontend:2026.08.1
restart: unless-stopped
ports:
- "8080:80"
volumes:
- /data/factory/runtime-config.json:/usr/share/nginx/html/runtime-config.json:ro
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1/healthz"]
interval: 10s
timeout: 3s
retries: 12

backend:
image: registry.example.com/factory/backend:2026.08.1
restart: unless-stopped
volumes:
- /data/factory/backend-config.yaml:/app/config.yaml:ro
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/health/ready"]
interval: 10s
timeout: 3s
retries: 12

发布前需要完成以下应用改造:

  • 镜像使用不可变版本标签,正式环境最好同时记录 digest;
  • 地区差异配置通过 Volume 在运行时挂载;
  • 前端提供 /healthz 和 /version.json;
  • 后端提供 /health/live、/health/ready 和 /version;
  • 数据库、用户上传和业务文件位于宿主持久化目录或外部服务;
  • Compose 设置明确的 restart 和 healthcheck;
  • 同一个镜像可以部署到所有地区,不能为每个地区重新构建。

如果私有 Registry 需要认证,先在构建机登录:

1
skopeo login registry.example.com

认证只用于构建机下载镜像。因为最终 Artifact 可以包含镜像归档,地区服务器不一定需要访问 Registry。

第八阶段:生成Mender Artifact

先检查镜像支持的架构:

1
2
3
gen_docker-compose \
--list-architectures \
--manifests-dir manifests

生成 amd64 Artifact:

1
2
3
4
5
6
7
8
9
gen_docker-compose \
--artifact-name factory-release-2026.08.1 \
--device-type region-server-amd64 \
--architecture amd64 \
--manifests-dir manifests \
--project-name factory-service \
--output-path output/factory-release-2026.08.1.mender \
-- \
--software-filesystem data-docker

参数作用如下:

参数作用
--artifact-name设备安装后上报的软件版本名
--device-type限制只有相同类型的设备能够安装
--architecture指定下载哪个 CPU 架构的容器镜像
--manifests-dirCompose 文件目录
--project-nameCompose 项目名,决定服务集合的管理范围
--output-path最终 .mender 文件位置
--software-filesystem声明容器镜像所在持久化文件系统

生成器会得到两个主要负载:

  • images.tar.gz:Compose 引用的容器镜像;
  • manifests.tar:Compose 文件和相关清单。

读取 Artifact 信息:

1
mender-artifact read output/factory-release-2026.08.1.mender

重点检查:

  • Artifact name;
  • Compatible devices;
  • payload type 是否为 docker-compose;
  • 架构是否正确;
  • Compose 项目名和软件文件系统是否正确。

第九阶段:签名并在客户端启用强制验签

TLS 保护传输过程,Artifact 签名则保证制品本身来自受信发布方。两者不能互相替代。

生成签名密钥

在独立签名机生成 RSA 3072 位密钥:

1
2
3
4
5
6
7
openssl genpkey \
-algorithm RSA \
-out private.key \
-pkeyopt rsa_keygen_bits:3072

openssl rsa -in private.key -out public.key -pubout
chmod 600 private.key
  • private.key:只保存在签名机、KMS、Vault 或 HSM,不能进入 Git 和地区服务器;
  • public.key:部署到所有地区服务器,用于验证签名。

签名Artifact

1
2
3
4
mender-artifact sign \
output/factory-release-2026.08.1.mender \
-k private.key \
-o output/factory-release-2026.08.1-signed.mender

验证:

1
2
3
mender-artifact validate \
output/factory-release-2026.08.1-signed.mender \
-k public.key

只有本地验证成功,才能上传到生产 Mender Server。

客户端安装验签公钥

在每台地区服务器执行:

1
2
3
sudo install -o root -g root -m 0644 \
public.key \
/etc/mender/artifact-verify-key.pem

在 /etc/mender/mender.conf 的现有 JSON 中加入:

1
2
3
{
"ArtifactVerifyKey": "/etc/mender/artifact-verify-key.pem"
}

重新启动:

1
sudo systemctl restart mender-updated

一旦启用 ArtifactVerifyKey,客户端会拒绝未签名 Artifact 和签名不匹配的 Artifact。公钥轮换期间可以使用 ArtifactVerifyKeys 同时配置新旧公钥,确认全部设备获得新公钥后再删除旧公钥。

第十阶段:加入数据库备份、迁移和健康检查

Mender 能触发回滚,但它不知道数据库语义,也不会自动撤销 State Script 对数据库做出的修改。数据库升级必须自己设计。

State Script命名

Artifact State Script 使用以下格式:

1
<STATE_NAME>_<ACTION>_<ORDER>_<DESCRIPTION>

典型脚本:

1
2
3
4
ArtifactInstall_Enter_10_backup-database
ArtifactInstall_Leave_20_migrate-database
ArtifactCommit_Enter_10_health-check
ArtifactRollback_Enter_10_restore-database

脚本退出码:

退出码含义
0成功,继续升级
1失败,进入回滚或失败流程
21稍后重试,受重试间隔和总超时限制

脚本必须满足:

  • 幂等,多次运行结果一致;
  • 有明确超时;
  • 诊断信息写到标准错误;
  • 不把密码打印到日志;
  • 备份放在持久化目录;
  • 每次备份与 Deployment 或 release ID 关联;
  • 实际验证备份可恢复,而不是只判断命令退出码。

健康检查示例

ArtifactCommit_Enter_10_health-check:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/sh
set -eu

attempt=1
while [ "$attempt" -le 30 ]; do
if curl --fail --silent --show-error \
http://127.0.0.1:8080/health/ready >/dev/null; then
exit 0
fi

attempt=$((attempt + 1))
sleep 10
done

echo 'backend readiness check failed after 300 seconds' >&2
exit 1

将健康检查放在 ArtifactCommit_Enter,可以在 Mender 正式提交版本之前阻止错误版本。返回 1 后,Mender 会执行 Update Module 回滚流程。

将脚本放进Artifact

给脚本执行权限:

1
2
3
4
chmod 755 scripts/ArtifactInstall_Enter_10_backup-database
chmod 755 scripts/ArtifactInstall_Leave_20_migrate-database
chmod 755 scripts/ArtifactCommit_Enter_10_health-check
chmod 755 scripts/ArtifactRollback_Enter_10_restore-database

生成 Artifact 时,将 --script 参数透传给 mender-artifact:

1
2
3
4
5
6
7
8
9
10
11
12
13
gen_docker-compose \
--artifact-name factory-release-2026.08.1 \
--device-type region-server-amd64 \
--architecture amd64 \
--manifests-dir manifests \
--project-name factory-service \
--output-path output/factory-release-2026.08.1.mender \
-- \
--software-filesystem data-docker \
--script scripts/ArtifactInstall_Enter_10_backup-database \
--script scripts/ArtifactInstall_Leave_20_migrate-database \
--script scripts/ArtifactCommit_Enter_10_health-check \
--script scripts/ArtifactRollback_Enter_10_restore-database

再次读取 Artifact,确认 State scripts 已被打包:

1
mender-artifact read output/factory-release-2026.08.1.mender

数据库迁移的准确执行时机必须根据业务确定。某些 Compose 安装流程会先启动新容器,因此更稳妥的方案可能是把迁移做成一次性 Compose service,并让业务服务在迁移成功后启动。不可逆迁移不应进入无人值守升级通道。

第十一步:上传Release

使用UI上传

进入 Mender UI:

1
Releases -> Upload

选择签名后的文件:

1
factory-release-2026.08.1-signed.mender

上传后展开 Artifact 信息,再次检查设备类型、版本、payload type 和签名状态。

使用mender-cli上传

在 Mender UI 的个人资料页面创建 Personal Access Token。Token 只显示一次,应存入 CI Secret。

1
2
3
4
5
6
7
export MENDER_SERVER_URL='https://mender.example.com'
export MENDER_PAT='Replace-With-Personal-Access-Token'

mender-cli artifacts \
--server "$MENDER_SERVER_URL" \
--token-value "$MENDER_PAT" \
upload output/factory-release-2026.08.1-signed.mender

PAT 是长期凭据,权限继承创建它的用户。CI 应使用权限最小化的专用账号,并设置过期和轮换策略。

第十二步:创建灰度Deployment

推荐发布顺序:

  1. 开发环境;
  2. 测试地区;
  3. pilot 试点组;
  4. 一个低风险生产地区;
  5. 10% 生产设备;
  6. 全量地区。

在 Mender UI 创建 Deployment:

  1. 选择 factory-release-2026.08.1 Release;
  2. 目标选择 pilot 静态组;
  3. 设置开始时间或立即开始;
  4. 检查设备数量;
  5. 创建 Deployment;
  6. 观察下载、安装、成功和失败状态;
  7. 试点观察期结束后,再创建下一批 Deployment。

Mender Server 不会让所有地区在同一秒执行。默认更新轮询为 30 分钟,本文示例改为 5 分钟,所以设备一般会在 5 分钟窗口内陆续开始。

中止和回滚不是同一操作

发现故障时,应先在 UI 或 API 中停止仍在进行的 Deployment,防止更多设备领取任务。中止任务不会自动把已经成功升级的设备降回旧版本。

需要人工回滚已经升级成功的设备时,应保留并重新发布上一版签名 Artifact,例如 factory-release-2026.07.4,再为受影响设备创建一个新的 Deployment。数据库只有在旧应用仍兼容当前 schema,或已执行经过验证的向下迁移、备份恢复后,才允许回退应用。

自动回滚只发生在当前安装流程尚未成功提交,并且 Update Module 或 State Script 报错的情况下。已经标记成功的 Deployment 不能依靠“中止”恢复旧版本。

第十三步:观察状态和排查失败

地区服务器日志

查看认证日志:

1
sudo journalctl -u mender-authd -n 200 --no-pager

查看更新日志:

1
sudo journalctl -u mender-updated -n 200 --no-pager

实时跟踪:

1
sudo journalctl -u mender-updated -f

失败 Deployment 的详细日志还会保存在:

1
/var/lib/mender/deployments.*.log

Mender 默认保留最近若干部署日志,并在失败时上传日志到服务端。

查看设备当前软件信息

1
sudo mender-update show-provides

应能看到当前 Artifact 和 Compose 软件版本。服务端 UI 中也可以从 Device 和 Release 页面交叉核对。

常见故障

设备一直Pending

检查:

  • 管理员是否在 UI 接受设备;
  • mender-authd 日志是否有 TLS 或认证错误;
  • 设备时间是否正确;
  • 是否错误复制了另一台服务器的 /var/lib/mender。

每台设备必须拥有独立身份。克隆服务器模板时,应在首次启动前清理模板中的 Mender 私钥和状态,再让每台机器自行生成。

certificate signed by unknown authority

表示客户端不信任总部 TLS 证书。使用公开 CA 时更新系统 ca-certificates;使用私有 CA 时,将正确 CA 放入 /etc/mender/server.crt 并配置 ServerCertificate。

不能通过关闭证书验证掩盖问题。

Artifact显示noartifact

通常是 Artifact 的 compatible device type 与客户端 Device Type 不一致。检查:

1
2
cat /var/lib/mender/device_type
mender-artifact read release.mender

两边的值必须完全相同。

签名验证失败

检查:

  • 上传的是签名后文件,不是原始文件;
  • 客户端配置指向正确公钥;
  • 签名后没有再次修改 Artifact;
  • 公钥轮换期间新旧密钥配置是否完整。

Compose安装失败

检查:

1
2
3
4
5
docker compose version
docker info
df -h
df -i
ls -l /usr/share/mender/modules/v3/docker-compose

常见原因包括磁盘不足、镜像架构错误、端口冲突、Volume 路径不存在、Compose 语法错误和健康检查命令缺失。

版本出现_INCONSISTENT

这表示上一次部署失败,并且回滚失败或 Update Module 无法完成回滚。此时不能继续自动发布,应先读取设备 Deployment 日志,确认容器、配置和数据库实际处于哪个版本。

可选:每个地区部署Mender Gateway

当一个地区有很多设备,或者只有地区出口服务器能访问总部时,可以部署 Mender Gateway。

Gateway 可以:

  • 代理设备到总部的 Mender API 请求;
  • 把 Artifact 下载地址替换为地区网关地址;
  • 第一次下载后缓存在本地,后续设备复用;
  • 为网关后的设备统一增加 region 等 Inventory;
  • 配合 mTLS 自动接纳持有有效客户端证书的设备。

Mender Gateway 属于 Enterprise 能力。它不是一套独立地区 Mender Server,也不会在总部上传 Release 后立即主动同步全部 Artifact;缓存通常在设备实际请求时产生。

示例 /etc/mender/mender-gateway.conf:

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
{
"HTTPS": {
"Enabled": true,
"Listen": ":443",
"MinimumTLSVersion": "1.2",
"ServerCertificate": "/var/lib/mender/server-cert.pem",
"ServerKey": "/var/lib/mender/server-pkey.pem"
},
"Features": {
"ArtifactsProxy": {
"Enabled": true,
"GatewayURL": "https://mender-gateway-east.example.com",
"DomainWhitelist": ["s3.example.com"],
"ArtifactsCache": {
"Enabled": true,
"Path": "/var/cache/mender-gateway",
"SignatureSecret": "Replace-With-Random-Base64-Secret",
"LinkExpireDuration": "30m"
}
},
"DeviceSystem": {
"Enabled": true,
"SystemID": "east-region-gateway",
"DefaultInventory": [
{
"Name": "region",
"Value": "east-china"
}
]
}
},
"UpstreamServer": {
"URL": "https://mender.example.com",
"CACertificate": "/etc/ssl/certs/ca-certificates.crt",
"InsecureSkipVerify": false
}
}

部署时还要完成:

  • 从企业下载区取得与系统匹配的 mender-gateway Debian 包;
  • 为 Gateway 配置受信 TLS 证书;
  • 为缓存准备独立磁盘或 Volume;
  • 将 DomainWhitelist 限制为真实 Artifact 存储域名;
  • 把地区设备 ServerURL 指向 Gateway;
  • Gateway 2.2.0 或更新版本可启用 Prometheus /metrics,应只监听 127.0.0.1:9102 或受信管理网;
  • 监控缓存磁盘、请求错误率和到总部的连通性。

如果每个地区只有一台服务器并且网络稳定,Gateway 的收益很低,可以先不部署。

如果每个地区必须有独立Mender Server

有些企业要求地区断开总部后仍能独立创建发布。此时可以在每个地区部署完整 Mender Server,但这已经是多套独立控制面。

需要额外开发或建设:

  • 总部 Artifact 向各地区对象存储复制;
  • Release 元数据同步;
  • 地区 Deployment 创建和状态汇总;
  • API Token、账号和权限管理;
  • 失败补偿和重复同步幂等;
  • 总部与地区版本冲突处理;
  • 断网期间操作审计合并。

Mender Gateway 不能替代这套联邦控制逻辑。除非有明确的地区自治或长期断网要求,否则优先使用一个中心 Mender Server 加多个 Gateway。

操作系统A/B升级与Compose升级的区别

本文安装 Debian 包的方式只能直接获得应用更新能力,不能自动获得完整操作系统回滚。

更新方式更新内容是否需要重启集成成本回滚能力
Docker Compose Update Module前端、后端、容器和 Compose通常不需要整机重启较低由模块和业务脚本共同保证
自定义 Update Module文件、安装包、业务组件取决于实现中等必须自己实现
A/B rootfs整个 Linux 根文件系统需要高启动失败可切回旧分区

A/B rootfs 需要:

  • 两个根文件系统分区;
  • 持久化数据分区;
  • GRUB 或 U-Boot 集成;
  • Mender 化的 Debian/Yocto 镜像;
  • 启动成功确认和 boot counter;
  • 重新刷写或迁移现有服务器磁盘布局。

对于已经运行 Docker Compose 的普通服务器,建议第一期只做应用升级;操作系统补丁继续使用现有的系统运维工具。等应用发布链路稳定后,再单独评估 rootfs OTA。

哪些是安装配置,哪些必须自己开发

工作类型说明
Mender Server、Client、CLI 安装现成组件按官方方式部署和配置
设备认证、静态分组、Deployment、状态上报现成能力Open Source 已覆盖基础流程
Gateway、mTLS、动态组、RBAC、审计企业能力取决于购买方案
Compose Artifact 生成和安装官方工具使用 gen_docker-compose 和 Update Module
Artifact 签名和客户端验签官方工具仍需企业管理私钥和公钥轮换
CI 上传和创建 Deployment流水线脚本调用 mender-cli 或 REST API
前后端健康和版本接口业务开发Mender 不知道业务是否真正可用
运行时配置外置业务改造确保一个镜像能部署到所有地区
数据库备份、迁移和恢复必须自研针对实际数据库和业务 schema
不可逆迁移审批流程建设不应自动回滚或无人值守执行
严格同一秒跨地区切换自定义协调Mender 客户端轮询不保证同时开始
多套地区 Mender Server 联邦同步自定义平台Gateway 不提供独立控制面同步

使用 Mender 的主要价值,是省掉设备注册、轮询协议、制品存储、部署状态机、基础重试和管理 UI。真正需要自己开发的部分集中在业务健康、Compose 约束、数据库和企业发布流程。

生产上线清单

正式启用无人值守更新前,至少确认:

  • Mender Server 使用固定 Chart 和镜像版本;
  • MongoDB、Redis、NATS 和对象存储有明确维护责任;
  • MongoDB 与 Artifact 存储已经完成恢复演练;
  • 总部入口只提供 HTTPS,证书续期有监控;
  • 每台地区服务器身份唯一;
  • 地区服务器只需要出站 HTTPS;
  • Artifact 强制签名验证;
  • 私钥不在构建机工作目录、Git 或地区服务器;
  • Device Type、架构和 Compose 项目名有统一规范;
  • 镜像使用不可变版本并保留 digest;
  • 前端、后端和数据库 schema 使用同一个 releaseId;
  • 配置、数据库和用户数据位于持久化目录;
  • 数据库备份和恢复在真实测试库演练通过;
  • State Script 幂等并有超时;
  • 健康检查失败能触发 Compose 和数据库回退;
  • 保留至少 N-1 版本所需制品和数据恢复点;
  • 发布按试点、灰度、全量执行;
  • 有人工暂停、终止、回滚和现场恢复手册;
  • 日志中不包含密码、私钥、Token 和业务敏感数据。

总结

使用 Mender 实现中心发布、多地区服务器升级,最合理的职责划分是:

  1. 总部 Mender Server 管理设备、Release、Deployment 和状态;
  2. 总部 CI/CD 构建 Compose、打包镜像、生成并签名 Artifact;
  3. 地区 Mender Client 主动轮询、下载、验签和调用 Update Module;
  4. 官方 Compose Update Module 负责容器和 Compose 安装流程;
  5. 企业自己负责业务健康检查、数据库备份、迁移和恢复;
  6. 设备较多或出口受限的地区使用 Mender Gateway 做代理和缓存;
  7. 只有明确要求地区自治时,才部署多套 Mender Server 并开发同步平台。

Mender 不是把所有升级问题自动解决,而是提供一套可靠的通用分发和设备状态基础。把 Artifact 验签、灰度发布、业务健康和数据库恢复四部分同时做好,才能把“能够远程更新”提升为“可以在生产环境无人值守更新”。

参考资料