docker命令合集

发布于 2019-07-16  292 次阅读


1.第一阶段初阶命令

1.docker run

$ docker run -it busybox /bin/sh
/ #

  1.-it参数告诉Docker项目启动容器后给我们分配一个文本输入、输出环境,即TTY,这样我们就可以与容器进行交互。后面的/bin/sh就是要运行的程序。

  2.在容器里执行ps可以看到容器内的进程,证明已经和宿主机隔绝了。其实调用的是系统进程相关的命令clone(),在其中选择CLONE_NEWPID参数就能进入新的参数空间。

2.pid namespace

int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);

  1.除了PID Namespace,Linux还提供了各种Namespace,如Mount、UTS、IPC、Network、User等Namespace来对进程进行操作。Mount能让其看到Namepsce的挂载点信息、Network可以看到网络设备和配置。所以对隔离环境负载的其实还是宿主机本身,而docker其实和运行起来的容器是同级的。

  2.虚拟机能模拟硬件靠的是Hypervisor的软件,该软件提供硬件虚拟化的功能。微软的Azure云计算平台实际上是运行在windows集群上的,但是并不妨碍在上面创建各个版本的Linux虚拟机。

  3.关于容器安全方面,虽然我们可以使用Seccomp对容器内部所有系统调用进行过滤和甄别,但是一层检查肯定会占用性能。

3.cgroups

$ mount -t cgroup

  1.在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下,在 Ubuntu 16.04 机器里,我可以用 mount 指令把它们展示出来。它的输出结果,是一系列文件系统目录。而文件目录的含义就是可以用cgroups来限制的资源,这里有CPU、进程、内存资源等等。
cgroups

  2.通过ls命令可以查看相关子系统的配置文件,可以使用这些配置文件进行限制资源。方法是:第一步,先在子系统下新建一个目录(即控制组,控制组会自动生成配置文件);第二步,修改控制组下的文件进行限制,如echo 20000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us,向 container 组里的 cfs_quota 文件写入 20 ms(20000 us),即在每 100 ms 的时间里,被该控制组限制的进程只能使用 20 ms 的 CPU 时间,也就是说这个进程只能使用到 20% 的 CPU 带宽;第三步,把配置对应进程写入echo 226 > /sys/fs/cgroup/cpu/container/tasks,把被限制的进程的 PID 写入 container 组里的 tasks 文件,上面的设置就会对该进程生效了,于是该进程就会只占20%CPU了。

  3.blkio,为 块 设 备 设 定 I/O 限 制,一般用于磁盘等设备;cpuset,为进程分配单独的 CPU 核和对应的内存节点;memory,为进程设定内存使用的限制。

  4.Linux Cgroups 简单来说就是一个子系统目录加上一组资源限制文件的组合。而对Docker这种Linux容器来说,只需要在Cgroups的各个资源子目录下,为每个容器创建对应的控制组(即新目录),再在容器进程启动后,把该进程pid填入对应task即可。

  5.与Namespace情况类似,Cgroups对资源的限制也有很多不完善的地方,提及最多的是/proc文件系统的问题。/proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以
通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源。但是,你如果在容器里执行 top 指令,就会发现,它显示的信息居然是宿主机的 CPU 和内存数据,而不是当前容器的数据。造成这个问题的原因就是,/proc 文件系统并不知道用户通过 Cgroups 给这个容器做了什么样的资源限制,即:/proc 文件系统不了解 Cgroups 限制的存在。需要利用LXCFS增强docker容器隔离性和资源可见性。

4.rootfs

mount("none", "/tmp", "tmpfs", 0, "");

  1.该语句告诉了容器以 tmpfs(内存盘)格式,重新挂载了 /tmp 目录。这样就能解决容器挂载目录的问题。

  2.因为我们创建的新进程启用了 Mount Namespace,所以这次重新挂载的操作,只在容器进程的 Mount Namespace 中有效。如果在宿主机上用 mount -l 来检查一下这个挂载,你会发现它是不存在的。这就是 Mount Namespace 跟其他 Namespace 的使用略有不同的地方:它对容器进程视图的改变,一定是伴随着挂载操作(mount)才能生效。

  3.由2知,我们想要的效果是创建容器时直接进行挂载目录操作,于是使用chroot命令完成该工作。事实上Mount Namespace 正是基于对 chroot 的不断改良才被发明出来的,它也是 Linux操作系统里的第一个 Namespace。

  4.当然Docker已经想到这一点,帮你完成了切换进程根目录这一功能,即首选pivot_root 系统调用,如果系统不支持,才会使用 chroot。

  5.问题是即使在4中解决了rootfs,解决了文件、配置和目录,但是还缺操作系统啊,事实上用的就是宿主机的操作系统内核。这就意味着一个容器修改了宿主机配置会影响所有容器。rootfs。它只是一个操作系统的所有文件和目录,并不包含内核,

  6.但毫无疑问rootfs也是Docker异军突起的原因,把文件、配置、目录一起打包这个思想,远超当时单纯的用namespace、cgroups进行隔离。rootfs给了镜像一致性,从而为之后的集群安装、控制在无意间打下了基础。顺便Docker在解决这个问题时还很优雅的引入了层的概念,一个镜像由多个层组成,每层都是增量rootfs,使用时由Docker把这些层联合挂载到统一挂载点上。

  7.rootfs分可读写层、init层、只读层。对镜像的增删改都会记录在可读写ceng层,并且用commit、push指令,保存这个被修改的可读写层,并上传到Docker Hub上,供他人使用,;而只读层的内容却不会有任何改变。init层会保存一些只对当前容器有效的修改,这些修改我们并不想commit上去,如系统配置、秘钥等。
8.以上内容都会被挂载到/var/lib/docker/aufs/mnt 目录下,表现为一个完整的容器供人们使用。

5.docker exec

6.docker commit

7.镜像仓库标准Docker Registry