虚拟化新技术Docker技术
对于用户来说,可能一开始在不了解的情况下会对容器报以拒绝的态度,但是在尝到容器的甜头、体验到它的强大性能之后,相信大家最终是无法抵挡其魅力的。容器技术能够解决IT业目前面临的很多问题,而且优势也很明显,比如说:
1、容器具有不可变的特性。
容器将操作系统、程序库、配置文件、路径和应用程序打包在一起运行,也就是说,我们在做QA测试的时候整个镜像是什么样,投入到产品环境以后就是什么样,其性能不会有任何差距。
2、容器都非常轻量。
单个容器的内存占用很小,不像其他进程动辄占用上万MB的内存空间,容器只会给主进程分配内存,可以有效降低系统开销。
3、容器的速度更快。
虚拟机的启动时间一般都在分钟级,容器的启动速度可以达到秒级,启动容器就跟启动linux进程一样快。虽然容器的好处这么多,但是有很多用户还不了解,还认为容器跟一般的虚拟机没什么差别。实际上,容器是可销毁的,这是容器跟虚拟机之间最大的差别。容器的存在周期很短,只要用户使用完毕,就可以立即销毁容器,所以用“朝生暮死”来形容也不算过分。
在对容器进行使用和维护时,我们应该充分利用容器的这个特性,不要再把容器当成一般的虚拟机来看待,不然就真的大材小用了。在实际使用过程中,为了最大限度地发挥容器的优势,有些错误还是少犯为妙。我总结出了下面几个要点供大家参考,在跑容器的时候大家最好还是尽量遵照这几条原则:
1)
不要将数据储存在容器中。
容器随时都可以停止、销毁或迁移,比方说,一个容器里运行的应用版本是1.0,我们分分钟就可以把这个应用升级到1.1,同时还不会对数据造成任何影响。所以如果用户想要存数
据的话,最好是用数据卷来存储。不过在用卷存数据的时候大家还是要注意一点,如果有两个容器共用一个数据卷,都往里面写数据的话,是有可能造成程序崩溃的。我们在设计应用程序的时候应该考虑到这一点,为保万无一失,应用程序应该具备特定的机制,以确保在往共享数据存储区写入数据的时候不会出错。
2) 不要把应用程序分块交付。
在部分用户看来,容器跟虚拟机没什么两样,所以有些人往往会把应用程序部署到当前运行的若干个容器中。这种做法在开发阶段没有太大的问题,因为做开发的时候我们会很频繁地进行部署和调试,但是到了持续交付(CD)阶段,下一步就是QA测试和正式投产了,这种做法就不太适合了。在这一阶段,我们应该充分考虑到容器的不可变特性,最好是将应用程序打包到一个镜像中交付。
3) 不要把镜像体积建得很大。
镜像越大,就越难发布。镜像中只包含必要的文件和library就可以了,能让应用或者进程运行起来就行。千万不要在镜像中安装些没必要的东西,在构建镜像的时候要避免使用yum这种update命令,免得系统自动下载很多不相干的文件到新镜像层中。
4)
建镜像的时候不要只建一层。
大家都知道,Docker的文件系统是分层的,在建镜像的时候我们应该这么建,将操作系统单独建一层,作为基础镜像,然后用户名定义文件、运行时安装环境、配置文件都要分别建一层镜像,最后才是应用镜像层。这么做的话,我们以后重建、管理以及发布镜像的时候就要轻省得多了。
5) 不要把本地运行的容器转成镜像。
换句话说就是创建镜像的时候不要用“docker commit”命令来创建。用这种办法建镜像是完全不可取的,因为这种办法是不能重复的。我们在建镜像的时候应该从Dockerfile创建,或者用其他S2I(从源文件构建镜像)的方式来创建,这样镜像才具有可再生性,而且如果我们把镜像存在git之类提供版本控制能的系统里的话,还可以对Dockerfile的改动进行跟踪。
6) 给镜像打tag的时候不要只打“latest”。
latest其实就相当于Maven里头的“快照”。因为容器的文件系统是分层的,我们最好是给镜像多打几个tag。如果只有latest的话,可能过段时间我们再来运行应用程序的时候就发现程序运行不起来了,因为应用的父层(就是Dockerfile里面的跟在FROM命令后面的那一层)被更新的版本覆盖了,而新版本又不能向下兼容,还有可能就是从build cache里面取镜像的时候取到了错的“latest”镜像。在产品环境中部署容器的时候也要避免使用latest,不然容易造成无法跟踪记录镜像版本的问题。
7) 不要在单个容器里面运行多个进程。
容器本来就是用来运行单个应用的(比如http daemon,应用服务器,数据库等等),如果我们非要在一个容器里跑几个应用,那么在管理每个应用进程、存取日志、升级应用的时候就会很麻烦。
8)不要把认证口令存在镜像中,用环境变量比较好。
如果我们把用户名/密码值对存在镜像里的话,就只有采用硬编码的方式来挨个处理,估计这种麻烦事没人愿意去干。所以我们最好是用环境变量的方从容器外部获取此类信息。
go语言开发环境搭建
9) 不要用root用户的角来运行进程。
Docker容器默认是以root权限运行的。不过随着技术的成熟,docker也会提供安全性更高的默认操作选项。在现有技术条件下,以root权限运行会对其他应用带来安全隐患,而且在有些运行环境下root权限是取不到的,所以我们在跑容器的时候应该用USER命令来指定非root权限的用户。
10) 不要过分依赖IP地址。
每个容器都有一个内部IP,这个IP不是固定的,我们启动容器或者停止容器的时候IP都会变。如果我们要让应用或者微服务模块在容器之间进行通信的话,正确的做法是通过设置环境变量来传递主机名和端口号。
其实看完这句话还是不明白究竟是啥的,下面就慢慢解释。不过长话短说的话,把他想象成一个用了一种新颖方式实现的超轻量虚拟机,在大概效果上也是正确的。当然在实现的原理和应用上还是和VM有巨大差别的,并且专业的叫法是应用容器(Application Container)。
为啥要用容器?
那么应用容器长什么样子呢,一个做好的应用容器长得就好像一个装好了一组特定应用的虚拟机一样。比如我现在想用MySQL那我就个装好MySQL的容器,运行起来,那么我就可以使用 MySQL了。
那么我直接装个 MySQL不就好了,何必还需要这个容器这么诡异的概念?话是这么说,可是你要真装MySQL的话可能要再装一堆依赖库,根据你的操作系统平台和版本进行设置,有时候还要从源代码编译报出一堆莫名其妙的错误,可不是这么好装。而且万一你机器挂了,所有的东西都要重新来,可能还要把配置在重新弄一遍。但是有了容器,你就相当于有了一个可以运行起来的虚拟机,只要你能运行容器,MySQL的配置就全省了。而且一旦你想换台机器,直接把这个容器端起来,再放到另一个机器就好了。硬件,操作系统,运行环境什么的都不需要考虑了。
在公司中的一个很大的用途就是可以保证线下的开发环境、测试环境和线上的生产环境一致。当年在 Baidu 经常碰到这样的事情,开发把东西做好了给测试去测,一般会给一坨代码和一个介绍上线步骤的上线单。结果代码在测试机跑不起来,开发就跑来跑去看问题,
一会儿啊这个配置文件忘了提交了,一会儿啊这个上线命令写错了。到了一个 bug 提上去,开发一看,啊我怎么又忘了把这个命令写在上线单上了。类似的事情在上线的时候还会发生,变成啊你这个软件的版本和我机器上的不一样……在 Amazon 的时候,由于一个开发直接担任上述三个职位,而且有一套自动化部署的机制所以问题会少一点,但是上线的时候大家还是胆战心惊。
若果利用容器的话,那么开发直接在容器里开发,提测的时候把整个容器给测试,测好了把改动改在容器里再上线就好了。通过容器,整个开发、测试和生产环境可以保持高度的一致。
此外容器也和VM一样具有着一定的隔离性,各个容器之间的数据和内存空间相互隔离,可以保证一定的安全性。
那为啥不用VM?
那么既然容器和 VM 这么类似为啥不直接用 VM 还要整出个容器这么个概念来呢?Docker 容器相对于 VM 有以下几个优点:
启动速度快,容器通常在一秒内可以启动,而 VM 通常要更久
资源利用率高,一台普通 PC 可以跑上千个容器,你跑上千个 VM 试试
性能开销小, VM 通常需要额外的 CPU 和内存来完成 OS 的功能,这一部分占据了额外的资源
为啥相似的功能在性能上会有如此巨大的差距呢,其实这和他们的设计的理念是相关的。 VM 的设计图如下:
VM 的 Hypervisor 需要实现对硬件的虚拟化,并且还要搭载自己的操作系统,自然在启动速度和资源利用率以及性能上有比较大的开销。而 Docker 的设计图是这样的: 
 
Docker 几乎就没有什么虚拟化的东西,并且直接复用了 Host 主机的 OS,在 Docker Engine 层面实现了调度和隔离重量一下子就降低了好几个档次。 Docker 的容器利用了  LXC,管理利用了 namespaces 来做权限的控制和隔离,  cgroups 来进行资源的配置,并且还通过  aufs 来进一步提高文件系统的资源利用率。
其中的 aufs 是个很有意思的东西,是  UnionFS 的一种。他的思想和 git 有些类似,可以把对文件系统的改动当成一次 commit 一层层的叠加。这样的话多个容器之间就可以共享
他们的文件系统层次,每个容器下面都是共享的文件系统层次,上面再是各自对文件系统改动的层次,这样的话极大的节省了对存储的需求,并且也能加速容器的启动。
下一步
有了前面的这些介绍,应该对 Docker 到底是啥有些了解了吧, Docker 是 用 Go 语言编写的,源代码托管在 github 而且居然只有 1W 行就完成了这些功能。如果想尝试一下的话可以看官方介绍了,应该上手会容易一些了。博主也是新手,如有错误欢迎拍砖指正。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。