【问题标题】:How can I write to a directory owned by ROOT when not running as ROOT for a Tomcat Docker Image that I don't want to edit?当我不想编辑的 Tomcat Docker 映像不作为 ROOT 运行时,如何写入 ROOT 拥有的目录?
【发布时间】:2020-12-30 11:15:12
【问题描述】:

我有一个正在尝试使用 K8s 运行的 docker 映像。我可以让它在我的家庭环境中运行,但不能在我的工作场所运行,因为我们无法在 k8 集群上以 root 身份运行。

docker 镜像是一个 Tomcat 服务器,其中包含一个 WAR 文件:

/usr/local/tomcat/webapps/ROOT.war

在启动过程中,Tomcat 尝试将 WAR 分解到此处的目录中:

/usr/local/tomcat/webapps/ROOT

但它不能这样做,因为 /usr/local/tomcat/webapps/ 归 ROOT 所有。

所以我认为最好的解决方法是像这样使用 emptyDir{} 挂载一个卷:

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers: 
    ...
    name: test-container
    volumeMounts:
    - mountPath: //usr/local/tomcat/webapps/ROOT
      name: tomcat
  volumes:
  - name: tomcat
    emptyDir: {}

但这不起作用,因为它只是在 webapps 下创建一个空的 ROOT 文件夹,Tomcat 无法将 WAR 爆炸到,因为它希望自己创建 ROOT。

我也试过这个:

    volumeMounts:
    - mountPath: //usr/local/tomcat/webapps
      name: tomcat

但现在 /webapps 只是一个空文件夹,因为我假设我正在覆盖容器在启动时为我设置的内容。

我显然在这里遗漏了一些基本的东西......我不想编辑图像,因为我相信必须有另一种方法解决这个问题我只是希望 /tomcat/webapps 可以由 runAsUser 写入,而不是根。

最好的方法是什么?

【问题讨论】:

  • 你在运行什么镜像?它是您自己构建的,还是可从 docker hub 获得的?无论哪种情况,我们都可以看看吗?我的直接反应是图像有问题,或者至少设计不佳,以至于它假定它以root 运行。
  • @larks 感谢您的关注,图像可以在这里找到:hub.docker.com/r/plantuml/plantuml-serverplantuml/plantuml-server:tomcat Jetty 图像也有类似的问题,它试图在 / 下创建一个新文件变量/库

标签: docker tomcat kubernetes containers root


【解决方案1】:

修复该问题的简单方法是通过initContainer:,尽管fsGroup: 是修复该问题的更具声明性的方法,只要您的集群的安全策略允许设置该字段

spec:
  initContainers:
  - name: chown
    image: docker.io/library/busybox:latest
    command:
    - chown
    - -R
    - whatever-the-uid-is-for-your-tomcat-image
    - /usr/local/tomcat/webapps/ROOT
    volumeMounts:
    - mountPath: /usr/local/tomcat/webapps/ROOT
      name: tomcat
  containers:
  # ... as before

【讨论】:

  • 你是不是忘了busybox容器和tomcat容器不包含相同的用户?另外,您将如何将应用程序 WAR 复制到此卷中?
  • 我说的是 uid,而不是用户,因为 chown bob 只是 chown $(awk -F: '/^bob/{print $2}' /etc/passwd) 的语法糖,目标永远不是将 WAR 复制到该卷中,而是使 ROOT 目录不由 root 拥有,因此主容器可以写入它。 webapps 目录也完全有可能需要被 chown-ed,但这不是最初的问题所问的
  • 不管你用的是uid还是users,图片都预装了不同的users。因此,您必须确保两个图像都知道您使用的 uid,例如没有人。关于 webapps 目录,它应该包含 ROOT.war。
  • 这显然是错误的,您应该仔细考虑在技术网站上留下这样的评论是否有帮助:docker run --rm -it busybox sh -exc 'touch fred.txt; chown 12345 fred.txt; ls -l fred.txt; grep 12345 /etc/passwd' 高兴地显示-rw-r--r-- 1 12345 root
  • 两点:当然你可以将busybox容器中的用户设置为任意的id,但是如果tomcat容器不知道那个用户,那是不行的,因为它不会能够运行这些文件。其次,我觉得你对我不会继续这个讨论会变得个人化和防御性。
【解决方案2】:

如果您还没有,只需为您的映像创建一个 Dockerfile 并在其中添加以下行:

...

ENV USER=<YOUR-CONTAINER-USER>
ENV UID=10014
ENV GID=10014
RUN addgroup "$USER" --gid "$GID" \
    && adduser \
    --disabled-password \
    --gecos "" \
    --home "$(pwd)" \
    --ingroup "$USER" \
    --no-create-home \
    --uid "$UID" \
    "$USER"
RUN chown -R "$USER":"$USER" /usr/local/tomcat/webapps/ROOT

USER "$USER"

...

【讨论】:

    【解决方案3】:

    我建议在 Docker 级别解决这个问题,因为无论如何您很可能必须为您的应用程序创建一个子映像。这种方法的优点是您可以在部署到 K8s 之前进行测试。此外,您可以生成更高质量的图像,而不是需要“调整”以进行保存部署的图像。

    使用 Docker 执行此操作如下所示:

    FROM tomcat
    RUN addgroup --system -gid 1000 app && adduser --system -uid 1000 -gid 1000 app
    RUN chown -R app /usr/local/tomcat/
    USER app
    COPY --chown=1000:root your-war /usr/local/tomcat/webapps
    

    任何基于 K8s 的解决方案,例如使用卷覆盖 webapp 文件夹并为该卷分配非 root 权限,都会遇到难以将 WAR 复制到 webapp 文件夹的问题。虽然理论上可以使用带有 init-containers 的复杂装置,但它们很脆弱且过于复杂(对于初学者,您必须确保 init 容器和主容器中的用户和组相同。此外,您的 WAR 需要在 init 容器中) .

    【讨论】:

    • 谢谢...如果 WAR 已经是图像的一部分,我不需要复制它对吗?我只需要做 chown -R 位
    • 没错。您在构建映像时将其复制过来。
    • 这不起作用我仍然得到同样的错误 - 这是我的 Dockerfile: RUN addgroup --system -gid 1000 app && adduser --system -uid 1000 -gid 1000 app RUN chown -R app /usr/local/tomcat/ USER app 然后在我的 k8 部署中,我将 runAsUser 设置为 1000。
    • 如果您照原样复制我的 Dockerfile,则会出现错误:它显示的是“/usr/local/tomcat/webapp”而不是“/usr/local/tomcat/webapps”。除此之外,它还有效——我只是对其进行了测试以确保。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    • 2018-10-23
    • 2018-11-15
    • 2021-06-21
    • 2019-06-10
    • 1970-01-01
    相关资源
    最近更新 更多