Docker 入门,共 3 篇,将带大家进入 Docker 的世界。
首先了解 Docker 的发展历程,

然后快速掌握 Docker 的基本使用;

Docker 版本及内核兼容性选择是这部分的重点内容。大家如果在生产环境中需要使用 Docker 的话,建议重点关注这一篇。

下面我们就进入第一篇的内容。

Docker 在大多数人眼中几乎是容器(container)的代名词,即使是现在我也常会听到有人说“我在服务器上启动了 N 个 docker 在跑 XX 服务” 之类的话。

我们来看看为何 Docker 能成为容器的代名词,引领容器的时代。

容器技术的发展

chroot

在我看来,要梳理容器技术的发展,最早可以追溯到 1979 年,那时候 chroot 系统调用首次问世。

之后 1982 年 chroot 机制被移植到了 BSD 系统上,再后来便是我们所熟知的 Linux 系统上的 chroot 了。

我们有时会使用 chroot 改变某进程的根目录,使它不能访问该目录之外的其他目录。

这和我们在一个容器内的感觉很像了。事实上在几年前确实有人用一百多行的 bash 利用 chroot 写了一个模拟 Docker 创建容器的实现,称之为 bocker , 有兴趣的读者可以去看看该项目的代码。

这里我们来介绍一个实际使用 chroot 创建隔离环境的例子:

比方说我们想创建一个 Debian 的隔离环境,那可以使用 chroot 将 Debian 的 rootfs 根文件系统作为新进程的根。

至于 rootfs 如何获得,我们这里用 Docker 来完成,但这不是本节的重点,可以暂时忽略它,在以后的章节中我们会详细介绍。

  1. # 创建一个空文件夹
  2. (MoeLove) ~ mkdir chroot-dir
  3. (MoeLove) ~ cd chroot-dir
  4. # 使用 Docker 来提取 Debian 的 rootfs
  5. (MoeLove) chroot-dir docker save -o debian.tar debian:buster
  6. (MoeLove) chroot-dir ls
  7. debian.tar
  8. (MoeLove) chroot-dir tar -xf debian.tar
  9. (MoeLove) chroot-dir ls
  10. 098963abf3c3b87b8114ff67d164097dfac2d5659e39f9beb5604db91585f375.json debian.tar repositories
  11. 0f28619fe69181d3af529d56692f1362b7a7c8a6bf8dc9ab0d6d4f9ef9b0004d manifest.json
  12. (MoeLove) chroot-dir mkdir -p debian
  13. (MoeLove) chroot-dir tar -C debian -xf 0f28619fe69181d3af529d56692f1362b7a7c8a6bf8dc9ab0d6d4f9ef9b0004d/layer.tar
  14. (MoeLove) chroot-dir ls debian
  15. bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

经过上述步骤,就拿到了 Debian 的 rootfs,接下来看看 chroot 的能力:

  1. # 使用 debian 文件夹作为容器的根
  2. (MoeLove) chroot-dir sudo chroot debian /bin/bash -i
  3. [sudo] tao 的密码:
  4. root@localhost:/# whoami
  5. root
  6. root@localhost:/# cat /etc/os-release
  7. PRETTY_NAME="Debian GNU/Linux 10 (buster)"
  8. NAME="Debian GNU/Linux"
  9. VERSION_ID="10"
  10. VERSION="10 (buster)"
  11. VERSION_CODENAME=buster
  12. ID=debian
  13. HOME_URL="https://www.debian.org/"
  14. SUPPORT_URL="https://www.debian.org/support"
  15. BUG_REPORT_URL="https://bugs.debian.org/"

此时我们就已经在一个“容器”内了,来看下使用这个“容器”能做些什么。

首先看看当前“容器”内的路由表:

  1. root@localhost:/# mkdir -p /sys
  2. root@localhost:/# mount -t sysfs sys /sys
  3. root@localhost:/# ip r
  4. default via 192.168.0.1 dev wlp2s0 proto dhcp metric 600
  5. 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
  6. 192.168.0.0/24 dev wlp2s0 proto kernel scope link src 192.168.0.108 metric 600
  7. 192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown

另外,还可以将 /proc 也挂载进去:

  1. root@localhost:/# mkdir -p /proc
  2. root@localhost:/# mount -t proc proc /proc
  3. # 这里是随意找了一个进程进行查看
  4. root@localhost:/# ls -al /proc/31730/ns/pid
  5. lrwxrwxrwx. 1 1000 1000 0 Jul 29 16:47 /proc/31730/ns/pid -> 'pid:[4026531836]'

可以看到在这个“容器”内,可以访问到主机上的进程信息,这表示没有任何的进程隔离,带来的危险是我们甚至可以在这个“容器”内杀掉主机上的进程,或者通过“容器”来攻击主机。

