目录
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,甚至利用它入侵主机。因此:
- 不需要从外部连接时,不要使用
-p;需要时只绑定到127.0.0.1。 - 设置密码:
$ 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 1 | 1 小时内至少有 1 个 key 发生变更,就保存 |
300 100 | 5 分钟内至少有 100 个 key 发生变更,就保存 |
60 10000 | 1 分钟内至少有 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*用于确认配置文件已生效:67108864bytes 就是 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日