目录

Docker Redis 教程:配置密码、保存数据与连接

Redis 是一种将数据存储在内存中的键值数据库,常用于缓存、Session 存储、计数器和队列。使用 Docker 运行只需几秒钟。

基本运行

$ docker run -d --name redis -p 127.0.0.1:6379:6379 redis:8-alpine
Unable to find image 'redis:8-alpine' locally
8-alpine: Pulling from library/redis
Digest: sha256:3811787313eba226a2ef38658c6ccb91cd5e110edc89c37767de373120a0e5a0
Status: Downloaded newer image for redis:8-alpine
6fbb2effcf1bc874eda1064575153984b6223fd6de15ac2452eae0bbf71a74f1

$ docker exec redis redis-cli PING
PONG

$ docker exec redis redis-cli SET greeting hello
OK

$ docker exec redis redis-cli GET greeting
hello

$ docker exec redis redis-cli SET session:abc "user42" EX 60
OK

$ docker exec redis redis-cli TTL session:abc
60

$ docker exec redis redis-server --version
Redis server v=8.10.2 sha=00000000:1 malloc=jemalloc-5.3.0 bits=64 build=6583f6419e33bdeb

$ docker rm -f redis
redis
  • -p 127.0.0.1:6379:6379:只允许本机访问。
  • 容器中自带 redis-cli,可以直接运行命令。
  • SET ... EX 60 用于设置 60 秒后自动过期,TTL 用于查看剩余秒数,常用于 Session 和缓存。

交互式使用时,运行 docker exec -it redis redis-cli,会出现 127.0.0.1:6379> 提示符。输入命令后按 Enter,输入 exit 退出。

设置密码

Redis 默认没有密码。只要端口对外开放,任何人都能读写 Redis,甚至利用它入侵主机。因此:

  1. 不需要从外部连接时,不要使用 -p;需要时只绑定到 127.0.0.1。
  2. 设置密码:
$ docker run -d --name redis redis:8-alpine redis-server --requirepass "change-me"
8dbd1f84d2541f264d93555142cb65f6497e9635111ff4f9544258516e06a0e2

$ docker exec redis redis-cli GET greeting
NOAUTH Authentication required.


$ docker exec redis redis-cli -a "change-me" PING
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
PONG

$ docker exec redis redis-cli -a "change-me" --no-auth-warning PING
PONG

$ docker exec -e REDISCLI_AUTH=change-me redis redis-cli PING
PONG

$ docker rm -f redis
redis
  • 没有密码时会得到 NOAUTH Authentication required.。
  • 使用 -a 传入密码可以执行命令,但会出现警告,因为密码会显示在进程列表中。--no-auth-warning 只会隐藏警告。
  • 更好的做法是使用环境变量 REDISCLI_AUTH 传入密码,redis-cli 会自动使用该密码,也不会显示警告。

应用程序的连接字符串(用户名留空):

redis://:change-me@redis:6379/0

最后的 /0 是数据库编号(0~15)。

数据持久化

Redis 的数据存储在内存中。要将数据保存到磁盘,有两种方式:RDB 快照和 AOF 日志。官方镜像默认只启用 RDB,文件存放在容器的 /data 中,因此需要挂载 Volume。

实测:RDB 不会即时保存

$ docker run -d --name redis -v redis_data:/data redis:8-alpine
882983e53f8e000fa65faaf8d71bbcbeb57192401b1854621172ce2df95c29a6

$ docker exec redis redis-cli SET visits 100
OK

$ docker rm -f redis
redis

$ docker run -d --name redis -v redis_data:/data redis:8-alpine
5ad1473152a6eafdfdb33df64f68355c73e454f10e6bc135688f7c51686bb059

$ docker exec redis redis-cli GET visits


$ docker exec redis redis-cli CONFIG GET save
save
3600 1 300 100 60 10000

明明挂载了 Volume,执行 docker rm -f 并重新创建容器后,visits 却是空的。CONFIG GET save 显示默认保存条件 3600 1 300 100 60 10000,含义如下:

条件含义
3600 11 小时内至少有 1 个 key 发生变更,就保存
300 1005 分钟内至少有 100 个 key 发生变更,就保存
60 100001 分钟内至少有 10000 个 key 发生变更,就保存

