如何应用Docker?简明教程告诉你new

JonCrittend 9年前
   <p>Docker已经迅速发展了一段时间,不少同学可能都在对Docker的应用,实际的应用,解决开发和运营中的实际问题,如何应用Docker,对docker能做什么有了更多的需求,为此,我整理了一份 Docker应用教程 ,致力提供更多的 Docker应用案例和问题解决。初学的同学还请有先按本文了解docker的基本操作。</p>    <p>Docker 是个容器,像个碗或者盆,其实更像个橱柜 带格子的那种.</p>    <p>你可以把喜欢的东西放在各种各种的格子里,然后不管橱柜搬到哪,就你在里面放置的好玩意不会变。</p>    <p>这样你就可以轻松的在ubuntu上运行一个centos</p>    <p>下面是老外做的一个不是很直观也能看明白的直观图,对比docker和VM的不同:</p>    <p><img src="https://simg.open-open.com/show/7d8dda1a987e1cf089943600b43e8aab.png"></p>    <p>这里有镜像可以下载 <a href="/misc/goto?guid=4959671259537923963" rel="nofollow,noindex">these slides(link is external)</a> 都是Docker提供的(不足最近github的访问速度是真xxx,随意最好找找有没有代理加快下载,如果对docker不了解,还是要谨慎一些,二次发布的镜像,也许会有问题).</p>    <h2>获取docker</h2>    <p>docker对mac支持不是很好,可以用 <a href="/misc/goto?guid=4959671259640274031" rel="nofollow,noindex">boot2docker(link is external)</a> 来解决.老外推荐使用CoreOs来操作Vagrant(这又是一个神器,将来会陆续在我的网站出现,请持续关注)</p>    <p>老外在这里强烈推荐CoreOS,说怎么怎么好,我还是推荐先使用ubuntu或者在windows上装个vbox在用ubuntu,coreos作为一个新型的服务器级别的系统,也十分值得关注,因为CoreOs将作为主力的docker容器发展。</p>    <p>下面这一段是老外将他在CoreOS安装docker的事,主要是 Vagrantfile (这是一个Vagrant可以识别的配置文件):</p>    <pre>  <strong>config.vm.box ="coreos" config.vm.box_url ="http://storage.core-os.net/coreos/amd64-generic/dev-channel/coreos_production_vagrant.box" config.vm.network "private_network", ip:"172.12.8.150" </strong><strong> 如果使用NFS 就加下面一段: </strong></pre>    <pre>  # This will require sudo access when using "vagrant up"  config.vm.synced_folder ".","/home/core/share",      id:"core",:nfs =>true,:mount_options =>['nolock,vers=3,udp']</pre>    <pre>  如果使用vmware不使用virtualbox:  </pre>    <pre>  config.vm.provider :vmware_fusion do|vb,override|override.vm.box_url ="http://storage.core-os.net/coreos/amd64-generic/dev-channel/coreos_production_vagrant_vmware_fusion.box"end<strong> 最好要加上一个插件: </strong></pre>    <pre>  # plugin conflictifVagrant.has_plugin?("vagrant-vbguest")then      config.vbguest.auto_update =falseend</pre>    <p>如果你不使用CoreOS而是使用其他的,可以在这个页面  <a href="/misc/goto?guid=4959671259734503237" rel="nofollow,noindex">this page(link is external)</a> 找到安装方式(这个是官方的,这里是民间的 <a href="/misc/goto?guid=4959671259823567005" rel="nofollow,noindex">http://www.simapple.com/255.html(link is external)</a> ,陆续完善中). Note: Docker是基于 Ubuntu开发的随意选择什么,你懂得。</p>    <p>如果在CoreOS上操作过程中,提示重启,请不要担心,这是为了启用特性所做的操作</p>    <h2>下面为docker正式内容</h2>    <p>你的第一个容器</p>    <p>第一步尝试是必须的,虽然你可能不是直接发现docker的强大,但是足以“管中窥豹”(这老外比我都罗嗦)</p>    <p>docker有一些基础的容器,也接受民间提供制作好的容器,以后你如果想贡献,也可以在这里 <a href="/misc/goto?guid=4959671259905615248" rel="nofollow,noindex"> index.docker.io (link is external) </a> 发布自己的容器.</p>    <p>最流行最基础的Docker镜像还是“Ubuntu”</p>    <p>如果没有这个镜像,那么需要下载~</p>    <h2>Run Bash:</h2>    <p> </p>    <pre>  docker run ubuntu /bin/bash    </pre>    <p>什么事情都没有发生! 哈哈, 实际上已经有东西运行了. 运行 docker ps (像在linux主机上运行 ps) - 你什么容器也看不到,一个进程都没有(这老外~尼玛). Run docker ps -a, 见证奇迹的时刻!</p>    <pre>  CONTAINER ID    IMAGE           COMMAND         CREATED              STATUS      PORTS       NAMES  8ea31697f021    ubuntu:12.04/bin/bash       About a minute ago   Exit0                  loving_pare</pre>    <p>我们已经可以看到一个在运行的 /bin/bash , 但是没有任何进程在维持它的执行.一个docker容器是伴随进程运行的.</p>    <p>先记住上面说的. 让我们继续操作docker,来玩一会儿:</p>    <pre>  docker run -t -i ubuntu /bin/bash<strong> </strong></pre>    <p>现在你可以看到你已经以root的身份登录到了docker 容器!</p>    <p>这些命令都在做什么?</p>    <ul>     <li>docker run  - 运行一个容器</li>     <li>-t  - 分配一个(伪)  <a href="/misc/goto?guid=4959671259989541049" rel="nofollow,noindex"> tty (link is external) </a></li>     <li>-i  - 开发输入(so we can interact with it)</li>     <li>ubuntu  - 使用ubuntu基础镜像</li>     <li>/bin/bash  - 运行bash shell</li>    </ul>    <h2>跟进改变</h2>    <p>使用 ( ctrl+d or type  exit ) 来退出然后继续执行  docker ps -a . :</p>    <pre>  <strong>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 30557c9017ec ubuntu:12.04/bin/bash About a minute ago Exit127 elegant_pike 8ea31697f021 ubuntu:12.04/bin/bash 22 minutes ago Exit0 loving_pare</strong></pre>    <p>复制粘贴现在运行的容器 ID (30557c9017ec in my case). 运行docker diff <container id>. :</p>    <pre>  <strong>core@localhost ~ $ docker diff 30557c9017ec A /.bash_history C /dev A /dev/kmsg </strong></pre>    <p>我们可以看到我们仅仅登录了 bash之后的改变,创建了 .bash_history file, a  /dev directory and a /dev/kmsg file. 这是细微的变化,确实伟大的存在! Docker 会跟踪我们在容器中的所有改动. 事实上,docker就是运行我们创造改动,提交改动,发布改动,然后将改变带到任何地方. 这就是我们使用docker所依赖的基础.</p>    <p>下面我们就来安装点新玩意到容器中,让把它们打包成我们自己的.</p>    <pre>  <strong># Get into Bash docker run -t -i ubuntu /bin/bash # Install some stuff apt-get update apt-get install -y git ack-grep vim curl wget tmux build-essential python-software-properties</strong></pre>    <p>等这些都运行完了之后,退出,再执行 docker ps -a . 在复制最新的ID (docker diff <Container ID>):</p>    <pre>  <strong>core@localhost ~ $ docker diff 5d4bdae290a4> A TON OF FILE LISTED HERE</strong></pre>    <p>当然又有很多的新文件被添加. 下面我们就来打包我们的版本,为了以后更好的使用.我们将提交修改,给它命名并打上标签。 我们将使用: docker commit <Container ID> <Name>:<Tag></p>    <pre>  <strong>core@localhost ~ $ docker commit 5d4bdae290a4 fideloper/docker-example:0.1 c07e8dc7ab1b1fbdf2f58c7ff13007bc19aa1288add474ca358d0428bc19dba6 # You'll get a long hash as a Success message</strong><strong> </strong></pre>    <p>我们来看看我们打包好的镜像. Run docker images:</p>    <pre>  <strong>core@localhost ~ $ docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE fideloper/docker-example 0.1 c07e8dc7ab1b 22 seconds ago 455.1 MB ubuntu 13.109f676bd305a46 weeks ago 178 MB ubuntu saucy 9f676bd305a46 weeks ago 178 MB ubuntu 13.04 eb601b8965b8 6 weeks ago 166.5 MB ubuntu raring eb601b8965b8 6 weeks ago 166.5 MB ubuntu 12.105ac751e8d6236 weeks ago 161 MB ubuntu quantal 5ac751e8d6236 weeks ago 161 MB ubuntu 10.049cc9ea5ea5406 weeks ago 180.8 MB ubuntu lucid 9cc9ea5ea5406 weeks ago 180.8 MB ubuntu 12.049cd978db300e6 weeks ago 204.4 MB ubuntu latest 9cd978db300e6 weeks ago 204.4 MB ubuntu precise 9cd978db300e6 weeks ago 204.4 MB</strong></pre>    <p>你已经注意到了那么多的ubuntu啊. 当我第一次加载使用ubuntu基础镜像的时候,就已经加载相应的ubuntu标记,更多知识请浏览 <a href="/misc/goto?guid=4959671260074478386" rel="nofollow,noindex"> Docker index (link is external) </a> .</p>    <p>非常有趣,不管怎样我们已经用了自己的镜像 叫做 fideloper/docker-example 并且有个版本标签 0.1 !</p>    <h2>使用 Dockerfile 建立一个服务器</h2>    <p>让我们使用Dockerfile来创建一个服务器,大概就是通过一个配置文件,让git和wget自动的完成这个服务器环境的搭建工作.</p>    <p>创建一个目录,然后cd进去,因为我们要使用nginx服务器,就需要有个默认的配置文件.</p>    <p>创建一个叫做 default 的配置文件:</p>    <pre>  <strong>server { root /var/www; index index.html index.htm;# Make site accessible from http://localhost/ server_name localhost; location /{# First attempt to serve request as file, then# as directory, then fall back to index.html try_files $uri $uri//index.html;}}</strong></pre>    <p>这就是nginx的基础配置了.</p>    <p>下面我们创建一个 Dockerfile 并添加如下内容, 修改镜像FROM为我们自己的镜像(多么happy):</p>    <pre>  FROM fideloper/docker-example:0.1    <strong>RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe">/etc/apt/sources.list RUN apt-get update RUN apt-get-y install nginx RUN echo "daemon off;">>/etc/nginx/nginx.conf RUN mkdir /etc/nginx/ssl ADD default/etc/nginx/sites-available/default EXPOSE 80 CMD ["nginx"] </strong></pre>    <p>这些东西有都是什么的?</p>    <ul>     <li>FROM  告诉docker使用哪个镜像,用什么版本</li>     <li>RUN  以root用户身份来执行linux命令</li>     <li>ADD  复制文件到容器内      <ul>       <li>这是一个非常方便来管理配置文件的方式</li>      </ul> </li>     <li>EXPOSE  暴露端口给主机,也可以添加更多的端口比如:  EXPOSE 80 443 8888</li>     <li>CMD  执行一个命令 (但不是以  sh -c ). 这通常是来运行长时间的进程,但是我们只是来启动nginx.      <ul>       <li>在生产环境中,我们想看到nginx在运行失败的情况下的表现</li>      </ul> </li>    </ul>    <p>保存好这些,让我们来build一个新镜像</p>    <pre>  <strong>docker build -t nginx-example .</strong></pre>    <p>如果它正常工作了并结束 Successfully built 88ff0cf87aba (这个容器ID并不一定都是一样的).</p>    <p>检查一下你有获得的什么镜像 docker images :</p>    <pre>  <strong>core@localhost ~/webapp $ docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE nginx-example latest 88ff0cf87aba35 seconds ago 468.5 MB fideloper/docker-example 0.1 c07e8dc7ab1b 29 minutes ago 455.1 MB ...other Ubuntu images below ...</strong></pre>    <p>再运行一下 docker ps -a:</p>    <pre>  <strong>core@localhost ~/webapp $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES de48fa2b142b 8dc0de13d8be/bin/sh -c #(nop) CM About a minute ago Exit 0 cranky_turing84c5b21feefc2eb367d9069c/bin/sh -c #(nop) EX About a minute ago Exit 0 boring_babbage3d3ed53987ec77ca921f5eef/bin/sh -c #(nop) AD About a minute ago Exit 0 sleepy_brattain b281b7bf017f cccba2355de7 /bin/sh -c mkdir /et About a minute ago Exit0 high_heisenberg 56a84c7687e9 fideloper/docker-e.../bin/sh -c #(nop) MA 4 minutes ago Exit 0 backstabbing_turing... other images ...</strong></pre>    <p>你可以看到 每一行Dockerfile中的指令, 一个新的容器已经诞生 if that line results in a change to the image used. Similar(ish) to version control! (Also, how funny is the name "backstabbing_turing"?)(这一段很难明白?难道又是老外在用,英语文化开玩笑,希望给个指点)</p>    <h2>最后,执行这个web服务</h2>    <p>让我们来运行web服务器! 使用 docker run -p 80:80 -d nginx-example (确定你要使用的名称).</p>    <p>-p 80:80 经容器的80端口 绑定到了主机上 通过curl localhost 或者访问主机ip就可以看到运行的状态</p>    <p>core@localhost ~/webapp $ docker run -d nginx-example</p>    <pre>  <strong>73750fc2a49f3b7aa7c16c0623703d00463aa67ba22d2108df6f2d37276214cc# Success! core@localhost ~/webapp $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a085a33093f4 nginx-example:latest nginx 2 seconds ago Up2 seconds 80/tcp determined_bardeen</strong></pre>    <p>现在我们使用 docker ps 而不是 docker ps -a - 我们可以看到容器中正在运行的进程(回想最初的命令). 执行 curl localhost:</p>    <p>core@localhost ~/webapp $ curl localhost/index.htmld &lt;html&gt;&lt;head&gt;&lt;title&gt;500InternalServerError&lt;/title&gt;&lt;/head&gt;&lt;body bgcolor=&quot;white&quot;&gt;&lt;center&gt;&lt;h1&gt;500InternalServerError&lt;/h1&gt;&lt;/center&gt;&lt;hr&gt;&lt;center&gt;nginx/1.1.19&lt;/center&gt;&lt;/body&gt;&lt;/html&gt;</p>    <p>我们看到了nginx的回应,但是是500错误. 这是因为我们并没有一个index.html 资源文件让nginx返回. 让我们停止这个容器的运行 docker stop <container id>:</p>    <pre>  <strong>core@localhost ~/webapp $ docker stop a085a33093f4 a085a33093f4</strong></pre>    <p>来解决一下这个问题,我们来共享一个目录在主机和容器之间,这样就用个index.html了,首先创建一个index.html在我们想要贡献的目录中</p>    <pre>  <strong># I'm going to be sharing the /home/core/share directory on my CoreOS machine echo "Hello, Docker fans!">>/home/core/share/index.html</strong></pre>    <p>然后我们再启动这个容器(注意命令):</p>    <pre>  <strong>docker run -v /home/core/share:/var/www:rw -p 80:80 -d nginx-example</strong></pre>    <ul>     <li>docker run  - 启动容器</li>     <li>-v /path/to/host/dir:/path/to/container/dir:rw  - 指定一个目录共享到容器,并且指定权限为读写,也可以指定为只读</li>     <li>-p 80:80  - 绑定端口.</li>     <li>-d nginx-example  启动nginx-example的容器,由于在配置文件的CMD中已经指定启动了  nginx ,在容器启动时nginx即启动</li>    </ul>    <p>运行 curl localhost:</p>    <pre>  <strong>core@localhost ~/webapp $ curl localhost Hello,Docker fans!</strong></pre>    <p>...或者直接访问主机ip</p>    <p>注意这个ip是主机的ip. 我已经在 Vagrantfile 中指定了ip。我不需要知道要转发的ip究竟是什么? 当时可以通过这个命令来看到  docker inspect <Container ID> .</p>    <pre>  <strong>core@localhost ~/webapp $ docker inspect a0b531aa00f4 [{"ID":"a0b531aa00f475b0025d8edce09961077eedd82a190f2e2f862592375cad4dd5","Created":"2014-03-20T22:38:22.452820503Z",... a lot of JSON ..."NetworkSettings":{"IPAddress":"172.17.0.2","IPPrefixLen":16,"Gateway":"172.17.42.1","Bridge":"docker0","PortMapping":null,"Ports":{"80/tcp":[{"HostIp":"0.0.0.0","HostPort":"80"}]}},... more JSON ...}] </strong></pre>    <h2>链接不同的容器</h2>    <p>现在已经可以将多个容器联合在一起了 。能将容器联合在一起,是一项非常重要的技能. 举个例子, 比如你的web容器想要链接你的数据库容器. 链接可以让多个分支应用,独立于你的应用。</p>    <p>举个例子:</p>    <p>启动一个容器,并且取个有意义点的名字 (在这里就叫, mysql ):</p>    <pre>  <strong>docker run -p 3306:3306-name mysql -d some-mysql-image</strong></pre>    <p>启动你的web容器 将它和另外一个容器链接在一起 -d name:db (where db is an arbitrary name used in the container's environment variables):</p>    <pre>  <strong>docker run -p 80:80-link mysql:db -d some-application-image</strong></pre>    <p>在例子中, some-application-image 有这样的环境变量设置DB_PORT_3306_TCP_ADDR=172.17.0.8 and DB_PORT_3306_TCP_PORT=3306 用于在应用中的设置</p>    <p>这是一个mysql的dockerfile <a href="/misc/goto?guid=4959671260166694413" rel="nofollow,noindex">MySQL Dockerfile</a></p>    <h2>结论</h2>    <p>我们就是可以这么简单的来创建一台服务器,添加应用代码,控制应用。执行环境中的每一件事都在你的掌控之中</p>    <p>通过这种方式,我们可以 跳过复杂的环境设置,专心于自己的代码.</p>    <h3>P.S. - Tips and Tricks</h3>    <p>如果执行完了这次体验,你想自己做点什么,并且清理掉之前的docker 容器:</p>    <ul>     <li>删除容器r:  docker rm <Container ID></li>     <li>删除所有容器:  docker rm $(docker ps -a -q)</li>     <li>移除镜像:  docker rmi <Container ID></li>     <li>移除所有镜像:  docker rmi $(docker ps -a -q)</li>    </ul>    <p>Note: 在移除镜像前,你必须删除掉,所有依赖于该镜像的容器</p>    <p>加入你已经完整体验了上面的教程,那么就已经对docker有了很系统的了解,因为docker 无非就是用来构建一个可移植环境,为了能有进一步的提高,推荐进行下面的学习:</p>    <ul>     <li>docker操作命令,主要熟悉一个常用的操作,docker的命令不多,基本上都会用到,推荐: <a href="/misc/goto?guid=4959671260251213911" rel="nofollow,noindex">docker命令详解</a></li>     <li>Dockerfile的编写,用于建立一个属于自己的定制化的docker image镜像,docker建立镜像很简单,主要是要能够编写Dockerfile进行定制,推荐: <a href="/misc/goto?guid=4959671260331483658" rel="nofollow,noindex">Dockerfile说明文档</a></li>    </ul>    <p>来自: <a href="/misc/goto?guid=4959671260416671564" rel="nofollow">http://www.yunweipai.com/archives/6615.html</a></p>