如何自定义 golang-docker 图像以使用 golang 编写脚本?

How to customize golang-docker image to use golang for scripting?

我看到这个博客:using go as a scripting language 并尝试创建一个自定义图像,我可以将其用于 运行 golang 脚本,即

FROM golang:1.15
RUN go get github.com/erning/gorun
RUN mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
RUN echo ':golang:E::go::/go/bin/gorun:OC' | tee /proc/sys/fs/binfmt_misc/register

失败并出现错误:

mount: /proc/sys/fs/binfmt_misc: permission denied.
ERROR: Service 'go_saga' failed to build : The command '/bin/sh -c mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc' returned a non-zero code: 32

它是只读文件系统,因此也无法更改权限。我在这里尝试完成的任务有据可查 here。请帮我解决以下问题:

  1. 这是否可能,即挂载 /proc/sys/fs/binfmt_misc 并写入文件:/proc/sys/fs/binfmt_misc/register ?
  2. 如果是,该怎么做?

我想,如果我们可以在容器中 运行 golang 脚本,那就太好了。

首先声明一下,我还没有对 运行 go 脚本使用 binfmt 技巧。我想它可能会起作用,但我只是在我想 运行 动态时使用 go run

这里面有很多东西要解压。容器隔离 运行 是一个在隔离环境中具有共享内核的应用程序。命名空间、cgroup 和安全设置旨在防止一个容器影响其他容器或主机。

为什么这很重要?因为 /proc/sys/fs/binfmt_misc 正在与内核交互,并且将更改推送到内核将被视为容器逃逸,因为您正在修改底层主机。

接下来要介绍的是构建映像与 运行 构建容器。当您使用 Docker 文件构建图像时,您正在定义图像文件系统和一些元数据(标签、入口点、公开端口等)。每个 运行 命令都会根据上一步的结果在临时容器内执行该命令,并且当命令完成时,它会捕获对容器文件系统的更改。当你挂载另一个文件系统时,这不会改变底层容器文件系统,所以即使你可以,挂载命令也会在镜像构建期间成为空缺。

因此,如果可能的话,您将需要在容器内而不是在构建期间执行此操作,该容器将需要特权,因为执行诸如挂载文件系统和修改 /proc 之类的操作需要通常不授予的访问权限容器,并且您将在此过程中修改主机内核。您需要使容器入口点 运行 挂载并注册 binfmt_misc 条目,并弄清楚如果该条目已经是 setup/registered 应该做什么,但可能是在另一个目录中另一个容器。

顺便说一句,在处理 binfmt_misc 和容器时,F 标志非常重要,但在您的用例中,没有它很重要。通常您需要 F 标志,以便在主机文件系统上找到二进制文件,而不是在容器文件系统命名空间中搜索。 binfmt_misc 和容器的典型用例是将主机配置为能够 运行 用于不同架构的容器,例如Docker 桌面可以 运行 amd64、arm64 和今天使用它的许多其他平台。

最后,如果你想 运行 一个容器作为一个关闭 运行 一个 go 命令作为脚本,我会跳过 binfmt misc 技巧并创建一个入口点做一个 go run 代替。但是,如果您将容器用于较长的 运行 进程,您希望定期 运行 一个 go 文件作为脚本,则需要在容器中执行此操作,并作为一个特权容器有能力逃到宿主那里