为了能更好的解决这个问题,接下来出现了另一个技术:Namespace。

Namespace

Namespace 是在 2002 年由 Linux 2.4.19 开始加入内核的特性,它的主要作用是做了一层抽象和隔离,使得在 namespace 中的进程 / 进程组可以看起来拥有自己的独立资源,具体的“资源”表现形式取决于给它赋予了哪些 namespace。

随着 2013 年 Linux 3.8 中 user namespace 的引入,对于我们现在所熟知的容器所需的全部 namespace 就都实现了:mnt、pid、net、ipc、uts、user 和 cgroup 对于这些 Namespace 和 Docker 的关系,我们在以后的章节中都会深入学习,这里先对 Namespace 做下介绍,便于大家了解容器技术的发展。

我们可以通过三个系统调用直接操作 Namespace,这三个系统调用分别是:

  • clone,可以通过传递不同 namespace 的标志来为新的(子)进程指定其所属的 namespace;
  • unshare,允许一个进程(或线程)取消当前与其他进程(或线程)共享的执行上下文;
  • setns,进入文件描述符指定的 namespace。

知道了这些基础知识后,我们回到前面“容器”的内容中。

我们在前面 chroot 的例子中看到没能做到进程隔离,现在来试试看用 namespace 完成该需求。

  1. (MoeLove) ~ sudo unshare -fp --mount-proc -n
  2. [sudo] tao 的密码:
  3. [root@localhost]/home/tao# ps -a
  4. PID TTY TIME CMD
  5. 1 pts/15 00:00:00 zsh
  6. 33 pts/15 00:00:00 ps

这里很明显,我们当前所在进程的 PID 为 1 并且看不到宿主机上的其他进程,达到了基础的隔离效果。

cgroups 和 LXC

另一条关键的时间线在 2008 年,cgroups 进入 Linux 2.6.24 后,基于它并且瞄准容器世界的一个项目诞生了。

Linux Container (LXC)结合了 namespace 和 cgroups 等技术,目标就是要创造出运行在 Linux 系统中,并且隔离性良好的容器环境。

LXC 的发布在 2008 年,但值得注意的是 cgroups 最初是由 Google 的工程师开发的,最早的记录是在 2006 年,事实上当时 Google 确实也在做类似的容器化项目。

Docker 的发展

时间一晃而过,就到了 2013 年的 PyCon 上,在这次大会上 Docker 正式面世。而它当时其实也只是构建在 LXC 之上的一个工具,屏蔽掉了 LXC 的使用细节,让用户可以一句 docker run 命令行便创建出自己的容器环境。

同时,它允许用户将容器环境打包成为一个 Docker 镜像进行分发,这也大大降低了用户使用的门槛。 Docker 镜像分发可以说是 Docker 成功的一个关键要素了。

另一个关键要素,我认为是开源生态,Docker 在首次亮相之后不久,就完全开源了,吸引了来自世界各地开发者的关注和积极贡献。

2014 年 Docker 发布 1.0 正式进入生产就绪的状态。在此之前它也将 LXC 逐步从它的底层移除,换成了自己实现的 libcontainer。

此后 Docker 便成为了风靡技术界的新热潮。

再后来也出现过 Swarm Mesos 和 Kubernetes 等众多容器编排系统争夺市场份额的情况,但是随着时间的推移,Kubernetes 成为了事实上的标准,国内外各个公司也都在推进 Kubernetes 的落地和实施。而 Docker 作为容器运行时,也正是极其关键的一环。

总结

从最先的 chroot 到后来的 namespace 和 cgroups 等,再到后来的 LXC 和 Docker 等技术的出现,这都是在容器技术领域的一种探索和前进。


当然,我这里只列出了我认为最核心和关键的内容,事实上当时技术圈除了这条主干之外,也有着很多支线剧情,比如从各类 PaaS (Platform as a Service)厂商的竞争到全面拥抱 Docker ,这些内容也从侧面来反映出了 Docker 的火热。

