首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  程序员

docker 镜像的用户密码的问题?

  •  
  •   rizon · 93 天前 · 2786 次点击
    这是一个创建于 93 天前的主题,其中的信息可能已经有所发展或是发生改变。

    突然想起这个问题。之所以问这个问题,是因为我最近使用 jupyter 的官方镜像,但是发现登陆的用户不是 root,缺少一些权限。

    1. docker 镜像默认是不是没有密码?
    2. 那么一些镜像如果用户不是 root 用户该怎么切换用户呢?(只有 使用--user参数这一种方法吗?)
    3. 如果我修改了用户的密码,那么 docker 的 exec 命令还可以直接进入到 bash 吗?如果可以想问一下这个 exec 命令是什么原理?为什么不用关心用户权限。
    第 1 条附言  ·  93 天前
    对于大家说的,把容器当虚拟机用这件事,其实我没有的啊。虽然我不是特别的理解容器当虚拟机或者打包整个系统为什么不对,v 友们可以指点一下哈。

    我是安装 jupyter notebook,这个程序官方就提供了镜像,这个镜像和很多其他镜像一样都是运行在一个非 root 账号下,但是 python 执行有时候要安装很多库,jupyter 的 console 不是 root 账号执行不了 apt 命令,因此我才突然想到这个问题(不给 jupyternotebook 服务 root 权限是出于安全考虑这件事我是理解的)。
    59 回复  |  直到 2018-11-27 15:55:03 +08:00
        1
    likuku   93 天前
    你这是把 docker 当虚拟机来用了...
        2
    CivAx   93 天前
    你这是把 docker 当虚拟机来用了...
        3
    zmj1316   93 天前
    我这里进去就是 root 啊,docker 默认就是 root,其他用户才需要自己建

    LS 别笑话,我还真拿 docker 当虚拟机使了🤣,每个容器单独开 ssh 映射接口出去,然后挂外面的文件夹。
    因为一台机器需要配各种环境给好多人用,每个人都要 root 权限装东西,折腾坏了还要重新配环境,除了 docker 没啥好用的了。
        4
    CivAx   93 天前
    1、docker history $imageID
    可以用来观察在你 docker pull 或者 docker run xxx 的时候,docker 自动帮你配置的镜像分别执行过什么命令。

    2、除非你用的自定义镜像;官方所有镜像都是(大都是)基于 Debian 8 来构建,并且使用 ROOT 账号执行命令, --user 的作用不是指定“这个容器内的默认用户是谁”,而是决定“由宿主机的谁来运行这个容器”,详见 Linux nameSpace 说明文档。如果一定要指定镜像的运行时用户,可以用 Dockerfile 中的 USER 参数指定,任何写在 USER 以下的命令都会被以 $USER 来执行

    3、docker -it exec root $containerName bash
    翻译:
    docker -参数(启用交互式 分配伪终端) exec 以 root 用户身份 $容器名 使用 bash 作为 session (你开心可以用 sh )
        5
    rizon   93 天前
    @CivAx #4
    你说的 --user 表示的是宿主机的用户?可是我使用`docker exec --user jovyan -it datascience_jupyter_lab bash`这个命令登陆进去就是 jovyan 这个用户,但是这个用户宿主机里是没有的。 所以这里匹配的还是容器里的用户吧
        6
    CivAx   93 天前
    @rizon docker run
        7
    stebest   93 天前
    这些都是 linux 的基本操作,,,和 docker 没啥关系,在 Linux 怎么创建用户怎么切换用户,在这里就怎么弄
        8
    gam2046   93 天前
    @CivAx 求大佬科普下。

    我感觉 Docker 内分帐号意义并不是很大,因为 docker 本身被设计成一个容器只做一件事(虽然有人会在单容器内启动多个业务)。

    那么在一个容器,只有一个工作的情况下,再划分多个帐号的意义是什么呢?退一步说,即使容器内业务存在漏洞,被人渗透,取得 webshell 或其他同等性质的权限。容器内的 root 并没有什么特别。

    尽管如此,我发现有些镜像,例如 php、Tomcat 一类的,依旧会采用多用户的形式,例如会创建一个 www-data 的用户。而非采用默认的 root。所以,我觉得这其中应该有我没想到的原因吧?
        9
    kios   93 天前
    我觉得你对 docker 的理解错了
        10
    grantonzhuang   93 天前 via Android
    @gam2046 我也有相同的疑问
        11
    shylockhg   93 天前
    docker container 就是活在妄想里的宿主机进程。。。
        12
    shylockhg   93 天前
    @gam2046 用户有各种需求,比如我现在在用 docker+vim 开发,开发环境异常纯净
        13
    shylockhg   93 天前
    1.看镜像 build 怎么设置
    2.su
    3.exec 就是执行 container 里的程序
        15
    passerbytiny   93 天前
    @zmj1316 如果你只把 /opt 目录挂载成卷,那么创建用户、yum/apt-get 安装程序等等操作,容器都是干不了的,必须重建镜像;如果你把 /etc、/usr/local、/var 都挂载成了卷,那这容器就是个云主机,还需要脱裤子放屁地映射端口:那么用 docker 当虚拟机到底有啥好处。不会是不挂载数据卷,出问题的时候直接销毁并重建容器吧,相当于“快速重新安装系统”。
        16
    CivAx   93 天前
    @gam2046
    第一段:
    我就被要求过一个 Docker 起一堆服务打包成一个“系统”来进行快速部署,然后在 V 友的帮助下劝说了他放弃了这个念头(可以翻翻我的发帖纪录,我觉得那个帖子仅为其中的评论也都值得收藏)。

    第二段:
    实际上是有“特别”的。
    除了极其严重的“ Docker 逃逸”等漏洞,还有一个十分低级但很常见的错误会导致以 root 权限运行的容器会另宿主机暴露在风险之中。
    由于 nameSpace 的关系,如果你在 docker run 的时候--user 指定为 root,那么这个容器(实际上恰当的叫法是进程)则活在 root 的 nameSpace 里,也就是俗称的“具有 root 权限”。如果你还不幸地挂载了高危目录,譬如 -v /:/host 或者 -v /etc:/etc,那么一旦因为某些软件的漏洞,攻击者攻破进入到容器中,他直接 chroot 就直接有可以破坏宿主机的能力。

    第三段:
    “ docker run -it debian ”
    “ cat /etc/passwd ”
    ----
    “ docker run -it tomcat ”
    “ cat /etc/passwd ”
    “ cat /etc/issue ”
        17
    julyclyde   93 天前
    我还以为没人批判把容器当虚拟机用呢,原来还是有懂行的人的
        18
    Beebird   93 天前
    @rizon 出于安全考虑,越来越多的 docker image 中的 User 不再是 root 了,如果你一定要以 root 身份登录到 docker container 中,可以试试 docker exec --privileged -u root -it <container id> sh
        19
    zmj1316   93 天前
    @passerbytiny 我只挂外面用户自己的数据卷,方便直接跑代码和模型,挂其他的我还怎么配不同的环境啊......非要建用户直接在 Dockerfile 里面建就行了啊。容器被玩坏了就直接从 image 重新开一个出来,数据卷一直在的。

    主要目的一个是方便配环境,网上去下就行了,还有因为用户是小白,经常会玩坏系统。。。。。。

    我的情况是,一个实际用户会需要开多个不同环境的容器,挂的是同一个数据卷,一个容器只有一个实际用户使用的。。。
        20
    ipwx   93 天前
    @zmj1316 我大概理解你的场景,但是我觉得你的管理方法有问题。

    我建议你开放 docker 权限给你们组里面其他人,每个人专用自己的环境。好多人共用一个 Docker 环境,这和原来的直接裸机装环境,有什么差别呢?

    什么,你说裸机装机太麻烦?我这边都是用 Ansible 装裸机环境的。被搞坏了很快就能回复。当然,在此之前,我会对一切要求我用 root 装环境的组员说不,所以也就没那么多可能的搞坏的情况了。

    如果不下方 Docker 容器的权限给组员,有组员要 Python 2,有组员要 Python 3,有组员要特殊的系统包才能运行 pip,都来找你处理吗?
        21
    ipwx   93 天前
    @zmj1316 然后对于小白用户,你直接给他们做一个巨大的整合的 Docker Image 就好了。。。
        22
    zmj1316   93 天前
    @ipwx
    1. 我这里容器专人专用,谁要用某个环境,我就给他从对应的 image 开一个容器和配套的端口,把他的数据卷挂进去,没有共用的说法。

    2. 这些都是一次性的要求,每次有新的环境要求出来,我都单独配好 image,下次谁再要的我就直接从现有的开容器出去了。像 py 版本这样简单的需求,让他自己去容器里面装都没事,反正容器就他自己用,root 自己折腾去😄
        23
    raysonx   93 天前
    @zmj1316 @rizon 又见 X-Y 问题( https://coolshell.cn/articles/10804.html )。。。
    用户需要的不是容器本身,而是为了解决某一实际问题,容器只是你为了解决某问题而设想的一种手段。你应该直接说为了解决什么问题,而不是隐藏要解决的问题,自己提出一种方案,然后询问要关于这种方案的问题。
        24
    raysonx   93 天前   ♥ 1
    回到正题:

    > docker 镜像默认是不是没有密码?
    没有。容器不是虚拟机,只是内核提供的一种资源隔离手段。Docker daemon 本身是以 root 用户运行的,在创建新进程时直接用 setuid 就可以切换为指定的用户。

    > 那么一些镜像如果用户不是 root 用户该怎么切换用户呢?(只有 使用--user 参数这一种方法吗?)
    对,只有这一种方法。实际用户是由容器启动时决定的而不是镜像构建时决定的,镜像中只是指定了--user 参数的默认值。

    > 如果我修改了用户的密码,那么 docker 的 exec 命令还可以直接进入到 bash 吗?如果可以想问一下这个 exec 命令是什么原理?为什么不用关心用户权限。
    假设无效,见问题 1 的回答。
        25
    zmj1316   93 天前
    @raysonx 实践出真知,又不是我设想的,我用了以后的确摆脱了大量的 SA 工作啊。

    用户要的就是个能 root 的虚拟机,可是显卡虚拟化太蛋疼了,还要帮用户配环境太蛋疼了,有那个找人问的时间我早已经把问题解决掉了。
        26
    raysonx   93 天前
    @zmj1316 我不知道你的具体应用场景,所以不扯太多了。总之感觉这种用法是歪路子。。。
        27
    passerbytiny   93 天前
    @zmj1316 结合你楼下的回复,大致推测你的管理方式:来一个人或任务就给一个容器,搞坏了或者不想用了,容器直接销毁;每个人有一个专门的数据卷。

    首先要说明一点,你这种环境,数据卷只起到了外置可共享磁盘的作用,或者就叫做:可挂载的网盘。

    你这种方式正好应了我原来的推测: [不会是不挂载数据卷,出问题的时候直接销毁并重建容器吧,相当于“快速重新安装系统”。]

    你这种工作,不用 docker,换成 hyper-v、vmware、virtualbox 都能做,而且制作镜像、挂载和管理共享盘、配置网络等等更方便。
        28
    rizon   93 天前
    @CivAx docker run 指定的用户也是镜像里的用户,我实际测试过,用户‘ games ’在 busybox 镜像里面没有,就无法使用该用户运行镜像


    @raysonx 你说的第三条假设无效,我不是很理解。我测试过了,修改了用户密码后,可以正常使用 sudo 和 su 操作了。不过 exec 命令确实可以直接登陆。
        29
    zmj1316   93 天前 via Android
    @passerbytiny 因为这几个虚拟机没有现成的镜像,而 docker 有丰富的 dockerfile 资源,拿来就用,我这人懒🤣。

    并且这几个要搞 gpu 虚拟化什么的,配起来很麻烦,不像 nvidia docker 基本无缝。
        30
    raysonx   93 天前 via Android
    @rizon 你的理解是不对的。Docker 默认不启用 user namespace,容器内的用户和主机的用户实际上是相同的。你看到的只是用户名不同,用户名只是一个显示问,那是虚的,实际的 uid 是相同的。假如你在 docker 里以 root 用户运行,他就是真正的 root 用户,只不过 docker 默认 drop 了一些 privilege。假如你挂载一个卷,里面只允许 root 用户读写,则容器里的 root 用户也是可以读写的。
    su 要求密码只是 su 自己的逻辑。在 host 上运行 docker exec --user 不需要任何密码。
        31
    raysonx   92 天前 via Android   ♥ 1
    继续补充:
    su 和 sudo 这种程序是带有 setuid 属性的程序,普通用户执行这个程序会被提权到 root。验证密码只是 su 和 sudo 的内部逻辑。

    总之,我想表达的意思是,docker run 或者 docker exec 不需要密码的本质原因是,docker daemon 是以 root 用户运行的,启动 container 的过程就是创建子进程的过程,子进程一开始也会继承 root 用户,接下来会通过 setuid 和 setgid 调用直接切换用户,不需要密码是因为它一开始是 root。这一切过程都和你 image 里的密码什么的无关。
        32
    htfy96   92 天前
    @zmj1316 这种情况建议使用 lxd,是最佳使用情景。现在 lxd 搞 GPU 虚拟化也非常方便。
        33
    zmj1316   92 天前
    @htfy96
    tensorflow 官方就两种安装方法,pip 和 docker ;
    cuda 对 docker 也有官方 dockerfile 支持;
    caffe 也有
    NV 有完整的 nvidia-docker 支持

    所以虽然 LXD 可能是很好,但是对我这种懒人来说,docker 是唯一选择,
    因为主要矛盾不在用什么虚拟化这里,而是配环境实在太 TM 麻烦了。。。。。。
        34
    ljtletters   92 天前
    有了 sudo 和有了 root 有什么区别。。。
        35
    ipwx   92 天前
    @zmj1316 我也是实践出真知。

    我目前的方案是,开放所有计算节点(含 GPU )的 SSH 登陆,通过编辑 /etc/sudoers 允许用户 sudo docker 和 sudo nvidia-docker。

    提供一些整合过的大型 image。

    结束。
        36
    ipwx   92 天前
    @zmj1316 这样的好处有两个:

    1、用户不满意我的镜像,可以字节去学 Dockerfile 怎么写呀,或者给我个 PR。 ( https://github.com/haowen-xu/docker-ml-runtime)
    2、我们有很多机器。要像你的做法,难道每台机器给每台用户预先都开一个 container 吗?太麻烦了。。。还不如让用户自己解决。
    3、我这边机器上有 Mesos 系统,用户可以直接跑 Dockerized Spark。后续正计划写个脚本,用户可以直接提交一个程序,作为 Mesos 任务并使用 Docker 镜像运行。
        37
    ipwx   92 天前
    @zmj1316 顺便我这边很早就部署了 LDAP 登陆验证,所以每台机器的账号系统是联通的。
        38
    zmj1316   92 天前
    我这里的用户要求比较挑,他们不希望去了解任何 docker 的东西,要求的就是开箱即用,SSH 连上去,root 耍起来,缺了什么东西装不了的就指挥我去装;

    一开始我也是直接几个 image 丢过去,让他们自己启动进去用,一 智障 说接受不了不想学怎么用,直接把整台服务器拔了电给搬自己位子用去了,所以我这操作实属无奈
        39
    zmj1316   92 天前
    @ipwx 忘记 @ 了,感觉歪楼了,不说了,都是泪啊
        40
    zmj1316   92 天前
    顺便给 LZ 说一下,你要在 docker 容器里面执行 apt 命令,其实已经是在当虚拟机用了,因为一般 apt 这种操作是在构建镜像的时候用的,你要是缺什么东西,可以写 dockerfile 里,装到镜像里面,然后再启动容器
        41
    rizon   92 天前
    @raysonx 谢谢,懂了,是 docker daemon 创建子进程,所以不需要密码。
        42
    rizon   92 天前
    @zmj1316 嗯,这样说的确是当虚拟机用了。。。可是,,,可是这样用是真的好用啊。做环境隔离和业务场景隔离,docker 和虚拟机比起来,实在是太好用了啊。。。
        43
    raysonx   92 天前
    @rizon 然而就你们这么个用法,容器的优点并没有最大发挥出来。容器最大的优点在于“一次构建,到处运行”,听起来是不是很熟悉?
        44
    ipwx   92 天前
    @zmj1316 你这管理员对于机器的管理怎么这么弱?。。。 我这边直接怼回去,要么学,要么别用。
        45
    wwhio   92 天前
    额,我和楼主的方法差不多,实验室里的一台 GPU 服务器被整个学院的同学分享,每个人都有自己的需求,于是最后做了几个不同的镜像,镜像里只提供 cuda + sshd,设置容器内 root 账户的密码后把密码和 ssh 端口提供给同学使用。

    看了楼上的大佬发言,我大概说一下需求,借楼问下有什么好的解决方案。

    1. 用户间不能互访数据,环境独立
    2. 可以限制 CPU、内存、GPU 等资源
    3. 不能拿到主机的 root 权限
    4. 可以 apt

    其实我这边的用户并没有使用 docker 的需求。另外,LXD 我会去看的,先谢谢大佬们。
        46
    passerbytiny   91 天前
    @zmj1316 #28 问一下,有没有出现过容器占用空间爆掉的情况,印象中容器中也是分层的,占用空间只增不减。
    @ipwx 你也看一下,他这种这么懒的情况,估计也不太可能把易变的目录都挂载成卷。
        47
    zmj1316   91 天前
    @passerbytiny docker 的文件系统应该都是有 COW 的,只开容器不修改的话基本不占用空间,占空间的只有 image 本身。

    如果出现容器空间爆了,一般是有人在容器里面除了数据卷之外的地方放了大量文件,
    这个我是直接告知,放在数据卷之外地方的文件不保证数据安全,所以目前他们应该还是乖乖放数据卷里面的
        48
    ipwx   90 天前
    @passerbytiny 我对容器没有多大限制,不过因为我们这边部署了 MooseFS,所以每个人的 /home 有配额限制。是按路径来的,不是按用户来的,所以当多人合作一篇论文的时候,哪怕都用 root 启动 docker,-v 挂载进去,配额还是在的。你总不好意思把你的文件放到别人 /home 下面不是?至于每台计算节点本身,不好意思,随时可能重装,不做备份警告。
        49
    ipwx   90 天前
    @passerbytiny MooseFS 是分布式文件系统,我单独开了五台服务器,和那十几台计算节点是独立的。
        50
    ipwx   90 天前
    @zmj1316 @wwhio 我一直是觉得,能够用管理的方法解决的问题就用管理的方法解决,不要什么都让技术做。所以我很强硬地推行了裸机无运行环境(包括无 CUDA )、分布式文件系统、配额,以及 Docker。配额是每个人的个人目录不超过 50 万个 inode 和不超过 2T 的数据。因为 50 万的 inode 限制,所以用 Anaconda 这种方式自己部署 Python 环境,是比较吃力的,所以他们不得不去学习 Docker 的用法。

    这些措施倒是一点点来的,最后一个 Docker 化是一年前完成的。不过讲道理一开始我们这边的这套集群计算系统(计算节点和存储节点集中管理,还包括 LDAP 集中式用户系统)就是我搭起来的,也没啥太大阻力。。。目前运行良好。说实话作为用户来说,这些东西的用法都很好学,明明是计算机专业的,根本不可能学不会,不会就是懒。
        51
    ipwx   90 天前
    @passerbytiny 回到正题吧。Docker 容器空间爆炸的事情?我这边是完全不考虑的。假设某台机器因为 Docker 镜像太多而磁盘占满了,大不了重装呗。再说我会不定时运行 docker system prune,不会占满的。

    你和 @zmj1316 会有这个顾虑,是因为你们俩希望 Docker 对用户透明,并且在 Docker 里面开了 sshd 让用户为所欲为。这个事情很难搞,说实话。因为 Docker 设计上就不是这么用的。

    而我这边就没这个顾虑,因为我一开始就教育用户,要把文件放在 MooseFS 的路径上。Docker 容器里面想用,就挂载进去用。其实只要教给他们普通用法就行了,他们一般不会出错的。更高级的用法他们可以自学,学会了自然更不会出错了。另外我还提供一项额外服务,就是给新手一个模板脚本,在 Docker 里面启动一个 Jupyter Notebook,并且正确地挂载他们的 /home。

    如果不是这么一套管理方法,10+ 的 CPU 计算节点和 3 台 GPU 计算节点,我不是得管死。。。
        52
    zmj1316   90 天前   ♥ 1
    @ipwx 管这么多机器,这已经是真 SA 了,换成我得加钱 2333333
        53
    ipwx   89 天前
    @zmj1316 其实还好,除了刚开始搭建这套系统用了不少时间,但因为用的都是尽可能鲁棒的体系,搭完之后基本不用维护 wwwww
        54
    rizon   89 天前
    @ipwx 问个事情啊,容器只能在启动之前挂载本地目录,是这样吧? 那如果一个容器在使用过程中突然发现有个目录需要映射到本地,这时候该怎么办呢?
        55
    rizon   89 天前
    @ipwx 你说的“因为我一开始就教育用户,要把文件放在 MooseFS 的路径上。Docker 容器里面想用,就挂载进去用。”这句我不是很理解,moosefs 就是类似 haoop hdfs 的东西?你说的“容器里想用就挂载进去”这句话 是怎么挂载进去??
        56
    ipwx   88 天前   ♥ 1
    @rizon

    1. 关掉容器,删掉容器,重新建立容器。
    2. MooseFS 不是类似 Hadoop HDFS 的东西。MooseFS 实现了全功能的 Posix Filesystem,可以像本地磁盘一样 mount 到本地目录上。所以可以 docker -v 挂载进容器。

    你看,因为 Docker 的限制,它的用法和虚拟机是很不同的。Docker 容器的正确用法是不在容器里面放持久数据。我选择的策略就是通过 MooseFS 给用户一个跨机器能持久存储数据的“本地文件系统”,用起来和普通的本地文件系统没有区别。在此基础上,他们可以使用跨机器的 Anaconda (如果不超过 50 万个文件的配额,我特别设置的),或者使用 Docker -v 挂载。事实上我这边,用户的整个 /home 目录都是在 MooseFS 上的。
        57
    rizon   88 天前
    @ipwx 好的,明白了,谢谢哈~

    @raysonx 谢谢哈~
        58
    passerbytiny   88 天前
    @ipwx 你的这种方式,是要使用人自己定义镜像的,自然可以进一步限制他们不能用 yum install/apt-get install,不能编辑 /usr/local/systemd ……等等,所以没啥可担心的。然而他哪种懒惰的方式,估计是啥也不会限制,等用户一通 install/remove 后,容器占用空间就可能爆了。
        59
    ipwx   87 天前
    @passerbytiny 我不太理解,如果持久数据不存在计算节点上,爆空间有啥可担心的,大不了重装一下裸机呗。再说服务器好歹少说 3T 一般都是 6T 以上的,哪这么容易爆。

    我反正没限制用户在 docker 容器里面 apt-get install。至于什么 -v 本机根目录然后 chroot,这种高端操作我这边用户都不会呢。再说哪怕搞坏了,参考前面说的,大不了重装一下呗。反正我有 ansible 脚本。

    所以综上所述,唯一最重要的一点就是持久性的数据要存在分布式文件系统上,不要放在计算节点上。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2228 人在线   最高记录 4385   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 23ms · UTC 05:18 · PVG 13:18 · LAX 21:18 · JFK 00:18
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1