正在学习Docker,留着看看
转自Docker的大坑小洼mysql
Docker成为云计算领域的新宠儿已是不争的事实,做为高速发展的开源项目,不免存在这样或那样的瑕疵。笔者最近在开发实战中曾经跌进去一些坑,有些坑还很深,写出来分享,至关因而在坑边挂个警示牌,避免你们重蹈覆辙。话很少说,一块儿来领略Docker的大坑小洼。sql
Docker中同种类型的镜像,通常会用tag来进行互相区分。如Docker中的mysql镜像,镜像tag有不少种,有5.6.17,5.6.22,latest等。用户的环境中若已经熟练使用mysql:5.6.17,并不表明用户若是使用mysql:5.6.22,环境依旧工做。docker
不一样tag同种类型的Docker镜像,会由于如下的缘由致使镜像差别。 (1).Docker镜像内容不一样。同种类型Docker镜像的tag不一样,很大程度上是由于镜像中应用版本的差别。Dockerfile表明Docker镜像的制做流程,换言之是Dockerfile的不一样,致使Docker镜像的不一样。 (2).Docker镜像的entrypoint.sh不一样。entrypoint.sh表明容器中应用进程按照何种形式启动,entrypoint.sh的差别直接致使应用容器的使用差别。举例说明:mysql:5.6.17和mysql:5.6.22的entrypoint.sh存在很大差别,二者对于隔离认为重要的环境变量的定义就不一致,使用的差别天然存在。json
不一样tag的同类型镜像做为替代品时,需谨慎。查看Docker镜像layer层的差别,查阅Dockerfile与entrypoint.sh的差别,能够提供起码的保障。ubuntu
在一个时间点使用latest镜像,应用容器运行正常;以后的另外一个时间点按照相应的Dockerfile,build出镜像再运行应用容器,失效。学习
Docker官方关于同种类型Docker镜像的latest标签,并未永久赋予某一指定的Docker镜像,而是会变化。举例说明:某一个时间点ubuntu镜像的latest标签属于ubuntu:12.04,以后的另外一时间点,该latest标签属于ubuntu:14.04,若Dockerfile在这两个时间点进行build时,结果必然相异。缘由回归至上文的第一个坑。ui
慎用latest标签,最好不用,Docker镜像都使用指定的tag。云计算
使用fig部署两个有依赖关系的容器A和B,容器A内部应用的启动依赖于容器B内应用的完成。容器A内应用程序尝试链接容器B内部应用时,因为容器B内应用程序并未启动完毕,致使容器A应用程序启动失败,容器A中止运行。spa
容器的启动分为三个阶段,依次为dockerinit、entrypoint.sh以及cmd,三个阶段都会消耗时间,不一样的容器消耗的时间不一,这主要取决于docker容器中entrypoint和command到底作了什么样的操做。如mysql容器B的启动,首先执行dockerinit;而后经过dockerinit执行entrypoint.sh,因为entrypoint.sh执行过程当中须要执行mysql_install_db等操做,会占据较多时间;最后由entrypoint.sh来执行cmd,运行真正的应用程序mysqld。综上所述,从启动容器到mysqld的运行,战线拉得较长,整个过程docker daemon都认为mysql容器存活,而mysqld正常运行以前,mysql容器并未提供mysql服务。若是fig中的容器A要访问mysql容器B时,虽然fig会简单辨别依赖关系,让B先启动,再启动A,当fig没法辨别容器应用的状态,致使A去链接B时,B中应用仍然未启动完毕,最终A一场退出。blog
对自身环境有起码的预估,如从容器B的启动到容器B内应用的启动完毕,所需多少时间,从而在容器A内的应用程序逻辑中添加延时机制;或者使得A内应用程序逻辑中添加尝试链接的机制,等待容器B内应用程序的启动完毕。 笔者认为,以上解决方案只是缓解了出错的可能性,并未根除。
笔者的Docker部署方式以下:在vSphere中安装一台ubuntu 14.04的虚拟机,在该虚拟机上安装docker 1.4.1;将该虚拟机制做vm使用的镜像;建立虚拟机节点时经过该镜像建立,从而虚拟机中都含有已经安装好的docker。若是使用Swarm管理这些虚拟机上的docker daemon时,仅一个Docker Node注册成功,其余Docker Node注册失败,错误信息为:docker daemon id已经被占用。
若是多个Docker Host上的Docker Daemon ID同样的话,Swarm会出现Docker Node注册失败的状况。原理以下: (1).Docker Daemon在启动的时候,会为自身赋一个ID值,这个ID值经过trustKey来建立,trustkey存放的位置为~/.docker/key.json。 (2).若是在IaaS平台,安装了一台已经装有docker的虚拟机vm1,而后经过制做vm1的镜像,再经过该镜像在IaaS平台上建立虚拟机vm2,那么vm1与vm2的key.json文件将彻底一致,致使Docker Daemon的ID值也彻底一致。
(1).建立虚拟机以后,删除文件~/.docker/key.json ,随后重启Docker Daemon。Docker Daemon将会自动生成该文件,且内容不一致,实现多Docker Host上Docker Daemon ID不冲突。 (2).建立虚拟机镜像时,删除key.json文件。 建议使用方案二,一劳永逸。
Dockerfile在build的过程当中只要涉及访问外网,所有失效。
用户在建立docker容器的时候,不指定dns的话,Docker Daemon默认给Docker Container的DNS设置为8.8.8.8和8.8.4.4。而在国内这个特殊的环境下,这两个DNS地址并不提供稳定的服务。如此一来,只要Docker Container内部涉及到域名解析,则当即受到影响。
(1)使用docker run命令启动容器的时候,设定–dns参数,参数值为受信的DNS地址,必须保证该DNS地址Docker Container可访问。 (2)若是按以上作修改,适用于docker run命令。而使用docker build的时候实际上是多个docker run的叠加,因为docker build没有dns参数的传入,所以docker container不能保证域名的成功解析。
启动Docker Daemon的时候设定DOCKER_OPTS,添加–dns参数,这样能够保证全部的docker run默认使用这个DNS地址。 以上这些坑深浅不一,但基本上还都集中在Docker外围的配置,行为模式等方面。
最近虽然在Docker的坑里摔得鼻青脸肿,可是“Docker虐我千百遍,我待Docker如初恋”的情怀始终不变,这货必定是云计算的将来,我坚信。前方的大坑,我来了,duang。。。 。。。