Docker容器启动后如何自动运行脚本

Phi*_*kie 17 elasticsearch docker elasticsearch-plugin kubernetes dockerfile

我正在使用 Search Guard 插件来保护由多个节点组成的弹性搜索集群。这是我的 Dockerfile:

#!/bin/sh
FROM docker.elastic.co/elasticsearch/elasticsearch:5.6.3

USER root

# Install search guard
RUN bin/elasticsearch-plugin install --batch com.floragunn:search-guard-5:5.6.3-16 \
    && chmod +x \
        plugins/search-guard-5/tools/hash.sh \
        plugins/search-guard-5/tools/sgadmin.sh \
        bin/init_sg.sh \
    && chown -R elasticsearch:elasticsearch /usr/share/elasticsearch

USER elasticsearch
Run Code Online (Sandbox Code Playgroud)

初始化 SearchGuard(创建内部用户并分配角色)。我需要init_sg.sh在容器启动后运行脚本。问题在于:除非elasticsearch 正在运行,否则脚本不会初始化任何安全索引。

脚本的内容是:

sleep 10
plugins/search-guard-5/tools/sgadmin.sh -cd config/ -ts config/truststore.jks -ks config/kirk-keystore.jks -nhnv -icl
Run Code Online (Sandbox Code Playgroud)

现在,我只是在容器启动后手动运行脚本,但由于我是在 Kubernetes 上运行它的。Pod 可能会因某种原因被杀死或失败并自动重新创建。在这种情况下,插件必须在容器启动后自动初始化!

那么如何实现这一点呢?任何帮助或提示将不胜感激。

小智 11

镜像本身有一个ENTRYPOINT ["/run/entrypoint.sh"]在 Dockerfile 中指定的入口点。您可以用自己的脚本替换它。因此,例如创建一个新脚本,挂载它并首先调用/run/entrypoint.sh,然后在运行您的init_sg.sh.

  • 我正在尝试做完全相同的事情,但是容器中不存在“/run/entrypoint.sh”。我找不到它所在的位置。有什么帮助吗? (3认同)

Vee*_*dra 8

不确定这是否能解决您的问题,但值得检查我的存储Dockerfile

我创建了一个简单的run.sh文件,复制到 docker 映像并在Dockerfile我编写的CMD ["run.sh"]. 以同样的方式定义你想要的任何内容run.sh并写入CMD ["run.sh"]。您可以找到另一个示例,如下所示

Dockerfile

FROM java:8

RUN apt-get update && apt-get install stress-ng -y 
ADD target/restapp.jar /restapp.jar 
COPY dockerrun.sh /usr/local/bin/dockerrun.sh 
RUN chmod +x /usr/local/bin/dockerrun.sh 
CMD ["dockerrun.sh"]
Run Code Online (Sandbox Code Playgroud)

dockerrun.sh

#!/bin/sh
java -Dserver.port=8095 -jar /restapp.jar &
hostname="hostname: `hostname`"
nohup stress-ng --vm 4 &
while true; do
  sleep 1000
done
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的回复,elasticsearch图像已经有一个entrypoint.sh文件,像这样使用CMD将覆盖它,并且elasticsearch搜索根本不会启动:/ (2认同)

小智 7

此处的文档对此进行了解决:https ://docs.docker.com/config/containers/multi-service_container/

如果您的某个进程依赖于主进程,则首先使用 wait-for-it 等脚本启动辅助进程,然后第二次启动主进程并删除 fg %1 行。

#!/bin/bash
  
# turn on bash's job control
set -m
  
# Start the primary process and put it in the background
./my_main_process &
  
# Start the helper process
./my_helper_process
  
# the my_helper_process might need to know how to wait on the
# primary process to start before it does its work and returns
  
  
# now we bring the primary process back into the foreground
# and leave it there
fg %1
Run Code Online (Sandbox Code Playgroud)


naf*_*esi 5

我试图解决确切的问题。这是对我有用的方法。

  1. 创建一个单独的 shell 脚本来检查 ES 状态,并且仅在 ES 准备就绪时才开始初始化 SG:

外壳脚本

#!/bin/sh

echo ">>>>  Right before SG initialization <<<<"
# use while loop to check if elasticsearch is running 
while true
do
    netstat -uplnt | grep :9300 | grep LISTEN > /dev/null
    verifier=$?
    if [ 0 = $verifier ]
        then
            echo "Running search guard plugin initialization"
            /elasticsearch/plugins/search-guard-6/tools/sgadmin.sh -h 0.0.0.0 -cd plugins/search-guard-6/sgconfig -icl -key config/client.key -cert config/client.pem -cacert config/root-ca.pem -nhnv
            break
        else
            echo "ES is not running yet"
            sleep 5
    fi
done
Run Code Online (Sandbox Code Playgroud)

在 Dockerfile 中安装脚本

您需要将脚本安装在容器中,以便在启动后可以访问它。

COPY sginit.sh /
RUN chmod +x /sginit.sh
Run Code Online (Sandbox Code Playgroud)

更新入口点脚本

您将需要编辑 ES 映像的入口点脚本或运行脚本。这样它就会在启动 ES 进程之前在后台启动 sginit.sh。

# Run sginit in background waiting for ES to start
/sginit.sh &
Run Code Online (Sandbox Code Playgroud)

这样sginit.sh就会在后台启动,并且只会在ES启动后初始化SG。

让 sginit.sh 脚本在后台 ES 之前启动的原因是这样它就不会阻止 ES 启动。如果你把它放在 ES 启动之后,同样的逻辑也适用,除非你把 ES 的启动放在后台,否则它永远不会运行。