仅在第一次启动时在Docker Container中运行命令

joh*_*ugh 21 docker

我有一个Docker Image,它使用Script(/bin/bash /init.sh)作为入口点.我想只在第一次启动容器时执行此脚本.在docker守护程序崩溃后重新启动或重新启动容器时应该省略它.

有没有办法用docker本身做这个,或者如果必须在脚本中实现某种检查呢?

Sam*_*cía 11

docker容器的入口点告诉docker守护程序当您想要"运行"该特定容器时要运行什么.让我们问一下问题"第二次启动容器时应该运行什么?" 或"重启后容器应该运行什么?"

也许你正在做的是采用与"老派"供应机制相同的方法.您的脚本正在"安装"所需的脚本,您将作为systemd/upstart服务运行您的应用程序,对吧?如果您这样做,您应该将其更改为更"停靠"的定义.

该容器的入口点应该是实际启动应用程序而不是设置的脚本.假设您需要安装java才能运行您的应用程序.所以在dockerfile中你设置了基本容器来安装你需要的所有东西:

FROM alpine:edge

RUN apk --update upgrade && apk add openjdk8-jre-base
RUN mkdir -p /opt/your_app/ && adduser -HD userapp

ADD target/your_app.jar /opt/your_app/your-app.jar
ADD scripts/init.sh /opt/your_app/init.sh

USER userapp
EXPOSE 8081

CMD ["/bin/bash", "/opt/your_app/init.sh"]
Run Code Online (Sandbox Code Playgroud)

在我工作的公司,我们的容器,在init.sh脚本中运行实际应用程序之前,他们从consul获取配置(而不是提供挂载点并将配置放在主机内或将它们嵌入到容器中).所以脚本看起来像:

#!/bin/bash

echo "Downloading config from consul..."
confd -onetime -backend consul -node $CONSUL_URL -prefix /cfgs/$CONSUL_APP/$CONSUL_ENV_NAME
echo "Launching your-app..."
java -jar /opt/your_app/your-app.jar
Run Code Online (Sandbox Code Playgroud)

我可以给你的一个建议是(在我使用容器时非常短暂的经验)将容器视为配置后无状态(在入口点之前运行的所有命令).

  • 我真的想跟着您的建议,但它不是那么容易的.我对应用程序的更改影响很小,必须改变A LOT才能按照你描述的方式使用它.例如:每次容器启动时,init脚本都会为应用程序设置数据库.当容器重新启动时不应该发生这种情况,因为它会覆盖已经存在的数据......不幸的是,它证明很难教会应用程序的开发人员如何使用docker.因此,我试图保持它为他们极其简单. (3认同)

Fra*_*ina 11

我有同样的问题,这里有一个简单的程序(即解决方法)来解决它:

步骤1:

创建包含以下代码的"myStartupScript.sh"脚本:

CONTAINER_ALREADY_STARTED="CONTAINER_ALREADY_STARTED_PLACEHOLDER"
if [ ! -e $CONTAINER_ALREADY_STARTED ]; then
    touch $CONTAINER_ALREADY_STARTED
    echo "-- First container startup --"
    # YOUR_JUST_ONCE_LOGIC_HERE
else
    echo "-- Not first container startup --"
fi
Run Code Online (Sandbox Code Playgroud)

第2步:

仅在第一次启动容器时,将"#YOUR_JUST_ONCE_LOGIC_HERE"行替换为您要执行的代码

第3步:

将scritpt设置为Dockerfile的入口点:

ENTRYPOINT ["/myStartupScript.sh"]
Run Code Online (Sandbox Code Playgroud)

总之,逻辑非常简单,它检查文件系统中是否存在特定文件; 如果没有,它会创建它并执行你曾经的代码.下次启动容器时,文件位于文件系统中,因此代码不会执行.

  • @KranthiKiranP“CONTAINER_ALREADY_STARTED”文件保存在容器文件系统中,因此如果容器使用卷,则该文件可能在卷中。清除卷应该可以解决您的问题。 (2认同)

小智 7

我不得不这样做,最后我做了一个docker run -d,它刚刚创建了一个分离的容器并开始bash(在后台),然后是一个docker exec,它进行了必要的初始化。这是一个例子

docker run -itd --name=myContainer myImage /bin/bash
docker exec -it myContainer /bin/bash -c /init.sh
Run Code Online (Sandbox Code Playgroud)

现在当我重新启动我的容器时,我可以做

docker start myContainer
docker attach myContainer
Run Code Online (Sandbox Code Playgroud)

这可能不理想,但对我来说很好用。