初次接触Docker是两年前, 那时候还没有docker-ce/docker-ee的区分, 叫docker-io, 稍微摸索了一下感觉这个技术确实是可以大幅度提高生产效率的, 当时国内各大云服务商开始提供Docker服务, 除了BAT, 还有网易蜂巢, Daocloud等等优秀的容器服务提供商, 可谓方兴未艾.

但可惜我所在的公司并不重视容器化和微服务这块, 两年过去了并没有在实践中用上这把利剑, 现在Docker的生态已经繁荣昌盛, 除了docker-compose, docker-swarm等相关组件, kubernetes也逐渐走向成熟. 本文先复习一下Docker相关的知识, 温故知新, 保持学习, 有机会就实践.

Docker概述

Docker提供了在称为容器的松散隔离环境打包和运行应用程序的能力. 隔离和安全性允许您在给定主机上同时运行多个容器. 容器是轻量级的, 因为它们不需要管理程序的额外负载, 而是直接在主机的内核中运行. 这意味着, 与使用虚拟机相比, 您可以在给定的硬件组合上运行更多的容器. 你甚至可以在实际上是虚拟机的主机中运行Docker容器.

Docker提供工具和平台来管理容器的生命周期:

  • 容器能够开发应用程序的运行时及其支持组件.
  • 容器可以作为分发和测试应用的单元.
  • 使用容器在不同环境中部署应用是无差别的.

Docker的作用和应用场景在于它简化了开发生命周期, 容器非常适合持续集成和持续交付(CI / CD)工作流程. 记得以前在Docker官网上的一句名言“Build once, run anywhere!”, 后来变成了“Build, Ship, and Run Any App, Anywhere!”, 这句话就是对Docker作用的最佳答案. 当你为了一个庞大的系统部署到测试环境、预上线环境、生产环境、XXX环境耗费大量人力的时候, 当你为了寻找一个问题为什么总是在生成环境上出现的时候, 当你维护大量部署脚本找不到头绪的时候, 当你为了应用水平扩展和负载均衡费劲周折的时候, Docker就是救星了, 甚至不需要出动Docker全家桶, 几行Docker命令就能轻松解决!

下面盗了官网的图来说明Docker的逻辑结构(第一个图)和使用结构(第二个图)
1
2

镜像

Dockerfile中的每条命令都会在文件系统中创建一个新的层次结构(layer),文件系统在这些层次上构建起来,镜像就构建于这些联合的文件系统之上. 所以本质上镜像是一种文件结构. 每一个layer有一个SHA1哈希码, 镜像的变化会反映在layer的增量更新上, 镜像可以修改再提交, 提交镜像就像是一条Git提交记录, 不过提交的对象不是代码, 而是操作系统的状态变化. 一个镜像就相当于一个操作系统的快照, 这些快照根据命名空间、名称、标签组织起来并由仓库管理版本. 镜像可以是包含了一个应用的运行时环境如Ubuntu+JRE+tomcat, 或是一个服务组件如mysql数据库, 也可以只包含一个操作系统如debian等. 一个镜像的大小一般只有几百兆, 并且layer的复用会带来更神奇的效果, 实际拉取镜像的时候可能只要下载几十兆甚至几兆. 镜像也能够通过Docker Hub或类似这样一个镜像注册中心, 提供给任何需要的人.

镜像仓库

仓库是集中存放镜像文件的场所,仓库注册服务器(Registry)上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag). 目前,最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载. 我们可以使用官方提供的registry镜像来搭建一个镜像注册中心, 现在更主流的做法是用开源项目harbor搭建企业级的镜像仓库.

容器

容器是从镜像创建的运行实例. 它可以被启动、开始、停止、删除. 每个容器都是相互隔离的、保证安全的平台. 可以把容器看做是一个简易版的Linux环境,Docker利用容器来运行应用. 说白了镜像和容器的关系,就是类与示例的关系. Docker的命令行工具大多都是对容器做管理的

网络

Docker的网络子系统是可插拔的,使用驱动程序. Docker自带几个驱动程序,并提供核心网络功能. Docker提供了很多种网络驱动, 默认是bridge模式,适用于不同的应用场景, 更改网络设置通过”docker network create”,下面是每种网络驱动的简述:

  • bridge默认的网络驱动程序. 应用程序运行在需要通信的独立容器中时,通常会使用桥接网络,打个比方就是同一个主机的容器直接有一座桥,容器直接可以直接通信,但主机外看不到这座桥. 这个桥是通过iptables的NAT功能实现的,这里有详述.
  • host:对于独立容器,删除容器和Docker主机之间的网络隔离,并直接使用主机的网络. host 仅适用于Docker 17.06及更高版本的群集服务.
  • overlay:覆盖网络将多个Docker守护进程连接在一起,并使群集服务能够相互通信. 主流的覆盖网络组件有:Flannel, weave等.kubernetes集群网络通信的基础就是覆盖网络, 这又是一个复杂庞大的话题. 以后再谈, 这里Mark一篇文章
  • macvlan:Macvlan网络允许为容器分配MAC地址,使其显示为网络上的物理设备。Docker守护进程通过其MAC地址将流量路由到容器。
  • none: 不需要网络

如何选择?

  • 需要多个容器在同一个Docker主机上进行通信时,用户定义的网桥是最好的.
  • 当网络堆栈不需要与Docker主机隔离而又需要隔离运行环境时,主机网络是最好的.
  • 当需要运行在不同Docker主机上的容器进行通信时,或者当多个应用程序使用群集服务一起工作时,覆盖网络是最好的.
  • Macvlan网络最适合从虚拟机设置迁移或需要容器看起来像网络上的物理主机,每个物理主机都有一个唯一的MAC地址.
  • 当上面的网络驱动都不符合要求时, 也可以选用第三方网络插件

以前没有关注过Docker网络的设计和实现, 回过头来看受益颇多, 这里是官网上对Docker网络架构的详述

卷存储

卷(volume)在Docker中相当于容器的数据盘, 它的用法这里有文档, 是非常常用的参数, 如果没有指定存储卷, Docker会在/var/lib/docker/volumes中自动创建一个GUID命名的卷用于容器的文件读写. 实际使用过程中按照一定规则将主机上的目录挂载到容器中更加便于管理.