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

yptwkmov  于 2023-04-11  发布在  Kubernetes
关注(0)|答案(7)|浏览(439)

我使用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正在运行,否则脚本不会初始化任何安全索引。
脚本的内容是:

sleep 10
plugins/search-guard-5/tools/sgadmin.sh -cd config/ -ts config/truststore.jks -ks config/kirk-keystore.jks -nhnv -icl

现在,我只是在容器启动后手动运行脚本,但由于我在Kubernetes上运行它.. Pod可能会被杀死或失败,并因某种原因自动重新创建。在这种情况下,插件必须在容器启动后自动初始化!
那么如何做到这一点呢?任何帮助或提示将不胜感激。

6rqinv9w

6rqinv9w1#

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

gblwokeq

gblwokeq2#

不确定这是否能解决您的问题,但值得检查我的repoDockerfile
我创建了一个简单的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"]

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
4jb9z9bj

4jb9z9bj3#

这在以下文档中进行了说明:https://docs.docker.com/config/containers/multi-service_container/
如果您的一个进程依赖于主进程,则首先使用类似wait-for-it的脚本启动辅助进程,然后启动主进程SECOND并删除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
kmpatx3s

kmpatx3s4#

我试图解决的正是这个问题。以下是对我有效的方法。
1.创建一个单独的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映像的入口点脚本或运行脚本。以便sginit.sh在启动ES进程之前在后台启动www.example.com。

# Run sginit in background waiting for ES to start
/sginit.sh &

这样,sginit.sh将在后台启动,并且仅在ES启动后初始化SG。
在sginit.shES之前在后台启动www.example.com脚本的原因是它不会阻止ES启动。同样的逻辑适用于如果你把它放在ES启动之后,它将永远不会运行,除非你把ES的启动放在后台。

mm9b1k5b

mm9b1k5b5#

我建议把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"
bwitn5fc

bwitn5fc6#

您也可以使用wait-for-it脚本。它将等待主机和TCP端口的可用性。它对于同步相互依赖的服务的启动非常有用,并且可以像容器一样工作。它没有任何外部依赖项,因此您可以将其作为RUN命令运行,而无需执行任何其他操作。
基于thread的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;
vom3gejh

vom3gejh7#

有一个专门的工具-s6-overlay
引用他们的描述:
一个简单的init进程,允许最终用户执行初始化等任务(...)单个容器中的多个进程(...)能够以“Docker方式”操作
仓库提供了冗长的解释它是如何工作的,如何安装等,我不会在这里重复。

示例

我认为他们的仓库缺少一个工作的,简单的最小例子如何运行一个进程+一个脚本,所以我提供了一个。我修改了他们在文档中提供的例子。
假设我们想要运行nginx(或任何运行到容器生命周期结束的进程)以及一些shell脚本myscript.sh
本地目录结构:

./Dockerfile
./myscript.sh
./s6-overlay/s6-rc.d/myapp/type
./s6-overlay/s6-rc.d/myapp/up
./s6-overlay/s6-rc.d/user/contents.d/myapp

Dockerfile

FROM ubuntu
ARG S6_OVERLAY_VERSION=3.1.4.1

RUN apt-get update && apt-get install -y nginx xz-utils
RUN echo "daemon off;" >> /etc/nginx/nginx.conf

# Minimal set of dependecies required for s6
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz

# Overhead of files to manage processes via s6
COPY s6-overlay /etc/s6-overlay
# Copy the script we intend to run
COPY myscript.sh /home

# CMD is the main process - nothing special here
CMD ["/usr/sbin/nginx"]
# ENTRYPOINT must be /init for s6 to work
ENTRYPOINT ["/init"]

myscript.sh-确保它是可执行的:

#!/bin/bash
echo "foo" > /home/foo.txt
echo "bar" > /home/bar.txt

s6-overlay/s6-rc.d/myapp/type

oneshot

“一个up文件只包含一个命令行”,所以只要我们的脚本有〉1行,我们就必须将我们的脚本外包给一个单独的文件。因此,这是我们的s6-overlay/s6-rc.d/myapp/up

/home/myscript.sh

s6-overlay/s6-rc.d/myapp/contents.d/myapp是一个空文件。
现在我们只需要docker build (...)docker run -p 80:80 (...)。如果您正确完成了所有操作,您应该在容器启动时看到日志消息s6-rc: info: service myapp successfully started
然后,您可以访问localhost:80并运行docker exec CONTAINER bash -c "cat /home/foo.txt",以确认它按预期工作。
请注意,使用s6-rc.d是推荐的方法。还有一种传统的方法可以通过将myscript.sh放入文件夹/etc/cont-init.d/来实现这一点。

相关问题