只修改了 1 个 key,需要等 1 小时才会保存。docker rm -f 会直接使用 SIGKILL 终止 Redis,来不及保存。

改用 docker stop 正常停止:

$ docker exec redis redis-cli SET visits 100
OK

$ docker stop redis
redis

$ docker logs redis 2>&1 | tail -n 5
1:M 13 Oct 2026 00:57:09.620 * User requested shutdown...
1:M 13 Oct 2026 00:57:09.620 * Saving the final RDB snapshot before exiting.
1:M 13 Oct 2026 00:57:09.621 * BGSAVE done, 1 keys saved, 0 keys skipped, 104 bytes written.
1:M 13 Oct 2026 00:57:09.623 * DB saved on disk
1:M 13 Oct 2026 00:57:09.623 # Redis is now ready to exit, bye bye...

$ docker start redis
redis

$ docker exec redis redis-cli GET visits
100

$ docker exec redis ls -l /data
total 4
-rw-------    1 redis    redis          104 Oct 13 00:57 dump.rdb

$ docker rm -f redis
redis

$ docker volume rm redis_data
redis_data

docker stop 会发送 SIGTERM,Redis 在退出前执行 Saving the final RDB snapshot before exiting,因此数据得以保存。所以:

  • 正常停止(docker stop、docker compose down、主机正常关机)不会丢失数据。
  • 发生崩溃、断电、执行 docker rm -f 或因内存不足被系统终止时,会丢失上次快照之后的数据。

AOF:记录每次写入

需要更可靠地保存数据时,启用 AOF(Append Only File),每条写入命令都会被记录:

$ docker run -d --name redis -v redis_data:/data redis:8-alpine redis-server --appendonly yes
aaac5c67a222018db886e0f3a3306841ec4bba7e8ae0b4b4eca71dc5cede91c9

$ docker exec redis redis-cli SET visits 41
OK

$ docker exec redis redis-cli INCR visits
42

$ docker rm -f redis
redis

$ docker run -d --name redis -v redis_data:/data redis:8-alpine redis-server --appendonly yes
1c880b5c2e8ef54b65baaa1fd99b1b9c976eb42f2d9c52f1eb9188eaeda955e4

$ docker exec redis redis-cli GET visits
42

$ docker exec redis ls /data/appendonlydir
appendonly.aof.1.base.rdb
appendonly.aof.1.incr.aof
appendonly.aof.manifest

$ docker rm -f redis
redis

$ docker volume rm redis_data
redis_data

即使使用 docker rm -f 强制删除,重新创建后 visits 仍然是 42。/data/appendonlydir 中存放 AOF 文件:base.rdb 是基础快照,incr.aof 记录之后的每次写入,manifest 记录文件清单。

方式优点缺点
RDB(默认)文件小,重启时加载快异常退出时可能丢失上次快照之后的数据
AOF默认每秒写入磁盘一次,最多丢失约 1 秒的数据文件较大,写入量大时磁盘负担较重
不保存速度最快重启后数据全部消失,只适用于纯缓存

纯缓存用途可以完全关闭保存:redis-server --save "" --appendonly no。

使用配置文件与内存上限

参数较多时,可以改用配置文件。redis-demo/redis.conf:

requirepass change-me
appendonly yes
maxmemory 64mb
maxmemory-policy allkeys-lru

用作缓存时,一定要设置 maxmemory,否则 Redis 会持续占用内存,直到主机内存耗尽。达到上限后,会根据 maxmemory-policy 处理:

策略行为
noeviction默认值,拒绝新的写入并返回错误
allkeys-lru从所有 key 中淘汰最久未使用的,最常用于缓存
volatile-lru只淘汰设置了过期时间的 key
allkeys-lfu淘汰使用频率最低的 key

实测:写入超过上限的数据

使用 Redis 内置的 redis-benchmark 写入 30 万条、每条 500 bytes(约 150 MB)的数据,远超 64 MB 的上限:

$ docker run -d --name redis -v "$(pwd)/redis.conf:/usr/local/etc/redis/redis.conf:ro" -v redis_data:/data redis:8-alpine redis-server /usr/local/etc/redis/redis.conf
af187c21e0d6ecb0e9a0299200a6d866dc605d92c715e49df8a7abd850107040

