Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
仅在第一次启动时在Docker容器中运行命令_Docker - Fatal编程技术网

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

仅在第一次启动时在Docker容器中运行命令,docker,Docker,我有一个Docker映像,它使用脚本(/bin/bash/init.sh)作为入口点。我只希望在容器的第一次启动时执行此脚本。当容器重新启动或docker守护进程崩溃后再次启动时,应该忽略此选项 是否有任何方法可以对docker本身执行此操作,或者如果必须在脚本中实现某种检查,是否可以执行此操作?docker容器的入口点告诉docker守护程序在您想要“运行”该特定容器时要运行什么。让我们问一下“第二次启动时容器应该运行什么?”或“重新启动后容器应该运行什么?” 也许,您所做的是遵循与“老式”供

我有一个Docker映像,它使用脚本(
/bin/bash/init.sh
)作为入口点。我只希望在容器的第一次启动时执行此脚本。当容器重新启动或docker守护进程崩溃后再次启动时,应该忽略此选项


是否有任何方法可以对docker本身执行此操作,或者如果必须在脚本中实现某种检查,是否可以执行此操作?

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

也许,您所做的是遵循与“老式”供应机制相同的方法。您的脚本正在“安装”所需的脚本,您将以systemd/upstart服务的形式运行应用程序,对吗?如果您正在这样做,您应该将其更改为一个更“dockerized”的定义

该容器的入口点应该是实际启动应用程序的脚本,而不是进行设置。假设您需要安装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"]
在我工作的公司,我们的容器在init.sh脚本中运行实际应用程序之前,它们从concur获取配置(而不是提供装载点并将配置放置在主机内或嵌入容器中)。因此,脚本将类似于:

#!/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

我可以给你的一个建议是(在我使用容器的短暂经验中),一旦容器被设置(在入口点之前运行的所有命令),就把它们当作无状态处理。

我想在windows容器上也这样做。它可以在windows上使用任务调度器来实现。任务调度器的Linux等价物是cron。你可以在你的案例中使用它。要执行此操作,请编辑dockerfile并在末尾添加以下行

WORKDIR /app 
COPY myTask.ps1 . 
RUN schtasks /Create /TN myTask /SC ONSTART /TR "c:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe C:\app\myTask.ps1" /ru SYSTEM
这将创建一个名为myTask的任务,并在启动时运行它,该任务本身将执行位于“c:\app\myTask.ps1”的powershell脚本

此myTask.ps1脚本将执行容器启动时需要执行的任何初始化操作。确保在成功执行此任务后将其删除,否则它将在每次启动时运行。要删除它,可以在myTask.ps1脚本末尾使用以下命令

schtasks /Delete /TN myTask /F

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

docker run -itd --name=myContainer myImage /bin/bash
docker exec -it myContainer /bin/bash -c /init.sh
现在,当我重新启动容器时,我可以

docker start myContainer
docker attach myContainer

这可能不太理想,但对我来说效果很好。

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

第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
第二步:

将行“#YOUR_JUST_ONCE_LOGIC_HERE”替换为只在容器第一次启动时执行的代码

第三步:

将Scriptpt设置为Dockerfile的入口点:

ENTRYPOINT ["/myStartupScript.sh"]

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

完全同意将容器视为无状态。如果有数据要初始化,就把它放在一个卷中。我真的很想听从你的建议,但这并不是那么容易。我对应用程序的更改几乎没有影响,为了按照您描述的方式使用它,不得不做很多更改。例如:每次容器启动时,init脚本都会为应用程序设置一个数据库。当容器重新启动时不应该发生这种情况,因为它会覆盖已经存在的数据。。。不幸的是,事实证明,要教应用程序开发人员如何使用docker非常困难。因此,我试图让它对他们来说非常简单。你是如何运行的?你能提供一个答案,然后解释为什么这是一个不好的做法,让人们决定他们是否想要它吗?我想运行一些cli命令来设置单元测试的数据,这个问题看起来和我想要的完全一样。但你的“不是答案”一点帮助都没有。这实际上是处理这种情况的最佳方式。您可以将容器作为无状态容器启动,然后在初始化命令执行一次后使其运行,这可能会执行许多操作,例如,我的操作会运行所有挂起的数据库迁移。我真的看不出有一个容器来运行迁移有什么意义。
init.sh
并没有保留下来……一开始似乎是正确的。但是,当我使用“docker容器修剪”修剪容器时,我希望启动脚本能够再次运行。这种情况不会发生。@KranthiKiranP“CONTAINER\u ready\u start”文件保存在容器文件系统中,因此如果容器使用卷,则该文件可能位于卷中。清除卷应该可以解决您的问题。我使用了这种方法,对于一个测试,如果容器已初始化,我将检查/tmp direcotry中是否有特定的文件,如:if[!-f/tmp/foo.txt];然后回显“未找到文件!”否则回显“找到文件!”fi。所以@KranthiKiranP这会涵盖你的案子。