我正在使用Java / Postgres / Docker / Gradle创建一个Web应用程序。我的项目设置如下:
有一个db容器和一个应用程序容器。 app容器只运行一个普通的jar文件。使用主机系统中的卷添加jar文件。容器最初运行此jar并监视它以进行更改。如果它发生变化,它会重新部署jar,允许开发人员立即查看其本地计算机上的更改。这就像在Tomcat上部署/更新war文件一样。当您按下按钮时,实时应用程序会更新。无需停止应用程序,重建并重新运行:只需重建即可。
使用Dockerhub上的Postgres映像,我想做类似的事情:我想在gradle中“按下一个按钮”,它将更新由DB容器监视的一些文件并重新部署。
不幸的是,我撞墙了。我最初的想法是创建一个扩展Postgres的Dockerfile。它只会像往常一样运行Postgres服务并运行脚本来查找某些文件中的更改并重新部署。
不幸的是,以下Dockerfile失败:
FROM postgres:9.4
WORKDIR /db
COPY monitor.py .
COPY run-pg-and-monitor.sh .
CMD ["run-pg-and-monitor.sh"]
shell脚本具有以下命令:
# Run monitor in the background
python3 monitor.py &
# Run postgres normally
postgres
不幸的是,这与Postgres没有关系。我收到错误:
db_1 | "root" execution of the PostgreSQL server is not permitted.
db_1 | The server must be started under an unprivileged user ID to prevent
db_1 | possible system security compromise. See the documentation for
db_1 | more information on how to properly start the server.
如果我要将命令设置为:
CMD ["postgres"]
这是Postgres容器最初做的,错误就消失了。显然,这不会运行我需要的monitor.py。
奇怪的是,在没有方括号的情况下运行CMD也会导致此问题。
CMD postgres
从shell环境运行它也会失败:
CMD [“sh”,“ - c”,“postgres”]
也许这与从shell运行它有关...
我知道postgres应该是从postgres用户而不是root用户运行的。我觉得奇怪的是,如果我将CMD设置为:
CMD ["whoami"]
我明白了:
db_1 | root
所以,它已经以root身份运行postgres而没有任何问题。
我的第二个想法是做一个gradle任务:
1)更新触发重新部署app容器的jar
2)运行docker exec ...
以手动更新正在运行的db容器。
这个想法的唯一问题是,如果没有运行app或db容器,作业显然会失败。我将不得不添加逻辑,检查它们是否是。这似乎并不理想。
有没有人有任何见解?有没有已经存在的解决方案我不知道?
这些奇怪的原因是postgres Dockerfile
将它自己的docker-entrypoint.sh脚本设置为图像的ENTRYPOINT。所以在容器启动时执行docker-entrypoint.sh
并设置任何设置为CMD
作为其参数传递给脚本。
只有当第一个传递的参数等于postgres
(参见here和here)时,入口脚本才会执行postgres所需的初始化步骤,最后只需执行通过CMD
传递的任何内容。
覆盖ENTRYPOINT
而不是CMD
,基本上用你自己的脚本包装docker-entrypoint.sh
,应该给你想要的行为:
# Run monitor in the background
python3 monitor.py &
# Run postgres normally
docker-entrypoint.sh "$@"