关于 Docker 系列其他文章的传送门

一、容器¶

18 年,容器技术红了半边天,哦不,已经红满天,如果哪家公司要说自己没用 docker,感觉像落后于这个时代似的,那到底什么是容器呢,容器为什么这么火,它凭什么火,本文将仔细聊聊容器,以及 docker 的基本使用方法。
什么是容器¶
容器是一种基础工具,泛指任何可以用于容纳其它物品的工具,可以部分或完全封闭,被用于容纳、储存、运输物品。物体可以被放置在容器中,而容器则可以保护内容物。
人类使用容器的历史至少有十万年,甚至可能有数百万年的历史。
容器的类型:
- 瓶 - 指口部比腹部窄小、颈长的容器。
- 罐 - 指那些开口较大、一般为近圆筒形的器皿。
- 箱 - 通常是立方体或圆柱体。形状固定。
- 篮 - 以条状物编织而成。
Linxu 中的容器是什么呢? 其实最早的时候,容器技术并不是在 Linux 上的,而是在 FreeBSD 中的。
容器的发展¶
1. jails¶

在大约 2000 年的时候,使用一种叫 jails 的技术,实现了类似于 Linux 之中 chroot 的方式,实现对文件系统的容器化管理,但是,jails 只能完成对文件系统的容器支撑。
众所周知,在系统运行中,有两颗大树,是“进程树”和“文件系统树”,“进程树”是由 init 顶级进程,和下面的很多枝枝叶叶的子进程组成,而“文件系统树”,是以 / 为顶级目录,下面也有很多枝枝叶叶的子目录组成,而 jails 只对“文件系统树”做容器管理,不能支持“进程树”。
2. VServer¶

Linux 觉得这种技术可能会在 Linux 上有用武之地,随后在 2001 年,便出现了 VServer,它基本上复刻了 jails 的实现方式,在 Linux 之上运行。
总的说,Linux 容器只不过是一组在系统上运行的线程而已,然后利用各种的 namespace 机制,让进程在隔离的空间内运行,这种进程和其他进程完全隔离开的机制,就是容器,那么,什么是 namespace 呢?
二、容器的技术¶
1. 名称空间¶
说起容器,就不得不说 Linux 中的 namespace(名称空间)。
Linux 的容器发展到今天,为了支撑容器这种机制,也经历了很多坎坎坷坷,直到前几年,功能才开始完善起来。
而 namespace 是用来封装一个全局级别的资源,在一个抽象层上,从而使得我们可以把它进行切分,这种资源包括 6 个。
| 内核版本 | namespace | 隔离内容 |
|---|---|---|
| 2.6.19 | UTS | 主机名、域名 |
| 2.6.19 | IPC | 系统级的进程间通信、消息队列 |
| 2.6.24 | PID | 进程编号 可以生成多个 PID 为 0 的 init 进程 |
| 2.6.29 | Network | 网络设备、网络协议栈、端口等 |
| 2.4.19 | Mount | 挂载点 文件系统 利用 chroot,生成多个根文件系统 |
| 3.8 | User | 用户和用户组 |
2. Cgroup¶
容器里运行的进程虽然是隔离的,但是使用的 cpu、内存、IO 等资源,其实根本上还是物理机来提供的,但是如果某一个容器里的进程使用资源很多,抢占了其他容器的资源,甚至让物理机需要使用的资源都岌岌可危,这就不得了了。所以为了不坐视这种事情发生,就让 Cgroup 来管理所有容器使用的 cpu、内存等。Cgroup 会把底层的计算资源 cpu、内存、io 划分成块,有效的调派到容器,实行资源管理限制。
3. LXC¶

LXC(Linux container) 的出现简化了容器的使用方式,它能够通过运行一个程序,指定一个模板,来创建出一个用户空间来,模板可以是 ubuntu、windows、debian 等,这个模板就是一个脚本,这个脚本可以触发一个操作系统的安装过程,类似一个真正的安装一样,把 yum 仓库中要安装软件下载到本地,把指定的切根的位置当做真正的根,往里边安装程序包,从而生成假根,或者说是子树的目录结构和所有文件,这是安装生成的,所以它和一个操作系统相比,从本质上没有太大的区别,安装时间很长,安装好后,只要切换根,就得到了另外一套系统环境。
所以 LXC 的缺点是:
- 慢:和安装完整的操作系统没有太大的区别。
- 难迁移:宿主机宕了就都宕了,除非使用 NFS 之类的共享存储。
但是总的来说,LXC 的使用已经简便了很多,但是量级很重,比起虚拟机来并没有很好的表现。
有兴趣的可以看看红帽官网对容器的介绍(网站打开可能微慢)
三、Docker 和容器编排¶
Docker 是什么¶

