我对docker不太成熟的认知!写的不好望指出!互相学习、交流!
对docker的认知
为什么说Linux内核又躺枪了,本人不想背锅,只能把锅甩给Linux 内核了,哈哈哈…
docker依赖于Linux的两个内核特性:
1 2 | Namespaces - 命名空间 Control groups(cgroups)- 控制组 |
Namespaces
命名空间提供了一种系统资源的隔离,包括了文件系统、网络、进程等。
docker有以下5种命名空间:
1 2 3 4 5 | PID:进程隔离 NET:网络管理接口 IPC:管理跨进程通信访问 MNT:管理挂载点 UTS:隔离内核和版本标识 |
Control groups
这是Linux内核提供的一种可以限制,记录,隔离物理进程组的机制。他提供了以下功能:
1 2 3 4 | 资源限制 优先级设定 资源计量 资源控制 |
docker 基本能力
1 2 3 4 5 6 | Namespaces和Control groups带给了容器下面的能力: 文件系统的隔离:每个容器都有自己的root文件系统 进程隔离:每个容器都运行在自己的进程环境中 网络隔离:每个容器间虚拟网络接口和ip地址都是分开的 资源隔离和分组:Control groups可以将CPU和内存之类的资源独立分配给每个docker容器 |
场景
我们在使用docker容器的时候,经常要给容器里面挂载本地服务器目录,从而实现某个文件在宿主机和容器内部都可以访问的效果。
例如:在容器内部进行删除、添加、复制、剪切、读写文件,说白了就是访问挂载的卷
问题 - docker挂载volume的权限问题
报错:一般都是在进行一系列操作抛出权限问题
1 2 3 | touch: cannot touch '/var/jenkins/copy_file.log' : Permission denied can not write to '/var/jenkins/copy_file.log' . Wrong volume permission? # 这是在说你没有权限在这个目录里面创建文件,以及写东西 |
原因
1 | 因为容器共享宿主机的uid,如果不指定user,容器内部默认使用root用户来运行,容器内部用户的权限与外部用户相同,所以一定要确保容器执行者的权限和挂载数据卷对应 |
扩展干货…(后续会继续补充)
1、为什么docker输出的文件权限为 root?
Docker容器运行的时候,如果没有指定user,容器内部默认以root用户运行
2、怎么确定运行的用户为root?
可以通过容器里的执行用户的id是0,输出文件的权限也是0。
当docker容器运行在宿主机上的时候,仍然只有一个内核。容器共享宿主机的内核,所以所有的uid和gid都受同一个内核来控制。
比如,当一个进程尝试去写文件,内核会检查创建这个进程的的user的uid和gid,来决定这个进程是否有权限修改这个文件。
1 2 3 4 5 | # 怎么查看用户的UID和GID? (1)id 用户名 (2)cat /etc/passwd | grep 用户名 # root:x:0:0:root:/root:/bin/bash # 两个bai0就是uid和gid |
3、为什么容器里的用户名不一定和宿主内核一样呢?
比如,test 容器的用户叫做 test, 而本机没有 test 这个用户。这是因为username不是Linux kernel的一部分。简单的来说,username是对uid的一个映射。由于权限控制的依据是uid,而不是username。
1 | That’s because the username (and group names) that show up in common linux tools aren’t part of the kernel, but are managed by external tools (/etc/passwd, LDAP, Kerberos, etc). So, you might see different usernames, but you can’t have different privileges for the same uid/gid, even inside different containers |
解决方案
方案一 : 关闭SELinux
- 临时关闭(不用重启机器)SELinux
1 2 | # 执行命令 setenforce 0 |
- 修改配置文件需要重启机器(或者使用source使其生效,没有亲测,不确定是否有效)
1 2 | # 修改/etc/selinux/config 文件 将SELINUX=enforcing改为SELINUX=disabled |
方案二:指定user
- 使用run的时候指定
1 2 3 | # 通过volume挂载的方式,指定运行user为1001, 启动容器 test: docker run -d --name test -p 8080:8080 -u 1001:1001 -v $(pwd):/tmp test # docker run -u 可以指定宿主机运行docker命令的用户, -u指定的uid就是docker实际运行的进程拥有者 |
- 亦可以在dockerfile的时候指定
1 2 3 4 5 6 | RUN useradd -r -u 1001 -g test test USER test # -g:指定用户所属的群组。值可以使组名也可以是GID。用户组必须已经存在的,期默认值为100,即users。 # -u:指定用户ID号。该值在系统中必须是唯一的。0~499默认是保留给系统用户账号使用的,所以该值必须大于499。 # -r:建立系统账号。 # USER指令用于指定容器执行程序的用户身份,默认是 root用户。 |