我们在本地把 Redis 玩得再熟一换电脑、一上服务器经常就栽在环境这关版本对不上、系统依赖缺、配置飘忽不定折腾半天才发现是环境不一致。后来我干脆把所有中间件都装进 Docker 里Redis 也照此办理。这篇文章我就完整记录一下怎么在 Docker 里装 Redis、怎么进容器操作它、怎么把数据和配置管理得明明白白。全是实操拿来就能用。1. 为什么开发环境里的 Redis 一定要跑在容器里先说个最常见的场景某开发者在 Windows 上写代码用的是 Redis 6.x 的 Windows 移植版换到 Linux 服务器上发现官方根本没有 Windows 版一说生产环境跑的是 7.x本地还是 6.x很多新命令不敢用排查问题的时候两边表现还不一样。这种“在我电脑上是好的”的经典尴尬八成是环境差异闹的。把 Redis 放进 Docker 之后解决的不只是版本一致性问题。Docker 镜像把 Redis 的二进制、运行库、默认配置全部打包在一起不管你在 macOS、Windows 还是 Linux 上拉取同一个镜像跑起来的 Redis 行为完全一致。你本地怎么测生产就怎么跑中间没有“系统和版本适配”这层不确定性。另一个实际收益是隔离和清理。Redis 默认监听 6379 端口你本地装一个万一别人也装一个端口冲突、配置文件互相覆盖排查起来非常痛苦。而容器内的 Redis 监听的是容器自己的网络空间你说暴露端口它才暴露不暴露的话外面完全感知不到它的存在。想删掉重来一条docker rm就可以不会像本机安装那样留一堆残留文件。还有一个很容易被忽略的点团队协作。新同事入职与其让他照着十几页文档在本机装 Redis不如直接给他一个写好的 Docker Compose 文件一条docker compose up -d环境就齐了。这里提前说一下这篇文章的操作我都基于 Docker 官方镜像和 Redis 7.x 版本如果你用的是更早的版本命令基本通用但个别参数可能会略有差异。顺带列一下我选择在 Docker 里跑 Redis 的几条核心理由版本可控镜像 tag 锁定版本不会因为系统包管理器更新而意外升级。环境一致开发、测试、生产都用同一个镜像行为可预期。销毁重建成本低配置错了、数据污染了删容器重来几秒钟的事。端口和应用隔离不污染宿主机和其他服务可以共存在一台机器上。2. 部署前的准备选镜像、确认端口、把握网络模式2.1 官方镜像怎么选redis、redis-stack 还是 alpine 变体Docker Hub 上的 Redis 镜像来源很杂我只推荐官方仓库里的镜像也就是redis这个镜像名。常见的 tag 有redis:7.4、redis:7.2、redis:6.2这种版本号格式以及redis:alpine这种精简版。redis:alpine基于 Alpine Linux镜像体积很小起步快适合对磁盘占用敏感的场景。但 alpine 变体用的是 musl libc 而不是 glibc某些 Redis 模块如果依赖 glibc 就可能不兼容。生产环境我倾向于用官方默认的redis:7.4或redis:7.2虽然镜像体积大一点大概 150MB 左右但兼容性和稳定性更有保障。如果你需要 RedisSearch、RedisJSON 这类扩展模块可以直接用redis-stack镜像里面自带了这些模块和 RedisInsight 可视化工具。不过 redis-stack 镜像更重通常我更推荐保持基础镜像需要什么能力通过配置文件打开而不是一股脑引入所有扩展。至于版本我目前用的是 7.2 系列因为 7.x 引入了不少新特性比如SET命令的 NX 和 GET 参数合并优化、List类型的底层改进对日常开发够用了。如果你的业务代码还在用 6.x别急着升先把镜像 tag 锁定在redis:6.2等代码适配之后再切。2.2 端口映射前先想清楚你真的需要把 6379 暴露给外部吗很多人在docker run的时候不加思索地写上-p 6379:6379把 Redis 端口映射到宿主机。这在本地开发没问题但在服务器上就要谨慎了。Redis 默认没有密码暴露到公网等于把自己家门钥匙插在锁孔里。如果只是让本机上的其他 Docker 容器访问 Redis根本不需要端口映射直接用 Docker 内部网络即可。只有当你需要在宿主机外面访问 Redis 时才需要-p映射。我建议的实践是本地开发可以用-p 127.0.0.1:6379:6379强制绑定回环地址只允许本机访问这样即使 6379 暴露了外部也连不进来。生产环境则彻底不暴露端口让应用服务和 Redis 处于同一个 Docker 网络内通过容器名互相访问。具体怎么用容器名互通我在后面第 4 节会详细演示。2.3 再看一眼 Docker 的网络模式bridge、host 和 none 的取舍容器网络模式里最常见的三种我对它们的理解是这样的bridge 模式Docker 默认模式容器有自己的 IP通过端口映射对外提供服务。适合大多数场景也是这节课的主要模式。host 模式容器直接使用宿主机网络没有独立 IP端口也不用映射性能损耗最小。但容器内的服务会直接占用宿主机端口隔离性变差。Redis 单实例跑在 host 模式下其实问题不大但一旦你跑两台 Redis 容器做集群端口直接冲突。none 模式容器没有网络主要用于跑一次性任务或者用外部网络插件。实操中我绝大多数情况都用 bridge 模式。host 模式只在明确追求极限网络性能、并且不担心端口冲突时用常规的 Redis 场景完全没必要。3. 快速启动第一个 Redis 容器最简命令的逐参数拆解3.1 先拉镜像再启动一个“裸” Redis环境检查完之后第一步很简单拉镜像。我习惯先用docker images看一眼本地有没有现成的 redis 镜像没有的话再拉docker pull redis:7.2.4这里不用管最新版是多少拉一个明确的版本号就好图的是可复现。拉完之后启动容器最基本的命令长这样docker run -d --name my-redis redis:7.2.4命令解释一下。-d表示后台运行--name my-redis给容器起个名字后续所有操作都靠这个名字定位容器。最后是镜像名和 tag。这样启动的容器没有做任何端口映射外面是访问不到它的但它自己跑得很欢快。你可以用下面的命令确认一下状态docker ps如果看到my-redis的状态是 Up说明 Redis 已经启动了。然后我们该怎么验证 Redis 真的活着进到容器里面去执行redis-cli ping这是最直接的检查方式docker exec -it my-redis redis-cli ping返回PONG恭喜你第一个容器版的 Redis 已经起来了。3.2 数据结构和配置文件去哪了理解容器文件系统容器启动之后有一点要马上讲清楚Redis 的配置文件redis.conf默认不是显式挂载的而是用的镜像内置默认配置。你进到容器里可以查看路径/usr/local/etc/redis/redis.conf但直接改容器内部的文件没有意义因为容器一删改动全没了。同理Redis 的数据在容器里默认写入/data目录。不挂载外部卷的时候所有数据都存在容器可写层里容器删除数据跟随消失。这个特性对于临时测试来说是方便的但任何带点真实业务的数据都不能这么干。持久化怎么做我在第 5 节专门讲。3.3 设置访问密码别让 Redis 裸奔刚才那个命令启动的 Redis 没有任何密码保护。本地开发图方便可以不管但只要你把端口映射到了宿主机哪怕只是回环地址我也建议至少设置一个密码。最简单的做法是在启动命令里追加--requirepass参数docker run -d --name my-redis -p 127.0.0.1:6379:6379 \ -v redis-data:/data \ redis:7.2.4 \ redis-server --appendonly yes --requirepass yourpassword注意redis-server后面的两个参数它们会覆盖镜像里的默认配置和直接改配置文件的效果等价。--appendonly yes开启 AOF 持久化--requirepass yourpassword设置访问密码。这样设置之后再用redis-cli连接就需要带密码了docker exec -it my-redis redis-cli -a yourpassword ping命令行里直接带-a参数会有告警提示说密码明文出现在进程列表里测试用没关系生产环境建议用REDISCLI_AUTH环境变量或者干脆不要用 redis-cli 暴露密码而是通过配置文件和认证机制管理。4. 在容器里操作 Redis 的四层姿势从 redis-cli 到可视化界面也许有人会问Redis 装在容器里和我本机装的 Redis操作起来有什么不同其实没有本质区别在容器里操作 Redis 只是多了一层 Docker 的“壳”。实际使用中操作层面的手段大概可以分为四层从命令行到代码客户端再到可视化工具按需选择。4.1 第一层容器内部执行 redis-cli也就是前面已经用到的方式docker exec -it my-redis redis-cli。这种方式最接近“登录到服务器上操作 Redis”的体验适合做运维排查、验证配置、临时看 key。里面支持所有 redis-cli 的交互命令比如info、keys *、dbsize等等。容器跑着你随时可以进去敲命令docker exec -it my-redis redis-cli -a yourpassword进去之后是 redis-cli 的交互模式直接输入命令回车执行。退出用exit或者quit。如果需要非交互式地执行单条命令可以这样docker exec -it my-redis redis-cli -a yourpassword SET site hello-redis docker exec -it my-redis redis-cli -a yourpassword GET site这种方式适合写脚本时调用。4.2 第二层宿主机直连映射端口如果你当初启动容器时加了-p 127.0.0.1:6379:6379那么宿主机上只要装了 redis-cli也可以直接连redis-cli -h 127.0.0.1 -p 6379 -a yourpassword ping这里有个容易糊涂的点redis-cli是装在宿主机上的程序Redis 服务端跑在容器里两者通过映射到本机的 6379 端口通信。和第一层的区别在于这一层不需要进容器适合在宿主机上用脚本做自动化巡检。如果宿主机没有安装 redis-cli也可以依赖 Docker 容器内的 redis-cli也就是第一层。4.3 第三层代码客户端连接 Daemon 化 Redis这是实际业务里最常用的操作方式。你的应用跑在另一个容器里连接 Redis 时host 不能写127.0.0.1而应该写 Redis 的容器名。前提是两个容器在同一个 Docker 网络内。比如创建一个自定义网络docker network create app-network启动 Redis 时指定网络docker run -d --name my-redis --network app-network redis:7.2.4再启动你的应用容器也加入同一个网络docker run -d --name my-app --network app-network your-app-image这样你的应用代码里连接 Redis 就写// Node.js 示例 const client createClient({ url: redis://my-redis:6379 });不需要关心 Redis 容器的 IP 是不是变了。Docker 内置 DNS 会解析容器名到对应 IP只要容器在同一网络下名字就是稳定的访问地址。4.4 第四层可视化工具 RedisInsight如果你习惯用带界面的工具可以用redis-stack镜像自带的 RedisInsight或者单独跑一个 RedisInsight 容器docker run -d --name redis-insight -p 8001:8001 redislabs/redisinsight:latest然后浏览器打开http://127.0.0.1:8001按照界面提示添加 Redis 连接信息填写主机Redis 容器名或 IP、端口和密码就能在页面上看到所有 key、内存分析结果和慢日志。日常调试、看某个 key 的 TTL、导出某些数据可视化工具点几下就行没必要一行行敲命令。四层操作方式对比一下操作方式场景连接地址是否需要端口映射docker exec redis-cli运维排查、容器内操作容器内直接执行否宿主机 redis-cli本机脚本、快速验证127.0.0.1:6379是代码客户端应用连接 Redis容器名:6379否同网络RedisInsight可视化分析、调试宿主机 IP:8001是5. 数据持久化Container 可以删数据不能丢Redis 容器随手docker rm一删如果真的把数据丢光了多半是因为没有做数据持久化。初次接触 Docker Redis 的开发者踩的坑基本都在这启动容器时图方便没有挂载 volume运行一段时间容器重建一次redis 里所有 key 全部蒸发。这里的关键概念是容器可写层是临时的只有 volume 或 bind mount 才能把数据落到宿主机磁盘。5.1 挂载数据卷用 named volume 还是 bind mountDocker 提供了两种持久化方式named volume 和 bind mount。对 Redis 来说我更推荐 named volume因为它把目录的权限和位置完全交给 Docker 管理不会出现权限不对导致 Redis 无法写入数据的问题。命令是这样的docker run -d --name my-redis \ -v redis-data:/data \ redis:7.2.4-v redis-data:/data前半部分redis-data是卷的名字后半部分/data是容器内的数据目录。Redis 镜像的WORKDIR和默认持久化路径都指向/data所以挂载这个目录就对了。启动后你可以用下面的命令确认卷已经创建并挂在docker volume inspect redis-data数据文件RDB 快照dump.rdb和 AOF 日志appendonly.aof会自动写在宿主机上容器怎么删都不影响数据。bind mount 则是直接把宿主机的某个目录映射进去比如docker run -d --name my-redis \ -v /my/host/redis/data:/data \ redis:7.2.4这种方式适合你希望数据目录在宿主机路径可控、便于直接备份的场景。但要注意目录权限问题容器内的 Redis 进程默认以 redis 用户运行如果宿主机目录权限是 root 所有Redis 可能写不进去表现为启动后报Cant open the log file: Permission denied之类。用 named volume 基本就避开了这个坑所以我个人绝大多数情况都用 named volume。5.2 RDB 和 AOF 到底怎么选默认 RDB 够不够Redis 持久化有 RDB 和 AOF 两种机制。RDB 是定时把内存数据快照写入dump.rdb性能好但在两次快照之间如果宕机这段时间的数据会丢。AOF 是把每次写命令追加到日志文件数据更安全但文件会越来越大需要定期 rewrite。镜像默认配置同时开了 RDB默认开启和 AOF默认关闭。换句话说如果你不额外配置Redis 默认在满足触发条件时生成 RDB 快照。像刚启动的空 Redis没写入任何数据快照可能都不会生成。对本地开发来说这个默认配置够用对业务数据我建议至少把 AOF 打开让每次写操作都落盘。我们直接通过启动参数开启 AOFdocker run -d --name my-redis \ -v redis-data:/data \ redis:7.2.4 \ redis-server --appendonly yes等 Redis 跑起来写入几个 key然后你可以去宿主机上看一眼数据文件到底持久化到哪了docker volume inspect redis-data输出里会有Mountpoint字段指向宿主机上的实际目录进去就能看到appendonly.aof或者dump.rdb文件。5.3 容器重建后的数据恢复验证持久化配好之后一定要做一次“灾难演练”删掉容器再启动一个新容器数据还在不在验证方式很简单docker stop my-redis docker rm my-redis docker run -d --name my-redis \ -v redis-data:/data \ redis:7.2.4然后查一下之前写入的 keydocker exec -it my-redis redis-cli keys *key 还在说明持久化生效。这个过程里唯一要注意的是新容器挂载的卷名和路径必须和旧容器一致否则 Redis 还是从头开始。6. 配置管理从命令行参数到 redis.conf 挂载再到 Docker Compose6.1 临时配置用参数正式配置用文件启动 Redis 容器时动态追加配置参数很方便但不适合保存。比如你配置了--maxmemory 256mb --maxmemory-policy allkeys-lru一长串参数堆在 docker run 命令里时间久了没人记得当时为什么这么配也没法做版本管理。正确的做法是把配置固化到redis.conf文件里挂载进容器再让 Redis 启动时读取它。先在宿主机建一个配置文件目录mkdir -p /opt/redis/conf编辑/opt/redis/conf/redis.conf内容示例bind 0.0.0.0 protected-mode no port 6379 appendonly yes maxmemory 256mb maxmemory-policy allkeys-lru这里面每行都是 Redis 配置项和命令行参数一一对应。注意bind 0.0.0.0和protected-mode no这是为了让其他容器可以访问 Redis。如果 Redis 只在本机被访问protected-mode yes会更安全但连容器内的应用也访问不了你会被这个坑卡很久。然后启动容器时挂载配置文件docker run -d --name my-redis \ -p 127.0.0.1:6379:6379 \ -v /opt/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf \ -v redis-data:/data \ redis:7.2.4 \ redis-server /usr/local/etc/redis/redis.conf注意redis-server后面跟的是容器内路径不是宿主机路径。挂载的宿主目录和容器内文件是一一对应的改宿主机上的redis.conf不用重建容器重启容器即可生效。6.2 用 Docker Compose 把配置固化到版本库当 Redis 的配置、数据卷、网络、密码都开始多起来之后docker run 命令会变得很长很长每次记不全还容易写错。这时候就该上 Docker Compose。一个典型的docker-compose.yml长这样services: redis: image: redis:7.2.4 container_name: my-redis restart: always ports: - 127.0.0.1:6379:6379 volumes: - /opt/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf - redis-data:/data command: redis-server /usr/local/etc/redis/redis.conf volumes: redis-data:启动就一条命令docker compose up -d查看状态和日志docker compose ps docker compose logs -f redis这个文件可以直接提交到 Git 仓库里团队每个人拉下来都能复现一模一样的 Redis 环境。换机器、换服务器无非是把这个 yml 文件拿过去改改路径up -d一下。配置文件本身也进入版本管理谁改了什么、为什么改全部有迹可循。6.3 容器里的 Redis 怎么改配置CONFIG SET 的临时与永久还有一种情况是 Redis 已经在跑你想临时调整一个运行参数不想重启容器。用 redis-cli 连进去执行docker exec -it my-redis redis-cli -a yourpassword CONFIG SET maxmemory 512mb这个命令立即生效但不会写入配置文件容器重启后就丢了。如果你确认这个配置要长期保留记得同步修改宿主机上的redis.conf并把它也标注为“需要持久化的配置”。我的习惯是临时调优用CONFIG SET稳定之后把结论固化到配置文件绝不让配置分成两套。7. 几个高频踩坑场景从日志看问题而不是猜跑 Docker 容器这件事新手和老手的差别往往体现在排查问题的思路上。不是运气好碰不到问题而是出了问题知道去哪看、怎么看。下面几个是我实际用到最多的排查场景记录一下完整思路。7.1 容器启动后秒退怎么看日志docker run -d --name my-redis redis:7.2.4执行完下一秒docker ps发现容器没了。这种情况几乎都是启动参数或者挂载路径有问题。第一步永远别去猜直接看日志docker logs my-redis日志里最常见的错误是Fatal error, cant open config file或者Cant chdir to /data。前者说明配置路径不对挂载的配置文件没到容器内指定位置后者说明/data权限有问题。看到日志之后再去检查路径映射和权限比盲猜快得多。还有一种情况是容器在反复重启docker ps显示状态为Restarting。这通常是因为启动命令里加了--restart always但 Redis 启动失败。仍然是先看日志确认是配置错误还是端口占用问题再决定要不要调整启动参数。7.2 外部连不上 Redis先分清端口映射和 Redis 本身环境也启动了Redis 日志也没报错但宿主机上的 redis-cli 就是连不上。排查顺序应该是这样确认容器有没有暴露端口docker port my-redis。没有输出说明没做端口映射这就是连不上的原因。确认端口是不是映射到了 127.0.0.1docker port my-redis会显示127.0.0.1:6379 - 6379/tcp说明只有本机可以访问。检查容器内 Redis 监听情况docker exec -it my-redis redis-cli ping如果返回 PONG说明 Redis 进程没问题问题出在端口映射或防火墙。这个排查思路可以扩展到任何“容器内服务正常、外部访问失败”的场景步骤固定照着走就可以定位。7.3 认证失败、拒绝访问这类坑NOAUTH Authentication required这个报错很典型意思是 Redis 设置了密码而连接方没有通过认证。出现这个报错的常见原因有三个启动命令里设置了--requirepass但 redis-cli 连接时没带-a参数。配置了密码但应用代码的连接串里没带密码。用 CONFIG SET 临时设置过密码但重启后配置文件里并没有保留。另一个容易混淆的是ERR Client sent AUTH, but no password is set意思是连接方发了 AUTH 命令但 Redis 根本就没设置密码。一般是代码里写了密码但 Redis 那端没设置两端对不上。解决办法也很简单确认 Redis 的密码配置把应用连接串里的凭据改成一致的。7.4 数据卷挂载后以前的数据“不见了”这个坑我见了不少次。明明挂了redis-data:/data启动之后keys *却什么都没有。原因几乎都是旧容器之前没有挂载卷数据存在容器可写层里新容器挂载了新的空卷所以看不到旧数据。解法是先看旧容器的状态和挂载信息docker inspect old-container-name | grep -A10 Mounts如果原来没有挂载卷唯一能抢救的方式是在旧容器未删除前用docker cp把容器内/data目录拷贝出来再复制到新容器挂载的卷目录里。如果旧容器已经删了数据就真找不回来了。借此也想强调容器可以随时删但数据卷是唯一的命根子任何要保留的东西都要落在挂载卷里。8. 收个尾个人维护这种 Redis 环境的一些习惯最后分享几个我长期操作下来成习惯的做法。第一所有 Redis 容器都很少用最新的 tag而是明确指定版本号比如redis:7.2.4这让你随时都知道生产跑的是哪个版本升级之前有明确的测试对象。第二数据卷和配置文件分开管理数据卷交给 Docker 管配置文件放在宿主机固定目录并纳入版本库这样既保障了数据安全又保留了配置审计能力。第三重要 Redis 实例一定会开 AOF并且设置密码RDB 可以关掉或者调低快照频率减少磁盘 IO 压力。还有一个很小的经验每次操作完 Redis 容器我都习惯跑一遍docker ps --filter nameredis看状态同时看一眼docker logs --tail 50 my-redis习惯性的健康检查可以帮你提前发现潜在问题比如内存快照失败或者 AOF 重写异常这些在日志里都会有早期迹象。总体来说在 Docker 里跑 Redis 本身不难难度在于把持久化、配置、网络这些事情想清楚并且形成一套可复用的操作流程。把这套流程跑熟了之后不只是 Redis其他中间件你也会发现自己越来越敢于放进容器里因为你知道怎么让它活得稳、死得干净、数据还不丢。