$ docker exec -e REDISCLI_AUTH=change-me redis redis-cli CONFIG GET maxmemory*
maxmemory
67108864
maxmemory-clients
0
maxmemory-eviction-tenacity
10
maxmemory-samples
5
maxmemory-policy
allkeys-lru

$ docker exec redis redis-benchmark -a change-me -t set -n 300000 -r 300000 -d 500 -q
SET: 31043.05 requests per second, p50=0.903 msec

$ docker exec -e REDISCLI_AUTH=change-me redis redis-cli INFO memory | grep -E "^(used_memory_human|maxmemory_human|maxmemory_policy)"
used_memory_human:63.89M
maxmemory_human:64.00M
maxmemory_policy:allkeys-lru

$ docker exec -e REDISCLI_AUTH=change-me redis redis-cli INFO stats | grep evicted_keys
evicted_keys:95511

$ docker exec -e REDISCLI_AUTH=change-me redis redis-cli DBSIZE
115038

Windows 中的写法(点击选项卡切换):

docker run -d --name redis -v "$(pwd)/redis.conf:/usr/local/etc/redis/redis.conf:ro" -v redis_data:/data redis:8-alpine redis-server /usr/local/etc/redis/redis.conf
docker run -d --name redis -v "${PWD}/redis.conf:/usr/local/etc/redis/redis.conf:ro" -v redis_data:/data redis:8-alpine redis-server /usr/local/etc/redis/redis.conf
docker run -d --name redis -v "%cd%/redis.conf:/usr/local/etc/redis/redis.conf:ro" -v redis_data:/data redis:8-alpine redis-server /usr/local/etc/redis/redis.conf
  • CONFIG GET maxmemory* 用于确认配置文件已生效:67108864 bytes 就是 64 MB,策略为 allkeys-lru。
  • 写入后,内存用量停留在 63.89M,没有超过上限。
  • evicted_keys:95511:有 9 万多个 key 被自动淘汰,最后剩下约 11.5 万个 key。

将相同情况改为 noeviction:

$ docker exec -e REDISCLI_AUTH=change-me redis redis-cli CONFIG SET maxmemory-policy noeviction
OK

$ docker exec -e REDISCLI_AUTH=change-me redis sh -c 'head -c 2000000 /dev/zero | tr "\\0" x | redis-cli -x SET big-value'
OOM command not allowed when used memory > 'maxmemory'.


$ docker exec -e REDISCLI_AUTH=change-me redis redis-cli GET greeting

内存已满,写入一个 2 MB 的值时会得到 OOM command not allowed when used memory > 'maxmemory',应用程序就会出错。因此,纯缓存应使用 allkeys-lru;如果 Redis 中存储的是不能丢失的数据(例如队列),则使用 noeviction 并监控内存用量。

在 Compose 中搭配应用程序

创建一个 Flask 计数器,每次收到请求就将 Redis 中的 visits 加 1:

redis-demo/
├── compose.yaml
├── .env
└── app/
    ├── app.py
    ├── requirements.txt
    └── Dockerfile

app/app.py:

import os

import redis
from flask import Flask

app = Flask(__name__)
r = redis.Redis.from_url(os.environ["REDIS_URL"], decode_responses=True)


@app.get("/")
def index():
    visits = r.incr("visits")
    return {"message": "Hello from Flask + Redis", "visits": visits}

app/requirements.txt:

flask==3.1.*
gunicorn==23.*
redis==6.*

app/Dockerfile(写法说明见 Python 应用):

FROM python:3.14-slim
ENV PYTHONUNBUFFERED=1 PIP_NO_CACHE_DIR=1
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
USER nobody
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

.env:

REDIS_PASSWORD=change-this-password

compose.yaml:

services:
  app:
    build: ./app
    ports:
      - "8000:8000"
    environment:
      REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0
    depends_on:
      redis:
        condition: service_healthy

  redis:
    image: redis:8-alpine
    command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}", "--appendonly", "yes"]
    environment:
      REDISCLI_AUTH: ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep -q PONG"]
      interval: 5s
      retries: 10
    restart: unless-stopped

volumes:
  redis_data:
