【问题标题】:How to send a command to container to change a file without running the container?如何在不运行容器的情况下向容器发送命令以更改文件?
【发布时间】:2021-05-07 14:57:28
【问题描述】:

我有一个容器 Postgres,它在其 Dockerfile 中启动一个 docker-entrypoint.sh,在该 shell 文件中有一个我想使用此命令删除的命令:

sed -i 's/exec "$@"//g' docker-entrypoint.sh

目标是能够使用修改后的 docker-entrypoint.sh 运行容器(没有 exec "@")

如何使用之前启动的命令运行容器? 我使用了另一种方法,我用另一个没有'exec“@”'的shell文件覆盖了docker-entrypoint.sh,然后我使用这个命令安装它来运行我的容器:

docker run -v $(pwd):/docker-entrypoint-initdb.d -e POSTGRES_PASSWORD=password \
     --entrypoint="docker-entrypoint-initdb.d/docker-entrypoint-custom.sh" postgres postgres

我确信有更好的方法可以让我在 bash 中运行命令,然后运行我自己的命令

我正在尝试这样的事情,但它不起作用:

docker run --rm -v $PWD:/docker-entrypoint-initdb.d -e POSTGRES_PASSWORD=password  --entrypoint=/bin/bash postgres sed -i 's/exec "$@"//g' docker-entrypoint.sh &&  postgres docker-entrypoint.sh

【问题讨论】:

  • 您当前使用的方法是 iMO 选项中最好的。
  • 您在sed 命令中使用单引号,并在其中使用$@ 变量。请注意,单引号内的任何变量都不会被插值。请使用双引号。
  • @P....exec "$@" 可能是 OP 想要替换的,即原样,没有任何替换。

标签: linux bash docker shell containers


【解决方案1】:

我使用了另一种方法,用另一个没有 'exec "@"' 的 shell 文件覆盖 docker-entrypoint.sh

好吧,您正在挂载整个目录,并且您拥有该入口点的副本。只需挂载一个文件,然后在文件中进行修改。

# docker-entrypoint-custom.sh
#!/bin/sh
# do the modification
sed -i 's/exec "$@"//g' /docker-entrypoint.sh
# Just run it
/docker-entrypoint.sh "$@"

$ docker run --rm \
       -v $PWD/docker-entrypoint-custom.sh:/docker-entrypoint-custom.sh:ro \
       -e POSTGRES_PASSWORD=password \
       --entrypoint=/docker-entrypoint-custom.sh \
       postgres postgres

另一种方法是使用修改的入口点构建另一个容器。

# Dockefile....
FROM postgres
RUN sed -i 's/exec "$@"//g' /docker-entrypoint.sh

【讨论】:

  • 这太干净了!谢谢你已经成功了!
【解决方案2】:

postgres 映像所做的默认操作是运行 postgres。如果您希望它运行其他命令,只需将该命令放在 docker run 命令的末尾即可。不用担心编辑入口点脚本。

出于调试目的,非常典型的做法是启动交互式 shell 而不是正常的服务器进程;然后你可以查看创建的文件系统,看看发生了什么。

docker run --rm -it \
  -v $PWD:/docker-entrypoint-initdb.d \
  -e POSTGRES_PASSWORD=password \
  postgres \
  /bin/bash

这里到底发生了什么?如果您查看the image's Dockerfile,您会注意到它同时包含ENTRYPOINTCMD

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["postgres"]

当你拥有这两样东西时,the CMD is passed as additional arguments to the ENTRYPOINTexec "$@" 行将入口点脚本替换为另一个由位置参数组成的命令;也就是说,它将docker-entrypoint.sh 替换为postgres。正如我在上面所做的那样,在命令行上覆盖 CMD 很容易,但替换 ENTRYPOINT 比较棘手。

这使得使用ENTRYPOINT 进行首次初始化,然后使用exec "$@" 运行CMD 的通用模式。

#!/bin/sh
# I am docker-entrypoint.sh
# Invoke me in a Dockerfile as (must use JSON-array syntax)
#   ENTRYPOINT ["/path/to/entrypoint.sh"]

# Do startup-time initialization, like creating a database or
# setting environment variables for the main process
...

# Then launch the CMD
exec "$@"

【讨论】:

  • 感谢您@David 的所有解释,但我的目标是从我的主 shell 文件中删除“exec "@" "!
  • 拥有它后你会怎么做?如果您只是希望容器在卷中设置初始数据库并运行初始化脚本,则可以将命令设置为 /bin/true,其最终效果与删除该行相同。
  • 目标是使用这个容器来运行模式的测试。/bin/true 将替换 /bin/sh 你的意思? (我不知道)
  • 如果你 docker run ... postgres /bin/true 它将启动入口点脚本。当它结束时,exec "$@" 将运行/bin/true 命令而不是启动数据库;它立即以状态码 0(成功)退出并导致容器停止。
猜你喜欢
  • 1970-01-01
  • 2019-02-02
  • 1970-01-01
  • 2021-03-14
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多