如何在 Docker 容器启动后自动 运行 编写脚本
How can I run script automatically after Docker container startup
我正在使用 Search Guard 插件来保护由多个节点组成的 elasticsearch 集群。
这是我的 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
初始化SearchGuard(创建内部用户和分配角色)。我需要在容器启动后 运行 脚本 init_sg.sh
。
问题是:除非 elasticsearch 是 运行ning,否则脚本不会初始化任何安全索引。
脚本内容为:
sleep 10
plugins/search-guard-5/tools/sgadmin.sh -cd config/ -ts config/truststore.jks -ks config/kirk-keystore.jks -nhnv -icl
现在,我只是在容器启动后手动 运行 脚本,但是因为我 运行 在 Kubernetes 上安装它。Pods 可能会被杀死或失败并重新创建出于某种原因自动。在这种情况下,插件必须在容器启动后自动初始化!
那么如何实现呢?非常感谢任何帮助或提示。
图像本身有一个在 Dockerfile 中指定的入口点 ENTRYPOINT ["/run/entrypoint.sh"]
。您可以将其替换为您自己的脚本。因此,例如创建一个新脚本,安装它并首先调用 /run/entrypoint.sh
然后等待 elasticsearch 在 运行 你的 init_sg.sh
.
之前开始
不确定这是否能解决您的问题,但值得检查一下我的 repo 的Dockerfile
我创建了一个简单的 run.sh
文件,复制到 docker 图像,并在 Dockerfile
中写了 CMD ["run.sh"]
。以同样的方式在run.sh
中定义你想要的任何东西并写成CMD ["run.sh"]
。您可以找到另一个示例,如下所示
Docker 文件
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"]
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
我建议将 CMD 放入您的 docker 文件中,以便在容器启动时执行脚本
FROM debian
RUN apt-get update && apt-get install -y nano && apt-get clean
EXPOSE 8484
CMD ["/bin/bash", "/opt/your_app/init.sh"]
还有其他方法,但在使用此方法之前请先查看您的要求,
ENTRYPOINT "put your code here" && /bin/bash
#exemple ENTRYPOINT service nginx start && service ssh start &&/bin/bash "use && to separate your code"
我正在尝试解决确切的问题。这是对我有用的方法。
- 创建一个单独的 shell 脚本来检查 ES 状态,并且仅在 ES 准备就绪时才开始初始化 SG:
Shell 脚本
#!/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
在 Dockerfile 中安装脚本
您需要在容器中安装脚本,以便在启动后可以访问它。
COPY sginit.sh /
RUN chmod +x /sginit.sh
更新入口点脚本
您需要编辑 ES 映像的入口点脚本或 运行 脚本。以便它在启动 ES 进程之前在后台启动 sginit.sh。
# Run sginit in background waiting for ES to start
/sginit.sh &
这样sginit.sh会在后台启动,ES启动后才会初始化SG
让这个 sginit.sh 脚本在后台 ES 之前启动的原因是它不会阻止 ES 启动。如果你把它放在 ES 启动之后,同样的逻辑适用,它永远不会 运行 除非你把 ES 的启动放在后台。
您也可以使用 wait-for-it 脚本。它将等待主机和 TCP 端口的可用性。它对于同步相互依赖的服务 spin-up 很有用,并且与容器一起工作时很有用。它没有任何外部依赖性,所以你可以 运行 它作为 运行 命令而不做任何其他事情。
基于此 的 Dockerfile 示例:
FROM elasticsearch
# Make elasticsearch write data to a folder that is not declared as a volume in elasticsearchs' official dockerfile.
RUN mkdir /data && chown -R elasticsearch:elasticsearch /data && echo 'es.path.data: /data' >> config/elasticsearch.yml && echo 'path.data: /data' >> config/elasticsearch.yml
# Download wait-for-it
ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/e1f115e4ca285c3c24e847c4dd4be955e0ed51c2/wait-for-it.sh /utils/wait-for-it.sh
# Copy the files you may need and your insert script
# Insert data into elasticsearch
RUN /docker-entrypoint.sh elasticsearch -p /tmp/epid & /bin/bash /utils/wait-for-it.sh -t 0 localhost:9200 -- path/to/insert/script.sh; kill $(cat /tmp/epid) && wait $(cat /tmp/epid); exit 0;
这在此处的文档中得到解决: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
我正在使用 Search Guard 插件来保护由多个节点组成的 elasticsearch 集群。 这是我的 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
初始化SearchGuard(创建内部用户和分配角色)。我需要在容器启动后 运行 脚本 init_sg.sh
。
问题是:除非 elasticsearch 是 运行ning,否则脚本不会初始化任何安全索引。
脚本内容为:
sleep 10
plugins/search-guard-5/tools/sgadmin.sh -cd config/ -ts config/truststore.jks -ks config/kirk-keystore.jks -nhnv -icl
现在,我只是在容器启动后手动 运行 脚本,但是因为我 运行 在 Kubernetes 上安装它。Pods 可能会被杀死或失败并重新创建出于某种原因自动。在这种情况下,插件必须在容器启动后自动初始化!
那么如何实现呢?非常感谢任何帮助或提示。
图像本身有一个在 Dockerfile 中指定的入口点 ENTRYPOINT ["/run/entrypoint.sh"]
。您可以将其替换为您自己的脚本。因此,例如创建一个新脚本,安装它并首先调用 /run/entrypoint.sh
然后等待 elasticsearch 在 运行 你的 init_sg.sh
.
不确定这是否能解决您的问题,但值得检查一下我的 repo 的Dockerfile
我创建了一个简单的 run.sh
文件,复制到 docker 图像,并在 Dockerfile
中写了 CMD ["run.sh"]
。以同样的方式在run.sh
中定义你想要的任何东西并写成CMD ["run.sh"]
。您可以找到另一个示例,如下所示
Docker 文件
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"]
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
我建议将 CMD 放入您的 docker 文件中,以便在容器启动时执行脚本
FROM debian
RUN apt-get update && apt-get install -y nano && apt-get clean
EXPOSE 8484
CMD ["/bin/bash", "/opt/your_app/init.sh"]
还有其他方法,但在使用此方法之前请先查看您的要求,
ENTRYPOINT "put your code here" && /bin/bash
#exemple ENTRYPOINT service nginx start && service ssh start &&/bin/bash "use && to separate your code"
我正在尝试解决确切的问题。这是对我有用的方法。
- 创建一个单独的 shell 脚本来检查 ES 状态,并且仅在 ES 准备就绪时才开始初始化 SG:
Shell 脚本
#!/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
在 Dockerfile 中安装脚本
您需要在容器中安装脚本,以便在启动后可以访问它。
COPY sginit.sh /
RUN chmod +x /sginit.sh
更新入口点脚本
您需要编辑 ES 映像的入口点脚本或 运行 脚本。以便它在启动 ES 进程之前在后台启动 sginit.sh。
# Run sginit in background waiting for ES to start
/sginit.sh &
这样sginit.sh会在后台启动,ES启动后才会初始化SG
让这个 sginit.sh 脚本在后台 ES 之前启动的原因是它不会阻止 ES 启动。如果你把它放在 ES 启动之后,同样的逻辑适用,它永远不会 运行 除非你把 ES 的启动放在后台。
您也可以使用 wait-for-it 脚本。它将等待主机和 TCP 端口的可用性。它对于同步相互依赖的服务 spin-up 很有用,并且与容器一起工作时很有用。它没有任何外部依赖性,所以你可以 运行 它作为 运行 命令而不做任何其他事情。
基于此
FROM elasticsearch
# Make elasticsearch write data to a folder that is not declared as a volume in elasticsearchs' official dockerfile.
RUN mkdir /data && chown -R elasticsearch:elasticsearch /data && echo 'es.path.data: /data' >> config/elasticsearch.yml && echo 'path.data: /data' >> config/elasticsearch.yml
# Download wait-for-it
ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/e1f115e4ca285c3c24e847c4dd4be955e0ed51c2/wait-for-it.sh /utils/wait-for-it.sh
# Copy the files you may need and your insert script
# Insert data into elasticsearch
RUN /docker-entrypoint.sh elasticsearch -p /tmp/epid & /bin/bash /utils/wait-for-it.sh -t 0 localhost:9200 -- path/to/insert/script.sh; kill $(cat /tmp/epid) && wait $(cat /tmp/epid); exit 0;
这在此处的文档中得到解决: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