全新的通过环境变量加载配置项的方式,添加init脚本,重新编写service脚本和redis-cli脚本

This commit is contained in:
chenqiang 2025-11-05 11:35:22 +08:00
parent 0e825e59d1
commit f009cd8413
15 changed files with 12997 additions and 76 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.envrc*
redis_password.enc*

152
README.md
View File

@ -1,46 +1,152 @@
# docker-redis # Redis 服务配置与管理
基于docker启动的redis服务 本目录包含了GuardDoc服务器使用的Redis服务配置与管理脚本基于Docker容器化部署支持环境变量配置、安全密码管理和便捷的服务控制。
## 用法 ## 目录结构
```sh
git clone https://git.wandoubaba.com/wandoubaba/docker-redis.git
cd docker-redis
./service start
``` ```
redis/
├── .gitignore # Git忽略文件
├── README.md # 本文档
├── conf/ # Redis配置文件目录仅包含版本配置文件供参考未实际使用
├── data/ # Redis数据持久化目录
├── docker-compose.yml # Docker Compose配置文件
├── init # 初始化脚本(环境配置、密码设置等)
├── redis-cli # Redis客户端连接工具
└── service # 服务控制脚本(启动、停止、重启等)
```
## 初始化
在首次使用前,需要运行初始化脚本来配置环境和安全设置:
```bash
cd /path/to/guarddoc-server/redis
./init
```
初始化过程中,脚本会:
- 检查必要的命令如docker、openssl是否已安装
- 创建必要的目录如data、conf
- 交互式收集用户输入的配置项:
- Redis密码用于连接Redis服务
- 加密主密钥用于加密存储Redis密码
- Redis版本默认8.2
- Redis端口默认6379
- 容器名称默认redis
- 生成加密的密码文件和`.envrc`环境配置文件
- 自动配置direnv以加载环境变量
## 环境变量加载
本项目使用direnv和`.envrc`文件管理环境变量,确保敏感信息安全存储:
1. 确保已安装direnv
```bash
# macOS
brew install direnv
# Linux
sudo apt-get install direnv # Debian/Ubuntu
# 或
sudo yum install direnv # CentOS/RHEL
```
2. 在shell配置文件如`~/.zshrc`或`~/.bashrc`)中添加:
```bash
eval "$(direnv hook zsh)" # 对于zsh
# 或
eval "$(direnv hook bash)" # 对于bash
```
3. 每次进入redis目录时direnv会自动提示输入主密钥以解密Redis密码
```
direnv: error .envrc is blocked. Run `direnv allow` to approve its content
```
首次进入时需要先运行:
```bash
direnv allow
```
然后根据提示输入主密钥。
## 服务控制 ## 服务控制
```sh 使用`service`脚本控制Redis服务
# 启动
```bash
# 启动服务
./service start ./service start
# 停止
# 停止服务
./service stop ./service stop
# 重启
# 重启服务
./service restart ./service restart
# 查看状态
# 查看服务状态
./service status ./service status
# 查看帮助信息
./service help
``` ```
## 配置 ## Redis客户端连接
- 容器名称 使用`redis-cli`脚本连接到Redis服务
在`docker-compose.yml`中设置容器名称,同时在`redis-cli`脚本和`service`脚本中修改对应的容器名称。 ```bash
# 基本连接
./redis-cli
- 服务端口号 # 执行具体命令
./redis-cli SET mykey "Hello Redis"
./redis-cli GET mykey
在`redis.conf`中修改`port 6379`一行,修改后需要重启服务生效。 # 查看所有键
./redis-cli KEYS *
- 连接密码 # 更多redis-cli命令请参考Redis官方文档
```
在`redis.conf`中修改`requirepass 123456`一行,修改后需要重启服务生效。 注意客户端脚本会自动从环境变量加载Redis连接信息主机、端口、密码无需手动指定
- 其他配置 ## 配置修改
在`redis.conf`中修改其他配置。 ### Redis配置文件
## 客户端 Redis的主要配置文件位于`conf/redis.conf`,可以根据需要修改以下关键配置:
`redis-cli`脚本就是调用容器内的`redis-cli`工具实现客户端连接的,用法与`redis-cli`工具相同。 - 持久化设置RDB/AOF
- 内存限制
- 连接数限制
- 日志级别
修改配置后,需要重启服务使更改生效:
```bash
./service restart
```
### 容器配置
如果需要修改容器相关配置(如端口映射、资源限制等),可以编辑`docker-compose.yml`文件,然后重启服务。
## 安全说明
1. Redis密码使用AES-256-CBC加密存储在`.envrc`文件中
2. 加密主密钥不会保存在任何文件中,需要用户在加载环境变量时手动输入
3. `.envrc`文件已添加到`.gitignore`中,避免敏感信息被提交到版本控制系统
4. 建议定期更新Redis密码和加密主密钥
## 故障排查
1. **服务启动失败**检查Docker是否正在运行以及端口是否被占用
2. **连接失败**确认主密钥输入正确Redis服务已启动密码配置正确
3. **数据问题**检查data目录权限确保Docker容器有写入权限
4. **环境变量加载失败**确认direnv已正确安装和配置`.envrc`文件存在且未被修改
## 注意事项
1. 首次使用请务必运行`./init`脚本完成初始化配置
2. 请妥善保管加密主密钥丢失后将无法恢复Redis密码
3. 定期备份data目录以防止数据丢失
4. 在生产环境中请进一步加强Redis的安全配置如绑定IP、限制访问等

