什么是Docker
一、容器技术
1、应用程序的部署问题
还原应用程序部署的场景,开发在开发应用的时候,要自己搭建一套环境,进行本地调试,这时就需要在本地搭建一套JVM,NODE,NGNIX等一些应用程序运行的环境;等环境搭建完成并开发完成之后,就需要搭建一套同样的测试环境,以供测试进行测试,测试过程中发现问题,原来是测试应用的环境和开发环境有出入导致的。
测试完成,要部署线上了,这时候又出线一个问题就是需要再搭建一套正式环境,上线之后还是会因为环境问题导致各种各样的问题。除了花费大量的时间来搭建环境之外,还会因为环境的不同导致各种各样的问题。
重复搭建了三套环境还要迫使程序员转行演员浪费表演才华,典型的浪费时间和效率,于是便有人想到了,为什么不能搭建一套,其他的clone就行了,于是虚拟机就诞生了。再后来,人们想到干脆在别人的环境上运行就好了,于是就诞生了容器技术。
2、虚拟机和容器技术
和一个单纯的应用程序相比,操作系统是很笨重的;
虚拟机就是每套虚拟机都要搭载一套很重的操作系统,例如JVM。一台机器上运行几个程序就会消耗多少个操作系统的内存,这些内存是没办法减少的,但是对应用程序的运行是没有什么有用的地方的。还有另一个问题,那就是启动时间问题,我们知道操作系统重启是非常慢的,因为操作系统要从头到尾把该检测的都检测了该加载的都加载上,这个过程非常缓慢,动辄数分钟。
那么有没有一种技术可以让我们获得虚拟机的好处又能克服这些缺点,如是容器技术就诞生了。
3、什么是容器
容器一词的英文是container,其实container还有集装箱的意思,集装箱绝对是商业史上了不起的一项发明,大大降低了海洋贸易运输成本。让我们来看看集装箱的好处:
- 集装箱之间相互隔离
- 长期反复使用
- 快速装载和卸载
- 规格标准,在港口和船上都可以摆放
回到软件中的容器,其实容器和集装箱在概念上是很相似的。
现代软件开发的一大目的就是隔离,应用程序在运行时相互独立互不干扰,这种隔离实现起来是很不容易的,其中一种解决方案就是上面提到的虚拟机技术,通过将应用程序部署在不同的虚拟机中从而实现隔离。
与虚拟机通过操作系统实现隔离不同,容器技术只隔离应用程序的运行时环境但容器之间可以共享同一个操作系统,这里的运行时环境指的是程序运行依赖的各种库以及配置。
们可以看到容器更加的轻量级且占用的资源更少,与操作系统动辄几G的内存占用相比,容器技术只需数M空间,因此我们可以在同样规格的硬件上大量部署容器,这是虚拟机所不能比拟的,而且不同于操作系统数分钟的启动时间容器几乎瞬时启动,容器技术为打包服务栈提供了一种更加高效的方式。容器是一种通用技术,docker只是其中的一种实现。
二、什么是docker
docker是一个用Go语言实现的开源项目,可以让我们方便的创建和使用容器,docker将程序以及程序所有的依赖都打包到docker container,这样你的程序可以在任何环境都会有一致的表现,这里程序运行的依赖也就是容器就好比集装箱,容器所处的操作系统环境就好比货船或港口,程序的表现只和集装箱有关系(容器),和集装箱放在哪个货船或者哪个港口(操作系统)没有关系。
因此我们可以看到docker可以屏蔽环境差异,也就是说,只要你的程序打包到了docker中,那么无论运行在什么环境下程序的行为都是一致的,程序员再也无法施展表演才华了,不会再有“在我的环境上可以运行”,真正实现“build once, run everywhere”。
此外docker的另一个好处就是快速部署,这是当前互联网公司最常见的一个应用场景,一个原因在于容器启动速度非常快,另一个原因在于只要确保一个容器中的程序正确运行,那么你就能确信无论在生产环境部署多少都能正确运行。
1、如何使用docker
docker中有这样几个概念:
- dockerfile
- image
- container
实际上你可以简单的把image理解为可执行程序,container就是运行起来的进程。
那么写程序需要源代码,那么“写”image就需要dockerfile,dockerfile就是image的源代码,docker就是"编译器"。
因此我们只需要在dockerfile中指定需要哪些程序、依赖什么样的配置,之后把dockerfile交给“编译器”docker进行“编译”,也就是docker build命令,生成的可执行程序就是image,之后就可以运行这个image了,这就是docker run命令,image运行起来后就是docker container。
后面会结合具体的程序部署进行说明。
2、docker是如何工作的
实际上docker使用了常见的CS架构,也就是client-server模式,docker client负责处理用户输入的各种命令,比如docker build、docker run,真正工作的其实是server,也就是docker demon,值得注意的是,docker client和docker demon可以运行在同一台机器上。
2.1、docker build
当我们写完dockerfile交给docker“编译”时使用这个命令,那么client在接收到请求后转发给docker daemon,接着docker daemon根据dockerfile创建出“可执行程序”image。
2.2、docker run
有了“可执行程序”image后就可以运行程序了,接下来使用命令docker run,docker daemon接收到该命令后找到具体的image,然后加载到内存开始执行,image执行起来就是所谓的container。
2.3、docker pull
docker registry 可以用来存放各种image,公共的可以供任何人下载image的仓库就是docker Hub。这个时候就可以使用docker pull,这个命令的实现也很简单,那就是用户通过docker client发送命令,docker daemon接收到命令后向docker registry发送image下载请求,下载后存放在本地,这样我们就可以使用image了。
2.4、docker的底层实现
docker基于Linux内核提供这样几项功能实现的:
- NameSpace
我们知道Linux中的PID、IPC、网络等资源是全局的,而NameSpace机制是一种资源隔离方案,在该机制下这些资源就不再是全局的了,而是属于某个特定的NameSpace,各个NameSpace下的资源互不干扰,这就使得每个NameSpace看上去就像一个独立的操作系统一样,但是只有NameSpace是不够。 - Control groups
虽然有了NameSpace技术可以实现资源隔离,但进程还是可以不受控的访问系统资源,比如CPU、内存、磁盘、网络等,为了控制容器中进程对资源的访问,Docker采用control groups技术(也就是cgroup),有了cgroup就可以控制容器中进程对系统资源的消耗了,比如你可以限制某个容器使用内存的上限、可以在哪些CPU上运行等等。
有了这两项技术,容器看起来就真的像是独立的操作系统了。