以 Docker 容器玩转 Mesos 和 Marathon

vn114226 7年前
   <h2>人生在于折腾</h2>    <p>身为技术人,折腾技术是人生的一种乐趣,也是一种挑战。上次看老肖为了能更便利的安装Mesos做了个开源项目 Crane 深有感触。不过这个方式是否还是太重了呢?既然技术上都是玩容器的,那么为什么不直接通过容器的方式来折腾Mesos集群呢?当然只是个人测试环境,不要考虑用到生产上啊。</p>    <p>我用的是Mac,所以就想用docker声称的”Native”的docker来快速安装一套Mesos集群。而不是使用虚拟机的方式来做,因为哪样和Linux搭建没啥区别了。谁知道,还是真的不少坑,弄了两天才搞定。自己都觉得有点丢人了。</p>    <p>下面总结一下是如何做的,希望你不用这么折腾就能在Mac上玩转Mesos,同时也不用安装一堆的应用工具如VirtualBox等。我已经将我自己机器的VirtualBox给删除了,因为没有磁盘空间了。</p>    <p>虽然是Mac下测试的,但是既然是以容器的方式启动,对于Linxu和Windows下原理是一样。</p>    <p>后面这些步骤,希望你能在电脑前一步一步参照去做,而不是只是读这个文章。现在太多文章是只能读读,这些没有太多作用。我还是希望技术类的文章真正能帮到大家去操作的。</p>    <h3><strong>折腾一:Mesosphere的基础镜像坑</strong></h3>    <p>折腾一个可以测试/试用的Mesos环境是为了测试一下Mesos新版本的unitified container的功能,但是在使用中就发现了,Mesosphere打Mesos Slave的Image中竟然没有 curl 命令,但是不知道为什么Mesos会直接使用curl的方式来拉取镜像Image。(据说会改掉,这个方式太low了)所以在开始搭建环境之前,想将mesosphere的Mesos Slave的Image补充curl命令</p>    <p>需要的镜像和版本</p>    <ul>     <li> <p>Zookeeper: latest版本就可</p> </li>     <li> <p>Mesos Master: 1.1.0-2.0.107.ubuntu1404</p> </li>     <li> <p>Mesos Slave: 1.1.0-2.0.107.ubuntu1404</p> </li>     <li> <p>Marathon: v1.3.6</p> </li>    </ul>    <p>如果需要拉这些Image,最好用国内的代理镜像仓库,如Daocloud,不过正是因为用了这个代理镜像库,给我造成了另外一个坑。后面讲</p>    <p>打包自己的Mesos Slave镜像</p>    <p>前面讲了,需要给Slave镜像补个 CURL 命令,对应的Dockerfile为:</p>    <p>FROM mesosphere/mesos-slave:1.1.0-2.0.107.ubuntu1404</p>    <p>MAINTAINER duffqiu@gmail.com</p>    <p>RUN apt-get update && apt-get install -y curl && apt-get clean</p>    <p>然后运行命令打包: docker build -t mesos-slave .</p>    <p>后面就使用这个包而不是mesosphere的官方包来运行。不过还是得吐槽下Mesosphere,做为容器生态体系的领军公司,这个容器image打的实在是不够水平。</p>    <h3>折腾二: Docker Registry的国内代理DaoCloud不用HTTPS</h3>    <p>搭建环境的目的是测试 Unitified Container ,它有个最大的优势是直接支持Docker Image,只需Slave启动的时候配置Registry的地址就可以使用镜像的国内代理地址(启动需要的参数: MESOS_DOCKER_REGISTRY ),原本挺好的设计,谁知道这里也有个坑,一点文档都没有。那就是它默认使用的是 HTTPS 传输,但是我一开始使用的是daocloud的代理库,它是http的最后造成拉包总是不成功。后来在Yu jie@Mesosphere的指导下,才知道,目前Mesos的实现是如果需要用http,则需要在配置url后面加上80端口。如果你用的私用仓库不是80端口,那么没有办法,因为Mesos还没支持类似Docker daemon那样的 insecure-registry 配置。所以最后在网上找了个阿里的registry地址来测试。估计这个地址的流量要猛涨了。-:)</p>    <p>另外需要提示一点,就是用容器启动Mesos,对应的官方文档对应的配置参数,都可以用环境变量的方式配置,对应环境变量名的规则是MESOS_ ,都要是全大写。如上面的registry的配置,启动参数是 --docker_registry ,而环境变量是 MESOS_DOCKER_REGISTRY</p>    <h3>折腾三: Mac下的’Native’ Docker不是’Native’</h3>    <p>一开始就被Docker的官方文档误导了,以为‘Native’就真的是类似Linux支持哪样,直接使用了Mac的能力来做Docker。好在jason@uber指导了一下,豁然开朗。其实Mac Native还是有VM的,只是从用户体验上让你感觉不到而已,对此相对于Mesos,还是要为Docker的用户体验点个赞。就像你在Mac下找不到docker daemon一样。其实docker daemon还是真实存在。但是这个docker daemon配置已经被hardcode了,你没法更改。同时有个问题,在Mac下这个VM占用的空间会一直增大,无论你是否删除了docker image。这个文件存放在 /Users/macbook/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/Docker.qcow2 。之前犯了个低级错误,将这个文件一下子扩大了10G,而我的Mac的硬盘又小,害我一直要删文件腾空间。</p>    <p>Docker Build占空间</p>    <p>Docker build会将Dockerfile所在的目录下的内容都装载进来后才开始打包。所以千万千万要给Dockerfile一个独立的目录。不然就会像我一样无端将Mac下虚拟机扩大了10G空间。</p>    <p>Hack Mac Docker’s VM</p>    <p>虽然Mac下的Docker还是用的虚拟机的方式,那么如何进入这个虚拟机呢?可以使用以下方式:</p>    <p>docker run -it --rm --privileged --pid=host --net=host -v /:/rootfs --entrypoint=/bin/sh alpine</p>    <p>cd /rootfs</p>    <p>chroot /rootfs</p>    <ul>     <li> <p>首先将虚拟机的根目录mount给一个容器。这里就是一个理解的坑,我一直以为Mac是native的,所以主机的目录就是Mac的目录,其实不是,而是说主机目录其实是虚拟机的目录</p> </li>     <li> <p>用chroot的方式,在虚拟机的根目录为根运行,这样就相当于在虚拟机中了(注意,不是完备的虚拟机能力,如网络等)</p> </li>    </ul>    <p>这个时候,你就可以查找出dockerd的进程了</p>    <p>ps -ef|grep dockerd</p>    <p>可以看到对应的dockerd的运行参数,这也就解释了为什么Mac下的docker不能配置tcp端口了,因为这个已经被这个VM的配置写死了,而且还改不了。(如何有任何方式可以改,请留言告诉我)以下是Mac的dockerd的启动命令</p>    <p>/usr/bin/dockerd --pidfile=/run/docker.pid -H unix:///var/run/docker.sock --swarm-default-advertise-addr=eth0 --debug --storage-driver aufs</p>    <p>同时可以查看这个虚拟机的磁盘情况,这里就比较清晰展示哪些是VM的磁盘,哪些是Mac的磁盘了。同时,也可以看见,docker用的VM是开了50几G的动态空间的,默认可以最大占用主机50几G的,这个大家一定要注意,不然哪天机器没有磁盘空间了都不知道用到那里去了。后续如果需要清理这些空间,只能卸载Docker再装一次。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/cd08778377ce7cff0520c79f3311a2b4.jpg"></p>    <p>docker vm disk</p>    <p>提供Mac Docker的TCP以及Portainer</p>    <p>最近通过阅读微信文章,找到一个本机管理Docker Daemon的一个好的带界面的Container: portainer/portainer ,可能需国内或许不能访问。但是这个需要通过tcp的方式链接docker dameon,所以需要想个办法将Mac下的unix socket转为TCP。这个可以使用socat工具。Mac下可以通过port工具安装,不过最好还是KX上网安装,不然又是一个折磨。</p>    <p>socat的用法:</p>    <p>socat TCP-LISTEN:2375,range=192.168.31.254/32,reuseaddr,fork UNIX-CLIENT:/var/run/docker.sock</p>    <p>然后启动portainer:</p>    <p>docker run -d  -p 9000:9000 --restart always portainer/portainer -H tcp://192.168.31.254:2375</p>    <p>192.168.31.254 是你的机器ip,需要根据你的实际情况替换</p>    <p>这里需要注意的是,不要使用127.0.0.1的方式链接docker,因为在portainer里的127.0.0.1不是主机的127.0.0.1</p>    <p>下面是portainer的一个界面预览,还是相当清爽的,值得使用</p>    <p><img src="https://simg.open-open.com/show/63614e81ac6d8b8543c2cc4c2992858f.jpg"></p>    <p>portainer</p>    <p>另外可以在Mesos的集群的每个Slave主机上装个这个容器,然后在集群的管理系统中嵌套改页面,这样就可以监控和管理主机的容器/Image等了。同时它还提供了WEB Terminal,可以直接进入容器,方便调试,非常好用。</p>    <p>到此,之前遇到的坑都列举出来了,我们正是开始进入正题,安装Mesos+Marathon集群</p>    <h3>Mesos+Marthon集群搭建</h3>    <p><em>Zookeeper容器化搭建</em></p>    <p>docker run --name zookeeper --restart always -d -p 2181:2181 -p 2888:2888 -p 3888:3888 zookeeper</p>    <p>启动单机版本的Zookeeper,如果需要保留Zookeeper的数据以备下次启动继续使用,则必须将zookeeper的data路径放到主机的目录下,这个具体就不详细描述了。</p>    <p>telnet 10.100.150.22 2181 连接到Zookeeper,并输入 stat 来验证是否安装正确。</p>    <p><em>Mesos Master容器化搭建</em></p>    <p>docker run -d -p 5050:5050 \</p>    <p>-e MESOS_PORT=5050 \</p>    <p>-e MESOS_ZK=zk://192.168.31.254:2181/mesos \</p>    <p>-e MESOS_QUORUM=1 \</p>    <p>-e MESOS_REGISTRY=in_memory \</p>    <p>-e MESOS_LOG_DIR=/var/log/mesos \</p>    <p>-e MESOS_WORK_DIR=/var/tmp/mesos \</p>    <p>-e MESOS_HOSTNAME=192.168.31.254 \</p>    <p>mesosphere/mesos-master:1.1.0-2.0.107.ubuntu1404</p>    <p>这里有一点需要注意:需要设置MESOS_HOSTNAME为你主机的ip地址(例子是我的机器ip,你需要根据实际情况替换),不然打开 Mesos Master 地址的时候总是不稳定。</p>    <p>只要能打开mesos的UI地址,并且能在界面打得开LOG则证明安装成功了。</p>    <p><em>Mesos Slave容器化搭建</em></p>    <p>启动第一台Slave</p>    <p>这里就需要用到我之前提的自己打包的Mesos Slave镜像了,因为需要用到CURL命令来启动Unified Container。同时我也希望Slave能够同时使用Docker Container或者Mesos Container。</p>    <p>docker run -d --privileged -p 5051:5051 \</p>    <p>-v /usr/bin/docker:/usr/bin/docker \</p>    <p>-v /var/run/docker.sock:/var/run/docker.sock \</p>    <p>-v /sys/fs/cgroup:/sys/fs/cgroup \</p>    <p>-e MESOS_PORT=5051 \</p>    <p>-e MESOS_MASTER=zk://172.17.0.3:2181/mesos \</p>    <p>-e MESOS_SWITCH_USER=0 \</p>    <p>-e MESOS_CONTAINERIZERS=mesos,docker \</p>    <p>-e MESOS_LOG_DIR=/var/log/mesos \</p>    <p>-e MESOS_WORK_DIR=/var/tmp/mesos \</p>    <p>-e MESOS_IMAGE_PROVIDERS=docker \</p>    <p>-e MESOS_ISOLATION=filesystem/linux,docker/runtime \</p>    <p>-e MESOS_DOCKER_REGISTRY=https://r6w9c7qa.mirror.aliyuncs.com \</p>    <p>-e MESOS_ADVERTISE_IP=192.168.31.254 \</p>    <p>-e MESOS_ADVERTISE_PORT=5051 \</p>    <p>-e GLOG_v=1 \</p>    <p>mesos-slave</p>    <p>这里有几点注意点:</p>    <ul>     <li> <p>如果需要用docker container,需要将-v的这几个盘挂载到容器中。注意,这里的主机盘地址是VM的地址,不是Mac主机的地址</p> </li>     <li> <p>MESOS_MASTER 配置可以直接写Mesos Master的http地址就可,不用连接Zookeeper了。或许这样可以减轻Zookeeper的压力。不过依然可以使用zookeeper的方式链接。这里的地址使用容器间的地址就可。不过文档没有说如果是配置Master的http地址的话,如何支持多台Mesos地址。(据说目前http方式只能用于测试,生产的话要用zk的链接,因为zk支持多个服务器配置)</p> </li>     <li> <p>MESOS_CONTAINERIZERS 需要指明mesos和docker,这样才可以运行docker container以及mesos container</p> </li>     <li> <p>IMAGE_PROVIDERS 指明都是用docker镜像,这个是给Mesos container用的</p> </li>     <li> <p>MESOS_ISOLATION 使用Mesos Container,则必须制定这两个隔离器</p> </li>     <li> <p>MESOS_DOCKER_REGISTRY 指明用Unified Container需要的docker image的拉取地址。注意我前面提到的坑。这个和docker container没有关系</p> </li>     <li> <p>MESOS_ADVERTISE_IP 和 MESOS_ADVERTISE_PORT 公开对外的ip和对外的port。如果不是用这个,在容器部署里,无法在Mesos master上获取到agent的log</p> </li>     <li> <p>这里不要设置 MESOS_HOSTNAME ,因为设置了就无法在界面看见agent的LOG了</p> </li>    </ul>    <p>启动第二台Slave</p>    <p>docker run -d --privileged -p 5052:5051 \</p>    <p>-v /usr/bin/docker:/usr/bin/docker \</p>    <p>-v /var/run/docker.sock:/var/run/docker.sock \</p>    <p>-v /sys/fs/cgroup:/sys/fs/cgroup \</p>    <p>-e MESOS_PORT=5051 \</p>    <p>-e MESOS_MASTER=zk://172.17.0.3:2181/mesos \</p>    <p>-e MESOS_SWITCH_USER=0 \</p>    <p>-e MESOS_CONTAINERIZERS=mesos,docker \</p>    <p>-e MESOS_LOG_DIR=/var/log/mesos \</p>    <p>-e MESOS_WORK_DIR=/var/tmp/mesos \</p>    <p>-e MESOS_IMAGE_PROVIDERS=docker \</p>    <p>-e MESOS_ISOLATION=filesystem/linux,docker/runtime \</p>    <p>-e MESOS_DOCKER_REGISTRY=https://r6w9c7qa.mirror.aliyuncs.com \</p>    <p>-e MESOS_ADVERTISE_IP=192.168.31.254 \</p>    <p>-e MESOS_ADVERTISE_PORT=5052 \</p>    <p>-e GLOG_v=1 \</p>    <p>mesos-slave</p>    <p>在同一台机器启动多个Slave,这里只需要更改暴露的端口就可以了</p>    <p>部署Marathon</p>    <p>docker run -d -p 8080:8080 mesosphere/marathon:v1.3.6 --master zk://172.17.0.3:2181/mesos --zk zk://172.17.0.3:2181/marathon</p>    <p>然后在Mac主机访问 Marathon UI 就可</p>    <p><em>Marathon启动容器</em></p>    <p>启动一个Docker的容器</p>    <p>通过界面配置的方式启动一个docker容器应用,对应的json为</p>    <p>{</p>    <p>"id": "testapp",</p>    <p>"cmd": " while true;do echo hello;sleep 1;done",</p>    <p>"cpus": 1,</p>    <p>"mem": 128,</p>    <p>"disk": 0,</p>    <p>"instances": 1,</p>    <p>"container": {</p>    <p>"docker": {</p>    <p>"image": "centos",</p>    <p>"network": "BRIDGE"</p>    <p>},</p>    <p>"type": "DOCKER"</p>    <p>}</p>    <p>}</p>    <p>默认Marathon启动的是docker容器。启动后,可以在Mac上 docker ps 看到这个运行的容器了。</p>    <p>启动一个Docker Image的Mesos的容器(Unified Container)</p>    <p>因为现在Marathon的界面还没有得选择Mesos容器类型,所以需要在JSON模式修改,将之前的JSON配置的type改为 MESOS 就可</p>    <p>{</p>    <p>"id": "mesostest",</p>    <p>"cmd": "while true;do echo hello docker >> txt.log ;sleep 1;done",</p>    <p>"cpus": 1,</p>    <p>"mem": 128,</p>    <p>"disk": 0,</p>    <p>"instances": 1,</p>    <p>"container": {</p>    <p>"docker": {</p>    <p>"image": "102010cncger/centos:v1",</p>    <p>"network": "BRIDGE"</p>    <p>},</p>    <p>"type": "MESOS"</p>    <p>}</p>    <p>}</p>    <p>上面的image名字是因为我随便搜索了个阿里的registry地址,所以要通过 curl https://r6w9c7qa.mirror.aliyuncs.com/v2/_catalog 获取它存在的镜像名字,然后再通过 curl https://r6w9c7qa.mirror.aliyuncs.com//v2/102010cncger/centos/tags/list 获取它的tag,从而指导它可用的镜像是 102010cncger/centos:v1</p>    <p>因为Slave用的是ubuntu,我又不太了解怎么装个nsenter,所以只能用一下方法进入到这个Mesos容器中</p>    <ul>     <li> <p>先用 docker exec -it <slave container id> /bin/bash 从Mac进入到Slave的容器中</p> </li>     <li> <p>用 ps -ef |grep mesos-executor 找到mesos executor的执行命令参数,获得容器的具体路径 --rootfs 那段,如我的例子 /var/tmp/mesos/provisioner/containers/dd2a4567-4ad5-4b50-bdee-2351d0b863e8/backends/copy/rootfses/a913d575-9e5f-4384-b4bd-4ed36618f157</p> </li>     <li> <p>用chroot的方式进入这个容器: chroot /var/tmp/mesos/provisioner/containers/dd2a4567-4ad5-4b50-bdee-2351d0b863e8/backends/copy/rootfses/a913d575-9e5f-4384-b4bd-4ed36618f157 /bin/bash ,这样你就进入mesos的这个容器了的shell,但是无法获取这个容器的其它能力如网络等.</p> </li>    </ul>    <p>使用nsenter</p>    <p>ubuntu14.04安装nsenter的方式,这里谢谢黄浩松@shopee.sg</p>    <p>用docker 容器的方式来安装nsenter,步骤是</p>    <ul>     <li> <p>首先进入到Slave的容器中 docker exec -it <slave container id> /bin/bash</p> </li>     <li> <p>使用 jpetazzo/nsenter 这个镜像,但是很奇怪不能用它推荐的 docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter ,而是要使用导出nsenter的方式 docker run --rm jpetazzo/nsenter cat /nsenter > /tmp/nsenter && chmod +x /tmp/nsenter</p> </li>     <li> <p>获得nsenter后,执行 nsenter --target $PID --mount --uts --ipc --net --pid /bin/bash 进入容器, $PID为容器对应的进程pid,通过 ps -ef 查看,完整的容器镜像的cmd那个进程id</p> </li>    </ul>    <p>到此Mesos container的安装部署测试完成了。不过这里还是需要吐槽一下Mesos Container,这样启动容器,就算你配置上是 "network": "BRIDGE" ,但是如果没有配置CNI,还是没有bridge的,只能是host模式。</p>    <p>至此,整个测试环境就搭建完成了。</p>    <p> </p>    <p>来自:http://mp.weixin.qq.com/s/gp2YBq-_rebkDptD2N9Rtw</p>    <p> </p>