我正在使用Java / Postgres / Docker / Gradle创建一个Web应用程序。
我的项目是这样设置的:

有一个db容器和一个应用程序容器。该应用程序容器仅运行一个普通的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)更新jar,从而触发app容器的重新部署

2)运行docker exec ...手动更新正在运行的数据库容器。

这个想法的唯一问题是,如果没有应用程序或数据库容器正在运行,则作业显然会失败。我将不得不添加检查它们是否为逻辑的逻辑。这似乎并不理想。

有人有见识吗?是否存在我不知道的解决方案?

最佳答案

这些奇怪的原因是postgres Dockerfile将其自己的docker-entrypoint.sh脚本设置为图像的ENTRYPOINT。因此,在容器启动时执行docker-entrypoint.sh,并将设置为CMD的任何内容作为参数传递给脚本。

只有在第一个传递的参数等于postgres(请参阅herehere)之后,入口脚本才会执行postgres所需的初始化步骤,例如删除特权,然后才最终执行通过CMD传递的任何内容。

覆盖ENTRYPOINT而不是CMD,实际上是用您自己的脚本包装docker-entrypoint.sh,应该可以为您提供所需的行为:

# Run monitor in the background
python3 monitor.py &

# Run postgres normally
docker-entrypoint.sh "$@"

09-04 08:14
查看更多