
简介面向ARM64架构CPU环境下离线部署Tendis 2.7.0单机版的运维与开发人员这份工具包以docker-compose一键脚本方式完成部署、启动、停止、卸载与健康检测特别适合内网隔离或无法访问外网镜像的生产环境。包内共19个文件类型涵盖sh运维脚本、conf与tpl配置模板、yaml编排文件、dockerfile构建文件、离线镜像压缩包以及redis-cli等客户端和检测工具整体体积约310.27MB目录按scripts、conf、images、pkgs等模块组织便于按需替换和问题排查。当前已有283人学习浏览可作为ARM64平台部署Tendis单机版的高参考性方案。该工具支持自定义数据目录、端口和访问密码主配置和数据目录均持久化容器重启后配置不丢失同时附带构建镜像所需的基础环境与Tendis二进制包离线状态下也能完整还原部署链路对信创适配或私有化交付场景尤为实用。即便缺少公网仓库也能快速交付一个可用实例。1. ARM64 离线部署 tendis 2.7.0 单机版为什么这条链路值得抄很多团队一听到“tendis 离线部署”第一反应是去编译 RocksDB、到处找依赖源。实际把 2.7.0 单机版容器化以后交付物料就一个镜像 tar 包加一个 compose 文件。这条链路里真正返工的坑都在镜像平台没对齐x86 打包机上导出的镜像搬到 ARM64一启动就报exec format error。下面按“镜像物料准备 → compose 参数 → 排错 → 真机验证”往下讲适合手里有国产 ARM64 服务器、需要内网交付缓存/存储服务的同学。先花两分钟把原理聊透再动手能少走一半弯路。2. tendis 单机版在 ARM64 上的选型逻辑协议兼容、RocksDB 与容器化边界2.1 单机版不是玩具存量 Redis 业务迁移的最短路径tendis 是腾讯开源的高性能 KV 存储走 Redis 协议但底层数据落在 RocksDB不像纯内存 Redis 那样受内存上限约束。业务侧用 redis-cli 能直接连现有代码几乎不用改只是数据全量刷在磁盘上适合对数据可靠性要求更高、又不想动应用层的场景。单机版就是这个架构里最简单的一种形态没有分片协商、没有跨节点选举、没有多角色协调部署复杂度直接低一个数量级。在 ARM64 离线场景里我优先选单机版理由很直接。集群版一次要拉起多个角色每个角色都要调线程、调内存水位离线环境里监控和日志都不全出了故障很难定位是哪个节点先崩。单机版一个容器就是一个服务配置集中在 compose 文件里数据目录独立挂出来宿主机重启后只要 compose 文件和数据目录都在一条docker-compose up -d就能原样恢复。这里说一句大家关心的事单机版能不能当生产。我的态度是能用 Redis 的业务模型tendis 单机版就能用。缓存穿透和一致性由业务层处理tendis 管好存储底层那些追求极高并发写入的堡垒型业务才需要把集群版提上日程。2.2 为什么离线场景绑定 docker-compose镜像分发与可重演性离线部署最大的问题是依赖不会自己出现。源码编译 tendis 要 g、zlib、snappy、lz4、gflags 这些库ARM64 源里缺一两个就会卡一整天。用镜像把运行环境和依赖全部锁进黑匣子到目标机docker load完剩下的动作就只是 compose 一键拉起。这就是容器化对离线部署最实在的价值不是追“云原生潮流”是省事。选 docker-compose 而不是单条docker run一是因为 compose 文件把端口、数据卷、内存限制、健康检查都写成一个声明文件整份 yml 就是交付物二是重演性好只要镜像 tar 和 compose 文件一致两台机器起出来的容器行为就一致。离线环境未必有私有镜像仓库但绝大多数有 docker engine把 docker-compose 插件一并拷进物料包就能闭合成完整链路。在准备物料时要先把 docker engine 和 docker-compose 的版本关系搞清楚。compose v2 是官方插件新装机器上docker compose子命令可用老机器通常只认docker-compose这个独立二进制。离线装的时候不看版本就会翻车脚本里写的是docker compose up -d机器报docker: compose is not a docker command实际上是插件根本没装上。我一般会在物料包里同时准备两种方式目标机上先确认docker compose version能打印出来不行就退回docker-compose --version。这套方案换到别的宿主环境也成立。比如 Windows Server 2022 上用 WSL containers 做离线交付镜像准备、导入、编排的节奏完全相同只是运行时名字不同。正因为 compose 层屏蔽了容器运行时的差异离线部署这套流程才值得沉淀成固定脚本。2.3 ARM64 兼容边界官方镜像有没有 arm64 标签先查 manifest 再动手ARM64 不算新平台但镜像平台机制真的容易给人挖坑。docker 镜像在拉取时会按 manifest list 挑平台网络好的时候什么都不用管离线物料准备阶段往往会忘掉--platform在一台 x86 机器上打出 tar搬到 ARM64 上启动直接报Exec format error。我在任何一台打包机动手前都会先看一眼 manifestdocker manifest inspect 你的内网镜像地址:2.7.0重点看输出里的platform段arch 是不是arm64。如果仓库里根本没有 arm64 条目--platform参数也救不了你你拿到的永远是 x86 那份。这种情况常见做法是找一台联网的 ARM64 构建机把 Dockerfile 重打一遍或者用 buildx 在 x86 上交叉构建。docker pull --platform linux/arm64 你的内网镜像地址:2.7.0 docker image inspect 你的内网镜像地址:2.7.0 --format {{.Architecture}}--platform只在客户端做选择远程仓库给你的是不是 arm64看Architecture字段才算数。有些镜像 tag 写得是 arm64Architecture 仍然返回 amd64这种“标签和实质不一致”的镜像就是源头上种下的雷。我习惯在 CI 里用 QEMU 模拟 arm64 做一次冒烟确认入口命令能跑起来。但我不会拿模拟器的结果当作 ARM64 原生结论。QEMU 模拟只能覆盖指令集行为覆盖不了 RocksDB 对文件系统、io_uring 这类特性的真实表现最终验证一定要放到真机上。2.4 RocksDB 在单机版里的存在感写放大、compaction 与磁盘预算很多人把 tendis 当“Redis 换壳”看忽略它底层是 LSM 树结构的 RocksDB。写路径先写 WAL 和 memtable大批量写入时后台做 compaction 合并层文件这个动作是持续的、占 CPU 和磁盘的。离线环境里业务刚接入时可能一切正常跑几天之后磁盘空间掉得比预想快写延迟偶尔抖一下多半就是 compaction 在干活。选单机版不代表不用关心存储底层。数据目录是 RocksDB 真正落盘的地方我会在部署前确认两件事宿主机上挂载给/data的文件系统是 ext4/xfs 这类常规日志文件系统别拿 tmpfs 当数据卷磁盘剩余空间至少是预估数据量的 3 倍给 compaction 和临时文件留余地。这个预算参数在后续运维里最常改离线交付时如果连磁盘预算都没谈后面扩容空间都没着落。至此选型逻辑已经清楚单机版负责把部署复杂度压下来docker 负责把依赖关进运行盒RocksDB 相关的行为预判决定你要给数据卷多大空间。接下来进入物料准备环节。3. 离线物料准备在能联网的机器上制作 ARM64 镜像包离线交付的第一步是在能联网的机器上备齐三样东西镜像 tar、docker-compose.yml、配置目录。镜像 tar 管运行时compose 文件管启动方式配置文件管服务的端口、日志级别和数据落盘位置。三者缺一样都会在目标机上多耗一整天。3.1 在联网机器上拉取适配 ARM64 的镜像pull --platform 与 manifest 双保险先在打包机上把镜像拉到本地。我所说的“打包机”可以是一台开发机或构建机关键它要么和目标机同架构要么能用 manifest 明确过滤 arm64。拉取命令docker pull --platform linux/arm64 你的内网镜像地址:tendis-2.7.0 docker image inspect 你的内网镜像地址:tendis-2.7.0 --format {{.Architecture}}第一行显式指定目标平台第二行是复盘动作。docker pull的--platform参数会从 manifest list 里选择匹配平台子镜像如果目标仓库是单架构镜像这一行可能拉下来 x86 或直接失败。docker image inspect的Architecture字段才是全部镜像层的真实架构不是 tag 文本能骗过的。为什么我要求“manifest 双保险”因为很多内网镜像仓库是从外网地址搬运回来的搬运时只搬了 x86 层arm64 层丢了但 tag 没变。你在客户端加--platform没有报错是因为 daemon 直接返回了唯一的单架构镜像。所以看 architecture 比看 tag 诚实得多。检查字段确认是arm64之后再生成镜像包。万一仓库里确实没有 arm64有两种补法找一台 ARM64 机器重新构建或者用 buildx 在 x86 上交叉构建。交叉构建需要 Dockerfile 里的基础镜像也支持 multi-arch不建议离线场景一上来就碰先把“有原装 arm64 镜像”的路径走通。3.2 导出镜像 tarsave 不带平台信息但 SHA256 能帮你防拷包损坏镜像拉对了接下来把它重新打包成本地文件docker save -o tendis-arm64-2.7.0.tar 你的内网镜像地址:tendis-2.7.0 sha256sum tendis-arm64-2.7.0.tar tendis-arm64-2.7.0.tar.sha256docker save把镜像的 manifest、layer 和 config 整体打成 tar这个 tar 不附带肉眼可读的平台标签架构信息藏在每一层的 config JSON 里。所以拷包时如果只靠文件名区分 arm64/x86非常容易错最好把文件重命名成tendis-arm64-2.7.0.tar这种可识别名字。镜像 tar 的体积取决于基础镜像和层数大压缩包在拷贝过程中更容易出问题。U 盘、网盘、scp 都可能静默丢数据tar 包损坏到docker load时才会爆报错又长得很像平台的错很容易误导排查方向。所以我在打包之后必须生成 sha256 校验文件并把校验动作写进交付说明。目标机上校验sha256sum -c tendis-arm64-2.7.0.tar.sha256返回OK再继续任何WARNING都说明包有问题重新拷不要赌。这一步很便宜但每次都能在 load 失败之前把问题挡下来。很多人 skip 它结果在半路花费的时间比重新准备一次还多。3.3 离线导入与预检load 成功不代表能用先看三个地方目标机上第一个动作是把镜像 load 进去docker load -i tendis-arm64-2.7.0.tar docker images --format {{.Repository}}:{{.Tag}} {{.ID}}load成功只代表数据包完整不代表容器能跑在 ARM64 上。这里有两个隐含前提镜像 config 里的架构与当前 CPU 一致以及 daemon 能按镜像入口找到可执行文件。所以我在docker compose up之前一定会做三项预检。第一项docker images输出的镜像 ID 和 tar 的 sha256 对得上。第二项确认 docker-compose 可用新机器上跑docker compose version老机器上跑docker-compose --version哪个能出现就用哪个脚本里不要写死。第三项用一个临时容器验证平台docker run --rm --platform linux/arm64 你的内网镜像ID uname -m输出aarch64就说明内核能认这个 ARM64 二进制。输出了别的架构十有八九是 load 的 tar 本身就是 x86。这一步做完才轮到 compose 上场。3.4 物料目录建议一个交付包里该有什么离线交付不是丢一个 tar 给现场。我会把整个物料包按固定结构整理复制到目标机后能直接操作tendis-offline/ ├── images/ │ ├── tendis-arm64-2.7.0.tar │ └── tendis-arm64-2.7.0.tar.sha256 ├── docker-compose.yml ├── conf/ │ └── tendis.conf └── README.mdimages/放镜像和校验文件docker-compose.yml就是目标机上执行的文件conf/里放需要按机器调整的配置README.md写清楚执行顺序和关键命令。目录结构能逼着你在交付前把所有变量想清楚。配置文件里如果只有默认值现场还要自己试离线环境里没人能上网查文档。4. 编写 docker-compose.yml单机版需要的 6 个参数镜像包只是运行时真正决定“一键”体验的是 compose 文件里的参数。tendis 单机版不依赖集群通信所以不需要复杂的 service 编排但端口、数据卷、内存、健康检查这几个参数缺一个都会在之后找补。4.1 compose 文件骨架镜像、端口、数据卷、启动命令一份能直接跑起来的单机版 compose 文件大概长这样version: 3.8 services: tendis: image: 你的内网镜像地址:tendis-2.7.0 container_name: tendis-single platform: linux/arm64 ports: - 6379:6379 volumes: - ./data:/data - ./conf/tendis.conf:/etc/tendis/tendis.conf:ro command: [tendis-server, -f, /etc/tendis/tendis.conf] mem_limit: 4g cpus: 2 restart: unless-stopped healthcheck: test: [CMD, redis-cli, -p, 6379, ping] interval: 10s timeout: 3s retries: 5 start_period: 20splatform: linux/arm64是 compose 层面的平台约束防止编排器在 multi-arch 镜像上挑错。ports把容器内 6379 映射到宿主机 6379如果现场已有 Redis 占着端口把左边宿主机端口改成 16379 就行容器内不用动。volumes里有两条/data是 RocksDB 数据落盘目录tendis.conf以只读方式挂进容器以后改配置不用重新打镜像。command里写的是容器内路径不是宿主机路径。这个细节我在排错环节还会重点提第一次写跑起来报 no such file or directory 的基本都是把路径写到了宿主机视角。restart: unless-stopped是为了让宿主机重启后 docker daemon 自动拉起 tendis这是单机版在无人值守环境里的自恢复能力。参数概览可以提炼成一张表方便复制到自己的交付文档里配置项作用单机版建议image platform锁定 ARM64 镜像显式写 linux/arm64不靠标签猜ports业务访问入口6379:6379冲突时改左端口volumes数据与配置持久化/data 挂宿主目录conf 只读挂载command启动参数与配置路径指向容器内可用的配置文件路径mem_limit / cpus资源水位4g / 2按数据量上调healthcheck服务就绪判断redis-cli ping start_period这 6 组参数是单机版 compose 文件的骨架。下面重点说最容易出问题的两类资源和健康检查。4.2 内存与 CPU 限制别让 RocksDB 把容器撑爆tendis 数据虽然落盘运行期内存消耗照样不小。block cache、write buffer、compaction 线程都吃内存不设mem_limit时容器可以吃满整台机器。离线 ARM64 机器通常还跑着别的服务一个 tendis 把宿主机 OOM 拖挂是我见过多次的现场。给单机版起步经验值是mem_limit: 4g、cpus: 2。如果业务读多写少block cache 占主导可以把内存给到 8gCPU 维持 2 不变如果写入量大、compaction 频繁CPU 反而更值钱把 cpus 升到 4内存不动。cpus是 CPU 份额上限不是独享核数写2表示最多用两个核的算力。RocksDB 相关的线程数、写缓冲区大小通常在 tendis.conf 里控制不同小版本字段有差异。我一般先docker exec 容器名 cat /etc/tendis/tendis.conf | grep -iE thread|buffer看当前版本有哪些字段再到宿主机conf/tendis.conf修改后 restart。离线交付别把一个版本的默认配置当成标准答案镜像版本和配置文件必须配套否则 RocksDB 行为会和你预想完全不同。4.3 healthcheck 与 depends_oncompose 不会替你等 tendisdepends_on只能保证容器的启动顺序不能保证服务 ready。tendis 启动时要加载 RocksDB 目录、恢复 WAL慢机器上可能到 10 秒以上下游服务立刻去连必然 Connection refused。给 tendis 配一个healthcheck再用condition: service_healthy把依赖关系绑牢depends_on: tendis: condition: service_healthyhealthcheck 命令本身很简单healthcheck: test: [CMD, redis-cli, -p, 6379, ping] interval: 10s timeout: 3s retries: 5 start_period: 20sstart_period是启动宽限时间容器刚开始运行的那段时间不会立刻判失败给 RocksDB 恢复留下余量。retries: 5配合 10 秒间隔连续五次失败才标记 unhealthy。这样编排器只在 tendis 真正返回 PONG 后才启动下游业务侧一接入就是可用的而不是先报一堆连接错误再人工等待。配完 healthcheck 之后再谈一键部署才成立。否则一键 up 是起来了应用层却在疯狂重试等于把等待逻辑丢给了业务。5. 单机版离线部署常见问题排查从镜像起不来到数据丢失5.1 现象一容器启动报 Exec format error 或 bad linux arm64 image magic现象目标 ARM64 机器上docker-compose up -d之后容器秒退docker logs只看见exec /usr/local/bin/tendis-server: exec format error。极少数老内核或压缩的启动环境下还会出现类似bad linux arm64 image magic!的底层报错。在引导介质场景里也有“内核段既不是 arm64 image”的说法本质上都是同一个问题程序头的魔数和当前架构不匹配。原因镜像实际上是 x86 架构或者镜像 config 里 Architecture 字段被误标成 amd64。exec format error出现在 load 之后、执行入口那一刻很容易被误判成依赖缺失或权限问题实际上跟依赖一点关系都没有。解决回到联网打包机执行docker image inspect 镜像ID --format {{.Architecture}}确认这个字段是arm64。不是 arm64 就重新docker pull --platform linux/arm64再 save、再拷贝、再 load。在目标机上也可以用docker run --rm --platform linux/arm64 镜像ID uname -m验证能输出 aarch64 才往下走。不要试图在目标机上用 QEMU 模拟或改启动参数糊弄过去模拟器跑通不代表原生能用绕过平台错误后面还会有更乱的错。5.2 现象二镜像 load 成功compose up 报 no such file or directory现象docker load 显示 Loaded image 正常docker-compose up -d显示容器创建成功但容器状态 Exited日志是could not open configuration file /root/tendis/conf/tendis.conf: no such file or directory。原因command 里的路径是容器内路径但很多新手直接写了宿主机路径。另一个常见原因是宿主机上的./conf目录是空的或者配置文件权限不足容器内用户读不了。还有可能是镜像的入口脚本会先切到一个固定工作目录而你挂载的数据卷恰好把那个目录占了。解决先docker run --rm 镜像ID ls /etc/tendis/把镜像里的真实路径列出来再回头改 compose 的 command 和 volumes。配置文件挂载前先确认宿主机 conf 目录里确实有文件docker compose exec tendis cat /etc/tendis/tendis.conf能打印内容说明挂载关系没问题。这一步把容器内路径和宿主机路径的差异理清楚后面就顺畅了。5.3 现象三容器删了重建数据全丢现象用docker-compose down停服务再up -d后 Redis 协议还能连但 get 返回空数据像回到昨天一样。原因数据目录根本没挂出来tendis 在容器可写层里写 RocksDB。容器删除时可写层一起被销毁数据就跟容器一起没了。还有一种更隐蔽的volumes 挂到了宿主机/tmp这类会被系统清理的目录表面看挂载了实际目录随时可能被清。解决compose 里的 volumes 必须指向宿主机的长命目录比如/data/tendis:/data。部署前执行ls -ld确认宿主机目录存在且权限对容器用户可写必要时先拷一份配置文件进去再启动。操作上要特别小心docker-compose down -v-v会删除匿名卷和命名卷对运行了半年的单机版执行这个命令等于给数据判死刑。注意对已经写入数据的数据卷永远不要在清理命令里加-v。docker-compose down -v在部分 compose 版本里会连同匿名卷一起删除生产数据没有回收站。我一般把交付文档里的停止命令明确写成docker-compose stop不写 down。stop 只停容器down 会清网络和卷声明这个习惯能避免不少误操作。5.4 现象四离线机器没有 docker-compose脚本第一个命令就报错现象交付脚本里写的是docker compose up -d目标机报docker: compose is not a docker command。另一台机器可能是docker-compose: command not found两个错还不一样。原因离线机器的 docker engine 是装系统时带的compose v2 插件没随 engine 一起装。老机器只有 docker-compose 独立二进制新机器则是docker compose子命令。交付前没有把 docker engine 和 docker-compose 的版本关系确认清楚脚本里写死一个命令就会翻车。解决物料包准备阶段就把 compose 插件一起放进去。新版本机器把插件放到 docker CLI 插件目录mkdir -p /usr/local/lib/docker/cli-plugins cp docker-compose-linux-aarch64 /usr/local/lib/docker/cli-plugins/docker-compose chmod x /usr/local/lib/docker/cli-plugins/docker-compose docker compose version老版本机器则把独立二进制放到/usr/local/bin/docker-compose并加可执行权限。这里说的文件名是常见打包命名你从内网软件源拿到的具体名字可能不同但落盘目录和权限要求是一样的。自动化脚本里最好写一段检测逻辑优先docker compose version失败就退到docker-compose --version两个都失败就停止并提示补装插件。5.5 现象五写入延迟升高、宿主机 Load 飙升现象部署前期一切正常运行几周后偶发写延迟从 1ms 跳到 200ms 以上系统 load 平均负载飙到核数的两倍。业务投诉缓存写入变慢。原因RocksDB compaction 在后台做大合并磁盘 IO 和 CPU 同时打满或者内存水位给得太高write buffer 堆积后一次 flush 把 IO 打穿。离线环境没有集群分摊单机版会独自承受这种尖峰。解决先用docker stats看容器 CPU 和内存是不是贴着限制跑再进容器日志找 compaction 相关记录。调优方向上把mem_limit和cpus往合理区间收条件允许时给数据目录独立挂盘。要预期内接受写放大不要在部署文档里写“无限容量”这种话。单机版要长期稳一次性把数据和资源预算谈清楚比事后调参更省心。6. 真机验证与日常维护从 redis-cli ping 到把后悔药留好6.1 三步验证启动日志、端口探测、真实读写我部署完不开香槟也不马上交接先跑三件事docker compose logs -f tendis redis-cli -p 6379 ping redis-cli -p 6379 set deploy:check ok redis-cli -p 6379 get deploy:check第一步看日志里有没有 ready 之类的服务就绪字样第二步确认 Redis 协议层通第三步写一个键再读出来验证数据真正落盘而非只进缓存。三步都过了才把服务地址交给业务做联调。6.2 数据备份与回滚配置变更前把后悔药留好tendis 单机版的数据就是 RocksDB 目录没有 Redis 那种单独导出快照文件的接口用得顺手。常见做法是停机后直接cp -a /data/tendis /data/tendis.bak-日期或者依赖宿主机磁盘快照。备份文件要放跟主库不同的盘甚至不同的机器否则磁盘坏了备份一起完蛋。改配置前我习惯先复制一份原配置加上日期后缀再 restart。启动成功后观察写入和延迟确认没问题再清掉备份。别把配置变更放在周五晚上做一旦 RocksDB 因为参数不兼容起不来现场没有上网查文档的窗口周末就搭进去了。6.3 别让 QEMU 模拟验证替代真机压测前面提到 QEMU 模拟 arm64 只能做冒烟真正验收一定在目标 ARM64 机器上跑一次十分钟左右的读写混合压测。主要看三组数字redis-cli INFO 里 ops 吞吐、写入延迟 P99、以及docker stats的 CPU 波动。压测期间可以把日志级别打开但别长期跑 debugdebug 日志会让 RocksDB 行为偏离真实负载这也是我在 QEMU 验证里吃过亏的地方。这套部署方案经历几次之后我自己的固定习惯是任何离线交付都先啃镜像平台确认任何 compose 改动都先留备份任何压测都只认真机结论。一次到位还是返工多次差别就在这些习惯里。希望这些细节能在你的下一次离线交付里帮到你。本文还有配套的精品资源点击获取