简介这是一套面向ARM64架构CPU的Tendis 2.7.0单机版离线部署工具适合在无外网或内网受限的服务器上通过docker-compose一键完成部署解决ARM环境下依赖包多、镜像获取困难、节点重复搭建成本高等问题。压缩包共19个文件包含sh运维脚本、conf配置模板、yaml编排文件、Dockerfile及可直接加载的镜像压缩包images与templates目录分别保存基础镜像和配置模板redis-cli、binlog_tool等配套工具也一并提供便于部署后的连接测试与日志处理。操作层面支持数据目录、端口、密码自定义并提供配置文件与数据目录持久化以及部署、启动、停止、卸载、检测等完整生命周期管理。包体约310.27MB结构清晰适合有一定Linux和Docker基础的后端或运维工程师使用。目前已有283人学习下载借助该工具可大幅缩短环境搭建时间离线镜像和脚本也便于在多个ARM64节点快速复用交付。1. ARM64 离线部署 tendis 单机版没有外网一条命令也能把服务拉起来在鲲鹏、飞腾这类 ARM64 服务器上装 tendis最尴尬的不是 tendis 本身而是环境。内网隔离、yum 源不通、docker pull 拉不到 arm64 的 centos 基础镜像想验证一个 Redis 兼容的持久化 KV 都费劲。这套资源就是把整个部署链路的产物打成一个离线包docker-compose 单机编排、arm64 架构的 centos 基础镜像、预先构建好的 tendis 镜像、模板化的配置文件外加一个 op.sh 统一管理部署、启动、停止、卸载、检测。适用对象很清晰在 arm64 信创环境里做 tendis 落地验证的运维和开发。标题写的版本号是 2.7.0实际解包后是 2.4.2 落地产物这个口径差异后文会专门展开先按包内的真实产物来走。2. 拆包看结构解包后的几类文件从模板到镜像各自管什么2.1 离线包的内层结构与职责划分拿到手的tendis-single-arm64-2.4.2.tar.gz是外层分发包解开之后内层还能看到多个独立产物。我拆了一遍主要有这么几类op.sh是操作入口images目录下是centos8.3.2011.tar.gz和tendis-arm64-2.4.2.tar.gz两个镜像归档templates目录里放着docker-compose-single-tpl.yaml、tendisplus-tpl.conf、single.conf.tpl三个模板根目录还有Dockerfile、build.sh、pkgs、nc。这套文件布局对应的是两段式构建思路先在能联网的 arm64 母机上用Dockerfile和build.sh把 tendis 镜像构建出来再连同基础镜像一起打成 tar 归档分发到内网机器上离线导入。pkgs与nc在这种包里通常是构建期依赖和连通性自检工具服务于镜像构建与部署前检查不是运行期的东西。明白这个分工之后部署路径就很清晰了不需要在目标机器上重新编译任何源码只做镜像导入与容器编排。2.2 docker-compose-single-tpl.yaml为什么配置和数据都要落到宿主机模板里最核心的编排文件是docker-compose-single-tpl.yaml渲染之后的效果类似这样version: 3.8 services: tendis-single: image: tendis-arm64:2.4.2 container_name: tendis-single restart: unless-stopped environment: - TENDIS_PORT9100 - TENDIS_PASSWORDyour-password ports: - 9100:9100 volumes: - /opt/tendis-data:/data - /opt/tendis-single/conf/tendisplus.conf:/etc/tendis/tendisplus.conf:ro command: [tendisplus, /etc/tendis/tendisplus.conf]这段 yaml 的逻辑很直白镜像固定为 arm64 构建产物容器名固定为tendis-single端口从宿主机映射到容器内部数据目录和配置文件全部落在宿主机路径上。restart: unless-stopped的作用是 docker daemon 重启或异常退出时自动拉起容器但注意它不会拉起被手动docker-compose stop停掉的容器这一点在批量重启机器的时候容易产生认知偏差。配置文件和数据的宿主机化是这套单机部署最值得借鉴的地方。tendis 的数据是写在 rocksdb 里的文件目录必须持久化配置文件放到宿主机并以只读方式挂进容器意味着改配置不需要重新构建镜像改完重启容器即可生效。容器可以随时删了重建数据和配置不丢这是单机部署里少有的“后悔药”。command直接指定了启动入口和配置文件路径绕开了镜像内默认入口参数可能带来的干扰。2.3 Dockerfile 与离线基础镜像为什么选 centos8.3.2011 而不是现场 pullDockerfile的FROM centos8.3.2011放在这里有两层考量。第一层是构建可复现性基础镜像固定版本tendis 二进制的 glibc 依赖环境就锁定在同样版本区间不会出现拉了个不同 minor 版本的 centos 导致动态库缺失的情况。第二层是离线分发centos8.3.2011.tar.gz是预先打好的 arm64 基础镜像归档内网环境里docker pull centos:8.3.2011大概率拉不动就算能拉docker 的 manifest 机制在部分镜像仓库上会回退到错误的平台架构拉下来一个 x86_64 的基础镜像再构建后面就是连环坑。尽量所有镜像都在 arm64 母机上导出再分发不要在目标机器上现拉现构。镜像归档里如果混入了 x86_64 的层docker load阶段不一定会报错容器启动阶段才暴露exec format error排查成本反而更高。离线环境里镜像的“架构纯度”是部署成功的第一前提后面避坑章节会再展开。3. op.sh 一键操作实测部署、启动、停止、卸载和检测各自做了什么3.1 部署链路解包、导入镜像、渲染模板、compose upop.sh的部署动作不是魔法而是把手工操作串成了固定顺序。常见的编排方式是先做环境检查再解包、导入镜像、渲染模板、拉起容器。一个典型的部署脚本骨架是下面这样#!/bin/bash set -euo pipefail # 1. 环境检查确认当前机器是 arm64 架构且 docker 可用 if [ $(uname -m) ! aarch64 ]; then echo 当前架构不是 aarch64请确认镜像与宿主机架构匹配 exit 1 fi docker info /dev/null 21 || { echo docker 未运行; exit 1; } # 2. 解包把内层资源释放到部署目录 tar -zxvf tendis-single-arm64-2.4.2.tar.gz -C /opt/tendis-single cd /opt/tendis-single # 3. 导入离线镜像归档 docker load -i images/centos8.3.2011.tar.gz docker load -i images/tendis-arm64-2.4.2.tar.gz docker tag tendis-arm64:2.4.2 tendis-single-arm64:latest # 4. 用环境变量渲染 compose 模板生成最终编排文件 export TENDIS_PORT9100 export TENDIS_PASSWORDyour-password export TENDIS_DATA_DIR/opt/tendis-data sed -e s/{{TENDIS_PORT}}/${TENDIS_PORT}/g \ -e s/{{TENDIS_PASSWORD}}/${TENDIS_PASSWORD}/g \ -e s|{{TENDIS_DATA_DIR}}|${TENDIS_DATA_DIR}|g \ templates/docker-compose-single-tpl.yaml docker-compose.yaml # 5. 拉起容器 docker-compose -f docker-compose.yaml up -d --force-recreate脚本里的set -euo pipefail是防御性的关键任何一步出错立即终止避免在镜像没导入成功的情况下继续往下跑。uname -m检查放在最前面是为了把架构不匹配的问题挡在第一时间。三个export变量分别控制端口、密码、数据目录对应资源描述里“支持数据目录、端口、密码”的能力。sed用不同的分隔符是为了兼容密码里可能出现斜杠的情况——第三处替换用了|代替/这是处理路径和密码类变量时的常见技巧。注意--force-recreate的使用前提它保证每次部署都基于最新渲染出的 compose 文件重建容器而不是复用旧容器。这在反复改配置调试的阶段非常有用。3.2 启动、停止与重启接口约定与 restart 策略的边界部署完成之后的操作接口是另一组命令。日常管理依赖 docker-compose 的子命令但op.sh这层封装的意义在于统一操作入口避免团队成员各敲各的。常见做法是op.sh start对应docker-compose startop.sh stop对应docker-compose stop用的都是同一个 compose 文件# 启动启动已创建的容器不重新创建 docker-compose -f docker-compose.yaml start # 停止优雅停止容器保留容器与数据目录 docker-compose -f docker-compose.yaml stopstart和up -d的差异值得说清楚。up -d会检查配置、创建并启动容器配置有变动时会重建start只启动已存在的容器不检查配置变更。换句话说改了宿主机上的tendisplus.conf之后不要只执行start那个动作不会让新配置生效得走一遍up -d或者restart。restart: unless-stopped的边界也要理解机器重启后 docker daemon 起来的时候会自动拉起这个容器但如果你在维护窗口期手动stop了它除非状态被清理掉否则不会自动重启。此外健康检测动作通常用一个独立子命令实现比如检查容器运行状态以及用 redis-cli 连一次端口确认服务可用docker-compose -f docker-compose.yaml ps redis-cli -h 127.0.0.1 -p 9100 -a your-password pingps看的是容器层状态ping看的是协议层状态两层都过才算真正健康。这里也呼应了资源描述里“支持检测”的功能点。3.3 卸载动作的清理边界容器、网络删干净数据目录留不留卸载往往是脚本里最需要谨慎设计的动作。docker-compose down -v会删除容器、默认网络和 compose 定义的 named volume但不会删除宿主机上的 bind mount 目录。也就是说/opt/tendis-data 下的 rocksdb 数据文件默认是保留的。我的建议是保留数据目录。理由很朴素单机环境里数据比容器金贵。卸载脚本设计成默认保留/opt/tendis-data只删除容器和运行目录这样重装之后数据还能接回来。如果你确实要彻底清场需要手动删数据目录但一定先确认里面没有要留的东西——最稳妥的做法是先打一个 tar 备份再删。这一条放在后面避坑章节里会作为典型问题展开。4. 改配置再上产线端口、密码、数据目录与持久化的注入方式4.1 tendisplus.conf 模板里值得改的参数不止是端口和密码tendisplus沿用了 Redis 协议配置文件也兼容 Redis 风格所以你把 redis.conf 的经验迁移过来基本成立。模板里需要重点关注的参数是这几类配置键作用建议port服务监听端口默认 9100与 compose 映射保持一致bind监听地址单机可留 0.0.0.0 或按网卡限定requirepass访问密码产线必须设置避免裸奔dirrocksdb 数据落盘目录指向容器内的持久化挂载点daemonize是否后台运行容器内必须为 no由 docker 负责托管logfile日志路径指向挂载目录便于宿主机查看这几个参数里最容易写错的是daemonize。把它在容器内设为yes会出大问题tendis 进程后台化之后容器的主进程瞬间退出docker 认为容器挂了直接进入重启循环。容器内任何服务进程的托管原则都是一样的——前台运行交给 docker 守护。dir这一项也要注意它指定的是容器内路径不是宿主机路径。挂载关系是宿主机/opt/tendis-data映射到容器/data那么dir应该写/data/tendisplus而不是直接写宿主机路径。理解这一点配置持久化的逻辑就通了改的是宿主机文件写入的是容器路径数据最终落回宿主机目录。4.2 配置注入方式用 sed 做变量替换而不是手改模板资源描述里提到“支持 tendis 配置文件持久化”落地姿势是用模板加变量替换。实际工程里我一般不会手改tendisplus-tpl.conf而是写一段渲染逻辑把可变参数集中在一个变量区域# 从模板渲染 tendisplus.conf端口、密码、数据目录全部参数化 sed -e s/^port .*/port 9100/ \ -e s/^requirepass .*/requirepass your-password/ \ -e s|^dir .*|dir /data/tendisplus| \ -e s/^daemonize .*/daemonize no/ \ templates/tendisplus-tpl.conf conf/tendisplus.conf这里的sed替换用了锚定符^确保匹配的是行首配置项而不是注释行里的同名文本。第三处用|做分隔符是因为路径里带斜杠如果继续用/会让替换表达式直接坏掉。每一处都锚定行首是这个渲染命令没有翻车的根基。渲染完成之后检查一下生成的配置文件确认没有残留的^或模板占位符再重启容器。我见过太多因为 sed 表达式没锚定把注释行里的示例配置也替换掉导致启动时读到一个不认识的参数而崩溃的情况。4.3 参数映射表compose、容器内配置与宿主机目录怎么对上为了让配置关系一目了然我把三层参数对应关系整理成一张表。这张表在排查问题时最有用看到容器里报错说dir目录不存在能立刻定位到是挂载段写错了而不是配置文件写错了。宿主机 compose 段容器内表现对应配置项说明ports: 9100:9100容器监听 9100port 9100两侧端口需一致environment: TENDIS_PORT供启动脚本取用间接映射到port渲染期变量volumes: /opt/tendis-data:/data容器内 /datadir /data/tendisplus数据持久化核心volumes: xx.conf:/etc/tendis/tendisplus.conf:ro配置只读挂载整文件生效改宿主机后重启无进程前台运行daemonize no容器托管前提排查问题时按这张表逐层核对先看宿主机端口通不通再进容器看监听端口再翻日志看配置项是否被正确读取。三层对应关系一旦有一条错位表现出的症状都是连不上或者起不来但根因完全不同。持久化这块还有个小习惯数据目录和配置目录最好分开两个宿主机路径管理这样备份时可以只打包数据目录配置变更时也只动配置目录互不干扰。单机部署虽然没有集群那么讲究但这个边界清楚之后后续不管是升级还是迁移都省事。5. 避坑与常见问题ARM64 离线部署最容易翻车的五个问题5.1 架构不匹配x86 机器上起 arm64 容器qemu 用户态模拟的黏糊表现现象把 arm64 镜像归档 load 进一台 x86_64 机器docker-compose up之后容器状态反复Restarting日志里出现exec format error或者进程docker-stats显示 CPU 占用奇高但服务就是不通。原因docker 在宿主架构与镜像架构不一致时会尝试用 qemu 做用户态模拟。模拟层能把指令翻译过去但性能折损极大部分系统调用在模拟层就是玄学级不稳定tendis 这种多线程 IO 密集型的进程很容易在这种环境里卡死或崩溃。离线包里虽然所有产物都是 arm64但你不能假设每台目标机器都是 arm64。解决部署前强制跑uname -m确认是aarch64再用docker inspect查看镜像的Architecture字段两边一致再执行up。x86 机器上验证 arm64 镜像这种需求要么用构建机做产物验证要么走真正的 arm64 虚拟机不要指望 docker 的 qemu 兜底能扛住产线负载。5.2 版本号对不上标题写 2.7.0包里是 2.4.2先核对再动手现象资源标题写着 tendis 2.7.0解包后镜像 tag 是tendis-arm64:2.4.2配置模板里 rocksdb 版本是v5.13.4向领导汇报版本时说不清楚到底部署的是哪个。原因平台对外发布的版本口径与包内构建产物的版本维护不一致。这类离线包常见的问题是标题版本是规划版本镜像 tag 才是实际构建版本两者存在时间差。解决部署前解包看一眼Dockerfile里的镜像 tag 和 LABEL再用容器内二进制输出确认真实版本。操作上是docker exec tendis-single sh -c tendisplus -v以这个输出为准登记资产。后续对外说明版本永远以二进制输出的真实版本为准不要沿用标题。5.3 容器退出码非 0先看日志而不是先重启现象docker-compose up -d之后容器秒退restart策略把它拉起来再退循环反复看起来像是一只“起不来的黑匣子”。原因绝大多数是配置问题集中在三类配置文件语法错误、端口被宿主机占用、数据目录无权限。tendisplus.conf里一个参数名拼错启动阶段解析失败直接退出。解决第一动作永远是docker logs tendis-single不是docker-compose restart。日志里会明确给出解析失败的配置行号或者 bind 地址冲突信息。改完配置重启之前先在宿主机上用ss -lntp | grep 9100确认端口没被占再检查数据目录属主是否与容器内运行用户匹配权限不对就 chown 调整而不是简单粗暴加 777。5.4 卸载后数据残留重装加载旧数据的黑匣子现象卸载之后重新部署起来的数据还是上一个环境的旧数据密码甚至都能用旧的登录进去新配置完全不生效反过来的另一个极端是脚本把数据目录一起删了想找回旧数据只能翻备份。原因docker-compose down -v只删除 named volumebind mount 的宿主机目录由脚本逻辑决定。卸载脚本如果默认删除数据目录就没有“后悔药”如果默认保留重装时又容易在不知情的情况下接回旧数据。解决卸载前把/opt/tendis-data先 tar 一份再决定删不删。重装前有意判断一次数据目录是否为空非空的话确认是否要清空。习惯养成很简单——卸载动作永远备份先行数据目录清不清让它成为一个显式选择而不是脚本里的隐式默认。5.5 时区没处理日志时间对不上的排查成本现象tendis 日志里的事件时间比宿主机时间慢 8 小时告警时间线对不上出问题的时候按容器日志排查感觉时间轴是歪的。原因基础镜像 centos 默认 UTC 时区容器内/etc/localtime指向 UTC。宿主机是东八区两边日志一对比就出现了固定偏差。解决compose 的 environment 里加上TZAsia/Shanghai同时把宿主机/etc/localtime以只读方式挂载进容器。改完重启容器再次确认日志时间与宿主机一致。这种问题不大但排查告警的时候能省下大把“时间对不上”的纠结。顺手把这个配置写进模板后续所有实例都带上别留给每个新环境单独补救。6. 三条命令验证部署结果从 ELF 架构到 info 全链路确认6.1 三层验证file 查 ELF、inspect 查镜像、redis-cli 查 info部署完成后的验证不要只做端口连通测试端口通只能说明容器在跑不能说明跑的是正确的 arm64 原生程序。建议按三层验证走最外层用 redis-cli 验证协议层中间层用 docker inspect 验证镜像架构最底层进容器用 file 验证可执行文件的 ELF 架构。三层都过这个部署才算真正落地。# 1) 协议层确认服务可响应 redis-cli -h 127.0.0.1 -p 9100 -a your-password info server | head -n 8 # 2) 镜像层确认镜像架构是 arm64 docker inspect tendis-single | grep -i architecture # 3) 进程层直接看容器内可执行文件的 ELF 架构 docker exec tendis-single sh -c file $(command -v tendisplus)第三层用file而不是uname -m是有讲究的uname查的是容器内内核的架构在 qemu 模拟环境里它可能显示 aarch64但实际跑的是翻译层查不出模拟的痕迹。file直接读二进制文件的 ELF 头看到ARM aarch64才是真正的原生可执行文件。这一条是从 x86 机器上 load arm64 镜像翻车那次之后养成的习惯。info server输出里的tendis_version字段同时可以用于核对真实版本和 5.2 里说的版本口径问题形成闭环。验证命令走完再执行一遍op.sh的检测动作确认整体状态部署工作才算收口。6.2 把验证写进日常交付习惯从那以后我每次交付 arm64 离线部署都强制走一遍这个三连file查 ELF、docker inspect查镜像架构、redis-cli info查版本和响应。步骤不复杂但能在一分钟内把“架构错误”“版本错误”“服务不可用”三类最常见问题全部排除。推荐的顺序是先 inspect 再 file 最后 info架构不对就先别浪费时间连服务。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?