# 需求
  • A:master,不加密(普通端口 6379)
  • B:slave,从 A 同步,不加密(端口 16379),同时监听 TLS 加密端口 16380
  • C:slave,从 B 同步,通过 TLS(端口 16380)

部署

生成自签名TLS证书 使用openssl生成自签名证书

mkdir -p certs && cd certs

# 创建 CA
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt -subj "/CN=Redis-CA"

# 创建 server key 和证书签名请求(CSR
openssl genrsa -out redis.key 2048
openssl req -new -key redis.key -out redis.csr -subj "/CN=redis-server"

# 使用 CA 签发 server 证书
openssl x509 -req -in redis.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out redis.crt -days 3650 -sha256

# 权限设置
chmod 644 redis.crt redis.key ca.crt

CA相关证书

  • ca.key:CA的私钥,用来签发证书(给redis.crt签名)
  • ca.crt:CA的公钥证书,用来让客户端验证某个证书(比如redis.crt)是不是CA签发的,客户端拿redis.crt来验证时,会用这个公钥解签名。

Redis服务器相关证书

  • redis.key:Redis 服务端的私钥,用来解密客户端发来的数据、以及在 TLS 握手时证明”我是 Redis 服务端”。
  • redis.csr:证书签名请求(Certificate Signing Request)包含 Redis 服务器的公钥 + 服务器身份信息(域名、组织等),生成 CSR 的目的是交给 CA 签名,生成一个正式证书。
  • redis.crt:Redis 服务器的证书

Redis 配置文件

port 6379
tls-port 6380
tls-cert-file /certs/redis.crt
tls-key-file /certs/redis.key
tls-ca-cert-file /certs/ca.crt
tls-auth-clients no

# 作为slave,同步redis-a
replicaof redis-a 6379
# 关闭非加密 TCP 端口
port 0

tls-port 6380
tls-cert-file /certs/redis.crt
tls-key-file /certs/redis.key
tls-ca-cert-file /certs/ca.crt
# 单向TLS
tls-auth-clients no

# 从加密端口同步 redis-b
replicaof redis-b 6380
# 允许主从复制也走 TLS 加密通道
tls-replication yes

docker-compose

启动三个redis容器

redis-a作为master,暴露容器端口6379到6379

redis-b作为slave,暴露容器端口6379到16379,容器端口6380到16380(TLS)

redis-c作为slave,暴露容器端口6380到26380(TLS)

version: '3.8'

services:
redis-a:
image: redis:latest
container_name: redis-a
ports:
- "6379:6379"
volumes:
- ./data/redis-a:/data
command: ["redis-server", "--port", "6379"]
networks:
- redis-net

redis-b:
image: redis:latest
container_name: redis-b
ports:
- "16379:6379"
- "16380:6380"
volumes:
- ./data/redis-b:/data
- ./certs:/certs
- ./redis-b.conf:/usr/local/etc/redis/redis.conf
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
networks:
- redis-net
depends_on:
- redis-a

redis-c:
image: redis:latest
container_name: redis-c
ports:
- "26380:6380"
volumes:
- ./data/redis-c:/data
- ./certs:/certs
- ./redis-b.conf:/usr/local/etc/redis/redis.conf
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
networks:
- redis-net
depends_on:
- redis-b


networks:
redis-net:
driver: bridge

验证

查看主从状态

目标:

  • B 是 A 的从节点
  • C 是 B 的从节点(通过 TLS)

查看 Redis B 是否同步 Redis A(非 TLS)

可以看到b以a作为master,master_link_status:up 说明同步正常

root@liyixiong01:~/redis# docker exec -it redis-b redis-cli -p 6379 info replication
# Replication
role:slave
master_host:redis-a
master_port:6379
master_link_status:up

查看 Redis C 是否通过 TLS 同步 Redis B

root@liyixiong01:~/redis# docker exec -it redis-c redis-cli   --tls   --cert /certs/redis.crt   --key /certs/redis.key   --cacert /certs/ca.crt   -p 6380 info replication
# Replication
role:slave
master_host:redis-b
master_port:6380
master_link_status:up

验证数据同步链路是否真实工作

在 Redis A 写入数据

root@liyixiong01:~/redis# docker exec -it redis-a redis-cli -p 6379 set hello world
OK

在 Redis B 查看是否能读到(非TLS)

root@liyixiong01:~/redis# docker exec -it redis-b redis-cli -p 6379 get hello
\"world"

在 Redis C 查看是否能读到(TLS)

root@liyixiong01:~/redis# docker exec -it redis-c redis-cli \
--tls \
--cert /certs/redis.crt \
--key /certs/redis.key \
--cacert /certs/ca.crt \
-p 6380 get hello
"world"