Tag Archives: docker

去哪儿网基于Mesos和Docker构建私有云服务的实践

作者:徐磊

【导读】本文深入介绍了去哪儿网利用Mesos和Docker构建私有云服务的全过程,分享了从无状态应用向有状态应用逐步过度的经验与心得。

平台概览

2014年下半年左右,去哪儿完成了有关构建私有云服务的技术调研,并最终拍定了Docker/Mesos这一方案。下图1展示了去哪儿数据平台的整体架构:

大数据

图1:去哪儿数据平台的整体架构

该平台目前已实现了如下多项功能:

  • 每天处理约340亿/25TB的数据;
  • 90%的数据在100ms内完成处理;
  • 最长3h/24h的数据回放;
  • 私有的Elasticsearch Cloud;
  • 自动化监控与报警。

为什么选择Docker/Mesos

目前为止,这个数据平台可以说是公司整个流数据的主要出入口,包括私有的Elasticsearch Cloud和监控报警之类的数据。那么为什么选择Docker/Mesos?

选择Docker有两大原因。第一个是打包:对于运维来讲,业务打完包之后,每天面对的是用脚本分发到机器上时所出现的各种问题。业务包是一个比较上层的话题,这里不做深入的讨论,这里讲的“打包”指软件的Runtime层。如果用Docker的打包机制,把最容易出现问题的Runtime包装成镜像并放在registry里,需要的时候拿出来,那么整个平台最多只执行一个远程脚本就可以了,这是团队最看好的一个特性。第二个是运维:Docker取消了依赖限制,只要构建一个虚拟环境或一个Runtime的镜像,就可以直接拉取到服务器上并启动相应的程序。此外Docker在清理上也较为简单,不需要考虑环境卸载不干净等问题。

以常见的计算框架来说,它们本质上仍然属于运行在其上的Job的Runtime。综合上述情况,团队选择针对Runtime去打包。

选择Mesos是因为它足够简单和稳定,而且拥有较成熟的调度框架。Mesos的简单体现在,与Kubernetes相比其所有功能都处于劣势,甚至会发现它本身都是不支持服务的,用户需要进行二次开发来满足实际要求,包括网络层。不过,这也恰好是它的强项。Mesos本身提供了很多SDN接口,或者是有模块加载机制,可以做自定义修改,平台定制功能比较强。所以用Mesos的方案,需要考虑团队是否可以Hold住整个开发过程。

从框架层面来看,Marathon可以支撑一部分长期运行的服务,Chronos则侧重于定时任务/批处理。

以下图2是Mesos的一个简单结构图:

大数据

图2:Mesos结构

数据平台的最终目标架构如下图3所示:

大数据

图3:平台目标

组件容器化与部署

组件的容器化分为JVM容器化和Mesos容器化。JVM容器化需要注意以下几方面:

潜在创建文件的配置都要注意

  • java.io.tmpdir
  • -XX:HeapDumpPath
  • -Xloggc

-Xloggc会记录GC的信息到制定的文件中。现在很少有直接用XLoggc配置的了(已经用MXBean方式替代了)。如果有比较老的程序是通过-Xloggc打印GC日志的话,那么要额外挂载volume到容器内。

时区与编码

  • –env TZ=Asia/Shanghai
  • –volume /etc/localtime:/etc/localtime:ro
  • –env JAVA_TOOL_OPTIONS=”-Dfile.encoding=UTF-8 -Duser.timezone=PRC

时区是另一个注意点。上面所列的三种不同的方法都可以达到目的,其中第一/三个可以写在Dockerfile里,也可以在docker run时通过–env传入。第二种只在docker run时通过volume方式挂载。另外,第三种额外设置了字符集编码,推荐使用此方式。

主动设置heap

  • 防止ergonomics乱算内存

这是Docker内部实现的问题。即使给Docker设置内存,容器内通过free命令看到的内存和宿主机的内存是一样的。而JVM为了使用方便,会默认设置一个人机功能会根据当前机器的内存计算一个堆大小,如果我们不主动设置JVM堆内存的话,很有可能计算出一个超过 Memory Cgroup限制的内存,启动就宕掉,所以需要注意在启动时就把内存设置好。

CMS收集器要调整并行度

  • -XX:ParallelGCThreads=cpus
  • -XX:ConcGCThreads=cpus/2

CMS是常见的收集器,它设置并行度的时候是取机器的核数来计算的。如果给容器分配2个CPU,JVM仍然按照宿主机的核数初始化这些线程数量,GC的回收效率会降低。想规避这个问题有两点,第一点是挂载假的Proc文件系统,比如Lxcfs。第二种是使用类似Hyper的基于Hypervisor的容器。

Mesos容器化要求关注两类参数:配置参数和run参数。

  • 需要关注的配置参数
    • MESOS_systemd_enable_support
    • MESOS_docker_mesos_image
    • MESOS_docker_socket
    • GLOG_max_log_size
    • GLOG_stop_logging_if_full_disk