配置说明
REDIS_URL 中的 @redis:6379使用服务名称连接
command 中的 ${REDIS_PASSWORD}Compose 会从 .env 替换为实际密码
REDISCLI_AUTH让容器中的 redis-cli(包括健康检查)自动使用密码
redis 没有 ports只有 app 需要连接,因此不对外开放
$ docker compose up -d --build

[+] Building 0.3s (12/12) FINISHED
 => [internal] load local bake definitions                                                                                                       0.0s
 => => reading from stdin 486B                                                                                                                   0.0s
 => [internal] load build definition from Dockerfile                                                                                             0.0s
 => => transferring dockerfile: 263B                                                                                                             0.0s
 => [internal] load metadata for docker.io/library/python:3.14-slim                                                                              0.0s
 => [internal] load .dockerignore                                                                                                                0.0s
 => => transferring context: 2B                                                                                                                  0.0s
 => [1/5] FROM docker.io/library/python:3.14-slim@sha256:a2b82f3c48559aa0a8446d9af49826b6e2b2016f4cd2afabfe6013ec53729170                        0.0s
 => => resolve docker.io/library/python:3.14-slim@sha256:a2b82f3c48559aa0a8446d9af49826b6e2b2016f4cd2afabfe6013ec53729170                        0.0s
 => [internal] load build context                                                                                                                0.0s
 => => transferring context: 93B                                                                                                                 0.0s
 => CACHED [2/5] WORKDIR /app                                                                                                                    0.0s
 => CACHED [3/5] COPY requirements.txt .                                                                                                         0.0s
 => CACHED [4/5] RUN pip install -r requirements.txt                                                                                             0.0s
 => CACHED [5/5] COPY . .                                                                                                                        0.0s
 => exporting to image                                                                                                                           0.0s
 => => exporting layers                                                                                                                          0.0s
 => => exporting manifest sha256:2cb1f769137117a44dde49bfb2f8551a8ce989fe8bd0a72696ba37987c29fd13                                                0.0s
 => => exporting config sha256:88373d2af6030b965f8b4e878d871e906738cd9194ec77bd007c6bbbace7c1b9                                                  0.0s
 => => exporting attestation manifest sha256:c8f570c26323c3e08476544296d44ed0e159d27d9f25b86bf879cd08c6b6e186                                    0.0s
 => => exporting manifest list sha256:46bd2450b425a935481fb6ef8567c915f5543996f4e35018bdb955ecf858b361                                           0.0s
 => => naming to docker.io/library/redis-demo-app:latest                                                                                         0.0s
 => => unpacking to docker.io/library/redis-demo-app:latest                                                                                      0.0s
 => resolving provenance for metadata file                                                                                                       0.0s
[+] up 5/5
 ✔ Image redis-demo-app         Built                                                                                                             0.4s
 ✔ Network redis-demo_default   Created                                                                                                           0.0s
 ✔ Volume redis-demo_redis_data Created                                                                                                           0.0s
 ✔ Container redis-demo-redis-1 Healthy                                                                                                           5.8s
 ✔ Container redis-demo-app-1   Started                                                                                                           5.9s

$ curl -s http://localhost:8000/
{"message":"Hello from Flask + Redis","visits":1}

$ curl -s http://localhost:8000/
{"message":"Hello from Flask + Redis","visits":2}

$ curl -s http://localhost:8000/
{"message":"Hello from Flask + Redis","visits":3}

Redis 变为 Healthy 后,app 才会启动。每次请求都会让 visits 加 1。由于启用了 AOF 并挂载了 Volume,重建所有容器后计数仍会延续:

$ docker compose up -d --force-recreate
[+] up 2/2
 ✔ Container redis-demo-redis-1 Healthy                                                                                                           6.1s
 ✔ Container redis-demo-app-1   Started                                                                                                           6.2s

$ curl -s http://localhost:8000/
{"message":"Hello from Flask + Redis","visits":4}

为什么健康检查要 grep PONG

网上常见的写法是 test: ["CMD", "redis-cli", "ping"]。实测它的退出代码:

$ docker compose exec redis redis-cli ping; echo "exit code: $?"
PONG
exit code: 0

$ docker compose exec -e REDISCLI_AUTH=wrong redis redis-cli ping; echo "exit code: $?"
AUTH failed: WRONGPASS invalid username-password pair or user is disabled.
NOAUTH Authentication required.

