作者:@diyun

Docker

安装 Docker

首次安装 Docker 之前,需要添加 Docker 安装源。添加之后,我们就可以从已经配置好的源,安装和更新 Docker。添加 Docker 安装源的命令如下:

  1. $ sudo yum-config-manager \
  2. --add-repo \
  3. https://download.docker.com/linux/centos/docker-ce.repo

**
正常情况下,直接安装最新版本的 Docker 即可,因为最新版本的 Docker 有着更好的稳定性和安全性。你可以使用以下命令安装最新版本的 Docker。

  1. $ sudo yum install docker-ce docker-ce-cli containerd.io

如果你想要安装指定版本的 Docker,可以使用以下命令:

  1. $ sudo yum list docker-ce --showduplicates | sort -r
  2. docker-ce.x86_64 18.06.1.ce-3.el7 docker-ce-stable
  3. docker-ce.x86_64 18.06.0.ce-3.el7 docker-ce-stable
  4. docker-ce.x86_64 18.03.1.ce-1.el7.centos docker-ce-stable
  5. docker-ce.x86_64 18.03.0.ce-1.el7.centos docker-ce-stable
  6. docker-ce.x86_64 17.12.1.ce-1.el7.centos docker-ce-stable
  7. docker-ce.x86_64 17.12.0.ce-1.el7.centos docker-ce-stable
  8. docker-ce.x86_64 17.09.1.ce-1.el7.centos docker-ce-stable

然后选取想要的版本执行以下命令:

  1. $ sudo yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io

安装完成后,使用以下命令启动 Docker。

  1. $ sudo systemctl start docker

**

容器技术原理

chroot 是在 Unix 和 Linux 系统的一个操作,针对正在运作的软件行程和它的子进程,改变它外显的根目录。一个运行在这个环境下,经由 chroot 设置根目录的程序,它不能够对这个指定根目录之外的文件进行访问动作,不能读取,也不能更改它的内容。

chroot演示:

$ mkdir rootfs
这里为了方便演示,我使用现成的 busybox 镜像来创建一个系统,镜像的概念和组成后面我会详细讲解,如果你没有 Docker 基础可以把下面的操作命令理解成在 rootfs 下创建了一些目录和放置了一些二进制文件。

  1. $ cd rootfs
  2. $ docker export $(docker create busybox) -o busybox.tar
  3. $ tar -xf busybox.tar

执行完上面的命令后,在 rootfs 目录下,我们会得到一些目录和文件。下面我们使用 ls 命令查看一下 rootfs 目录下的内容。

  1. $ ls
  2. bin busybox.tar dev etc home proc root sys tmp usr var

可以看到我们在 rootfs 目录下初始化了一些目录,下面让我们通过一条命令来见证 chroot 的神奇之处。使用以下命令,可以启动一个 sh 进程,并且把 /home/centos/rootfs 作为 sh 进程的根目录。

  1. $ chroot /home/centos/rootfs /bin/sh

此时,我们的命令行窗口已经处于上述命令启动的 sh 进程中。在当前 sh 命令行窗口下,我们使用 ls 命令查看一下当前进程,看是否真的与主机上的其他目录隔离开了。

  1. / # /bin/ls /
  2. bin busybox.tar dev etc home proc root sys tmp usr var

这里可以看到当前进程的根目录已经变成了主机上的 /home/centos/rootfs 目录。这样就实现了当前进程与主机的隔离。到此为止,一个目录隔离的容器就完成了。
但是,此时还不能称之为一个容器,为什么呢?你可以在上一步(使用 chroot 启动命令行窗口)执行以下命令,查看如下路由信息:

  1. /etc # /bin/ip route
  2. default via 172.20.1.1 dev eth0
  3. 172.17.0.0/16 dev docker0 scope link src 172.17.0.1
  4. 172.20.1.0/24 dev eth0 scope link src 172.20.1.3

执行 ip route 命令后,你可以看到网络信息并没有隔离,实际上进程等信息此时也并未隔离。要想实现一个完整的容器,我们还需要 Linux 的其他三项技术: Namespace、Cgroups 和联合文件系统

Docker 是利用 Linux 的 Namespace 、Cgroups 和联合文件系统三大机制来保证实现的, 所以它的原理是使用 Namespace 做主机名、网络、PID 等资源的隔离,使用 Cgroups 对进程或者进程组做资源(例如:CPU、内存等)的限制,联合文件系统用于镜像构建和容器运行环境。

Namespace

Namespace 是 Linux 内核的一项功能,该功能对内核资源进行隔离,使得容器中的进程都可以在单独的命名空间中运行,并且只可以访问当前容器命名空间的资源。Namespace 可以隔离进程 ID、主机名、用户 ID、文件名、网络访问和进程间通信等相关资源。
Docker 主要用到以下五种命名空间。

  • pid namespace:用于隔离进程 ID。
  • net namespace:隔离网络接口,在虚拟的 net namespace 内用户可以拥有自己独立的 IP、路由、端口等。
  • mnt namespace:文件系统挂载点隔离。
  • ipc namespace:信号量,消息队列和共享内存的隔离。
  • uts namespace:主机名和域名的隔离。

    Cgroups

    Cgroups 是一种 Linux 内核功能,可以限制和隔离进程的资源使用情况(CPU、内存、磁盘 I/O、网络等)。在容器的实现中,Cgroups 通常用来限制容器的 CPU 和内存等资源的使用。

    联合文件系统

    联合文件系统,又叫 UnionFS,是一种通过创建文件层进程操作的文件系统,因此,联合文件系统非常轻快。Docker 使用联合文件系统为容器提供构建层,使得容器可以实现写时复制以及镜像的分层构建和存储。常用的联合文件系统有 AUFS、Overlay 和 Devicemapper 等。