Docker化运维方式

jugd8484 8年前
   <h2>应用迁移需求</h2>    <p>应用运维需要考虑的一个重要问题就是迁移, 在不同机器、机房、环境间迁移。迁移的原因有很多, 比如硬件过保(硬件故障), 机房迁移, 应用扩缩容等。</p>    <p>应用迁移的核心需求是:</p>    <p>简单。迁移操作必须足够简单, 没有学习成本, 点击一下即可。</p>    <p>快速。迁移过程能在极短的时间内完成。</p>    <p>无损。迁移之后应用与原应用一模一样, 不丢失任何配置和数据。迁移之后应用功能和业务逻辑与原部署应用一模一样,无任何业务风险。</p>    <p>许多公司还在使用古老的 rhel 5/6 和 linux 2.6.x 内核, 难以充分发挥现代操作系统和硬件的能力, 部分原因也是受制于应用迁移技术不成熟, 不能保证快速无损迁移应用, 不敢迁移。</p>    <p>具备快速迁移的能力, 同样可将应用快速切换到任意版本, 实现快速回滚。</p>    <h2>tomcat webapp 部署结构</h2>    <p>我们看一下一个基于 tomcat 部署的 java webapp 应用部署结构如下:</p>    <pre>  apache-tomcat-8.0.35/  ├── bin/  ├── conf/  ├── lib/  ├── logs/  ├── temp/  ├── webapps/  ├── work/  ├── LICENSE  ├── NOTICE  ├── RELEASE-NOTES  └── RUNNING.txt</pre>    <p>其主要分为两个部分:</p>    <ol>     <li>静态二进制文件。包含 bin/, lib/。这部分是三方软件包 tomcat 自带的内容。对应用而言, 这部分内容是只读访问的, 不会修改。</li>     <li>外部配置和数据。包含 conf/, logs/, temp/, webapps/, work/。这里的“外部”是指从 tomcat 软件包的角度来看, 对应用来说, 这部分才是真正的应用软件包。</li>    </ol>    <p>注意: tomcat 软件包也包含 conf/。但应用可能会对 conf/ 进行修改, 所以应用使用了一个独立维护的 conf/ 副本, 而不是 tomcat 软件包自带的 conf/ 内容。</p>    <p>很显然, 要迁移这个应用, 只需要迁移第 2 部分, 即外部配置和数据即可。为了简化迁移, 许多应用被设计为无状态的, 即 logs/, temp/, work/ 等外部数据目录不包含任何影响应用功能的配置或数据, 这部分内容不需要迁移。只需要迁移 conf/, webapps/ 目录, 这部分内容可打包为应用软件包。</p>    <p>这样, 在新环境部署应用, 只需要安装 tomcat 软件包和应用软件包即可。</p>    <h2>新环境部署</h2>    <p>在新环境上完成应用部署, 有两种玩法:</p>    <ol>     <li>列一个软件包清单 (如上例中的 tomcat 和应用), 在新环境上按照清单完成软件包安装, 这是 juju 的玩法。</li>     <li>将所有软件包安装好并打包成一个二进制镜像, 拷贝到新环境上部署运行, 这是 docker 的玩法。Dockerfile 描述如何创建镜像, 类似于软件包清单。</li>    </ol>    <p>docker 镜像不止是预安装软件包, 还包含基础操作系统环境, 统一的日志、数据路径, 环境变量等标准化应用运行环境。这可难不倒 juju, juju 同样基于一个标准镜像创建 vm 或 lxc 容器, 再安装软件包, 同样提供标准化的运行环境。这两种方式各有优缺点, 在此不作深究。但就使用成本来说, docker 目前在国内外发展火热, 技术和实践经验相对成熟, 更容易使用。</p>    <h2>单机多实例隔离部署</h2>    <p>使用 docker 应用容器部署应用, docker 容器为应用提供了标准一致且相互独立的运行环境, 这样应用使用相同的配置和路径, 也可以在单个宿主机上实现多实例部署。与 vm 的单机单部署模式相比, 应用容器要做的足够轻, 消除 vm 的额外开销, 并且完美支持微服务编排。</p>    <h2>软件包与配置分层</h2>    <p>有些软件包很好的实现了软件包默认配置与应用自定义配置的分离, 如 tomcat, 只需指定 CATALINA_BASE 目录与 CATALINA_HOME 目录分开, 将应用部署到 CATALINA_BASE 下, 即可实现应用自定义配置和 tomcat 软件包默认配置分离, 两者独立维护, 互不影响。</p>    <p>许多软件包没有实现这样的能力, docker 通过分层文件系统解决这个问题, 同时可以避免每个软件包都去考虑设计配置分离功能。</p>    <p><img src="https://simg.open-open.com/show/ab03429af10dbea851b8ff7ccc9c3116.png"></p>    <p>应用自定义配置在软件包安装层的上层, 运行容器时覆盖默认配置, 但在软件包安装层升级软件包时看不到应用自定义配置, 不会受应用自定义配置影响。需要注意的是, 软件包升级后是否兼容旧的应用自定义配置, 是否需要更新自定义配置, 需要应用负责人关注和测试。</p>    <p>按照 docker 的分层设计思想, 越基础越固定不变的东西越要放到底层, 越容易变化的东西越要放到上层, 因此应用依赖的软件包和基础配置要放到底层, 可以独立为一个 base 镜像, 应用本身和自定义配置放在上层。如果应用本身或配置更新更频繁, 可将这两者再分成两层。</p>    <h2>配置管理</h2>    <p>假设我们要修改一个应用配置, 一种方式是登陆一台机器修改, 测试 ok 后将修改同步到所有其他机器。这种方式很原始并且缺乏监管, 容易出错。比如新扩容了 100 台机器每台都要更新一遍, 如果操作有遗漏, 哪些机器配置已经更新, 哪些机器还是旧的配置也缺乏监管。</p>    <p>按 docker 的玩法, 应该是先更新镜像, 测试 ok 后分发镜像到所有机器更新容器。docker 监管了所有容器部署的镜像版本和容器状态, 从而可以很方便的检查哪些容器更新了, 哪些没有更新。对于很少变化的静态配置, 应该固化到镜像中。</p>    <p>对于一些经常变化的配置, 重新打镜像和更新容器成本太高, 应该设计成预定义的开关, 使用开关平台进行监控和管理, 或者使用 diamond 等配置管理平台管理。</p>    <h2>docker 容器数据卷</h2>    <p>docker 容器内的文件系统伴随容器而生, 销毁或更新容器时 (如升级镜像或修改容器配置), 原有数据将会丢失。并且受分层文件系统设计影响, 其性能可能更差(与存储引擎实现有关)。</p>    <p>因此, 需要持久化保存的配置和数据, 或有高写性能要求的, 如 logs/, data/ 等外部数据目录, 应使用 docker 数据卷 挂载到宿主机上。</p>    <p>Dockerfile 中使用 VOLUME 指定容器中需要挂载为数据卷的目录列表。</p>    <h2>docker 化运维方案</h2>    <p>综上所述, docker 化运维需要将应用拆分为 3 部分:</p>    <ol>     <li>基础环境, 应用所有依赖, 应用软件包和静态配置, 固化到镜像。</li>     <li>需要动态修改的配置, 通过开关平台或 diamond 等配置平台进行管理。</li>     <li>需要持久化保存或频繁写需求的配置或数据目录, 挂载为数据卷。</li>    </ol>    <p>部署运维时, 使用 docker 分发镜像, 配置平台推送配置, 即可实现应用快速部署、迁移、更新、回滚、扩缩容等运维操作。</p>    <p> </p>    <p>来自: <a href="/misc/goto?guid=4959674944841908704" rel="nofollow">http://h2ex.com/1211</a></p>    <p> </p>