我有一个已安装并配置好软件的 Docker 容器。
没有任何程序应该一直启动/运行。
我想要的是 - 它能够根据外部事件启动一些命令。例如:
docker exec mysupercont /path/to/mycommand -bla -for
和
docker exec mysupercont /path/to/myothercommand
但是当容器停止时“执行”是不可能的,而且这个容器里面有一些“工作”数据,用于命令,所以我不能使用
docker run ...
每次都是因为它从图像重新创建容器并破坏我的数据。
保持此类容器运行的“正确”和“最佳”方法是什么?我可以在容器内启动哪个命令?
答案1
您不需要每次都执行docker run
。
docker run
实际上是两个命令的序列:“create”和“start”。
当你运行容器时,必须指定“ -it
”:
-i, --interactive=false 即使未连接也保持 STDIN 打开
-t, --tty=false 分配伪 TTY
例子:
docker run -it debian:stable bash
工作完成后,执行启动时指定的命令(在我的示例中为 bash)。例如,执行“exit”。容器停止:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1329c99a831b debian:stable "bash" 51 seconds ago Exited (0) 1 seconds ago goofy_bardeen
现在你可以重新开始
docker start 1329c99a831b
容器启动后再次执行命令“bash”。
使用以下命令连接到此会话“bash”
docker attach 1329c99a831b
总结:你必须了解run
和start
容器之间的区别。
此外,看看文档为参数“ ”的作用,为-i t
“ -d
”的“运行”
答案2
既然你提到了定期任务,而且你可能因为想要使用 的方式而使用 cron 之类的东西docker exec
,那么我就有适合你的药了。至少我最终做了类似的事情。
Dockerfile
FROM <some base> CMD tail -f /dev/null
按照通常的方式运行
docker run -d ....
(我使用过docker-compose
)设置主机crontab,例如:
* * * * * docker exec mysupercont foo >> /var/log/foo.log 2>&1 * * * * * docker exec mysupercont bar >> /var/log/bar.log 2>&1
我觉得这个解决方案很不错,因为我们可以在相当默认的 Linux 环境中依赖古老且经过验证的 crontab,而 Docker 可以处理业务逻辑中更奇特的依赖和环境变量。如果您的定期任务卡住并出现内存泄漏等问题,您还可以设置一些限制。
答案3
Tail 仍然会时不时地引发一些文件操作。
永远睡觉,无任何副作用
# Ah, ha, ha, ha, stayin' alive...
while :; do :; done & kill -STOP $! && wait $!
怎么运行的
while :; # Run an endless loop,
do :; # of do nothing,
done & # as background task.
kill -STOP $! # Stop the background task.
wait $! # Wait forever, because background task process has been stopped.
答案4
我自己已经使用了这里提出的所有解决方案,但是当 Docker 守护进程想要关闭容器时,它们都无法处理来自 Docker 守护进程的 SIGTERM 信号(例如docker stop $containername
)。
因此我建议如下:
FROM base:image
# ...
CMD sh -c 'trap "exit" TERM; while true; do sleep 1; done'
它基本上是一个简短的 shell 脚本,首先拦截(“捕获”)SIGTERM 信号,然后在无限循环中休眠一秒钟。
我主要将它与docker-compose一起使用,奥菲莉亚提供侧车容器来备份另一个容器中的其他服务(例如 MariaDB 数据库)。