docker run -it redis /bin/bash。执行这个命令运行一个redis容器,以交互模式运行容器,为容器重新分配一个伪输入终端,并执行/bin/bash。这个命令背后都做了什么?

  • 1.如果本机没有redis镜像,则会从你配置的镜像仓库里面拉取一个redis的latest版本的镜像,跟运行了docker pull redis效果一样。
  • 2.创建容器。跟运行docker create一样。
  • 3.给容器分配一个读写文件系统作为该容器的final layer(最底层),容器可以在它的文件系统创建和修改文件。
  • 4.Docker为容器创建了一套网络接口,给容器分配一个ip。默认情况下,容器可以通过默认网络连通到外部网络。
  • 5.Docker启动容器并执行 /bin/bash。因为启动时指定了-it参数,我们可以使用当前终端与docker客户端进行输入输出交互。
  • 6.运行exit可以退出容器,但是此时容器并没有被删除,我们可以再次运行它或者删除它。

可以发现,容器的内核版本是跟宿主机一样的,不同的是容器的主机名是独立的,它默认用容器ID做主机名。我们运行ps -ef可以发现容器进程是隔离的,容器里面看不到宿主机的进程,而且它自己有PID为1的进程。此外,网络也是隔离的,它有独立于宿主机的IP。文件系统也是隔离的,容器有自己的系统和软件目录,修改容器内的文件并不影响宿主机对应目录的文件。

root@stretch:/home/vagrant# uname -r 4.9.0-6-amd64
root@stretch:/home/vagrant# docker run -it --name demo alpine /bin/ash
/ # uname -r   ## 容器内
4.9.0-6-amd64

/ # ps -ef
PID   USER     TIME   COMMAND
    1 root       0:00 /bin/ash
    7 root       0:00 ps -ef
    
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

这些隔离机制并不是Docker新开发的技术,而是依托Linux 以及一些已有的技术实现的,主要包括:

  • Linux Namespaces:Namespaces用于环境隔离,用于进程(PID)、网络(NET)、挂载点(MNT)、UTS、IPC等隔离。
  • Linux Control Groups(CGroups):用于限制容器使用的资源,包括内存,CPU等。
  • Union File Systems:UnionFS把多个目录结合成一个目录,对外使用,最上层目录为读写层(通常只有1个),下面可以有一个或多个只读层,见容器和镜像分层图。Docker支持OverlayFS,AUFS、DeviceMapper、btrfs等联合文件系统。