Mesos是配置参数最多的。在物理机上,Mesos默认使用系统的Systemd管理任务,如果把Mesos通过Docker run的方式启动起来,用户就要关systemd_Enable_support,防止Mesos Slave拉取容器运行时数据造成混乱。

第二个是Docker_Mesos_Image,这个配置告诉Mesos Slave,当前是运行在容器内的。在物理机环境下,Mesos Slave进程宕掉重启,、就会根据executor进程/容器的名字做recovery动作。但是在容器内,宕机后executor全部回收了,重启容器,Slave认为是一个新环境,跳过覆盖动作并自动下发任务,所以任务有可能会发重。

Docker_Socket会告诉Mesos,Docker指定的远端地址或本地文件,是默认挂到Mesos容器里的。用户如果直接执行文件,会导致文件错误,消息调取失败。这个时候推荐一个简单的办法:把当前物理机的目录挂到容器中并单独命名,相当于在容器内直接访问整个物理机的路径,再重新指定它的地址,这样每次一有变动Mesos就能够发现,做自己的指令。

后面两个是Mesos Logging配置,调整生成logging文件的一些行为。

  • 需要关注的run参数
    • –pid=host
    • –privileged
    • –net=host (optional)
    • root user

启动Slave容器的时候最好不加Pid Namespace,因为容器内Pid=1的进程一般都是你的应用程序,易导致子进程都无法回收,或者采用tini一类的进程启动应用达到相同的目的。–privileged和root user主要是针对Mesos的持久化卷功能,否则无法mount到容器内,–net=host是出于网络效率的考虑,毕竟源生的bridge模式效率比较低。

大数据

图4:去哪儿数据平台部署流程图

上图4就是去哪儿数据平台部署的流程图。

基于Marathon的Streaming调度

拿Spark on Mesos记录子,即使是基于Spark的Marathon调度,也需要用户开发一个Frameworks。上生产需要很多代码,团队之前代码加到将近一千,用来专门解决Spark运行在Master中的问题,但是其中一个软件经常跑到Master,对每一个框架写重复性代码,而且内部逻辑很难复用,所以团队考虑把上层的东西全都跑在一个统一框架里,例如后面的运维和扩容,都针对这一个框架做就可以了。团队最终选择了Marathon,把Spark作为Marathon的一个任务发下去,让Spark在Marathon里做分发。

除去提供维标准化和自动化外,基于Spark的Marathon还可以解决Mesos-Dispatcher的一些问题:

  • 配置不能正确同步;这一块更新频率特别慢,默认速度也很慢,所以需要自己来维护一个版本。第一个配置不能正确同步,需要设置一些参数信息、Spark内核核数及内损之类,这里它只会选择性地抽取部分配置发下去。
  • 基于attributes的过滤功能缺失;对于现在的环境,所设置的Attributes过滤功能明显缺失,不管机器是否专用或有没有特殊配置,上来就发,很容易占满ES的机器。
  • 按role/principal接入Mesos;针对不同的业务线做资源配比时,无法对应不同的角色去接入Mesos。
  • 不能re-registery;框架本身不能重注册,如果框架跑到一半挂掉了,重启之后之前的任务就直接忽略不管,需要手工Kill掉这个框架。
  • 不能动态扩容executor。最后是不能扩容、动态调整,临时改动的话只能重发任务。

整个过程比较简单,如下图5所示:

大数据

图5:替代Spark Mesos Dispatcher

不过还是有一些问题存在:

Checkpoint & Block

  • 动态预留 & 持久化卷
  • setJars
  • 清理无效的卷

关于Checkpoint&Block,通过动态预留的功能可以把这个任务直接“钉死”在这台机器上,如果它挂的话可以直接在原机器上重启,并挂载volume继续工作。如果不用它预留的话,可能调度到其他机器上,找不到数据Block,造成数据的丢失或者重复处理。

持久化卷是Mesos提供的功能,需要考虑它的数据永存,Mesos提供了一种方案:把本地磁盘升级成一个目录,把这个转移到Docker里。每次写数据到本地时,能直接通过持久化卷来维护,免去手工维护的成本。但它目前有一个问题,如果任务已被回收,它持久化卷的数据是不会自己删掉的,需要写一个脚本定时轮巡并对应删掉。

临时文件

  • java.io.tmpdir=/mnt/mesos/sandbox
  • spark.local.dir=/mnt/mesos/sandbox

如果使用持久化卷,需要修改这两个配置,把这一些临时文件写进去,比如shuffle文件等。如果配置持久化卷的话,用户也可以写持久化卷的路径。

Coarse-Grained

