我有一个使用脚本(/bin/bash /init.sh
)作为入口点的Docker镜像。我希望在容器第一次启动时执行此脚本,但在docker守护进程崩溃后重新启动或再次启动容器时跳过此脚本。
是否可以通过docker本身实现这一点,还是必须在脚本中实现某种检查?
我有一个使用脚本(/bin/bash /init.sh
)作为入口点的Docker镜像。我希望在容器第一次启动时执行此脚本,但在docker守护进程崩溃后重新启动或再次启动容器时跳过此脚本。
是否可以通过docker本身实现这一点,还是必须在脚本中实现某种检查?
我遇到了同样的问题,这里是一个简单的过程(即解决方法)来解决它:
步骤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
步骤 2:
将“# YOUR_JUST_ONCE_LOGIC_HERE”一行替换为您想要在容器首次启动时执行的代码。
步骤 3:
将该脚本设置为 Dockerfile 的入口点:
ENTRYPOINT ["/myStartupScript.sh"]
简而言之,逻辑很简单,它检查文件系统中是否存在特定的文件;如果不存在,则创建该文件并执行您的一次性代码。下次启动容器时,文件已经存在于文件系统中,因此代码不会被执行。
docker容器的入口点告诉docker守护进程在你想要“运行”特定容器时要运行什么。让我们问一些问题,“当第二次启动容器时它应该运行什么?”或者“重启后容器应该运行什么?”
可能,你所做的是遵循“老式”的软件配置机制的相同方法。你的脚本正在“安装”所需的脚本,并将你的应用程序作为systemd/upstart服务运行,对吧?如果你这样做了,你应该把它改成更加“docker化”的定义。
该容器的入口点应该是一个实际启动你的应用程序而不是设置的脚本。假设你需要安装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脚本时会从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
我能给你的一个建议是(在我和容器一起工作的非常短的经验中):一旦容器被创建,把它们当做无状态的处理(包括所有在入口点之前运行的命令)。
我必须执行以下命令: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
这可能不是最理想的,但对我来说效果很好。
我希望在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的任务,在ONSTART时运行,该任务本身将执行放置在“c:\ app \ myTask.ps1”位置的powershell脚本。
此myTask.ps1脚本将执行您需要在容器启动时进行的任何初始化。确保在成功执行后删除此任务,否则它将在每次启动时运行。要删除它,您可以在myTask.ps1脚本的末尾使用以下命令。
schtasks /Delete /TN myTask /F