什么是Docker ? —— 轻量级的VM
Docker直接基于Linux内核,支持各种语言,它比VM虚拟机更加轻量,能够在Linux或云计算IaaS等平台上直接运行,带着你的应用无缝地移植到各种运行环境。
所以你也可以简单理解成是轻量级的VM,但他的能力并不一般。
有人无奈地说:Docker流行起来是因为我们的依赖设计做得不够到位,最后只能在运行阶段依靠Docker这样的微容器帮我们松耦合。
Docker与VM的区别。
1.肥胖的虚拟机VM
虚拟机(vm)是一个了不起的工具,它有助于进一步抽象运行时环境的物理硬件。 但不幸的是在启动和执行,有一个非常陡峭的性能损失。
vm的大部分问题的原因是因为重复。 要理解这种重复,想想Linux操作系统的结构。 有一个清晰的分离, Linux内核负责管理深层网络和线程等任务和内核之外的一切的用户空间。
virtualbox 和 VMware 等传统虚拟机运行在用户空间, 传统的VM启动一个实例时,它携带了一个Linux内核和在现有的用户空间内的一个用户空间。
这就是重复发生的地方,为什么要在用户空间再启动一个Linux内核呢?而不是使用已经有的内核?
下面是Docker的示意图:
Docker启动一个实例时,它会将用户空间和所在主机的Linux内核连接,因此启动只需要毫秒, 性能是97%。这就是VM和docker的核心区别点;
再细一步的比较:
VM | Docker |
通过上面的比较,我们知道Docker 几乎就没有什么虚拟化的东西,并且直接复用了 Host 主机的 OS
,
在 Docker Engine
层面实现了调度和隔离重量一下子就降低了好几个档次。
Docker 的容器利用了 LXC,
管理利用了 namespaces
来做权限的控制和隔离,
cgroups
来进行资源的配置,并且还通过 aufs
来进一步提高文件系统的资源利用率。
其中的 aufs 是个很有意思的东西,是 UnionFS 的一种。他的思想和 git 有些类似,可以把对文件系统的改动当成一次 commit 一层层的叠加。这样的话多个容器之间就可以共享他们的文件系统层次,每个容器下面都是共享的文件系统层次,上面再是各自对文件系统改动的层次,这样的话极大的节省了对存储的需求,并且也能加速容器的启动。
优势:通过上面的比较,相对于VM
- 启动速度快,容器通常在一秒内可以启动,而 VM 通常要更久
- 资源利用率高,一台普通 PC 可以跑上千个容器,你跑上千个 VM 试试
- 性能开销小, VM 通常需要额外的 CPU 和内存来完成 OS 的功能,这一部分占据了额外的资源
为啥要用容器?
那么应用容器长什么样子呢,一个做好的应用容器长得就好像一个装好了一组特定应用的虚拟机一样。
若果利用容器的话,那么开发直接在容器里开发,提测的时候把整个容器给测试,测好了把改动改在容器里再上线就好了。
通过容器,整个开发、测试和生产环境可以保持高度的一致。
此外容器也和VM一样具有着一定的隔离性,各个容器之间的数据和内存空间相互隔离,可以保证一定的安全性。
在公司中的一个很大的用途就是可以保证线下的开发环境、测试环境和线上的生产环境一致,使用docker这避免了开发,测试,上线环境不一致等带来的大量冲突问题。
相信这句话你已经听腻了,
怎么可能,在我的电脑上明明可以的
Docker:VM、代码迁移和SOA解决方案
Docker在部署软件方面解决了最困难的问题,将应用程序代码开发和部署环境。在不同平台之间移植代码变得很简单,因为我们的应用程序代码是被包装在Docker环境中。
解决部署
一个Docker VM是由定义良好的脚步 Dockerfile 产生的, Dockerfile指定什么风味和使用的Linux版本,安装什么软件,什么端口开放,如何把源代码打包在一起等。所有你需要的是捆绑这一切在一个文件中。下面是一个示例:
FROM ubuntu:12.04
MAINTAINER Zach Gardner <zgardner@keyholesoftware.com>
# Create container
# Update apt-get
RUN apt-get update
RUN mkdir /container
RUN mkdir /container/project
# Install NodeJS
RUN apt-get --yes install python g++ make checkinstall fakeroot wget
RUN src=$(mktemp -d) && cd $src && \
wget -N http://nodejs.org/dist/node-latest.tar.gz && \
tar xzvf node-latest.tar.gz && cd node-v* && \
./configure && \
fakeroot checkinstall -y --install=no --pkgversion $(echo $(pwd) | sed -n -re"s/.+node-v(.+)$/\1/p") make -j$(($(nproc)+1)) install && \
dpkg -i node_* && \
rm -rf $src
# Install NPM
RUN apt-get --yes install curl
RUN curl --no-check-certificate https://www.npmjs.org/install.sh | sh
# Install Bower's dependencies
RUN apt-get install --yes git
# Install PhantomJS dependencies
RUN apt-get install --yes freetype* fontconfig
# Move source code to container
ADD / /container/project
# Install NPM dependencies
RUN cd /container/project/ && npm install
# Install Project's Bower dependencies
RUN cd /container/project && (echo -e "n" | ./node_modules/bower/bin/bower install --allow-root)
# Compile code
RUN cd /container/project && ./node_modules/grunt-cli/bin/grunt build
# Start server
CMD /container/project/node_modules/grunt-cli/bin/grunt --gruntfile /container/project/Gruntfile.js prod
我们所做的第一件事是定义这个脚本,假设Ubuntu 12.04 安装NodeJS NPM,git,我们可以从源码库拷贝源码,下载依赖库,编译代码 启动服务器。
当你将Dockerfile交付给Docker以后,它会生成一个Docker Image,这是一个独立的ZIP文件,它包含应用程序需要的一切。
源码和执行环境的绑定是一种完全不同于传统部署方式的全新范式,传统方式是迁移代码,人工在shell执行脚本来更新环境,你可以切换Docker Image在不同环境平台,没有人工介入,降低了出错率,你可以确保对QA已经签名的代码在没有任何改变情况下迁移平台环境。
Docker进行迁移的范式使用一些前沿的成就,如反应式Reactive编程,我们知道管理状态是应用开发中最难的一件事,可变性状态使得创建线程安全代码变得困难,通过切换思维,基于一片片不可变数据,CPU能够以一种比以前方便的方式优化线程, Docker克服了在平台上更新软件的传统方式,只需要用新的Image替代旧的即可,而不是更新当前的Image,这种替换没有脚本,不用担心Java版本过期,这些Dcoker都帮你照顾了。
跨平台迁移Docker Image非常方便,将Docker Image推送到一个Dcoker注册表( 公共 或 私人 ),然后使用和Git非常相似的办法拉到所在的平台:
在开发平台发布Image:
docker push zgardner/myapp
在生产平台拉取Image:
docker pull zgardner/myapp
docker run -i -t zgardner/myapp
第一次是发布myapp到Docker注册表,然后再拉取它到所在平台运行。
运行Docker image是一个Docker容器,有关容器开启和关闭命令这里忽略了,包括容器运行的端口等等。
面向服务架构SOA
Docker是第一个真正的DevOps的工具 , 它允许开发人员方便地指定他们的代码应该执行的环境。 它还消除了升级环境的压力担忧。
Docker非常适合SOA的微服务架构,每一个单独的Dockerfile代表一个微服务,这些微服务是不同与在SOA范围内的传统服务。 传统的服务通常是整体性的,很难被分割和碎片化, Micro-services专注于非常小的、可重用的组件,尽可能少知道他们所处的环境。 Docker提供工作的隔离,可以部署在任何地方执行小micro-services。