Spark有两种资源调度模式:细粒度和粗粒度。目前已经不太推荐细粒度了,考虑到细粒度会尽可能的把所有资源占满,容易导致Mesos资源被耗尽,所以这个时候更倾向选择粗粒度模式。

大数据

图6:Storm on Marathon

上图6展示了基于Storm的Marathon调度,Flink也是如此。结合线上的运维和debug,需要注意以下几方面:

源生Web Console

  • 随机端口
  • OpenResty配合泛域名
  • 默认源生Web Console,前端配置转发,直接访问固定域名。

Filebeat + Kafka + ELK

  • 多版本追溯
  • 日常排错
  • 异常监控

大部分WebUI上看到的都是目前内部的数据处理情况,可以通过ELK查询信息。如果任务曾经运行在不同版本的Spark上,可以把多版本的日志都追踪起来,包括日常、问题监控等,直接拿来使用。

Metrics

第三个需要注意的就是指标。比如Spark ,需要配合Metrics把数据源打出来就行。

ELK on Mesos

目前平台已有近50个集群,约100TB+业务数据量,高峰期1.2k QPS以及约110个节点,Elasticsearch需求逐步增多。

大数据

图7:ELK on Mesos

上图7是ELK on Mesos结构图,也是团队的无奈之选。因为Mesos还暂时不支持multi-role framework功能,所以选择了这种折中的方式来做。在一个Marathon里,根据业务线设置好Quota后,用业务线重新发一个新的Marathon接入进去。对于多租户来讲,可以利用Kubernetes做后续的资源管控和资源申请。

部署ES以后,有一个关于服务发现的问题,可以去注册一个callback,Marathon会返回信息,解析出master/slave进程所在的机器和端口,配合修改Haproxy做一层转发,相当于把后端整个TCP的连接都做一个通路。ES跟Spark不完全相同,Spark传输本身流量就比较大,而ES启动时需要主动联系Master地址,再通过Master获取相应集群,后面再做P2P,流量比较低,也不是一个长链接。

监控与运维

这部分包括了Streaming监控指标与报警、容器监控指标与报警两方面。

Streaming监控指标与报警

Streaming监控含拓扑监控和业务监控两部分。

  • Streaming拓扑监控
  • 业务监控
    • Kafka Topic Lag
    • 处理延迟mean90/upper90
    • Spark scheduler delay/process delay
    • Search Count/Message Count
    • Reject/Exception
    • JVM

拓扑监控包括数据源和整个拓扑流程,需要用户自己去整理和构建,更新的时候就能够知道这个东西依赖谁、是否依赖线上服务,如果中途停的话会造成机器故障。业务监控的话,第一个就是Topic Lag,Topic Lag每一个波动都是不一样的,用这种方式监控会频繁报警,90%的中位数都是落在80—100毫秒范围内,就可以监控到整个范围。

容器监控指标与报警

容器监控上关注以下三方面:

  • Google cAdvisor足够有效
    • mount rootfs可能导致容器删除失败 #771
    • –docker_only
    • –docker_env_metadata_whitelist
  • Statsd + Watcher
    • 基于Graphite的千万级指标监控平台
  • Nagios

容器这一块比较简单,利用Docker并配合Mesos,再把Marathon的ID抓取出来就可以了。我们这边在实践的过程发现一个问题,因为Statsd Watcher容易出现问题,你直接用Docker的时候它会报一些错误出来,这个问题就是Statsd Watcher把路径给挂了的原因。目前我们平台就曾遇到过一次,社区里面也有人曝,不过复现率比较低。用的时候如果发现这个问题把Statsd Watcher直接停掉就好。指标的话,每台机器上放一个statsd再发一个后台的Worker,报警平台也是这个。

其实针对Docker监控的话,还是存在着一些问题:

  • 基础监控压力
    • 数据膨胀
    • 垃圾指标增多
    • 大量的通配符导致数据库压力较高
  • 单个任务的容器生命周期
    • 发布
    • 扩容
    • 异常退出

首先主要是监控系统压力比较大。原来监控虚拟机时都是针对每一个虚拟机的,只要虚拟机不删的话是长期汇报,指标名固定,但在容器中这个东西一直在变,它在这套体系下用指标并在本地之外建一个目录存文件,所以在这种存储机制下去存容器的指标不合适。主要问题是数据膨胀比较厉害,可能一个容器会起名,起名多次之后,在Graphite那边对应了有十多个指标,像这种都是预生成的监控文件。比如说定义每一秒钟一个数据点,要保存一年,这个时候它就会根据每年有多少秒生成一个RRD文件放那儿。这部分指标如果按照现有标准的话,可能容器的生命周期仅有几天时间,不适用这种机制。测试相同的指标量,公司存储的方式相对来说比Graphite好一点。因为Graphite是基于文件系统来做的,第一个优化指标名,目录要转存到数据库里做一些索引加速和查询,但是因为容器这边相对通配符比较多,不能直接得知具体对应的ID,只能通配符查询做聚合。因为长期的通配符在字符串的索引上还是易于使用的,所以现在算是折中的做法,把一些常用的查询结果、目录放到里边。

