【问题标题】:Access Docker socket within container访问容器内的 Docker 套接字
【发布时间】:2014-03-03 00:56:19
【问题描述】:

我正在尝试创建一个容器,该容器可以通过 docker 套接字文件(主机 - /var/run/docker.sock)访问主机 docker 远程 API。

答案here 建议将请求代理到套接字。我该怎么做呢?

【问题讨论】:

    标签: docker


    【解决方案1】:

    如果打算在容器中使用 Docker,他应该清楚地了解安全隐患。

    从容器内访问 Docker 很简单:

    1. 使用docker官方镜像或者在容器内安装Docker。或者您可以按照 here 的描述使用 docker 客户端二进制文件下载存档
    2. 将 Docker unix 套接字从主机公开到容器

    这就是为什么

    docker run -v /var/run/docker.sock:/var/run/docker.sock \
           -ti docker
    

    应该可以解决问题。

    或者,您可以暴露到容器中并使用 Docker REST API

    UPD:此答案的先前版本(基于 jpetazzo post 的先前版本)建议将 docker 二进制文件从主机绑定安装到容器。这不再可靠,因为 Docker 引擎不再作为(几乎)静态库分发。

    注意事项:

    1. 容器可以访问所有主机容器,因此它可以在顶级 Docker 容器中停止、删除、以任何用户身份运行任何命令
    2. 所有创建的容器都是在顶级 Docker 中创建的。
    3. 当然,你应该明白,如果容器可以访问主机的 Docker 守护进程,它就拥有访问整个主机系统的特权。根据容器和系统 (AppArmor) 配置,它可能更危险或更危险
    4. 这里有其他警告dont-expose-the-docker-socket

    /var/lib/docker 暴露给容器等其他方法可能会导致数据损坏。详情请见 do-not-use-docker-in-docker-for-ci

    官方 Jenkins CI 容器用户注意事项

    在这个容器(可能还有很多其他容器)中,jenkins 进程以非 root 用户身份运行。这就是它无权与 docker socket 交互的原因。如此快速而肮脏的解决方案正在运行

    docker exec -u root ${NAME} /bin/chmod -v a+s $(which docker)
    

    启动容器后。这允许容器中的所有用户以 root 权限运行 docker 二进制文件。更好的方法是允许通过无密码 sudo 运行 docker 二进制文件,但官方 Jenkins CI 映像似乎缺少 sudo 子系统。

    【讨论】:

    • 另外,还有一篇很棒的进阶文章:jpetazzo.github.io/2016/04/03/one-container-to-rule-them-all
    • 挂载 docker 二进制文件是 discouraged: Former versions of this post advised to bind-mount the docker binary from the host to the container. This is not reliable anymore, because the Docker Engine is no longer distributed as (almost) static libraries.
    【解决方案2】:

    我在尝试使 docker 套接字调用从以 nobody 用户身份运行的容器中工作时偶然发现。

    在我的情况下,当my-service 尝试调用 docker 套接字以列出可用容器时,我遇到了拒绝访问错误。

    我最终使用 docker-socket-proxy 将 docker 套接字代理到 my-service。这是在容器中访问 docker 套接字的另一种方法,所以我想分享它。

    我让my-service 能够接收它应该与之通信的docker 主机,在这种情况下是docker-socker-proxy,通过DOCKER_HOST 环境变量。

    请注意,docker-socket-proxy 需要以 root 用户身份运行才能将 docker 套接字代理到 my-service

    例如docker-compose.yml:

    version: "3.1"
    
    services:
      my-service:
        image: my-service
        environment:
          - DOCKER_HOST=tcp://docker-socket-proxy:2375
        networks:
          - my-service_my-network
      docker-socket-proxy:
        image: tecnativa/docker-socket-proxy
        environment:
          - SERVICES=1
          - TASKS=1
          - NETWORKS=1
          - NODES=1
        volumes:
         - /var/run/docker.sock:/var/run/docker.sock
        networks:
          - my-service_my-network
        deploy:
          placement:
            constraints: [node.role == manager]
    
    networks:
      my-network:
        driver: overlay
    

    请注意,上面的 compose 文件已准备好 (docker stack deploy my-service),但它也应该在 compose 模式下工作 (docker-compose up -d)。这种方法的好处是 my-service 不再需要在 swarm manager 上运行。

    【讨论】:

    • 您介意解释一下为什么您的网络称为my-network,而您的服务将其称为my-service_my-network吗?
    【解决方案3】:

    我想通了。您可以简单地通过卷参数传递套接字文件

    docker run -v /var/run/docker.sock:/container/path/docker.sock
    

    正如@zarathustra 指出的那样,这可能不是最好的主意。见:https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container/

    【讨论】:

    • 你不应该这样做,见lvh.io/posts/…
    • @Zarathustra 同意并感谢。然而,问题不在于是否应该这样做。我将在此处更新答案并发出警告。
    • 那么有什么选择呢?
    • @DesmondMorris 似乎链接已失效。有更新的版本吗?
    猜你喜欢
    • 2017-07-02
    • 2018-10-13
    • 2019-08-06
    • 1970-01-01
    • 1970-01-01
    • 2015-11-29
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多