ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Docker部署Redis全攻略:从启动容器到主从复制与运维排坑

Docker部署Redis全攻略:从启动容器到主从复制与运维排坑 最近好几个朋友来问我同一个问题docker启动redis 到底卡在哪一步了。有人是镜像拉下来了但容器几秒就退出有人是容器起来了可客户端怎么都连不上还有人更惨卡在Docker Desktop本身启动不了报错信息在搜索引擎里一搜一大片。这些坑我早期全都踩过而且回头看绝大多数都不是Redis本身的问题而是对Docker运行机制的一两个关键点没想清楚。这篇文章我就按自己实际的操作顺序来写怎么把第一个Redis容器跑起来、怎么让数据持久化、怎么把Docker Desktop启动失败的坑填平、怎么用Compose做一主一从以及跑起来之后的日常运维。无论你用Windows、macOS还是Linux这个思路都通用适合刚上手Docker的新手也适合那些已经能启动但不知道怎么配置持久化和安全的同学。1. 为什么我建议用Docker跑Redis而不是直接装1.1 一条命令解决版本与环境的老大难问题如果你在裸机环境装过Redis大概率经历过这么几个场景Ubuntu上用apt装了个老版本macOS上用brew install又装了个新版本公司服务器上可能还是编译安装的3.2。版本之间命令有差异配置文件散落在不同目录升级一次还要小心翼翼处理数据兼容性。Docker把这些麻烦全挡在外面了。镜像就像打包好的运行时里面带了Redis二进制、依赖库和默认配置你只需要关心数据放在哪、端口暴露在哪、密码是什么。更重要的是多个版本可以共存。docker run -d --name redis7 -p 6379:6379 redis:7 docker run -d --name redis6 -p 6380:6379 redis:6.2这两个容器互不干扰一个用6379一个用6380本质上就是两个独立进程。不想用了直接docker rm -f宿主机干干净净不会留下编译残留、系统服务和路径配置。这就是我推荐Docker跑Redis的最重要原因隔离带来的干净。1.2 官方镜像这么多 tag到底该选哪个Redis官方镜像的tag很多常见的有redis:7、redis:7.2-alpine、redis:7-bookworm、redis:6.2-alpine。选的时候主要看基础系统和体积。镜像tag基础系统体积适合场景redis:7Debian bookworm约120MB生产主力调试工具全redis:7-alpineAlpine Linux约35MB本地快速验证追求体积redis:6.2-alpineAlpine Linux约35MB老版本兼容需求redis:7.2Debian bookworm约120MB指定7.2小版本我的建议是本地开发用redis:7-alpine体积小、启动快生产环境用redis:7这种Debian系镜像出问题的时候容器里可以apt-get装排查工具。尽量别用latest因为你不知道哪天拉下来的最新版Redis改了什么行为对比版本差异的时候会很痛苦。1.3 Docker Desktop 和裸 Docker Engine 怎么选本地开发跑Docker最常见的选择是Docker Desktop。它自带了Docker Engine、Compose插件还有图形界面能看容器状态和volume。Linux用户则直接用Docker Engine就行不需要桌面端。Windows和macOS的Docker Desktop本质上是靠虚拟机来模拟Linux内核Windows下面走的是WSL2或者Hyper-VmacOS走的是Apple虚拟化框架。这就是为什么网上那么多Docker Desktop failed to start because virtualisation support wasnt detected的报错虚拟化支持是它的命门。如果你现在还无法启动Docker Desktop别急着往下读Redis命令先跳到第4章把虚拟化问题解决。2. 跑起来再说第一个Redis容器的最小可用命令2.1 五条命令把Redis拉起来并完成自检第一步别想太复杂先跑一个不带任何持久化、不带密码的最小容器。docker pull redis:7 docker run -d --name redis-demo -p 6379:6379 redis:7 docker ps docker exec -it redis-demo redis-cli pingdocker pull redis:7是把镜像拉到本地。docker run里的-d表示后台运行不然终端会一直挂着。--name redis-demo是给容器起名之后操作都用这个名字不需要记容器ID。-p 6379:6379是端口映射左边的6379是宿主机端口右边的6379是容器内Redis监听的端口。如果一切正常最后一条命令会输出PONG。这说明容器里的Redis进程活着redis-cli也能和它正常对话。2.2 你连不上Redis八成是少了 -p 这个参数我见过不少新手执行docker run -d --name redis-demo redis:7然后拿着可视化客户端去连127.0.0.1:6379结果连接被拒绝。原因很简单没有-p的时候宿主机6379端口根本没有监听Redis只存在于容器内部网络里。-p做的事情是把宿主机的一个端口转发到容器内部的端口。用-p 16379:6379这种写法宿主机端口可以是16379容器内Redis照常监听6379。这样你即使本机有别的服务占了6379也能用16379访问Redis。验证宿主机到容器的通路是否正常可以直接在本机执行redis-cli -h 127.0.0.1 -p 6379 ping如果本机没有安装Redis客户端也可以用Dockerexec进去执行redis-cli但这样就绕过了端口映射无法验证网络转发。2.3 容器管理的基本动作和端口占用的坑日常操作容器就三组命令docker stop redis-demo docker start redis-demo docker rm -f redis-demostop是优雅停止start是重新启动rm -f是先强制停止再删除。注意rm不会删除镜像只是把容器销毁。端口占用是最常见的报错场景。假设你6379端口被一个残留容器占着重新run时会看到类似这样的错误Error response from daemon: driver failed programming external connectivity on endpoint redis-demo: Bind for 0.0.0.0:6379 failed: port is already allocated解决办法不是换端口而是先看看是哪个容器占了端口docker ps --format table {{.Names}}\t{{.Ports}}找到占用的容器判断能不能删。如果只是端口被本机进程占了那就在run命令里换一个宿主机端口比如-p 6380:6379。3. 持久化与配置文件从玩具级变成能用3.1 容器一删数据就消失不是玄学用第2章的命令跑起来的Redis一旦执行docker rm -f里面存的Key全部消失。这不是Redis不持久化而是容器文件系统本身是临时的。容器被删除时它的可写层也跟着没了。要让数据活下来就必须把Redis的数据目录挂载到宿主机。Redis默认会把数据写到/data目录所以挂载时瞄准这个路径。docker run -d --name redis-stable -p 6379:6379 -v redis-data:/data redis:7 --appendonly yes这里的-v redis-data:/data是创建一个名为redis-data的命名卷挂到容器的/data。--appendonly yes是让Redis开启AOF持久化因为默认情况下Redis只存快照可能好几秒才写一次挂载了目录也不一定能第一时间看到数据。AOF开启后每次写操作都会被追加到文件里数据安全性高很多。验证一下docker exec -it redis-stable redis-cli set foo bar docker rm -f redis-stable docker run -d --name redis-stable2 -p 6379:6379 -v redis-data:/data redis:7 --appendonly yes docker exec -it redis-stable2 redis-cli get foo最后一条命令输出bar说明数据成功跨容器存活。注意用的是同一个命名卷redis-data。3.2 要让 redis.conf 生效启动命令必须这样写官方镜像虽然自带一份配置但很多时候我们需要改maxmemory、requirepass、appendonly这些关键项。正确姿势是把配置文件挂载进容器然后在启动命令里显式指定配置路径。先准备一份配置文件建议放在~/docker/redis/redis.confbind 0.0.0.0 protected-mode yes port 6379 daemonize no appendonly yes appendfsync everysec requirepass your-strong-password maxmemory 512mb maxmemory-policy allkeys-lru然后启动docker run -d \ --name redis-conf \ -p 6379:6379 \ -v ~/docker/redis/redis.conf:/usr/local/etc/redis/redis.conf \ -v redis-data:/data \ redis:7 \ redis-server /usr/local/etc/redis/redis.conf注意最后一行。官方镜像的默认入口会执行redis-server但你给了配置文件路径之后Redis会读指定文件而不是镜像内置配置。这里有两个必须说的坑一daemonize一定要写成no。Docker容器要求前台保持一个主进程如果Redis自己fork到后台变成守护进程容器会认为主进程退出然后直接停止。二文件权限对不上可能报错。官方镜像里Redis是以UID 999的用户运行的如果挂载进来的配置文件属主不是999有可能读到日志目录时出现Permission denied。简单粗暴的办法是sudo chown -R 999:999 ~/docker/redis3.3 密码、bind、protected-mode三件套缺一不可把Redis暴露到Docker端口之后千万别裸奔。公网上有大量扫描器在扫6379端口一旦发现没有密码的Redis分分钟给你写入挖矿程序成为肉鸡。这不是危言耸听真实环境里我见过太多因为Redis没设密码被打穿的案例。设置密码有三种方式方式命令/配置特点配置文件在redis.conf里写requirepass xxx推荐可版本管理命令行参数docker run ... redis-server --requirepass xxx快速测试但容易被ps看到环境变量官方镜像7.x支持REDIS_PASSWORDxxx适合Compose里管理同时还要理解Redis的默认保护逻辑。Redis 3.2之后默认protected-mode yes如果没设密码Redis只允许本机回环地址访问宿主机从外部连过来会被拒绝。当你用-p 6379:6379把端口暴露出来时docker网络转发里的源IP不是127.0.0.1所以必须设密码并且把bind设为0.0.0.0才能稳定访问。如果不想让Redis对宿主机所有网卡开放只给局域网用可以这样写配置bind 127.0.0.1 192.168.1.100 protected-mode yes requirepass your-strong-password这会在宿主机IP上监听但不会暴露到公网网卡。4. Docker Desktop 启动失败排查从报错到跑通4.1 先把报错原文记住Docker Desktop在Windows上最常见的启动报错就是Docker Desktop failed to start because virtualisation support wasnt detected.有些版本也会显示Virtualization support not detected这行字一旦出现基本可以断定Docker Desktop想要的虚拟化后端没就绪。它要么是WSL2没装好要么是Hyper-V无效要么是CPU的硬件虚拟化没开启。别第一时间重装先按下面的链路排查。4.2 虚拟化是什么为什么Docker Desktop偏偏依赖它Docker Desktop运行原理和Linux上的Docker Engine不太一样。Linux上的Docker直接调用Linux内核的命名空间和cgroup天生就是原生的。而macOS和Windows的进程并不是Linux程序Docker Desktop必须在系统里养一个轻量级Linux虚拟机所有容器都跑在这台虚拟机里。这台虚拟机总得有东西支撑。Windows上要么用WSL2要么用Hyper-VmacOS上用的是Apple虚拟化框架。这些基础设施全都依赖CPU硬件虚拟化能力也就是Intel的VT-x或AMD的AMD-V。如果CPU虚拟化没打开或者WSL2/Hyper-V组件没启用Docker Desktop当然无法启动。你可以理解成Docker Desktop像个杂技演员虚拟化就是舞台。舞台没搭好演员再专业也上不了场。4.3 Windows 修复链路WSL2、系统功能、BIOSWindows上排查顺序我建议从软件到硬件第一步看任务管理器。按CtrlShiftEsc切到性能标签底部有个虚拟化状态。如果显示已启用说明CPU没问题问题出在系统组件如果显示已禁用得进BIOS打开。第二步启用Windows功能。WinR输入optionalfeatures把这三项勾上适用于Linux的Windows子系统虚拟机平台Windows虚拟机监控程序平台第三步安装WSL2。以管理员身份打开PowerShellwsl --install wsl --set-default-version 2装好以后重启电脑再打开Docker Desktop。如果还是报错在Docker Desktop设置里找到Resources - WSL Integration确认WSL2后端已经启用。第四步如果任务管理器里虚拟化显示已禁用那就重启进BIOS/UEFI找Intel Virtualization TechnologyIntel平台或SVM ModeAMD平台把它设为Enabled。不同主板叫法不同但核心词就是Virtualization。我遇到过一台Windows 11的机器所有组件都开了虚拟化也开了Docker Desktop还是起不来。最后发现是之前装过旧版本Hyper-V没完全卸载干净跟WSL2后端冲突。解决办法是把Docker Desktop的后端切换成Hyper-V试试或者彻底卸载重装。这种问题很折腾但能摆平。4.4 macOS 上的启动授权与资源分配macOS上的Docker Desktop启动失败相对少一些但有两个常见的坎。一个是首次安装后需要授权。第一次打开Docker Desktop系统会弹窗提示需要Docker访问某些资源必须去系统设置 - 隐私与安全性里手动允许不然界面会卡在Docker Engine is starting。另一个是资源不够。如果你用Docker Desktop同时跑Redis、MySQL、Kibana多个容器默认内存配额很容易不够。柚子容器起一个崩一个Redis容器起来以后docker logs里全是Cannot allocate memory。这时去Docker Desktop的Settings - Resources把Memory调高到4GB以上CPU也可以给2到4核。苹果芯片的Mac跑Docker性能通常比Intel版流畅但个别旧版本Docker Desktop在Rosetta模式下会有兼容性问题。直接选Use Rosetta for x86/amd64 emulation on Apple Silicon这个选项如果勾了反而启动慢就把勾去掉。4.5 Docker起来了但Redis容器网络不通怎么办Docker Desktop本身能启动了可Redis容器还是连不上这时候按三个方向排查。第一确认容器真的在跑。docker ps看看redis-demo的状态是不是Up。如果显示Exited (0)大概率是redis.conf里daemonize yes导致的回第3章改成no。第二看日志。docker logs redis-demo如果有网络相关错误直接搜索错误关键字基本上能找到答案。第三查看容器IP和网络模式。如果不做任何网络配置Redis容器默认在bridge网络上宿主机通过-p映射访问即可。有些同学为了让Redis连MySQL自己创建了自定义网络却忘了-p不能和自定义网络同时生效于容器启动命令的场景导致宿主机永远连不上Redis。我的建议是开发环境一律用-p映射多容器互通靠Docker Compose的自定义网络不要手工混用。还有一个最容易被忽略的点Docker Desktop重启后之前那些没有设置自动重启的Redis容器不会自己起来。启动Redis时加上--restart unless-stopped能省下一半的运维事故。5. 从单机到主从用Docker Compose编排一主一从5.1 为什么要多一个从节点单机Redis能跑通只是第一步。实际项目里Redis承担缓存、分布式锁、临时数据存储这些职责一旦单节点挂了缓存全部穿透到数据库很容易把服务打垮。最轻量级的容灾方案就是主从复制一个主节点负责写一个或多个从节点负责同步数据读请求可以分散到从节点。这种方案还有个额外好处备份的时候可以从从节点导出数据不影响主节点性能。做分布式锁之类的场景主从也能提供一些基础保障但要真正保证安全得配合红锁或哨兵这里先不展开。主从本身不是高可用方案主节点挂掉后从节点不会自动顶上需要哨兵或人工介入。但对于个人项目、中小型内部系统一主一从的内存型Redis已经足够爽了。5.2 目录结构和配置文件先写好用Docker Compose管理主从最清晰。先建一个目录比如redis-clusterredis-cluster/ ├── docker-compose.yml ├── master.conf └── slave.confmaster.confbind 0.0.0.0 protected-mode yes port 6379 daemonize no appendonly yes requirepass 123456slave.confbind 0.0.0.0 protected-mode yes port 6379 daemonize no appendonly yes requirepass 123456 masterauth 123456 replicaof redis-master 6379关键点是slave.conf里必须有两行masterauth填主节点的密码replicaof指定主节点的服务名和端口。Docker Compose默认会创建一个网络服务名redis-master在容器内可以直接当作DNS解析。docker-compose.ymlservices: redis-master: image: redis:7 container_name: redis-master ports: - 6379:6379 volumes: - ./master.conf:/usr/local/etc/redis/redis.conf command: [redis-server, /usr/local/etc/redis/redis.conf] redis-slave: image: redis:7 container_name: redis-slave ports: - 6380:6379 depends_on: - redis-master volumes: - ./slave.conf:/usr/local/etc/redis/redis.conf command: [redis-server, /usr/local/etc/redis/redis.conf]从节点的ports写6380:6379意思是宿主机用6380访问从节点。容器内部从节点依然监听6379和主节点不冲突。5.3 启动并验证复制状态在redis-cluster目录下执行docker compose up -d docker compose ps两条命令都正常后分别看主从的复制信息docker exec -it redis-master redis-cli -a 123456 info replication docker exec -it redis-slave redis-cli -a 123456 info replication主节点预期输出role:master connected_slaves:1从节点预期输出role:replica master_host:redis-master master_link_status:up如果master_link_status是down说明同步没建立。接着实测数据复制docker exec -it redis-master redis-cli -a 123456 set hello world docker exec -it redis-slave redis-cli -a 123456 get hello主节点写入hello从节点能读到world主从复制链路就通了。5.4 主从常见两个坑NOAUTH和bind限制第一次搭主从时我踩过最深的坑就是NOAUTH Authentication required。现象是主节点能正常写从节点一直连不上docker logs redis-slave刷出来MASTER - REPLICA sync started Error reply to MASTERAUTH: NOAUTH Authentication required.原因很简单主节点设置了requirepass 123456但从节点没有配置masterauth 123456所以每次握手都被主节点拒绝。解决办法就是在slave.conf里补上masterauth。另一个坑是bind限制。如果主节点的配置里只写了bind 127.0.0.1从节点在容器网络里访问redis-master:6379时会发现主节点只监听回环地址连接直接被拒绝。我在3.2节特意强调Docker环境要把bind设为0.0.0.0就是这个原因。这两个问题都不难但报错信息很有迷惑性第一次遇到可能花掉一下午。6. 容器跑起来之后的日常运维与备份6.1 日志、资源占用以及给Redis限量Redis启动后第一时间看日志docker logs -f redis-demo-f是持续跟踪日志输出CtrlC退出查看。启动阶段有没有加载配置文件、主从同步有没有异常都能在日志里看到。资源占用用docker stats它像个任务管理器实时显示每个容器的CPU、内存、网络IO。如果Redis内存不设上限一旦业务里写入大量缓存它可能会把宿主机内存吃光。开发环境下可以在启动命令里加上资源限制docker run -d --name redis-limited --memory 512m --cpus 1 redis:7更优雅的做法是在配置文件里设maxmemory让Redis自己控制内存超了就走maxmemory-policy指定的淘汰策略。allkeys-lru是常用策略适合缓存场景如果只是做分布式锁和临时状态存储建议用noeviction宁可报错也不丢数据。6.2 可视化客户端怎么连、连不上怎么查命令行用多了总想偷懒可视化客户端确实更适合日常看监控和key分布。市面上的选择很多客户端特点Another Redis Desktop Manager轻量、跨平台、免费Redis Insight官方出品功能全面自带分析和集群管理redis-cli命令行排查最快连接参数就是三件套host填宿主机IPport填映射出来的宿主机端口password填配置里的密码。比如本机Docker映射的Redishost填127.0.0.1、port填6379。连不上的时候照着这个顺序查docker ps确认容器是Up状态docker logs redis-demo看有没有报错宿主机直接curl或者用nc测端口通不通确认不是防火墙拦截如果Redis运行在云服务器上还要检查云厂商的安全组是否放行了6379端口。这个坑特别隐蔽本地客户端死活连接超时容器明明在跑最后发现是安全组没开。6.3 备份Redis数据别只靠Docker的volume挂载volume能解决容器删除的数据丢失问题但解决不了整块磁盘损坏和误删容器卷的问题。备份是另一回事。Redis持久化文件就两种RDB快照和AOF日志。日常备份最简单的做法是直接打包volume比如把redis-data卷导出成一个tar包docker run --rm -v redis-data:/data -v $(pwd):/backup alpine tar czf /backup/redis-data.tar.gz -C /data .这条命令会启动一个临时Alpine容器把redis-data卷的数据打包到当前目录。也可以趁Redis运行中用客户端触发一次持久化docker exec -it redis-demo redis-cli -a 123456 --rdb /tmp/dump.rdb但它写的是容器内的临时路径还是要把文件拷贝出来docker cp redis-demo:/tmp/dump.rdb ./dump.rdb恢复的时候先把容器停掉把备份文件放到正确的persist目录再启动容器。千万别在Redis运行的时候直接往数据目录塞文件文件损坏概率极高。6.4 顺手把缓存治理和容器清理做了Redis做中间件用久了最大的敌人不是性能而是缓存本身。Key设计不合理、value过大、过期时间设成永久慢慢把内存拖垮。容器环境下我见过太多人把所有数据塞进Redis然后看着内存报警。缓存治理的基础操作就是给Redis设置淘汰策略。6.1里提到的maxmemory-policy allkeys-lru适合大部分缓存场景内存满了自动淘汰最久没用的Key。同时要在业务层给Key加统一的过期时间别指望兜底策略扛住所有脏数据。另外容器体积会随着镜像的更新越来越大。定期清理一下没用的容器和镜像能避免磁盘爆掉docker container prune docker image prune这些命令不会影响正在运行的容器但会清掉已停止的容器和悬空镜像。如果要强制清空所有未使用资源用docker system prune -a执行前想清楚Redis的volume如果没有挂载宿主机路径会连数据一起删掉。最后说一点我自己的习惯。用Docker跑Redis踩过的最大跟头就是一开始只图能启动密码不设、数据不挂volume、配置不持久化结果一次docker system prune把开发环境的缓存全清空了。现在我的做法是每个项目第一次拉Redis容器时先把redis.conf、命名卷、密码三类事情配齐再考虑端口和主从。你按这篇文章的顺序先把最小命令跑通然后立刻补上持久化和密码再研究主从后面基本不会有大坑。如果你在Windows上还卡在Docker Desktop启动阶段别急着继续往下折腾容器回头把虚拟化那一章看完要先让舞台搭起来演员才有地方施展。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表