另一个是容器的生命周期。可以做一些审计或者变更的版本,在Mesos层面基于Marathon去监控,发现这些状态后打上标记:当前是哪一个容器或者哪一个TASK出了问题,对应扩容和记录下来。还有Docker自己的问题,这样后面做整个记录时会有一份相对比较完整的TASK-ID。

End.

转载请注明来自36大数据(36dsj.com):36大数据 » 去哪儿网基于Mesos和Docker构建私有云服务的实践

Docker:带给现代开发人员的福利

Docker 就像是用于 DevOps 的一把瑞士军刀,这一点已得到充分证明。但 Docker 托管的应用程序容器的用途不仅是在云中部署服务器。Docker 容器还可以在许多常见的开发场景中帮助开发和显著提高生产力。本教程将重点介绍 Docker,了解从开发人员角度讲它有何用途。我将介绍 Docker,解释基本概念和术语,并提供一系列实际的开发示例。

您会看到:

  • Docker 可以可简化 Node.js Web 应用程序编码。
  • 您可以使用 Docker 在 Apache Tomcat 服务器上快速创建和测试 Java™ Enterprise Edition (Java EE) 应用程序。
  • Docker 可以通过 Bottle 框架加快 Python Web 应用程序的编码、测试和开发。
  • 您可以通过使用一个 Docker 容器,在几分钟内创建并测试一个具有 NoSQL 数据库后端的完整的三层 Node.js 应用程序。

Docker、golang 和 Bluemix

阅读配套教程 “使用 Docker 和 Bluemix 容器化 golang 应用程序”,将您的多语言探索扩展到 Go 编程语言。另外,了解通过 IBM Containers for Bluemix 将 Docker 化的三层应用程序部署到 Bluemix™ 有都没容易。

您可以在单个 Linux 系统上获得所有这些收益,而不会妨碍任何预设的配置。在了解一些示例后,您就能够轻松地运行各种 Docker 容器来提高日常开发工作流中的生产力。

Docker 基础

Docker 是一个容器管理器。容器将应用程序和它的依赖项捆绑在一起。您从一个存储在存储库中的镜像实例化每个容器,在主机操作系统内隔离的虚拟化环境中运行容器。因为虚拟化技术(通常)是轻量型的,所以您可以同时运行多个容器:

该图演示了 Docker 容器管理器

理解基本术语

了解镜像与容器之间的区别很重要。这两个概念紧密相关,但初学者常常难以了解它们之间的区别。

镜像 是一个静态的层集合。没有任何运行时行为与镜像关联。镜像存储在存储库中(例如 Docker Hub)。

容器 是一个从镜像启动的运行实例。尽管容器可以停止(并在此盘上临时冻结其状态),但它仍是一个容器。

潜在的混淆源于一个事实,那就是通过提交和保存容器,您可以将容器转换为镜像。在这种情况下,您可以将得到的镜像想作是运行的容器的 “冻干 (freeze-dried)” 版本。

您可以使用 Docker 容器管理器执行以下操作:

  • 从镜像运行容器
  • 检查和操作运行的容器的属性
  • 停止运行的容器
  • 在运行的容器内执行额外的任务
  • 启动或重新启动运行的容器
  • 执行其他许多管理任务

容器化的应用程序几乎可以在任何地方运行:桌面 PC 上、服务器上、公共云中,甚至是在一些移动电话上。

学习更多知识。开发更多项目。联系更多同行。

全新的 developerWorks Premium 会员计划提供了强大的开发工具和资源,包括 500 篇通过 Safari Books Online 提供的顶级技术文章(其中超过 100 篇文章是专门面向 Web 开发人员的)、最重要开发人员活动的大幅折扣、最新的 O’Reilly 大会的视频回放,等等。立即注册

Linux 目前是得到最广泛使用和支持的 Docker 平台。Docker 所管理的容器化(轻量型虚拟化)技术在 Linux 平台上最成熟,使用了最新的 Linux 特性,比如 控制组命名空间

如何运行 Docker

您可以通过 docker 命令行客户端来运行 Docker 容器管理器,该客户端有许多可用的开关和选项。这是运行容器化应用程序镜像(在这个例子中是 MySQL 数据库)的一个简化的命令:

docker run -d mysql:5.5

Docker 项目运行着可公开访问的 Docker Hub。用户可以注册并创建自己的容器化应用程序镜像存储库,然后推送镜像来供大家共同使用。例如,您可以找到 Tomcat 服务器、Node.js 和大多数流行的开源数据库的镜像。Docker Hub 的操作理念与 GitHub 相同,因为应用程序镜像是全球 DevOps 和开发人员社区共享和协同创建的。