3
conf/README.md Normal file
View File

@ -0,0 +1,3 @@
# 配置文件说明
这里的配置文件只是各个版本的配置文件参数,在实际服务中并没有使用这些配置文件。

1381
conf/redis-5.0.conf Normal file

File diff suppressed because it is too large Load Diff

1879
conf/redis-6.0.conf Normal file

File diff suppressed because it is too large Load Diff

2054
conf/redis-6.2.conf Normal file

File diff suppressed because it is too large Load Diff

2280
conf/redis-7.0.conf Normal file

File diff suppressed because it is too large Load Diff

View File

@ -51,6 +51,7 @@
# #
# loadmodule /path/to/my_module.so # loadmodule /path/to/my_module.so
# loadmodule /path/to/other_module.so # loadmodule /path/to/other_module.so
# loadmodule /path/to/args_module.so [arg [arg ...]]
################################## NETWORK ##################################### ################################## NETWORK #####################################
@ -109,7 +110,7 @@ bind 0.0.0.0
# By default protected mode is enabled. You should disable it only if # By default protected mode is enabled. You should disable it only if
# you are sure you want clients from other hosts to connect to Redis # you are sure you want clients from other hosts to connect to Redis
# even if no authentication is configured. # even if no authentication is configured.
protected-mode no protected-mode yes
# Redis uses default hardened security configuration directives to reduce the # Redis uses default hardened security configuration directives to reduce the
# attack surface on innocent users. Therefore, several sensitive configuration # attack surface on innocent users. Therefore, several sensitive configuration
@ -339,7 +340,7 @@ daemonize no
# #
# Note that on modern Linux systems "/run/redis.pid" is more conforming # Note that on modern Linux systems "/run/redis.pid" is more conforming
# and should be used instead. # and should be used instead.
pidfile /var/run/redis_60613.pid pidfile /var/run/redis_6379.pid
# Specify the server verbosity level. # Specify the server verbosity level.
# This can be one of: # This can be one of:
@ -389,6 +390,11 @@ databases 16
# ASCII art logo in startup logs by setting the following option to yes. # ASCII art logo in startup logs by setting the following option to yes.
always-show-logo no always-show-logo no
# To avoid logging personal identifiable information (PII) into server log file,
# uncomment the following:
#
# hide-user-data-from-log yes
# By default, Redis modifies the process title (as seen in 'top' and 'ps') to # By default, Redis modifies the process title (as seen in 'top' and 'ps') to
# provide some runtime information. It is possible to disable this and leave # provide some runtime information. It is possible to disable this and leave
# the process name as executed by setting the following to no. # the process name as executed by setting the following to no.
@ -411,8 +417,8 @@ set-proc-title yes
# #
proc-title-template "{title} {listen-addr} {server-mode}" proc-title-template "{title} {listen-addr} {server-mode}"
# Set the local environment which is used for string comparison operations, and # Set the local environment which is used for string comparison operations, and
# also affect the performance of Lua scripts. Empty String indicates the locale # also affect the performance of Lua scripts. Empty String indicates the locale
# is derived from the environment variables. # is derived from the environment variables.
locale-collate "" locale-collate ""
@ -657,7 +663,7 @@ repl-diskless-sync-max-replicas 0
# replication history. # replication history.
# Note that this requires sufficient memory, if you don't have it, # Note that this requires sufficient memory, if you don't have it,
# you risk an OOM kill. # you risk an OOM kill.
# "on-empty-db" - Use diskless load only when current dataset is empty. This is # "on-empty-db" - Use diskless load only when current dataset is empty. This is
# safer and avoid having old and new dataset loaded side by side # safer and avoid having old and new dataset loaded side by side
# during replication. # during replication.
repl-diskless-load disabled repl-diskless-load disabled
@ -918,10 +924,10 @@ replica-priority 100
# commands. For instance ~* allows all the keys. The pattern # commands. For instance ~* allows all the keys. The pattern
# is a glob-style pattern like the one of KEYS. # is a glob-style pattern like the one of KEYS.
# It is possible to specify multiple patterns. # It is possible to specify multiple patterns.
# %R~<pattern> Add key read pattern that specifies which keys can be read # %R~<pattern> Add key read pattern that specifies which keys can be read
# from. # from.
# %W~<pattern> Add key write pattern that specifies which keys can be # %W~<pattern> Add key write pattern that specifies which keys can be
# written to. # written to.
# allkeys Alias for ~* # allkeys Alias for ~*
# resetkeys Flush the list of allowed keys patterns. # resetkeys Flush the list of allowed keys patterns.
# &<pattern> Add a glob-style pattern of Pub/Sub channels that can be # &<pattern> Add a glob-style pattern of Pub/Sub channels that can be
@ -948,10 +954,10 @@ replica-priority 100
# allchannels (if acl-pubsub-default is set), off, clearselectors, -@all. # allchannels (if acl-pubsub-default is set), off, clearselectors, -@all.
# The user returns to the same state it has immediately after its creation. # The user returns to the same state it has immediately after its creation.
# (<options>) Create a new selector with the options specified within the # (<options>) Create a new selector with the options specified within the
# parentheses and attach it to the user. Each option should be # parentheses and attach it to the user. Each option should be
# space separated. The first character must be ( and the last # space separated. The first character must be ( and the last
# character must be ). # character must be ).
# clearselectors Remove all of the currently attached selectors. # clearselectors Remove all of the currently attached selectors.
# Note this does not change the "root" user permissions, # Note this does not change the "root" user permissions,
# which are the permissions directly applied onto the # which are the permissions directly applied onto the
# user (outside the parentheses). # user (outside the parentheses).
@ -977,7 +983,7 @@ replica-priority 100
# Basically ACL rules are processed left-to-right. # Basically ACL rules are processed left-to-right.
# #
# The following is a list of command categories and their meanings: # The following is a list of command categories and their meanings:
# * keyspace - Writing or reading from keys, databases, or their metadata # * keyspace - Writing or reading from keys, databases, or their metadata
# in a type agnostic way. Includes DEL, RESTORE, DUMP, RENAME, EXISTS, DBSIZE, # in a type agnostic way. Includes DEL, RESTORE, DUMP, RENAME, EXISTS, DBSIZE,
# KEYS, EXPIRE, TTL, FLUSHALL, etc. Commands that may modify the keyspace, # KEYS, EXPIRE, TTL, FLUSHALL, etc. Commands that may modify the keyspace,
# key or metadata will also have `write` category. Commands that only read # key or metadata will also have `write` category. Commands that only read
@ -1164,7 +1170,8 @@ requirepass 123456
# configuration directive. # configuration directive.
# #
# The default of 5 produces good enough results. 10 Approximates very closely # The default of 5 produces good enough results. 10 Approximates very closely
# true LRU but costs more CPU. 3 is faster but not very accurate. # true LRU but costs more CPU. 3 is faster but not very accurate. The maximum
# value that can be set is 64.
# #
# maxmemory-samples 5 # maxmemory-samples 5
@ -1384,6 +1391,10 @@ disable-thp yes
# If the AOF is enabled on startup Redis will load the AOF, that is the file # If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees. # with the better durability guarantees.
# #
# Note that changing this value in a config file of an existing database and
# restarting the server can lead to data loss. A conversion needs to be done
# by setting it via CONFIG command on a live server first.
#
# Please check https://redis.io/topics/persistence for more information. # Please check https://redis.io/topics/persistence for more information.
appendonly no appendonly no
@ -1599,8 +1610,8 @@ aof-timestamp-enabled no
# #
# cluster-node-timeout 15000 # cluster-node-timeout 15000
# The cluster port is the port that the cluster bus will listen for inbound connections on. When set # The cluster port is the port that the cluster bus will listen for inbound connections on. When set
# to the default value, 0, it will be bound to the command port + 10000. Setting this value requires # to the default value, 0, it will be bound to the command port + 10000. Setting this value requires
# you to specify the cluster bus port when executing cluster meet. # you to specify the cluster bus port when executing cluster meet.
# cluster-port 0 # cluster-port 0
@ -1735,12 +1746,12 @@ aof-timestamp-enabled no
# PubSub message by default. (client-query-buffer-limit default value is 1gb) # PubSub message by default. (client-query-buffer-limit default value is 1gb)
# #
# cluster-link-sendbuf-limit 0 # cluster-link-sendbuf-limit 0
# Clusters can configure their announced hostname using this config. This is a common use case for # Clusters can configure their announced hostname using this config. This is a common use case for
# applications that need to use TLS Server Name Indication (SNI) or dealing with DNS based # applications that need to use TLS Server Name Indication (SNI) or dealing with DNS based
# routing. By default this value is only shown as additional metadata in the CLUSTER SLOTS # routing. By default this value is only shown as additional metadata in the CLUSTER SLOTS
# command, but can be changed using 'cluster-preferred-endpoint-type' config. This value is # command, but can be changed using 'cluster-preferred-endpoint-type' config. This value is
# communicated along the clusterbus to all nodes, setting it to an empty string will remove # communicated along the clusterbus to all nodes, setting it to an empty string will remove
# the hostname and also propagate the removal. # the hostname and also propagate the removal.
# #
# cluster-announce-hostname "" # cluster-announce-hostname ""
@ -1754,13 +1765,13 @@ aof-timestamp-enabled no
# a user defined hostname, or by declaring they have no endpoint. Which endpoint is # a user defined hostname, or by declaring they have no endpoint. Which endpoint is
# shown as the preferred endpoint is set by using the cluster-preferred-endpoint-type # shown as the preferred endpoint is set by using the cluster-preferred-endpoint-type
# config with values 'ip', 'hostname', or 'unknown-endpoint'. This value controls how # config with values 'ip', 'hostname', or 'unknown-endpoint'. This value controls how
# the endpoint returned for MOVED/ASKING requests as well as the first field of CLUSTER SLOTS. # the endpoint returned for MOVED/ASKING requests as well as the first field of CLUSTER SLOTS.
# If the preferred endpoint type is set to hostname, but no announced hostname is set, a '?' # If the preferred endpoint type is set to hostname, but no announced hostname is set, a '?'
# will be returned instead. # will be returned instead.
# #
# When a cluster advertises itself as having an unknown endpoint, it's indicating that # When a cluster advertises itself as having an unknown endpoint, it's indicating that
# the server doesn't know how clients can reach the cluster. This can happen in certain # the server doesn't know how clients can reach the cluster. This can happen in certain
# networking situations where there are multiple possible routes to the node, and the # networking situations where there are multiple possible routes to the node, and the
# server doesn't know which one the client took. In this case, the server is expecting # server doesn't know which one the client took. In this case, the server is expecting
# the client to reach out on the same endpoint it used for making the last request, but use # the client to reach out on the same endpoint it used for making the last request, but use
# the port provided in the response. # the port provided in the response.
@ -2072,7 +2083,7 @@ client-output-buffer-limit pubsub 32mb 8mb 60
# amount by default in order to avoid that a protocol desynchronization (for # amount by default in order to avoid that a protocol desynchronization (for
# instance due to a bug in the client) will lead to unbound memory usage in # instance due to a bug in the client) will lead to unbound memory usage in
# the query buffer. However you can configure it here if you have very special # the query buffer. However you can configure it here if you have very special
# needs, such us huge multi/exec requests or alike. # needs, such as a command with huge argument, or huge multi/exec requests or alike.
# #
# client-query-buffer-limit 1gb # client-query-buffer-limit 1gb
@ -2080,7 +2091,7 @@ client-output-buffer-limit pubsub 32mb 8mb 60
# errors or data eviction. To avoid this we can cap the accumulated memory # errors or data eviction. To avoid this we can cap the accumulated memory
# used by all client connections (all pubsub and normal clients). Once we # used by all client connections (all pubsub and normal clients). Once we
# reach that limit connections will be dropped by the server freeing up # reach that limit connections will be dropped by the server freeing up
# memory. The server will attempt to drop the connections using the most # memory. The server will attempt to drop the connections using the most
# memory first. We call this mechanism "client eviction". # memory first. We call this mechanism "client eviction".
# #
# Client eviction is configured using the maxmemory-clients setting as follows: # Client eviction is configured using the maxmemory-clients setting as follows:
@ -2197,6 +2208,26 @@ rdb-save-incremental-fsync yes
# lfu-log-factor 10 # lfu-log-factor 10
# lfu-decay-time 1 # lfu-decay-time 1
# The maximum number of new client connections accepted per event-loop cycle. This configuration
# is set independently for TLS connections.
#
# By default, up to 10 new connection will be accepted per event-loop cycle for normal connections
# and up to 1 new connection per event-loop cycle for TLS connections.
#
# Adjusting this to a larger number can slightly improve efficiency for new connections
# at the risk of causing timeouts for regular commands on established connections. It is
# not advised to change this without ensuring that all clients have limited connection
# pools and exponential backoff in the case of command/connection timeouts.
#
# If your application is establishing a large number of new connections per second you should
# also consider tuning the value of tcp-backlog, which allows the kernel to buffer more
# pending connections before dropping or rejecting connections.
#
# max-new-connections-per-cycle 10
# max-new-tls-connections-per-cycle 1
########################### ACTIVE DEFRAGMENTATION ####################### ########################### ACTIVE DEFRAGMENTATION #######################
# #
# What is active defragmentation? # What is active defragmentation?
@ -2278,20 +2309,20 @@ jemalloc-bg-thread yes
# the taskset command: # the taskset command:
# #
# Set redis server/io threads to cpu affinity 0,2,4,6: # Set redis server/io threads to cpu affinity 0,2,4,6:
# server_cpulist 0-7:2 # server-cpulist 0-7:2
# #
# Set bio threads to cpu affinity 1,3: # Set bio threads to cpu affinity 1,3:
# bio_cpulist 1,3 # bio-cpulist 1,3
# #
# Set aof rewrite child process to cpu affinity 8,9,10,11: # Set aof rewrite child process to cpu affinity 8,9,10,11:
# aof_rewrite_cpulist 8-11 # aof-rewrite-cpulist 8-11
# #
# Set bgsave child process to cpu affinity 1,10,11 # Set bgsave child process to cpu affinity 1,10,11
# bgsave_cpulist 1,10-11 # bgsave-cpulist 1,10-11
# In some cases redis will emit warnings and even refuse to start if it detects # In some cases redis will emit warnings and even refuse to start if it detects
# that the system is in bad state, it is possible to suppress these warnings # that the system is in bad state, it is possible to suppress these warnings
# by setting the following config which takes a space delimited list of warnings # by setting the following config which takes a space delimited list of warnings
# to suppress # to suppress
# #
# ignore-warnings ARM64-COW-BUG # ignore-warnings ARM64-COW-BUG