exit code: 0

$ docker compose exec -e REDISCLI_AUTH=wrong redis sh -c "redis-cli ping | grep -q PONG"; echo "exit code: $?"
AUTH failed: WRONGPASS invalid username-password pair or user is disabled.
exit code: 1

密码错误时,redis-cli 会输出 NOAUTH Authentication required.,但退出代码仍然是 0。Docker 只根据退出代码判断健康状态,因此密码设错时健康检查仍会通过,app 启动后才会连接失败。加上 | grep -q PONG 后,只有确实收到 PONG 时退出代码才会是 0。

常用 redis-cli 命令

docker exec redis redis-cli INFO memory      # 记忆体使用
docker exec redis redis-cli INFO stats       # 统计,包含 evicted_keys
docker exec redis redis-cli DBSIZE           # key 的数量
docker exec redis redis-cli --scan --pattern 'session:*' | head
docker exec -it redis redis-cli MONITOR      # 即时显示所有指令(除错用,会影响效能,Ctrl+C 结束)

设置了密码时,在 docker exec 中加上 -e REDISCLI_AUTH=密码。

避免在生产环境使用 KEYS *,它会扫描所有 key 并阻塞 Redis。key 很多时可能卡住好几秒。请改用 SCAN(redis-cli --scan)。

想要通过图形界面浏览数据,可以使用官方的 Redis Insight(镜像 redis/redisinsight,默认端口 5540)。首次打开时需要阅读并同意其许可条款,然后添加连接,将主机填写为 Compose 的服务名称 redis,端口填写 6379,并输入密码即可。

Redis 许可与 Valkey

Redis 在 2024 年将许可改为 RSALv2/SSPL 这类非开源许可;从 Redis 8 开始,又加入 AGPLv3 作为选项。Linux 基金会在 2024 年推出了兼容的开源分支 Valkey(BSD 许可),命令和用法几乎相同:

$ docker run -d --name valkey valkey/valkey:8-alpine
Unable to find image 'valkey/valkey:8-alpine' locally
8-alpine: Pulling from valkey/valkey
Digest: sha256:081c2f5cb575efc901aa80ff9cdbd1ec6a301682fd35e1ebb4b0990a4a4a8507
Status: Downloaded newer image for valkey/valkey:8-alpine
3e7385b8f0d22a999ccf9306938e178c8f82bb4bc1ef9d304bd307917a890087

$ docker exec valkey valkey-cli PING
PONG

$ docker exec valkey redis-cli SET greeting hello
OK

$ docker exec valkey valkey-server --version
Valkey server v=8.1.10 sha=00000000:1 malloc=jemalloc-5.3.0 bits=64 build=fd3b186b1408478b

$ docker rm -f valkey
valkey

Valkey 镜像同时提供 valkey-cli 和兼容的 redis-cli,应用程序的 Redis 库也可以直接连接。一般情况下,自行使用 Redis 不受许可变更影响;如果要将 Redis 作为服务提供给他人,请自行确认许可条款。

重点回顾

  • Redis 默认没有密码,使用 --requirepass 设置密码,使用 REDISCLI_AUTH 传入密码。
  • RDB 不会即时保存;需要可靠保存时,启用 --appendonly yes。
  • 用作缓存时,设置 maxmemory 和 allkeys-lru。
  • 健康检查使用 redis-cli ping | grep -q PONG。

动手练习

练习 1:使用 docker exec redis redis-cli 设置一个 30 秒后过期的 key,并查看剩余时间。

答案
docker exec redis redis-cli SET temp hello EX 30
docker exec redis redis-cli TTL temp

设置了密码时,加上 -e REDISCLI_AUTH=密码。

常见问题

Redis 一定要设置密码吗?

只要有可能被其他人连接,就一定要设置。最佳做法是不对外开放端口,并设置密码。

Redis 重启后数据不见了?

默认情况下,RDB 只会在达到保存条件或正常停止时写入磁盘;使用 docker rm -f 或发生崩溃时会丢失数据。需要可靠保存时,请启用 AOF。

Valkey 和 Redis 可以互换吗?

Valkey 是 Redis 的开源分支,命令和协议兼容,应用程序通常不需要修改。

更新于 2026年10月14日