举例而言,运行 docker run -d mysql:5.5 命令时,如果还没有将 mysql(5.5 版)容器化应用程序镜像存储在本地,就会自动从 Docker Hub 拉取(下载)它。

构建容器化应用程序镜像

还可以使用 docker 命令行客户端来构建容器化应用程序镜像。一种方式是从 Dockerfile 构建镜像 — 一个包含如何安装、设置和配置一个应用程序和它的依赖项的说明的文本文件。

使用 docker 命令行客户端构建容器化镜像的另一种方法是以交互方式设计它们。您在一个运行的容器内手动安装和配置一个应用程序和它的依赖项,然后提交容器并保存为镜像。

一个 Docker 镜像包含一些层,每层大体相当于在安装一组应用程序期间写入磁盘的更改。Docker 管理这些层,并帮助在添加或删除这些镜像时高效地存储和重用。举例而言,一个 mysql 镜像中的层可能包含 Linux 操作系统、Perl、共享库、MySQL 安装和一种基本的 MySQL 配置:

该图演示了一个容器化镜像中的层

Dockerfile 构建容器化镜像或设计自定义容器时,通常不会从头开始。相反,您的工作以现有的 Dockerfile 或一个来自 Docker Hub 的镜像为基础。这样,开发人员和操作人员就能够以彼此的工作为基础,协同创建和管理一组有用的镜像。

将镜像发送到镜像存储库(比如 Docker Hub)的命令是 docker push。下载镜像以供本地使用的命令是 docker pull


开始之前

即使使用 Java、Tomcat、Node.js、Python 和 CouchDB 进行开发,也不需要安装它们中的任何一个。这是在开发工作流中使用 Docker 的美妙之处。

在开始之前,需要一个安装并运行 Docker 的 Linux 系统。要安装 Docker,可以按照适合您的 Linux 发行版的 安装说明 进行操作。

如果无法直接访问 Linux 系统,可以依靠云。大多数云主机都提供了随时可运行的虚拟服务器或虚拟机,只需几分钟就可以为它们配备 Linux 并(通过 SSH 或基于 Web 的终端)连接到它们。这些主机通常与 Docker 兼容。

本教程中的示例假设您在 Linux 系统上运行 Docker。如果您已经在 Mac OS X 或另一个非 Linux 系统上运行 Docker,您的容器可能会在一个由虚拟机管理程序虚拟化的额外虚拟机(常常为 VirtualBox)内运行。在这种情况下,您需要相应地修改示例中的命令才能继续操作。

检查您的 Docker 版本

运行以下命令来检查您的 Docker 版本:

docker --version

高效的层管理

拉取镜像后,请注意指明已存在一个层的消息。Docker 通过层来管理在镜像创建期间写入磁盘的更改,这有助于高效地管理镜像更改集。例如,基础 Ubuntu 镜像或核心实用程序的安装可被多个镜像共享 — 节省了宝贵的磁盘空间和下载时间。

如果您运行 1.8.3 或更高版本,您的系统现在已经设置好。即使使用 Java、Tomcat、Node.js、Python 和 Apache CouchDB 进行开发,也不需要安装或卸载它们中的任何一个。这是在开发工作流中使用 Docker 的美妙之处。

拉取镜像

第一次从 Docker Hub pull(拉取)一个镜像时,必须将它下载到本地 PC 的存储库。根据您的网络访问速度,下载可能很耗时,但对镜像的后续使用将会很快。

运行以下命令来拉取您将在示例中使用的所有镜像:

docker pull node:0.10.40

docker pull java

docker pull tomcat:8

docker pull webratio/ant

docker pull python:3.5

docker pull frodenas/couchdb

有关每个镜像的更多信息,请访问 Docker Hub 的 nodejavatomcatwebratio/antpythonfrodenas/couchdb 页面。

现在,在设置完成后,就可以使用 Docker 处理一个 Node.js 应用程序来进行我们的探索了。


快速设置和开发服务器端 JavaScript 代码

代码发行版中的 javascript 目录(参见 下载)包含一个使用 Node.js 编写的网络商店示例应用程序的源代码。该应用程序(最初由 Lauren Schaefer 设计和编写)使用了 Express Web 框架和 Jade Node 模板引擎。(有关这个应用程序的更多信息,请参阅 “Bluemix 基础:将一个示例 Node.js 应用程序部署到云中。”)通过使用 Docker,您可以在您的计算机上使用这个应用程序,无需安装 Node.js 或它的任何依赖项— 或者排除包安装冲突。

主要程序在 app.js 中。CSS 和关联的 JavaScript 文件在 javascript/public/static 中。Jade 模板在 javascript/view 中。

运行以下命令来安装此应用程序的 Node.js 依赖项:

docker run -it --rm --name lllnode -v "$PWD":/usr/src/myapp -w /usr/src/myapp node:0.10.40 npm install