2350
conf/redis-8.0.conf Normal file

File diff suppressed because it is too large Load Diff

2364
conf/redis-8.2.conf Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,13 @@
services: services:
redis: redis:
image: quay.io/wandoubaba517/redis:7.4 image: redis:${REDIS_VERSION:-8.2}
container_name: redis container_name: ${REDIS_CONTAINER_NAME:-redis}
restart: always restart: always
volumes: volumes:
- ./data:/data - ./data:/data
- ./conf:/etc/redis command: redis-server --port ${REDIS_PORT:-6379} --requirepass ${REDIS_PASSWORD} --bind ${REDIS_BIND:-0.0.0.0} --tcp-backlog ${REDIS_TCP_BACKLOG:-511} --protected-mode ${REDIS_PROTECTED_MODE:-yes}
command: redis-server /etc/redis/redis.conf
network_mode: host
healthcheck: healthcheck:
test: ["CMD", "redis-cli", "-a", "123456", "ping"] test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s interval: 10s
timeout: 5s timeout: 5s
retries: 3 retries: 3

194
init Executable file
View File

@ -0,0 +1,194 @@
#!/bin/bash
# Redis初始化脚本
# 用于初始化或重新初始化Redis配置环境
# 获取脚本所在目录的绝对路径
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
# 切换工作目录到脚本所在目录
cd $SCRIPT_DIR
# 检查必要的命令
check_commands() {
if ! command -v openssl &> /dev/null; then
echo "错误: 未找到openssl命令请先安装"
exit 1
fi
if ! command -v direnv &> /dev/null; then
echo "警告: 未找到direnv命令建议安装以获得最佳体验"
fi
}
# 创建必要的目录结构
create_directories() {
echo "创建必要的目录结构..."
mkdir -p ./data
mkdir -p ./conf
echo "目录结构创建完成"
}
# 初始化配置文件
initialize_files() {
# 提示用户输入Redis密码步骤1
read -s -p "请输入Redis密码: " redis_password
echo
read -s -p "请再次输入密码确认: " redis_password_confirm
echo
# 验证密码一致性
if [ "$redis_password" != "$redis_password_confirm" ]; then
echo "错误: 两次输入的密码不一致"
return 1
fi
# 验证密码强度(可选)
if [ ${#redis_password} -lt 6 ]; then
echo "警告: 密码长度少于6个字符建议使用强密码"
read -p "是否继续使用此密码?(y/n): " continue
if [ "$continue" != "y" ]; then
return 1
fi
fi
# 创建加密文件步骤2
echo "创建加密的密码文件..."
read -s -p "请为加密文件设置一个密码(主密钥): " encryption_key
echo
read -s -p "请再次输入加密文件密码确认: " encryption_key_confirm
echo
# 验证加密密钥一致性
if [ "$encryption_key" != "$encryption_key_confirm" ]; then
echo "错误: 两次输入的加密文件密码不一致"
return 1
fi
# 加密密码并保存到文件
echo -n "$redis_password" | openssl enc -aes-256-cbc -salt -pbkdf2 -iter 10000 -out redis_password.enc -k "$encryption_key"
# 提示用户输入Redis版本步骤3
default_version="8.2"
read -p "请输入Redis版本 [$default_version]: " redis_version
# 如果用户直接回车,使用默认值
if [ -z "$redis_version" ]; then
redis_version="$default_version"
fi
echo "Redis版本设置为: $redis_version"
# 提示用户输入Redis映射端口号步骤4
default_port="6379"
read -p "请输入Redis映射端口号 [$default_port]: " redis_port
# 如果用户直接回车,使用默认值
if [ -z "$redis_port" ]; then
redis_port="$default_port"
fi
echo "映射端口号设置为: $redis_port"
# 提示用户输入容器名称步骤5
default_container_name="redis"
read -p "请输入Redis容器名称 [$default_container_name]: " redis_container_name
# 如果用户直接回车,使用默认值
if [ -z "$redis_container_name" ]; then
redis_container_name="$default_container_name"
fi
echo "容器名称设置为: $redis_container_name"
# 检查加密是否成功
if [ $? -ne 0 ]; then
echo "错误: 创建加密文件失败"
return 1
fi
# 设置加密文件权限
chmod 600 redis_password.enc
echo "加密文件创建成功权限设置为600"
# 创建.envrc文件
echo "创建.envrc配置文件..."
cat > .envrc << EOF
# Redis配置环境变量
export REDIS_VERSION=$redis_version
export REDIS_PASSWORD=\$(openssl enc -aes-256-cbc -d -pbkdf2 -iter 10000 -in redis_password.enc)
export REDIS_PORT=$redis_port
export REDIS_BIND=0.0.0.0
export REDIS_PROTECTED_MODE=yes
export REDIS_TCP_BACKLOG=511
export REDIS_CONTAINER_NAME=$redis_container_name
EOF
# 设置.envrc文件权限
chmod 600 .envrc
echo ".envrc文件创建成功权限设置为600"
# 自动执行direnv allow并提供状态反馈
if command -v direnv &> /dev/null; then
echo ""
echo "📝 初始化完成!自动配置环境变量..."
echo "正在执行 direnv allow..."
if direnv allow > /dev/null 2>&1; then
echo "✅ direnv allow 执行成功!环境变量已启用"
else
echo "❌ direnv allow 执行失败,请手动运行 'direnv allow' 来启用环境变量"
fi
else
echo ""
echo "初始化完成建议安装direnv以获得更好的使用体验"
echo " macOS: brew install direnv"
echo " Linux: apt-get install direnv 或 yum install direnv"
fi
return 0
}
# 主函数
main() {
echo "Redis环境初始化脚本"
echo "==================================="
# 检查必要的命令
check_commands
# 检查文件是否存在
if [ -f "redis_password.enc" ] && [ -f ".envrc" ]; then
echo ""
echo "检测到redis_password.enc和.envrc文件已存在"
read -p "是否重新初始化?这将覆盖现有配置!(y/n): " reinitialize
if [ "$reinitialize" != "y" ]; then
echo "初始化取消"
exit 0
fi
# 备份现有文件(可选)
backup_suffix="_bak_$(date +%Y%m%d%H%M%S)"
echo "备份现有文件..."
cp redis_password.enc "redis_password.enc$backup_suffix" 2>/dev/null
cp .envrc ".envrc$backup_suffix" 2>/dev/null
echo "备份完成"
fi
# 创建目录结构
create_directories
# 初始化配置文件
while ! initialize_files; do
echo "请重新输入密码..."
done
echo ""
echo "==================================="
echo "初始化成功!"
echo "使用说明:"
echo "1. 使用 './service start' 启动服务"
echo "2. 使用 './service stop' 停止服务"
echo "3. 使用 './service status' 查看服务状态"
echo "4. 使用 './service restart' 重启服务"
}
# 执行主函数
main

View File

@ -6,9 +6,37 @@ SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
# 切换工作目录到脚本所在目录 # 切换工作目录到脚本所在目录
cd $SCRIPT_DIR cd $SCRIPT_DIR
container_name="redis" # 加载环境变量
load_env_variables() {
if [ -f ".envrc" ]; then
# 使用direnv加载环境变量
if command -v direnv &> /dev/null; then
eval "$(direnv export bash)"
# 检查REDIS_PASSWORD是否已设置
if [ -z "$REDIS_PASSWORD" ]; then
echo "错误: 密码验证失败,无法继续操作"
return 1
fi
else
echo "错误: 未安装direnv请先安装direnv"
return 1
fi
else
echo "错误: 找不到.envrc文件"
return 1
fi
return 0
}
export REDIS_PASSWORD="123456" # 调用函数加载环境变量
export REDIS_PORT=6379 if ! load_env_variables; then
echo "无法加载环境变量,脚本退出"
exit 1
fi
docker exec -it $container_name bash -c "redis-cli -p $REDIS_PORT -a $REDIS_PASSWORD $@" # 使用环境变量或默认值
container_name=${REDIS_CONTAINER_NAME:-redis}
redis_port=${REDIS_PORT:-6379}
# 执行Redis CLI命令
docker exec -it $container_name bash -c "redis-cli -p $redis_port -a $REDIS_PASSWORD $@"

279
service
View File

@ -1,22 +1,273 @@
#!/bin/bash #!/bin/bash
# Redis服务控制脚本
# 支持: start, stop, restart, status
# 获取脚本所在目录的绝对路径 # 获取脚本所在目录的绝对路径
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
# 切换工作目录到脚本所在目录 # 切换工作目录到脚本所在目录
cd $SCRIPT_DIR cd "$SCRIPT_DIR"
container_name="redis" # 加载环境变量
load_environment() {
# 检查.envrc文件是否存在
if [ ! -f .envrc ]; then
echo "⚠️ 警告: 未找到.envrc文件将使用默认配置"
return 0
fi
if [ "$1" = "start" ]; then # 创建临时文件用于存储解密结果
docker compose up -d local temp_env=$(mktemp)
elif [ "$1" = "stop" ]; then local success=1
docker compose down
elif [ "$1" = "restart" ]; then # 首先尝试使用direnv加载如果安装了
docker compose down if command -v direnv &> /dev/null; then
docker compose up -d echo "📋 正在通过direnv加载环境变量..."
elif [ "$1" = "status" ]; then # 捕获direnv输出到临时文件以便检查错误
docker ps -a | grep $container_name eval "$(direnv export zsh)" 2>$temp_env
else
echo "Usage: $0 [start|stop|restart|status]" # 检查是否有错误输出
fi if grep -q "error" "$temp_env" || grep -q "Error" "$temp_env"; then
echo "❌ 错误: 环境变量加载失败,请检查主密钥是否正确"
cat "$temp_env"
rm "$temp_env"
return 1
fi
# 检查REDIS_PASSWORD是否成功设置
if [ -z "$REDIS_PASSWORD" ]; then
echo "❌ 错误: Redis密码解密失败请检查主密钥是否正确"
rm "$temp_env"
return 1
fi
success=0
fi
# 如果direnv加载失败或未安装尝试直接加载.envrc
if [ $success -ne 0 ]; then
echo "📋 正在直接加载环境变量..."
# 逐个处理环境变量特别是需要特别处理REDIS_PASSWORD解密
local other_vars=$(grep -E '^export REDIS_' .envrc | grep -v 'REDIS_PASSWORD' | sed 's/^export //')
# 导出除REDIS_PASSWORD外的其他变量
if [ ! -z "$other_vars" ]; then
export $other_vars
fi
# 单独处理REDIS_PASSWORD的解密捕获错误
local openssl_cmd=$(grep -E '^export REDIS_PASSWORD=' .envrc | sed 's/^export REDIS_PASSWORD=//')
if [ ! -z "$openssl_cmd" ]; then
echo "🔑 请输入加密文件主密钥:"
# 执行解密命令并捕获错误
local decrypted_pwd=$(eval "$openssl_cmd" 2>$temp_env)
local decrypted_success=$?
# 检查解密是否成功
if [ $decrypted_success -ne 0 ] || grep -q "error" "$temp_env"; then
echo "❌ 错误: 主密钥错误,解密失败!"
cat "$temp_env"
rm "$temp_env"
return 1
fi
# 设置解密后的密码
export REDIS_PASSWORD="$decrypted_pwd"
echo "✅ 密码解密成功"
fi
fi
# 清理临时文件
rm -f "$temp_env"
return 0
}
# 检查Docker是否安装
check_docker() {
if ! command -v docker &> /dev/null; then
echo "❌ 错误: 未找到docker命令请先安装Docker"
return 1
fi
if ! command -v docker-compose &> /dev/null; then
echo "❌ 错误: 未找到docker-compose命令请先安装"
return 1
fi
if ! docker info &> /dev/null; then
echo "❌ 错误: Docker守护进程未运行或无权限访问"
return 1
fi
return 0
}
# 获取容器名称
get_container_name() {
# 优先使用环境变量中的容器名,否则使用默认值
local default_name="redis"
echo "${REDIS_CONTAINER_NAME:-$default_name}"
}
# 启动服务
start_service() {
echo "🚀 正在启动Redis服务..."
# 加载环境变量
if ! load_environment; then
echo "❌ 加载环境变量失败"
return 1
fi
# 检查Docker
if ! check_docker; then
return 1
fi
# 启动容器
if docker-compose up -d; then
echo "✅ Redis服务启动成功"
echo "📝 容器名称: $(get_container_name)"
echo "📝 端口: ${REDIS_PORT:-6379}"
return 0
else
echo "❌ Redis服务启动失败"
return 1
fi
}
# 停止服务
stop_service() {
echo "⏹️ 正在停止Redis服务..."
# 加载环境变量
load_environment
# 停止容器
if docker-compose down; then
echo "✅ Redis服务已停止"
return 0
else
echo "❌ Redis服务停止失败"
return 1
fi
}
# 重启服务
restart_service() {
echo "🔄 正在重启Redis服务..."
if ! stop_service; then
echo "❌ 停止服务失败,重启中断"
return 1
fi
echo ""
if ! start_service; then
echo "❌ 启动服务失败,重启不完全"
return 1
fi
echo "✅ Redis服务重启成功"
return 0
}
# 查看服务状态
status_service() {
echo "📊 Redis服务状态检查..."
# 加载环境变量
load_environment
local container_name=$(get_container_name)
# 检查容器是否存在
if docker ps -a | grep -q "$container_name"; then
# 检查容器是否正在运行
if docker ps | grep -q "$container_name"; then
echo "✅ Redis服务正在运行"
echo ""
echo "详细信息:"
docker ps | grep "$container_name"
# 尝试健康检查
if docker-compose ps | grep -q "$container_name.*Up.*healthy"; then
echo ""
echo "✅ 健康检查状态: 正常"
else
echo ""
echo "⚠️ 健康检查状态: 待检查"
# 运行健康检查命令
echo "运行健康检查..."
if docker-compose exec -T redis redis-cli -a "${REDIS_PASSWORD:-123456}" ping; then
echo "✅ 连接测试成功"
else
echo "⚠️ 连接测试失败,请检查配置"
fi
fi
return 0
else
echo "❌ Redis服务已停止"
echo ""
echo "停止的容器信息:"
docker ps -a | grep "$container_name"
return 1
fi
else
echo "❌ Redis容器不存在"
echo "请使用 './service start' 启动服务"
return 1
fi
}
# 显示帮助信息
show_help() {
echo "📚 Redis服务控制脚本使用说明"
echo "======================================"
echo "命令:"
echo " start - 启动Redis服务"
echo " stop - 停止Redis服务"
echo " restart - 重启Redis服务"
echo " status - 查看Redis服务状态"
echo " help - 显示此帮助信息"
echo "======================================"
echo "示例:"
echo " ./service start # 启动服务"
echo " ./service status # 查看状态"
echo "======================================"
}
# 主函数
main() {
case "$1" in
start)
start_service
;;
stop)
stop_service
;;
restart)
restart_service
;;
status)
status_service
;;
help|--help|h|--h)
show_help
;;
*)
echo "❌ 未知命令: $1"
show_help
return 1
;;
esac
}
# 执行主函数
main "$@"
# 退出并返回状态码
exit $?