在 2010 年,几个搞 IT 的年轻人,在美国旧金山成立了一家名叫 dotCloud 的公司,那就是 Docker 的母公司,一个划时代的产品来了。 如果想了解 dotCloud 公司的历史可以戳这里
在 Docker 出现之前,大家想使用容器技术,就需要用上边提到的三个组件结合使用,复杂程度可想而知。而 docker 的出现,打破了这种局面,让使用容器的难度大大降低,而容器技术,并不是新生事物,在最早在 2000 年就已经出现了,而 Docker 最大贡献,是利用划时代的技术,将容器的技术推向了火热,那就是 docker 的 镜像。在 kvm 中,也使用了镜像技术,但是 docker 镜像和 kvm 镜像的区别是,docker 的镜像是 分层实现 的。
其实镜像也不是新生技术,但是 docker 的镜像设计精巧的地方在于,镜像内 只包含应用程序及其自身的运行环境 而已,因为这种技术的引入,以后要创建一个容器,就变成了下面这个样子:
- docker 在互联网上建立了一个镜像仓库,拥有 docker 事先做好的各种镜像
- 个人在本地服务器上运行着一个 docker 的守护进行,用户想要启动一个 nginx 的话,直接从镜像仓库下载 nginx 的镜像到本地,然后启动即可,再也不用配置 yum 源,再使用
yum install安装之类的操作,只要一条命令,docker 守护进程就会从指定的镜像仓库把 nginx 的镜像下载回来,然后自动的创建好一个容器,在容器内运行这个 nginx 进程,而这一切,都是 docker 自动完成的。

在 Docker 中贯彻的核心观念是,一个名称空间,只用来运行一个进程,及其这个进程的子进程。
docker 最先是使用 LXC 来为自己提供容器管理,后来发现不能满足自己的需求,便研发了 libcontainer 使用,再后来演变成了符合 CNCF 通用标准的 runC,至于哪里冒出来的通用标准,那就是另一个故事了。
如果想了解 CNCF 是什么组织,以及 Docker 公司和 Google、CNCF 之间的“爱恨情仇”,戳这里。

总之一句话,Docker 不是容器,而是容器的管理软件。
容器编排¶
容器的运行是需要有 三个层次:
- 容器引擎:运行单个容器的底层引擎。
- 容器编排:根据规则对容器进行调度、配置、组合、部署、回收、迁移等,以提供应用部署、维护、扩展机制等功能。
- 服务治理:按照 Anne Thomas Manes 的定义是:企业为了确保事情顺利完成而实施的过程,包括最佳实践、架构原则、治理规程、规律以及其他决定性的因素。服务治理指的是针对 SOA 的建设和实施的过程。当然现在也适用于微服务的建设和实施过程。
1. Docker 的容器编排¶
容器单一的运行是没有价值的,需要用容器的 编排系统,所以 docker 的公司推出了自己的容器编排系统:docker 编排三剑客。
| 名字 | 功能 |
|---|---|
| docker-machine | 用来构建运行 docker 的主机 |
| docker-swarm | 负责 docker 集群管理 |
| docker-compose | 容器编排引擎 |
2. Google 的容器编排 kubernetes¶

其实容器技术在 google 已经运行了十几年,作为内部运行高效 IT 系统的不传之秘,没有公开过,现在 docker 开源了容器技术,而且异常火热,google 为了不让自己失去对容器技术的话语权,所以把自己的容器技术公开出来,但是对比 docker,显得很简陋和粗糙,简直不是同一个时代的。
但是 google 自己使用的容器编排技术 Borg,在内部已经运行十几年了,而且 google 在自己庞大的业务支持下,积攒了很多容器编排的技术,所以 google 就用自己家的 GO 语言,结合对容器编排丰富的经验,从头编写,造出了 Kubernetes,这对 docker 来说是一个很大的打击,堪比小说《三体》中,四维世界对三维世界的降维打击一样,打的 docker 毫无还手之力,所以 docker 自家的编排系统系统 docker-swarm,基本已经凉凉了,只有很少很少的公司还在使用。
扩展阅读:
从 Docker 的转变,谈容器生态与微服务的发展
OCI 和 runc:容器标准化和 docker
四、Docker 的详细使用方法¶
Docker 的一些基本知识¶
docker 属于 cs 架构,有客户端和服务端,两者之间通过 http 或 https 协议,使用 unix 套接字进行本地通信,相对于使用 TCP 的套接字应用来说,效率很高
在 docker 内部,使用了基于 RESTful 风格的 API 提供服务,所以 docker 将内部所有的管理组件视为对象 (Object),同一个对象被抽象成资源(Resource Type) 的概念,每个资源类型相当于 mysql 中的一个定义好的数据结构,在 docker 内部,一些比较重要的资源是 Container、Image、Network、Volume,docker 的客户端就是去连接 Daemon 端,去完成某一个对象的增删改查等操作,对应在 HTTP 里的无非就是 GET,PUT,DELETE,POST 等
Docker 的主要部件和功能
-
client
- docker build
- docker pull
- docker run
-
server daemon
- containers 容器运行时环境
- images 镜像存储环境 依赖分层文件系统:
- aufs linux 内核没收录 centos 不支持 ubuntu 支持
- overlayfs 红帽最新版支持的分层文件系统
- dm(devicemapper) 性能差的一批
-
Registry:可以理解为仓库 (Repository) 的注册列表,一般一个仓库 (Repository) 只用来放一个应用程序 (Application) 的不同版本 (Version),每个版本可以不用版本号标识,而是通过标签(tag) 来标识,一个镜像可以有多个标签,但是只有一个唯一的 ID 标示
CentOS 安装和配置 docker-ce 方法¶
docker 有 2 个版本:
- docker-ce 开源社区版
- docker-ee 商业版
这里主要介绍 docker-ce 的安装和使用,CentOS 官方源中也收录了 docker 二进制包,但是比较老旧,我们可以按照官方的安装文档,或者使用国内的各大 mirrors 站点,比如阿里云来安装最新版
1. 从 docker 官方安装¶
在新主机上首次安装 Docker CE 之前,需要设置 Docker 存储库。之后,可以从存储库安装和更新 Docker。
1 | yum install -y yum-utils \ |
2. 从阿里云安装¶
下载阿里云 mirrors 站点中关于 docker 的 repo 文件:
1 | curl https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo >> /etc/yum.repos.d/docker-ce.repo |
3. 配置镜像加速¶
因为某些不可抗力,如果国内访问 DockerHub 比较慢,可以使用国内的镜像加速服务,如果感觉速度不慢也可以不使用,这里推荐用阿里云或 docker 官方的,任选一种即可
-
阿里云 https://cr.console.aliyun.com/cn-hangzhou/new 需要注册账号,也可以使用阿里系账号
注册账号后,登录阿里云在这里看到配置教程