此命令将会启动 Node 容器,将当前应用程序目录挂载到容器中,然后在应用程序上运行 npm install

  • 基础命令是 docker run � node:0.10.40,它创建一个容器实例并运行您之前拉取的 node:0.10.40 镜像。
  • -it 开关指定您想要一个前台交互式终端。(备用模式是分离的后台进程,可以使用 -d 指定它。)
  • --rm 开关指定执行清理,表示在您退出容器后,Docker 会立即删除它。如果没有指定此开关,该容器会以停止状态持久保存在磁盘上,而且您可以从中断点开始重新启动它。但是,对于忘记删除容器实例的用户而言,重新启动容器是磁盘耗尽的常见来源。如果不使用 --rm,那么任何时候都能运行以下命令来查看您遗留下了多少陈旧的停止容器(数量可能会让您吃惊):
    docker ps -a
  • --name lllnode 选项显式命名容器,这对在其他 Docker 命令中引用该容器很有用。如果没有显式命名容器,Docker 会为它分配一个生成的文本名称 — 这个名称通常没什么意义。您还可以通过内部 ID(一个很长、对人类不友好的十六进制字符串)来引用该容器。
  • -v "$PWD":/usr/src/myapp 选项创建一个卷挂载点。将您当前的工作目录 ($PWD) 挂载为容器内的 /usr/src/myapp。然后可从该容器内访问应用程序的 Node.js 源代码(或您当前的工作目录中可能拥有的其他任何 Node.js 源代码)。
  • -w /usr/src/myapp 选项设置您运行的命令的工作目录。在这个示例中,工作目录更改为挂载的卷。
  • docker run 命令末尾的 npm install 命令在工作目录上的容器内运行。最终结果是您通过容器在当前目录上运行 npm install— 而不安装 Node.js 或它的任何前提软件。

在命令输出中,您可以看到 npm 正在运行的所有依赖项:

安装 Node.js 应用程序依赖项的屏幕截图

在安装依赖项后,可以通过容器运行该应用程序。使用此命令(将它键入为一行):

docker run -it --rm --name lllnode --env PORT=8011 --net="host" -v 
"$PWD":/usr/src/myapp -w /usr/src/myapp node:0.10.40 node app.js

这个命令类似于您之前运行的命令。但请注意,要在容器内运行的命令现在是 node app.js,它将启动应用程序。

查看 app.js 的内容。您会找到以下行:

var appEnv = cfenv.getAppEnv();
app.listen(appEnv.port, appEnv.bind, function() {
   console.log("server starting on " + appEnv.url);
});

这些行导致 Express Web 服务器在 PORT 环境变量指定的端口上监听。为了在容器中设置此环境变量,您刚运行的 docker 命令使用 --env PORT=8011 选项。

此外,该命令的 --net="host" 选项导致容器使用主机操作系统内部的网络堆栈(仅用于开发用途)。然后该应用程序在主机上的端口 8011 上进行监听。

在浏览器中访问 http://localhost:8011/,您可以在其中看到基于运行的容器的 Lauren’s Lovely Landscapes 印刷品商店:

Lauren's Lovely Landscapes 的 Node.js 的屏幕截图

您随时可以退出容器来修改代码或修复错误,然后再次运行容器— 所有操作在几秒内即可完成,不会让开发环境变得杂乱。


在几秒内从 Node.js 转换为 Java EE

现在您已确信 Docker 只需几秒即可启动并运行一个 Node.js 应用程序,您可能想知道它如何更轻量型地处理一些工作 — 比如 Java EE 开发。很高兴为您解答。

假设您刚刚阅读了我的 “使用 Vaadin 实现全堆栈 Java Web 开发” 教程,并渴望试用我的 Java EE Vaadin 示例。但您没有安装 JDK,而且不想因为花一下午时间笨拙地安装一个 JDK 而将系统弄得一团糟。Docker 可以拯救您!

代码下载 的 java 目录中的 ArticleViewer.war 文件是一个包含来自 Vaadin 教程的多个 Vaadin UI 组件的应用程序。您可以通过 Docker 在 Tomcat 8 服务器上运行 ArticleViewer.war。第一步是从您之前拉取的镜像启动一个 Tomcat 8 容器实例:

docker run -it --rm -p 8888:8080 --name=tomcat_server -v $PWD:/mnt tomcat:8

这个命令现在看起来可能很熟悉。为了更方便引用,容器名为 tomcat_server。您目前的工作目录在容器内挂载为 /mnt。

-p 8888:8080 选项告诉 Docker 将主机系统的端口 8888 映射到容器的(内部)端口 8080。在 tomcat 镜像的 Dockerfile 中,您可以看到 Tomcat 在容器内的端口 8080 上执行监听。

通过浏览器访问 http://localhost:8888/,您可以在其中看到熟悉的 Tomcat 8 服务器欢迎页面:

在 Docker 容器内运行的 Tomcat 的屏幕截图

请注意您保持容器在交互式模式下运行(通过 -it 开关)。在该模式下,会在标准输出中连续显示日志,以方便开发。

附加到一个运行的 Docker 容器

现在,容器内挂载的目录 /mnt 是您当前的工作目录,ActiveViewer.war 位于该目录中。

将 ActiveViewer.war 从 /mnt 复制到 Tomcat 8 的 webapps 目录,它会在这里自动部署:

docker exec tomcat_server cp /mnt/ArticleViewer.war /usr/local/tomcat/webapps

这一次不需要使用 docker run 命令,因为 tomcat_server 容器已在运行。相反,您连接到运行的容器并运行一个命令。所以您使用了 docker exec,提供 cp /mnt/ArticleViewer.war /usr/local/tomcat/webapps 命令作为整个命令的最后一部分。

观看 tomcat_server 窗口中的日志,查看来自 ArticleViewer 应用程序部署的日志轨迹。

现在,在浏览器中访问应用程序的 URL(http://localhost:8888/ArticleViewer/)来打开正在运行的应用程序。单击左侧列表中的一篇文章,在右侧查看文章内容:

在 Docker 所启用的 Tomcat 8 上运行的 Vaadin article-viewer 应用程序

在继续后面的操作之前,停下来思考片刻。您没有在系统上下载或安装 JDK 或 Tomcat 8。只需几秒即可在一个功能全面的 Tomcat 8 服务器上运行 Vaadin 应用程序的代码 — 这得益于 Docker。

为 Tomcat 8 开发和构建 Java Web 应用程序

您刚才已经看到,可以使用 Docker 轻松地部署用于测试的 Web 应用程序。也可以通过 Docker 同样轻松地从 Java 源代码编译和构建 Web 应用程序 — 同上面一样,无需让您的开发系统变得一团糟或花很长时间安装前提软件。

将目录更改为 代码发行版 中的 java/LaurenLandscapesJava。这个目录中包含您在 Node.js 示例中看到的 Lauren’s Lovely Landscapes 应用程序的一个 Java 版本。(如果想了解该代码的更详细描述,请阅读 “Bluemix 基础:将一个示例 Java 应用程序部署到云中”。)

build.xml 文件是一个标准的 Apache Ant 构建文件,它包含编译代码和构建 WAR 文件的指令。通过使用 webratio Apache Ant 镜像,可以在更改代码后(或其他任何时刻)快速编译和构建 WAR:

docker run -it --rm -v "$PWD":/mnt webratio/ant bash -c 'cd /mnt; ant'

您现在已经熟悉了这个 docker run 命令中的所有内容。该命令在作为 /mnt 挂载在容器内的当前工作目录内运行 Ant 构建工具。Ant 编译 src 子目录中的所有 Java 源代码,然后构建并绑定 WAR 文件,将它作为 lauren.war 放在 dist 子目录中。

将 lauren.war 从 java/LaurenLandscapesJava/dist 目录复制到 java 目录:

cp dist/lauren.war  ..

您可以使用此命令将 lauren.war 应用程序部署到 Tomcat 8:

docker exec tomcat_server cp /mnt/lauren.war /usr/local/tomcat/webapps

此命令附加到运行的 tomcat_server 容器,并将 lauren.war 文件复制到 Tomcat 8 的 webapps 子目录中用于自动部署。

现在,在浏览器中访问 http://localhost:8888/lauren/,您可以在其中看到在您的 Docker 化 Tomcat 8 上运行的 Lauren’s Lovely Landscape 的 Java 版本。


从 Java 切换到 Python

假设作为一位多语言开发人员的您希望暂时不执行 Java 编码,探索 Python Bottle Web Framework 提供的可能性。为了帮助您快速探索 Python Web 应用程序开发,避免麻烦的安装和依赖项带来的痛苦,Docker 再次挽救了您。

更改到代码发行版的 python/Laurens.Lovely.Landscapes 目录。该目录中包含 Lauren’s Lovely Landscape 应用程序的 Python 版本 — 为 Bottle Web 框架而编写。模板(.tpl 文件)位于 views 子目录中。(有关该代码的更多信息,请查阅 “Bluemix 和 DevOps Services 简介,第 1 部分:部署和更新一个简单应用程序。”)还可以在关联的 Bluemix DevOps Services 存储库 中找到此代码的一个版本。

运行这个 Python 应用程序 — 而不将 Python 安装在您的系统上— 通过以下 Docker 命令(将它们键入为一行):

docker run -it --rm --name lllpython -p 8000:8000 -v "$PWD":/usr/src/myapp -w 
/usr/src/myapp python:3.5 python wsgi.py

现在在浏览器中访问 http://localhost:8000/,您可以在其中看到正在运行的 Lauren’s Lovely Landscapes 应用程序的 Python 版本。

在 Python 中开发时,您可以更改代码并重新运行之前的命令来进行测试。运行 Docker 容器就像运行安装在本地的开发工具一样快。


添加和启动一个分离的数据库

大多数现代 Web 应用程序都涉及 3 层:浏览器作为客户端;一个中间层应用服务器,比如 Express、Tomcat 8 或 Bottle;以及一个后端数据库。通过使用 Docker,您可以快速添加一个数据库,无需将它安装在您的开发系统上。

在这个最后的示例中,您将一个 Apache CouchDB 数据库服务器添加到您的开发环境中。您可以使用 CouchDB API(它与 IBM Cloudant NoSQL 数据库完全兼容)在本地测试 CouchDB 或 Cloudant 代码。

更改到源代码发行版中的数据库目录。这个目录中包含 Lauren’s Lovely Landscapes 应用程序的高级 Node.js 版本。此版本从 CouchDB(或 Cloudant)抓取印刷品商店的库存信息。该网络商店依据可用印刷品的库存来动态更改外观。(您可以在 “Bluemix 基础:将 Cloudant NoSQL 数据库添加到您的 Node.js 应用程序中” 中找到该代码的更多信息。)

要启动 Apache CouchDB 的一个实例,可以使用这个 Docker 命令(将它键入为一行):

docker run -d --name couchdb -p 5984:5984 -e COUCHDB_USERNAME=user -e 
COUCHDB_PASSWORD=abc123 -e COUCHDB_DBNAME=prints -v $PWD/data:/data frodenas/couchdb

该命令使用 COUCHDB_USERNAMECOUCHDB_PASSWORDCOUCHDB_DBNAME 环境变量来配置实例,以便与代码中使用的值匹配。当前的工作目录在容器内挂载为 /data。CouchDB 将数据写入此目录中,使您可以重新启动容器而不丢失数据。

请注意,在这个示例中,您使用了 -d 选项运行该容器,而不是使用 -it --rm 选项。-d 选项启动分离的 CouchDB 实例。您可以使用 docker ps 命令查看所有正在运行的分离的 docket 容器。

接下来安装应用程序的 Node.js 依赖项:

docker run -it --rm --name llldepends -v "$PWD":/usr/src/myapp -w /usr/src/myapp node:0.10.40 npm install

Apache CouchDB 实例还没有任何数据。使用以下命令(将它键入为一行)来运行 dataseeder.js 代码,该代码在 Apache CouchDB 实例中创建一个文档,以便在商店中填充库存:

docker run -it --rm --name dataseeder --net="host" -v "$PWD":/usr/src/myapp -w 
/usr/src/myapp node:0.10.40 node dataseeder.js

在端口 8011 上运行 lllnode 应用程序:

docker run -it --rm --name lllnode --env PORT=8011 --net="host" -v "$PWD":/usr/src/myapp
-w /usr/src/myapp node:0.10.40 node app.js

在浏览器中访问 http://localhost:8011/ 来打开 Lauren’s Lovely Landscapes 商店:

该屏幕截图表明澳大利亚印刷品已脱销

您可以看到澳大利亚的印刷品已脱销。该产品类别突出显示为红色,无法选中。

为了模拟对澳大利亚印刷品补货的过程,您将访问 Apache CouchDB 文档并直接修改库存水平。

Apache CouchDB 提供了一个简单的 GUI(名为 Futon)来访问存储的文档。在浏览器中访问 http://127.0.0.1:5984/_utils/ 来打开 Futon GUI:

CouchDB Futon GUI 的屏幕截图

在 Futon 中,选择 prints。打开文档并展开编号为 3 的库存项。双击澳大利亚印刷品以打开文档进行编辑。将 quan 字段从 0 更改到 3。单击右侧的小型绿色勾号图标,然后单击左上角的 Save Document

使用 Futon 在 Apache CouchDB 中修改并保存一个 NoSQL 文档的屏幕截图

数据库中的数量更新后,在浏览器中重新加载页面 http://localhost:8011/。您可以看到商店现在已屯满货。澳大利亚印刷品不再标记为红色,而且可以选中。

使用 3 层 Web 应用程序时,Docker 简化了中间层应用程序编码的开发工作流,方便了即时本地部署后端数据库来实现测试。


结束语

在这个竞争激烈的时代,您承受不起没有将 Docker 整合进开发工作流中的生活。通过消除反复安装和卸载相互依赖的复杂开发人员包和工具的需求,Docker 可以缩短您的开发时间和探索时间。利用 Docker 来提高您的多语言开发智商,显著提高您的开发生产力。


下载

描述 名字 大小
代码示例 code_docker.zip 22MB

参考资料

from:http://www.ibm.com/developerworks/cn/web/wa-docker-polyglot-programmers/index.html?ca=drs-