$kernelink route --hydrate --safe

页面加载 /
跳到正文
auth://account/session

登录工作区

使用 Emlog 账户继续访问你的内容与互动记录。

忘记密码?

打开 Emlog 原生登录页

10.md
workspace / posts
~/posts/10.md 阅读中

Docker 部署 Redis:密码、持久化和启动失败排查

Redis 容器化最容易出的问题不是装不上,而是装上了没密码、重启丢数据、或者配置根本没被加载。这篇按顺序把这几件事定下来:密码、持久化、内存上限,以及出错时先看哪里。

一、镜像和目录

docker pull redis:7.2
sudo mkdir -p /data/redis/{conf,data}

官方镜像默认以 redis 用户(uid 999)运行,/data 要能让它写:

sudo chown -R 999:999 /data/redis/data

宿主机目录属主不改成 999,后面要么存 RDB 失败,要么直接起不来。

二、先起一个空壳验证

先在没有任何配置的情况下跑一遍,确认镜像和端口没问题:

docker run -d --name redis-test -p 6379:6379 redis:7.2
docker exec redis-test redis-cli ping

返回 PONG 就说明镜像正常。验证完删掉,正式部署要带配置文件和密码:

docker rm -f redis-test

三、redis.conf

/data/redis/conf/redis.conf:

bind 0.0.0.0
protected-mode yes
port 6379
timeout 0
tcp-keepalive 300

requirepass 换成你的强密码

daemonize no
loglevel notice
logfile ""

dir /data

# RDB
save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb

# AOF
appendonly yes
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 内存
maxmemory 512mb
maxmemory-policy allkeys-lru

几个参数的作用:

参数 说明
bind 0.0.0.0 容器内监听所有地址,宿主机能否访问由 -p 决定
protected-mode yes 没密码时拒绝外部连接,有密码时保留也没问题
daemonize no 容器里必须前台运行,写 yes 会启动即退出
dir /data RDB 和 AOF 都写这里,必须挂卷
appendonly yes 开 AOF,重启不丢最近写入
maxmemory + policy 防止把宿主机内存吃光

requirepass 写在配置文件里,不要写在 docker run 的 --requirepass 参数上,否则 docker inspect 和 ps 里都能直接看到。

四、docker run 或 compose

docker run 版本:

docker run -d --name redis \
  -p 6379:6379 \
  -v /data/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf:ro \
  -v /data/redis/data:/data \
  -e TZ=Asia/Shanghai \
  --restart=always \
  redis:7.2 redis-server /usr/local/etc/redis/redis.conf

compose 版本:

services:
  redis:
    image: redis:7.2
    container_name: redis
    restart: always
    ports:
      - "6379:6379"
    environment:
      TZ: Asia/Shanghai
      REDIS_PASSWORD: 换成你的强密码
    command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
    volumes:
      - /data/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf:ro
      - /data/redis/data:/data
    healthcheck:
      test: ["CMD-SHELL", "redis-cli --no-auth-warning -a \"$$REDIS_PASSWORD\" ping | grep -q PONG"]
      interval: 30s
      timeout: 5s
      retries: 3

两处说明:

  1. healthcheck 里的 $$ 是 compose 的转义,最终传给容器的是 $REDIS_PASSWORD,由 shell 展开。写成单个 $ 会被 compose 在解析阶段替换掉,密码就丢了。
  2. 配置文件里已经写了 requirepass,环境变量 REDIS_PASSWORD 只是为了给健康检查用,两边的值要一致,改密码时一起改。

command 一定要带配置文件路径。不带的话镜像会用自己的默认配置启动,requirepass、appendonly 全部不生效,看起来容器起得好好的,实际是个没有密码的空库。

五、验证

# 不带密码访问,应该被拒绝
docker exec redis redis-cli ping
# NOAUTH Authentication required.

# 带密码
docker exec redis redis-cli --no-auth-warning -a "$(grep requirepass /data/redis/conf/redis.conf | awk '{print $2}')" ping

# 确认配置真的加载了
docker exec redis redis-cli --no-auth-warning -a '密码' CONFIG GET appendonly
docker exec redis redis-cli --no-auth-warning -a '密码' CONFIG GET maxmemory

# 确认持久化文件
ls -lh /data/redis/data

CONFIG GET appendonly 返回 yes,/data/redis/data 下能看到 dump.rdb 或 appendonlydir,才说明配置生效、持久化在工作。

六、持久化和备份

Redis 有两种持久化:

方式 原理 丢数据窗口 开销
RDB 定时 fork 子进程写快照 两次快照之间 fork 时内存翻倍风险
AOF 追加写命令,everysec 每秒刷盘 最多 1 秒 磁盘 IO 和文件体积

生产环境一般两个都开:AOF 保证少丢,RDB 方便搬走做备份。

备份:

# 触发一次快照,然后复制文件
docker exec redis redis-cli --no-auth-warning -a '密码' BGSAVE
sleep 2
docker exec redis redis-cli --no-auth-warning -a '密码' LASTSAVE
sudo cp /data/redis/data/dump.rdb /backup/redis-$(date +%F).rdb

BGSAVE 是异步的,复制前用 LASTSAVE 确认时间戳已经更新。

不落盘直接拉一份也可以,适合数据量不大的场景:

docker exec redis redis-cli --no-auth-warning -a '密码' --rdb /tmp/backup.rdb
docker cp redis:/tmp/backup.rdb ./backup.rdb

恢复就是把 dump.rdb 放回 /data,重启容器。注意恢复前先停 Redis,否则可能被正在运行的实例覆盖。

七、常见报错

现象 原因 处理
NOAUTH Authentication required 客户端没带密码 客户端配置密码,或 AUTH 密码
ERR Client sent AUTH, but no password is set 配置没加载,服务端还是无密码状态 检查 command 是否带了配置文件路径,重启容器
容器启动后立刻退出,日志只有一两行 conf 里写了 daemonize yes 改成 no
MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk 磁盘满、目录没权限、或 overcommit 限制 看磁盘和 /data 属主,处理完执行 CONFIG SET stop-writes-on-bgsave-error no 只是临时放行
日志 WARNING overcommit_memory is set to 0 内核内存策略,fork 快照可能失败 宿主机 sysctl -w vm.overcommit_memory=1,写进 /etc/sysctl.d/ 持久化
WARNING The TCP backlog setting of 511 cannot be enforced somaxconn 太小 sysctl -w net.core.somaxconn=1024
Permission denied 写 dump.rdb /data 属主不是 999 chown -R 999:999 /data/redis/data
Bad directive or wrong number of arguments conf 语法错,常见于行尾多余空格或复制时带了中文引号 按报错行号改
重启后数据全没了 没挂 /data,或者没开 AOF/RDB 挂卷并确认 dir /data
READONLY You can't write against a read only replica 配置里残留 replicaof 删掉该配置重启

八、几条限制

  • 单机 Redis 没有高可用,主库挂了就是不可用。要主从或哨兵,是另一套部署,别指望 restart: always 顶上。
  • maxmemory-policy allkeys-lru 会淘汰任何键,包括没设过期时间的。做缓存可以,当存储用要换成 noeviction 并密切盯内存。
  • appendfsync everysec 是性能和数据安全之间的折中,要求零丢失得用 always,代价是每次写都等磁盘。

访问控制上还有一条:-p 6379:6379 会把 Redis 直接暴露到宿主机所有网卡。只给内网用的服务,端口映射写成 -p 127.0.0.1:6379:6379,让外面连不进来。

🤞 分享