又一篇Docker入门介绍

jopen 9年前
 

看到这标题你可能会想,网上不是已经有很多Docker的入门介绍了么?同一个主题被讲过很多次没还有必要必要再讲么?可是,我体内这混杂的的高傲与固执虽然让人厌恶,但却让我广受哺乳动物的欢迎,这也让我觉得我应该来一发(篇)。

举一个我遇到的场景,ELK三剑客,即Elasticsearch,Logstash,和Kibana。我可以选择把它们直接安装在我的 macbook上,这是我主力开发机,但是在上面已经装好一个Elasticsearch了。我不想破坏现在已有的环境。要解决这个问题,用2015年时 下最热门的解决方案就是Docker了。如果过去一年关于Docker的各种热闹你都错过了,那么请继续往下看。

Docker做的事情就是将的软件隔离起来,让它们即使出了问题也不会互相影响。这并不是什么横空出世的新思想。你很可能会说内核控制的进程不就 这样玩么?每一个进程都有自己的内存空间,并且在一个进程自身看来,内存空间与所处在的计算机的内存空间是一样的。然而内核欺骗了进程,在背后将内存地址 重新映射到了真实的内存空间中。想想今天高速运转处理器,任何地方见到的系统都能同时运行多个进程。今天的文明社会比人类历史任何一个时间点制造的谎言数 量级都要很多的量级。

扯远了,Docker将进程的隔离模型的进行了扩展,让隔离性变得更强。Docker是在Linux内核的基础上打造的一系列工具。整个文件系统 被抽象了,网络被虚拟化了,其他进程被隐藏了,并且从理论上,不可能逃脱容器去对在一个机器上的其他进程搞破坏。实际中,每个人对于怎么才能逃脱容器,至 少去收集一点运行容器的机器的相关信息,持开放的态度。跟虚拟机比较起来,容器的隔离性还是较弱。

又一篇Docker入门介绍

_(上面箭头:提升单机性能;下面箭头:提升隔离性)_

但换个角度看,进程比容器性能更好,容器性能比虚拟机性能更佳。原因很简单,隔离性更高,在每一个上下文中就需要运行更多的东西,从而拖慢速度。 选择一个隔离性的过程,实际就是决定你对要运行进程的信任有多少的过程 - 它会不会去干扰其他的进程?如运行的进程都是自己的亲儿子,那你对他们会有一个很高的信任度,对他们用最少的隔离,运行在一个进程中就行了。如果是 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上创建了新的虚拟机。

又一篇Docker入门介绍

一起看起来很顺利,然后启动随处可见的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  : 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入门介绍

居然不行,问题在于docker没有意识到自己运行在虚拟机的环境里面,因此我们需要将vm的端口映射到我们本地机器上:

Docker container:80 -> vm host:3001 -> OSX:3001

这个从虚拟机管理器里面可以轻松的搞定:

又一篇Docker入门介绍

现在我们可以看到页面了:

又一篇Docker入门介绍

这就是我们放在容器中的文件。好极了!现在我准备好尝试更复杂一点的容器了。

小贴士:

我注意到在虚拟机里面同时并行的运行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 , 翻译:钟最龙)