简介:面向ARM64架构服务器运维与开发人员,该工具提供基于docker-compose的Tendis 2.7.0单机版一键离线部署方案,解决内网环境缺少镜像、手工配置繁琐的痛点,适合需要快速搭建兼容Redis协议的缓存存储服务的场景。压缩包共19个文件,大小约310MB,主要包含Dockerfile、docker-compose yaml模板、tendis配置模板、启停与检测shell脚本、离线镜像包以及redis-cli等辅助工具,覆盖从环境准备到部署、启动、停止、卸载的完整操作链。目前已有283人学习下载,可见关注度较高。借助该方案,用户可自定义数据目录、端口和密码,并实现配置文件与数据目录持久化,避免容器重建导致数据丢失;同时离线设计使无外网机房也能顺利安装部署。对需要标准化交付Tendis单机服务或简化运维流程的ARM64平台用户,这是一份可直接落地的参考资源。
1. ARM64离线部署tendis:这份docker-compose一键包解决了什么
拿到一台ARM64服务器,没有外网,apt源全部指向内网,却要在上面跑tendis当Redis用——这套基于ARM64架构、借助docker-compose编排的tendis单机版离线部署工具,就是把整件事从半天工作量压到几分钟的东西。它把一个centos8.3.2011的基础镜像、tendis 2.4.2的ARM64二进制、配置模板、镜像构建脚本和op.sh操作脚本全部装进一个tar.gz包,解包后依次执行几条命令就能完成部署、启动、停止、卸载和检测。适合两类人:一类是在内网环境里被依赖问题卡住的运维,另一类是手里有一批ARM64板子、想快速验证tendis替代Redis场景的研发。下文我按拆包、镜像、配置、排坑、验证五个环节过一遍。
2. 拆解离线包:从tar.gz文件清单到docker-compose调用链
2.1 解包后的真实结构
拿到tendis-single-arm64-2.4.2.tar.gz,先别急着docker load,我习惯先解包看结构,确认目录层级再动手,避免后面挂载路径写错到处找文件:
mkdir -p ~/tendis-offline && tar -xzf tendis-single-arm64-2.4.2.tar.gz -C ~/tendis-offline cd ~/tendis-offline && find . -maxdepth 2 -type f | sort解包后你大概率会看到这样一批文件:op.sh、build.sh、Dockerfile、centos8.3.2011.tar.gz、tendisplus.conf、tendis-arm64-2.4.2.tar.gz,外加templates目录和pkgs、conf等子目录。
这里有个容易看懵的点:容器镜像的tar包和资原总包都是tar.gz,区分方式是看文件名带不带arch和版本号。centos8.3.2011.tar.gz是基础系统镜像,tendis-arm64-2.4.2.tar.gz是打好的tendis应用镜像,后者通常放在images目录下。总包里同时出现Dockerfile和build.sh,说明这个工具支持两种用法:直接用现成镜像,或者自己重新构建镜像。我一般先看images目录有没有成品,有就跳过build。
模板目录templates是整套配置的源头,里面放着docker-compose-single-tpl.yaml、tendisplus-tpl.conf、single.conf.tpl三个模板文件。这三个文件是部署时真正被渲染的对象,端口、密码、数据目录都在这一层替换,后续第4章细讲。conf和nc这类辅助文件,用于检测端口和下发配置,属工具集自带的小件。
2.2 每个文件分管的活
| 文件/目录 | 作用 | 使用时机 |
|---|---|---|
| op.sh | 一键操作总入口,封装deploy/start/stop/uninstall/check | 部署全流程 |
| build.sh | 基于Dockerfile构建tendis镜像 | 无现成镜像时 |
| Dockerfile | 镜像构建定义,固定基础镜像和二进制路径 | 配合build.sh |
| centos8.3.2011.tar.gz | ARM64基础系统镜像,离线导入用 | deploy时被docker load |
| tendis-arm64-2.4.2.tar.gz | 打好的tendis应用镜像 | deploy时被docker load |
| tendisplus.conf | tendis服务端配置模板 | 容器内生效 |
| templates/docker-compose-single-tpl.yaml | compose编排模板,定义端口、挂载、环境变量 | deploy时渲染 |
| templates/tendisplus-tpl.conf | tendis配置的变量版 | deploy时sed替换 |
| templates/single.conf.tpl | 精简配置模板,检查时用 | check时对比 |
| pkgs/ | 辅助软件包,如nc等 | check端口时 |
这个表对应的是最常见的解包结果。不同批次打包可能在文件层级上有出入,但不影响部署逻辑:总包负责运输,op.sh负责编排,templates负责渲染,两个tar.gz镜像负责提供运行环境。
2.3 docker-compose模板怎么变成最终yaml
部署时op.sh做的事情可以概括为三步:先把两个tar.gz镜像load进docker,再读取templates/docker-compose-single-tpl.yaml生成最终compose文件,最后执行docker-compose up。模板渲染这步,常见做法是直接用sed做变量替换,不需要额外装工具:
sed -e "s|TENDIS_PORT|6379|g" \ -e "s|TENDIS_PASSWORD|yourpass123|g" \ -e "s|DATA_DIR|/data/tendis|g" \ templates/docker-compose-single-tpl.yaml > docker-compose.yaml模板里的占位符被替换成实际值,这一步决定最终落地的端口、密码和数据目录。用|做分隔符是为了避免密码里出现/导致sed转义地狱,这是我在离线脚本里习惯性保留的写法。替换完建议先cat docker-compose.yaml人工过一遍,确认占位符没有残留再up。
3. 镜像与基础层:centos8.3.2011.tar.gz和Dockerfile怎么拼
3.1 为什么要自带基础镜像
ARM64离线部署最大的坑不在tendis本身,而在基础镜像。公网docker hub在部署环境通常不可达,即便能拉,也经常拉到手一个x86_64的镜像,在ARM64机器上直接exec format error。这个包把centos8.3.2011的ARM64镜像单独打成tar.gz,就是为了绕开这个链路。
选centos8.3.2011而不是alpine,我的理解是tendis的二进制依赖glibc,CentOS系镜像里glibc版本和动态链接器路径最稳。tendis的RocksDB模块对不同系统的依赖很敏感,alpine的musl libc大概率会出现运行时崩溃,所以这种生产向的包基本不会用最小镜像赌运气。
还有个细节:这个基础镜像同时是构建镜像和运行镜像。build.sh里FROM的就是它,构建时编译器用的头文件库和运行时依赖完全一致,不会出现"构建在一个系统、跑在另一个系统"的兼容性问题。对离线环境来说,少一个外部依赖就少一个故障点。
3.2 Dockerfile与build.sh的配合
Dockerfile的写法决定了镜像能不能跨机器复用。常见做法分四段:FROM基础镜像、COPY二进制和配置、暴露端口、指定前台启动参数:
FROM centos:8.3.2011 MAINTAINER offline-deploy COPY tendisplus /usr/local/bin/tendisplus COPY tendisplus.conf /etc/tendis/tendisplus.conf RUN mkdir -p /data/tendis && \ chmod +x /usr/local/bin/tendisplus EXPOSE 6379 ENTRYPOINT ["/usr/local/bin/tendisplus", "/etc/tendis/tendisplus.conf"]注意Dockerfile里COPY的是编译好的tendis二进制,不是源码。这里有个很容易翻车的点:tendisplus进程需要依赖RocksDB的动态库,如果源码包里有配套的librocksdb.so,也要一并COPY到/usr/local/lib并执行ldconfig,否则容器起来秒退,日志里全是error while loading shared libraries。
build.sh只是把这层逻辑封装成一条命令:
#!/bin/bash docker build -t tendis-arm64:2.4.2 . docker save tendis-arm64:2.4.2 | gzip > tendis-arm64-2.4.2.tar.gz构建完成后打成tar.gz,方便拷贝到无网机器。注意build.sh里tag一定要带具体版本号,不要用latest,离线环境里镜像一旦多了,latest指代不明非常难排查。
3.3 离线load镜像的时机与tag规则
拿到分发的tar.gz镜像后,部署环境只需要做一件事:
docker load -i centos8.3.2011.tar.gz docker load -i tendis-arm64-2.4.2.tar.gzload完成后用docker images确认镜像名和tag。不同的打包方式镜像名可能不一样,常见的是centos:8.3.2011和tendis-arm64:2.4.2。如果docker-compose模板里写的镜像名和load进本地的名字不一致,Compose会尝试远程拉取,离线环境直接失败。这个对不上往往是一开始没检查docker images造成的。
我一般会在load后加一个强制tag的习惯:
docker tag tendis-arm64:2.4.2 tendis-arm64:2.4.2这条命令看着多余,实际能保证后续部署用的镜像名和构建tag完全一致。如果分发包是从别的机器save出来的,镜像名很可能带了源机器的仓库前缀,这时候需要根据模板里的image:字段反推,把名字纠正成模板期望值再部署。
4. 配置模板与op.sh:端口、密码、持久化是这么生效的
4.1 tendisplus.conf模板里的变量位
tendis的核心配置和Redis高度接近:端口、绑定地址、requirepass、数据目录、日志路径。模板版的tendisplus.conf里不会直接写死值,而是留占位符交给sed替换:
bind 0.0.0.0 port TENDIS_PORT requirepass TENDIS_PASSWORD dir TENDIS_DATA_DIR daemonize no save 900 1 save 300 10 logfile /data/tendis/tendis.logdaemonize no这条很关键。容器里跑的应用必须是前台进程,如果拷贝配置时把默认值带成daemonize yes,容器启动后tendis进程立刻退到后台,主进程判定结束,整个容器会反复重启。我见过好几个案例都是栽在这里,现象是docker ps显示容器总是Restarting,日志又看不到具体堆栈。
dir决定RocksDB的数据落盘位置,也是第4.3节持久化的根基。这个目录必须提前创建,否则tendis启动时写不进去会直接abort。模板的价值在于:整个配置文件的变动范围被缩小到几个变量位,不需要懂tendis全量配置项,改同事留下的脚本也不容易改崩。
4.2 op.sh 的五条命令
op.sh是整个工具的操作入口,我解包后第一件事就是看它的用法:
./op.sh deploy ./op.sh start ./op.sh stop ./op.sh uninstall ./op.sh check内部实现一般是case分发,每种子命令做一组有限操作:
#!/bin/bash case "$1" in deploy) docker load -i centos8.3.2011.tar.gz docker load -i tendis-arm64-2.4.2.tar.gz sed "s|TENDIS_PORT|${TENDIS_PORT:-6379}|g" ... > docker-compose.yaml docker-compose up -d ;; stop) docker-compose stop ;; uninstall) docker-compose down -v ;; check) docker-compose ps nc -zvv 127.0.0.1 ${TENDIS_PORT:-6379} ;; esac部署顺序是写死的:先load镜像再渲染模板,最后才up。如果模板里的镜像名和实际load镜像tag不一致,这一层就会被卡住。
| op.sh命令 | 底层操作 | 注意点 |
|---|---|---|
| deploy | load镜像 + sed渲染 + compose up | 需先确认两个tar.gz存在 |
| start | compose start | 不重新创建容器 |
| stop | compose stop | 保留容器和数据 |
| uninstall | compose down -v | -v连数据卷一起删,慎用 |
| check | compose ps + nc探测端口 | 不能验证密码 |
stop和uninstall的边界要分清:stop只是停容器,数据还在;uninstall带-v会把匿名数据卷一并清掉。如果数据目录是bind mount方式挂载,-v不会删宿主机目录,但如果你把数据放在容器卷里,-v一执行数据就没了,没有后悔药。
4.3 数据目录与配置文件持久化的绑定逻辑
tendis的RocksDB把数据写在dir指定目录下,容器重启后目录清空就等于数据全没。所以compose模板里一定要做目录挂载:
services: tendis: image: tendis-arm64:2.4.2 container_name: tendis-single ports: - "6379:6379" environment: - TENDIS_PASSWORD=yourpass123 volumes: - /data/tendis:/data/tendis - /etc/tendis/tendisplus.conf:/etc/tendis/tendisplus.conf:ro宿主机/data/tendis和容器内/data/tendis一一对应,RocksDB的SST文件直接写到宿主机磁盘,容器删除也不怕。配置文件用只读方式挂载,防止容器内被意外改动,这是运维上一个值得保留的习惯。
这里有个参数细节:如果宿主机目录没提前创建,docker会自动建目录,但属主是root。如果容器内tendis以非root用户运行,就会变成"目录在但写不了",启动阶段报mkdir /data/tendis/tmp: permission denied。解决方法是部署前显式mkdir -p /data/tendis && chown,或者干脆让容器内以root跑,离线内网环境通常不纠结这个。
5. 避坑排查:ARM64上部署tendis的五条实测记录
5.1 容器起不来,报exec format error
现象:docker-compose up后容器秒退,docker logs看不到tendis日志,docker inspect显示状态为exited,错误信息里出现exec format error。
原因:镜像架构和宿主机CPU架构不匹配。最常见的是把x86_64的tendis镜像load到了ARM64机器上;少数情况是在x86机器上用qemu模拟ARM64底层后,误把模拟环境当成真机,镜像架构看着是arm64,实际执行链完全不对。
解决:先docker images看镜像架构是否带arm64标识,再检查宿主机uname -m是否输出aarch64。如果确实架构不匹配,只能重新分发arm64版本的tar.gz。如果你是在x86上跑qemu模拟ARM64做验证,建议直接放弃这条路线,RocksDB在这种模拟底下的IO行为失真,验证结果没有参考价值,不如找一台真机或云厂商的ARM64实例。
5.2 版本号对不上:工具叫2.7.0,二进制是2.4.2
现象:压缩包文件名写的是tendis-single-arm64-2.4.2,但工具命名线是2.7.0,配置参考2.7.0文档填参数,结果tendis启动报未知配置项。
原因:工具的版本和tendis内核版本是两条线。工具版本迭代到2.7.0,但里面的tendis二进制实际是2.4.2,配套的RocksDB是5.13.4。按新版本文档配置旧版本二进制,配置项不认识是必然。
解决:一切参数以包内tendisplus.conf模板和README为准。别只看工具命名去网上搜配置,拿到的文档版本未必和包内二进制匹配。检查方式也简单:进容器跑/usr/local/bin/tendisplus --version,实际输出是什么版本就按什么版本的文档来。
5.3 想升级RocksDB,结果进程直接崩
现象:为了所谓性能,把RocksDB动态库换成了更新版本,tendis启动后几秒内SIGSEGV,日志里能翻到rocksdb相关的调用栈,但没有明确报错。
原因:tendis 2.4.2编译时和rocksdb 5.13.4强绑定,RocksDB的接口在版本间经常变,动态库里符号对不上就直接崩。这个包里的二进制和数据库版本是配套打包的,拆开任何一个都会踩到黑匣子问题。
解决:不要动RocksDB版本。如果非要升级,得从源码重新编译整套tendis,而不是只换动态库。这个包的设计就是让你拿现成二进制直接用,性能调优的参数在tendisplus.conf里调,不要动依赖层。
5.4 密码设置了,redis-cli免密还能连
现象:配置里写了requirepass,容器也起来了,但redis-cli不带密码能连上,甚至能执行INFO。
原因:最常见的两种,一是配置模板里的requirepass占位符没被sed替换,实际落到容器内的配置还带着TENDIS_PASSWORD字符串,等于没有密码;二是配置目录挂载时把宿主机旧配置覆盖了容器内新配置,改了半天容器内跑的还是老文件。
解决:部署后第一步进容器内确认实际配置:docker exec tendis-single cat /etc/tendis/tendisplus.conf | grep requirepass。如果占位符没替换,回到宿主机重新跑sed,别手改容器内的文件,容器重建就丢。如果挂载覆盖了,检查docker-compose.yaml里volumes字段的源文件路径,确保指向渲染后的文件。
5.5 卸载后重部署,端口被占或数据残留
现象:执行uninstall后隔几天重新deploy,compose报端口已被占用,或者新的tendis实例起来后读到了旧数据,排查半天。
原因:uninstall的docker-compose down只停容器和网络,不会清理宿主机上通过bind mount挂载的数据目录。端口被占多数是旧容器没完全退出,或者别的进程占用了6379。
解决:重新部署前按顺序做三件事:docker ps -a看有没有同名容器残留,ss -lntp | grep 6379看端口占用,ls /data/tendis看数据目录里有没有老文件。确认不需要旧数据后手动清理再deploy。这个顺序我建议每次都走一遍,成本不到一分钟,能避免非常多的玄学问题。
6. 部署完怎么验证:从容器状态到数据写读一条龙
6.1 先看容器状态和日志
![未使用图片占位,如无必要不插入]
部署完成后先跑docker-compose ps,确认状态是Up且没有频频重启。随后看日志,重点不是看有没有输出,而是看有没有反复刷新的异常堆栈:
docker-compose ps docker logs --tail 100 tendis-single注意检查日志里是否出现signal字样的崩溃记录。tendis的启动日志通常很短,几行输出后就进入前台运行,如果日志停在初始化阶段且无后续,优先怀疑目录权限问题,而不是怀疑二进制有问题。
6.2 验证端口和密码
nc -zv 127.0.0.1 6379 redis-cli -h 127.0.0.1 -p 6379 -a yourpass123 PING第一条验证端口通不通,第二条验证密码对不对。如果nc通了但redis-cli报NOAUTH Authentication required,说明密码生效了只是没带对,属于正常防御。能PING通并返回PONG,再执行一个SET/GET组合,确认写入链路没问题。
6.3 我的落盘检查习惯
最后一步我会直接翻数据目录,确认RocksDB真的往宿主机写了文件:
ls -l /data/tendis find /data/tendis -name "*.sst" | head -5看到.sst文件落在宿主机目录里,说明持久化挂载是通的,容器删了也不慌。在那以后我每次deploy完都强制走一遍这个流程:先ps后logs,再nc再redis-cli,最后翻落盘目录,全过一遍才敢把手里的离线包标记为可用。希望帮到你。
本文还有配套的精品资源,点击获取