看到这标题你可能会想,网上不是已经有很多Docker的入门介绍了么?同一个主题被讲过很多次,还有没有必要必要再讲?可是,我体内这混杂的的高傲与固执虽然让人厌恶,但却让我广受大家的欢迎,这也让我觉得我应该来一发(篇),哈哈。
举一个我遇到的场景,ELK三剑客,即Elasticsearch、Logstash和Kibana。我可以选择把它们直接安装在我的MacBook上,这是我主力开发机,但是在上面已经装好一个Elasticsearch了。我不想破坏现在已有的环境。要解决这个问题,用2015年时下最热门的解决方案就是Docker了。如果过去一年关于Docker的各种热闹你都错过了,那么请继续往下看。
Docker做的事情就是将的软件隔离起来,让它们即使出了问题也不会互相影响。这并不是什么横空出世的新思想。你很可能会说内核控制的进程不就这样玩么?每一个进程都有自己的内存空间,并且在一个进程自身看来,内存空间与所处在的计算机的内存空间是一样的。然而内核欺骗了进程,在背后将内存地址重新映射到了真实的内存空间中。想想今天高速运转处理器,任何地方见到的系统都能同时运行多个进程。今天的文明社会比人类历史任何一个时间点制造的谎言数量级都要很多的量级。
扯远了,Docker将进程的隔离模型的进行了扩展,让隔离性变得更强。Docker是在Linux内核的基础上打造的一系列工具。整个文件系统被抽象了,网络被虚拟化了,其它进程被隐藏了,并且从理论上,不可能逃脱容器去对在一个机器上的其他进程搞破坏。实际中,每个人对于怎么才能逃脱容器,至少去收集一点运行容器的机器的相关信息,持开放的态度。跟虚拟机比较起来,容器的隔离性还是较弱。
上面箭头:提升单机性能;下面箭头:提升隔离性
但换个角度看,进程比容器性能更好,容器性能比虚拟机性能更佳。原因很简单,隔离性更高,在每一个上下文中就需要运行更多的东西,从而拖慢速度。选择一个隔离性的过程,实际就是决定你对要运行进程的信任有多少的过程 - 它会不会去干扰其他的进程?如运行的进程都是自己的亲儿子,那你对他们会有一个很高的信任度,对他们用最少的隔离,运行在一个进程中就行了。如果是SAP,那么你很可能需要尽可能高的隔离性:将电脑装在封存在箱子里,绑在火箭上发射到月球。
Docker另一个很好的特性是,容器可以作为一个整体交付。他们不会像虚拟机那么臃肿。这大大的提高了部署的简易度。在这个微服务流行的世界里,你可以很容易将你的服务捆在一起,用镜像来发布。你甚至可以将build的结果指定成一个Docker镜像。
Docker将会怎样改变软件开发和部署的过程仍然有待观察。尽管我觉得Docker是一种带有破坏性的技术,但影响还在几年之后才会到来。虽然我会认为Docker会让很多系统管理员丢掉工作,但是实际上Docker却会改变他们的工作。每个人现在都需要一点变革,赶上时代的脚步。
又扯远了,说说OSX上的Docker。
细心的你可能注意到,我之前说Docker是运行在Linux内核之上的。然而OSX没有Linux内核,那怎么运行Docker呢。为了解决这个问题,我们需要用虚拟机来运行Docker。我们可以用一个叫boot2docker的工具来做这件事情,但是最近被docker-machine取代了。
我的机上有一个比较老的Docker,但是我觉得想试试Docker Compose,因为我运行着很多的服务。Docker Compose能让很多的容器协作起来运行一个整体的环境。为了遵循保证隔离服务的宗旨,每一个服务都运行在单独的容器中。因而,一个典型的web应用中,可以把web服务器运行在一个容器里面,数据库运行在另外一个容器里面,然后这些容器可以放在同一个机器上。
我从Docker官网上下载了安装包,并且跟着安装指南
http://docs.docker.com/mac/step_one/安装。装好Docker后,我让docker-machine在Virtual Box上创建了新的虚拟机。
一起看起来很顺利,然后启动随处可见的hello-world镜像。
很惊讶这个镜像的并不完全,完全没有发现任何一个地方有“hello world”的输出。然而好在,不是每一个Docker镜像都实现地这般草率。这个hello world的例子比较无聊,看看能不能找到更加有意思的。我们想从容器中服务一个页面,我打算使用Nginx,已经有一个现成的Nginx的容器了,因此我创建了个新的Dockerfile。Dockerfile包含了一系列如何指导Docker从一系列镜像中创建出一个容器的指令。这里提到的容器包含以下内容:
- FROM nginx
- COPY *.html /usr/share/nginx/html/
第一行设置了我们容器的基础镜像。第二行将本地的带有html后缀的文件拷贝到Nginx容器中WEB服务器的目录里。为了使用这个Dockerfile文件,我们需要创建一个Docker的镜像:
- /tmp/nginx$ docker build -t nginx_test .
- Sending build context to Docker daemon 3.072 kB
- Step 0 : FROM nginx
- latest: Pulling from library/nginx
- 843e2bded498: Pull complete
- 8c00acfb0175: Pull complete
- 426ac73b867e: Pull complete
- d6c6bbd63f57: Pull complete
- 4ac684e3f295: Pull complete
- 91391bd3c4d3: Pull complete
- b4587525ed53: Pull complete
- 0240288f5187: Pull complete
- 28c109ec1572: Pull complete
- 063d51552dac: Pull complete
- d8a70839d961: Pull complete
- ceab60537ad2: Pull complete
- Digest: sha256:9d0768452fe8f43c23292d24ec0fbd0ce06c98f776a084623d62ee12c4b7d58c
- Status: Downloaded newer image for nginx:latest
- ---> ceab60537ad2
- Step 1 : COPY *.html /usr/share/nginx/html/
- ---> ce25a968717f
- Removing intermediate container c45b9eb73bc7
- Successfully built ce25a968717f
Docker build命令开始将拉取已经构建好的Nginx容器。然后将我们的文件拷贝到容器里面,并且显示容器的hash值,这让它们很容易辨认。要运行这个容器我们可以运行:
- /tmp/nginx$ docker run --name simple_html -d -p 3001:80 -p 3002:443 nginx_test
这条命令让Docker运行nginxtest的容器,并且取名为simple_html。-d选项是为了让Docker在后台运行这条命令,并且最终-p选项是为了转发端口,这里需要将本地的3001端口映射到容器的80端口 - 即正常的web服务器端口。现在我们可以连接到web服务上了。如果我们打开chrome,访问localhost:3001就会看到:
居然不行,问题在于Docker没有意识到自己运行在虚拟机的环境里面,因此我们需要将vm的端口映射到我们本地机器上:
- Docker container:80 -> vm host:3001 -> OSX:3001
这个从虚拟机管理器里面可以轻松的搞定:
现在我们可以看到页面了:
这就是我们放在容器中的文件。好极了!现在我准备好尝试更复杂一点的容器了。
小贴士: 我注意到在虚拟机里面同时并行的运行Docker会整个让系统hang住。我怀疑同时跑两个虚拟工具可能让某个地方卡住产生了冲突的结果。我相信docker-machine的并行的支持正在在积极的解决中,0.5版本可能会看到。直到这之前,你可以参考:
http://kb.parallels.com/en/123356并且看看:
https://github.com/Parallels/docker-machine中对docker-machine的fork版本。
原文链接:Yet another intro to docker (翻译:钟最龙 校对:宋喻) 译文来自:DockOne.io