-
docker 官方 https://registry.docker-cn.com/
修改/etc/docker/daemon.json文件并添加上registry-mirrors键值,默认没有这文件,需要手动创建
1 | { |
4. 启动 docker 守护进程¶
1 | systemctl daemon-reload |
docker 的守护进程不是 docker,而是containerd
1 | [root@docker ~] ps -ef|grep containerd |
docker daemon 启动后会创建一个叫 docker 的网桥,默认网段是 172.17.0.0/16
1 | [root@centos_1 docker] ip a s docker0 |
解决防火墙 FORWORD 链默认 DROP¶
安装 Docker 后,Docker 会把防火墙的 FORWORD 链默认规则改成 DROP,在有些情况下会影响网络转发,就算手动改成 ACCEPT,Docker 服务重启后还会恢复默认 DPOP,下面说一个永久的解决办法。
修改 Docker 的服务脚本。
1 | vim /usr/lib/systemd/system/docker.service |
在 ExecStart 下添加一行,意思是 Docker 启动后,把 FORWARD 改成 ACCEPT,但前提是需要安装了 iptables。
1 | ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock # 这行不动 |
然后刷新 system 文件,并重启 Docker。
1 | systemctl daemon-reload |
五、docker 客户端常用命令¶
查看版本信息¶
docker version
1 | [root@centos_1 ~] docker version |
输出详细信息¶
docker info
1 | [root@centos_1 ~] docker info |
docker client 常用命令参数¶
在 docker 比较旧的版本中,各种命令混在一起,在新版中将命令都分门别类了
每个命令后可以加 --help 或 help 查看语法等帮助信息,建议多用 help,这里不注明详细语法
1 | login 登录到 docker_hub |
启动容器¶
1. 下载镜像到本地¶
不指 tag 默认是最小化最新版的 Centos7 系统环境,这是一个非常小的系统,可以使用 yum 安装软件
1 | docker image pull centos |
2. shell 型容器的启动方法¶
比如 centos
1 | # t:tty 附加终端 -d:运行在后台,不加直接在前台 |
3. 服务型容器¶
启动方法,以及会遇到的问题,比如 nginx
1 | 如果不加 -d 会运行在前台,显示 nginx 的logs 信息,并阻塞当前 shell |
需要 特别注意 的是,启动的容器,如果没有特定指明执行命令的基础环境,默认运行的环境都是 shell,而 shell 是交互式接口,所以像 centos 这种不是以守护进程运行的镜像,都需要指定使用交互式方式运行,不然 shell 一启动就会马上停止,容器也就一起挂了
如果运行服务型的容器,容器中 PID 为 1 的服务,不能和往常一样以 Daemon 守护进程的方式在容器内后台运行(并不是指在后台运行容器),这违背了 docker 的规则,一旦程序在后台运行,容器就没认为没有框架支撑这个空间了,就会停止容器,所以服务要运行在前台,不然一启动就停止,一启动就停止
一般 -d 和 -rm 不在一起使用,因为 -d 放到后台 -rm 就无法判断状态了
如果想把容器的 shell 从当前终端剥离,可以使用下面的组合键,这样只是剥离而不是运行到后台,所以容器不会停止。ctrl + p,ctrl + q
