Docker Redis - 播种数据 - 无法通过 Docker 文件或 shell 脚本执行 redis-cli

Docker Redis - Seeding Data - Cannot execute redis-cli via Dockerfile or via shell script

通过 docker-compose(使用我的 Redis Dockerfile)设置了一个 Redis 实例,一切正常。

现在,我正在尝试在容器启动后为 Redis 实例播种数据。

(1) 试图 运行 redis-cli 直接在 Dockerfile 中(即 运行 by docker-compose

FROM redis:6.2.5
COPY ./redis.conf /test_dir/
COPY ./seed.txt /test_dir/

ENTRYPOINT ["redis-server", "/test_dir/redis.conf"]
RUN cat /test_dir/seed.txt | redis-cli -a <password> --pipe

这会抛出 Could not connect to Redis at 127.0.0.1:6379: Connection refused

(2) 略有不同 Dockerfile,运行 在容器启动后执行的 shell 脚本中使用相同的命令:

FROM redis:6.2.5
COPY ./redis.conf /test_dir/
COPY ./seed.txt /test_dir/
COPY ./init.sh /test_dir/

ENTRYPOINT ["redis-server", "/test_dir/redis.conf"]
RUN . /test_dir/init.sh
# init.sh
sleep 10  # ensure Redis server is up and running
cat /test_dir/seed.txt | redis-cli -a <password> --pipe

执行 shell 脚本,它等待 10 秒,我确认服务器已启动并且 运行ning 在数据导入被触发之前,但 Redis 抛出相同的错误.

备注:

(1) I've also disabled `protected-mode` and removed `requirepass`, but redis-cli can not connect
(2) when I jump into the container and manually execute the command, it DOES WORK !

那么我如何从 Dockerfile 或通过 shell 脚本 运行 redis-cli 或者播种 Docker Redis 实例的推荐方法是什么?

谢谢。

RUN cat /test_dir/seed.txt | redis-cli -a <password> --pipe 将在您执行 docker build 时执行,那时 ENTRYPOINT ["redis-server", "/test_dir/redis.conf"] 仍然不会 运行 因为它仅在容器启动时被调用。所以,你肯定会出错。

因此,您可以使用下一个解决方法:

/test_dir/seed.txt:

/test_dir/init.sh:

while :
do
    redis-cli -h redis-svr -p 6379 quit
    if [ $? -eq 0 ]; then
        cat /test_dir/seed.txt | redis-cli -h redis-svr -p 6379 --pipe
        break
    else
        echo "server not ready, wait then retry..."
        sleep 3
    fi
done

docker-compose.yaml:

version: '3'

services:
  redis-svr:
    image: redis
  redis-cli:
    image: redis
    volumes:
      - /test_dir:/test_dir
    entrypoint: sh -c /test_dir/init.sh

执行:

$ docker-compose up
WARNING: Found orphan containers (20210910_redis_1) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
Starting 20210910_redis-svr_1 ... done
Starting 20210910_redis-cli_1 ... done
Attaching to 20210910_redis-cli_1, 20210910_redis-svr_1
redis-cli_1  | Could not connect to Redis at redis-svr:6379: Connection refused
redis-cli_1  | server not ready, wait then retry...
redis-svr_1  | 1:C 11 Sep 2021 05:55:33.872 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis-svr_1  | 1:C 11 Sep 2021 05:55:33.872 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=1, just started
redis-svr_1  | 1:C 11 Sep 2021 05:55:33.872 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis-svr_1  | 1:M 11 Sep 2021 05:55:33.873 * monotonic clock: POSIX clock_gettime
redis-svr_1  | 1:M 11 Sep 2021 05:55:33.879 * Running mode=standalone, port=6379.
redis-svr_1  | 1:M 11 Sep 2021 05:55:33.879 # Server initialized
redis-svr_1  | 1:M 11 Sep 2021 05:55:33.890 * Loading RDB produced by version 6.2.5
redis-svr_1  | 1:M 11 Sep 2021 05:55:33.890 * RDB age 266 seconds
redis-svr_1  | 1:M 11 Sep 2021 05:55:33.890 * RDB memory usage when created 0.77 Mb
redis-svr_1  | 1:M 11 Sep 2021 05:55:33.890 * DB loaded from disk: 0.010 seconds
redis-svr_1  | 1:M 11 Sep 2021 05:55:33.890 * Ready to accept connections
redis-cli_1  | OK
redis-cli_1  | All data transferred. Waiting for the last reply...
redis-cli_1  | Last reply received from server.
redis-cli_1  | errors: 0, replies: 0
20210910_redis-cli_1 exited with code 0

说明:

redis-svr 将在一个容器中启动服务器,redis-cli 将启动另一个容器,它将首先调用 init.shinit.sh 将尝试 [= redis-cli -h redis-svr -p 6379 quit 92=] 到redis服务器看服务器是否真的启动了。如果没有,它会等待一段时间并重试,如果服务器已经启动,那么它可以调用客户端命令将初始数据导入服务器。

EDIT20210912 根据 OP 的评论使用一个容器:

文件夹结构:

$ tree
.
├── docker-compose.yaml
├── Dockerfile
├── init.sh
├── my-entrypoint.sh
└── seed.txt

docker-compose.yaml:

version: '3'

services:
  redis-svr:
      build: ./

Dockerfile:

FROM redis:6.2.5
COPY . /tmp
RUN chmod -R 777 /tmp
ENTRYPOINT ["/tmp/my-entrypoint.sh"]
CMD ["redis-server"]

init.sh:

while :
do
    redis-cli quit
    if [ $? -eq 0 ]; then
        echo "Server ready now, start to import data ..."
        cat ./seed.txt | redis-cli --pipe
        break
    else
        echo "Server not ready, wait then retry..."
        sleep 3
    fi
done

我的-entrypoint.sh:

#!/bin/sh
/tmp/init.sh &
docker-entrypoint.sh 

执行:

$ docker-compose up
Recreating test_dir_redis-svr_1 ... done
Attaching to test_dir_redis-svr_1
redis-svr_1  | Could not connect to Redis at 127.0.0.1:6379: Connection refused
redis-svr_1  | Server not ready, wait then retry...
redis-svr_1  | 7:C 12 Sep 2021 08:36:05.512 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis-svr_1  | 7:C 12 Sep 2021 08:36:05.512 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=7, just started
redis-svr_1  | 7:C 12 Sep 2021 08:36:05.512 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis-svr_1  | 7:M 12 Sep 2021 08:36:05.513 * monotonic clock: POSIX clock_gettime
redis-svr_1  | 7:M 12 Sep 2021 08:36:05.515 * Running mode=standalone, port=6379.
redis-svr_1  | 7:M 12 Sep 2021 08:36:05.515 # Server initialized
redis-svr_1  | 7:M 12 Sep 2021 08:36:05.515 * Ready to accept connections
redis-svr_1  | OK
redis-svr_1  | Server ready now, start to import data ...
redis-svr_1  | All data transferred. Waiting for the last reply...
redis-svr_1  | Last reply received from server.
redis-svr_1  | errors: 0, replies: 0

这定义自定义入口点让 init.sh 有机会在 redis 服务器 运行.

之前执行

这是另一个有效的解决方案,尽管@atline 解决方案更优雅。

Docker 文件

FROM redis:6.2.5-alpine3.14
RUN mkdir /foo
COPY ./redis.conf /foo/
COPY ./seed.txt /foo/
COPY ./init.sh /foo/

ENTRYPOINT /bin/sh -c "redis-server /foo/redis.conf" & sleep 2s \
&& source /foo/init.sh

init.sh

# seed db
cat /foo/seed.txt | redis-cli -a <pw_if_applicable> --pipe
# save .rdb dump
redis-cli -a <pw_if_applicable> save
# shutdown server
redis-cli -a <pw_if_applicable> shutdown
# restart server
redis-server "/foo/redis.conf"

这有效并使用提供的 redis.conf,因此它将数据播种到您在配置中定义的 .rdb