【docker系列2】docker 的前世今生的更多相关文章

  1. Docker系列03—Docker 基础入门

    本文收录在容器技术学习系列文章总目录 1.概念介绍 1.1 容器 1.1.1 介绍 容纳其它物品的工具,可以部分或完全封闭,被用于容纳.储存.运输物品.物体可以被放置在容器中,而容器则可以保护内容物. ...

  2. Docker系列05—Docker 存储卷详解

    本文收录在容器技术学习系列文章总目录 1.存储卷介绍 1.1 背景 (1)docker 的 AFUS 分层文件系统 docker镜像由多个只读层叠加面成,启动容器时,docker会加载只读镜像层并在镜 ...

  3. Docker系列之Docker镜像(读书笔记)

    一.基本概念 Docker包括三个基本概念镜像.容器.仓库. Docker镜像:就是一个只读的模板.例如:一个镜像可以包含一个完整的ubuntu操作系统环境,里面仅安装了Apache或其他应用程序.用 ...

  4. docker 系列之 docker安装

    Docker支持以下的CentOS版本 CentOS 7 (64-bit) CentOS 6.5 (64-bit) 或更高的版本 前提条件 目前,CentOS 仅发行版本中的内核支持 Docker. ...

  5. Docker系列二: docker常用命令总结

    https://docs.docker.com/reference/  官方命令总结地址 容器生命周期管理 1.docker run 创建一个新的容器并运行一个命令 docker run [optio ...

  6. Docker系列一: docker简介及基本环境安装

    Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Li ...

  7. Docker系列03—Docker 存储卷

    一.存储卷介绍 1.1 背景 Docker 的 AFUS 分层文件系统 docker镜像由多个只读层叠加而成,启动容器时,docker会加载只读镜像层并在镜像栈顶部加一个读写层: 如果运行的容器修改了 ...

  8. Docker系列01—Docker 基础入门

    一.初识Docker和容器 1.1 什么是docker 容纳其他物品的工具,可以部分或完全封闭,被用于容纳.存储.运输物品.物体可以被放置在容器中,而容器则可以保护内容物. 容器? 容器就是在隔离的环 ...

  9. Docker系列04—Docker的网络模式详解

    本文收录在容器技术学习系列文章总目录 1.Docker的四种网络模式 (1)docker四种网络模式如下: Bridge contauner   桥接式网络模式 Host(open) containe ...

  10. Docker系列09—Docker的系统资源限制及验证

    本文收录在容器技术学习系列文章总目录 1.限制容器的资源 默认情况下,容器没有资源限制,可以使用主机内核调度程序允许的尽可能多的给定资源.Docker提供了控制容器可以使用多少内存或CPU的方法,设置 ...

随机推荐

  1. wmic 内网使用

    先决条件: 1.远程服务器启动Windows Management Instrumentation服务,开放TCP135端口,防火墙放开对此端口的流量(默认放开): 2.远程服务器的本地安全策略的“网 ...

  2. P1680 奇怪的分组(组合数+逆元)

    传送门戳我 首先将n减去所有的Ci,于是是原问题转换为:n个相同的球放入m个不同盒子里,不能为空,求方案数. 根据插空法:n个球,放到m个箱子里去不能为空,也就是有m-1块板子放在n-1个空隙之间 那 ...

  3. POJ3279(开关后续)

    描述: 一个\(n*m的矩阵,每个格子有0和1两种状态.每次可以翻一个格子,并且此格子的上下左右都要被翻.\) \(目标状态应该全为0,求最少翻的次数,输出最小字典序的方案\) 这儿可就麻烦了啊,开关 ...

  4. php报错:strip_tags() expects parameter 1 to be string, array given

    囧....... 这个表示参数需要字符串,而你传入了数组,所以出错了~ 检查下函数或者方法是否正确,还有参数

  5. CF#132 C. Logo Turtle DP

    C. Logo Turtle 题意 有一个海龟在一个x轴的0点,给出一个由'F','T'组成的字符序列. 海龟要按照这个序列进行行动,如果第i个字符为'F',表示沿当前方向走,'T'表示转身. 现在你 ...

  6. tomcat 8.5 及其 9.0 response写cookie 设置damain为 [.test.com] 出错 An invalid domain [.test.com] was specified for this cookie

    抛出异常: java.lang.IllegalArgumentException: An invalid domain [.test.com] was specified for this cooki ...

  7. layui编辑商品时,怎么使用下拉菜单显示商品默认分类的问题

    //加载商品默认的分类$.get('/admin/category/selec/' + {$simple.0.first_pid},function(msg){ $("#two_cate&q ...

  8. 3、get请求(url详解)

    前言 上一篇介绍了Composer的功能,可以模拟get和post请求,get请求有些是不带参数的,这种比较容易,直接放到url地址栏就行.有些get请求会带有参数,本篇详细介绍url地址格式. 一. ...

  9. 【前端背景UI】鼠标磁性动态蜘蛛网背景源码

    <div style="float:right;" id="hub_iframe"></div> <script type=&qu ...

  10. XCode Interface Builder开发——2

    XCode Interface Builder开发--2 简单的练手项目--仿苹果自备的计算器 简介 制作一个简易功能的计算器并非难事,但是其中要考虑的不同情况却仍有许多,稍不留神就会踩坑. 例如: ...