一个更好的开发/测试体验:在AWS上运行Docker

  先来看一个经常会发生的例子:

  假如你被指派为一个用以监测运动健身的移动应用建立REST API,同时要求在笔记本上的开发环境完成第一个端点的编码。在运行了所有单元测试并成功通过后,你将代码放入Git,并且通知QA工程师程序已经等待检测,而且一切运行良好。然而,当QA工程师认真地将最新版本代码部署到测试环境后却发现,这个新开发的REST端点往往连前几分钟的测试都通不过。

  为什么会发生这样的情况?你明明已经完整的运行了单元测试,而代码传递给QA工程师之前又没发生任何问题。在与QA工程师一起奋斗数个小时后,你发现测试环境使用了一个过时版本的第三方库,而正是这个原因导致了你的REST端点崩溃。

  在软件开发过程中,这个问题并不稀奇,轻视开发、测试、演示、生产环境的区别很容易会造成应用程序崩溃,而传统的类似改变管理过程的处理方法已经适应不了当下应用程序快速的建立和部署周期。取而代之,我们需要的是将开发环境与测试环境无缝对接,消除人工干涉和容易出错的资源供应及配置。

  长期以来,AWS为开发者提供了自动化建立可靠及有效的开发环境。类似Amazon EC2和AWS CloudFormation等服务都允许开发者们像代码一样的管理基础设施。通过CloudFormation服务,AWS资源可以使用JSON做预分配。CloudFormation模板可以在应用程序代码中正确的进行描述,通过EC2的自动化能力,用户可以快速和可靠地建立及结束某个环境。正是基于这个原因,AWS非常适合开发和测试工作。

  类似Docker等容器技术,将资源配置声明理念进行的更深一步。类似CloudFormation提供给EC2实例的功能,Docker为容器建立提供了一个非常实用的声明语法。同时,Docker容器并不依赖任何虚拟化平台,或者一个专用的操作系统。容器的运行仅仅需要一个Linux内核,这就意味着它几乎可以运行在任何环境之下——不管是笔记本或者是EC2实例。

  Docker容器的架构如下图所示:

  

  图1

  Docker容器使用了一个被称为libcontainer的执行环境,它为不同的Linux内核隔离特性提供了一个接口,类似命名空间及控制组。这种架构允许多个容器在共享同一个Linux内核的情况下完全隔离地运行。鉴于Docker容器并不需要一个专用的操作系统,因此它比虚拟机更加的便捷和轻量。

  Docker平台架构由下图一系列组件组成:

  

  图2

  Docker客户端并不与运行的容器直接通信,取而代之,它通过TCP sockets或者REST与Docker守护进程通信,而守护进程将与主机上的容器直接通信。同时,Docker客户端并不需要与守护进程安装在同一台主机上。

  在使用Docker时有3个理念必须理解:镜像(image)、注册表(registry)和容器(container)。

  镜像,用于建立容器组件,它是个只读模板,使用它可以发布一个以上的容器实例。理论上说,它非常类似于AMI。

  注册表用于储存镜像,既可以在本地,也可以在远程。当我们发布一个容器时,Docker首先会在本地注册表上搜索镜像。如果在本地注册表上没有发现,它随后会搜索远程公用的注册表,也就是DockerHub。如果在DockerHub发现所需镜像,Docker会将它下载到本地注册表,并使用它来发布所需容器。DockerHub非常类似于GitHub,我们可以使用它来建立公用或私有镜像资源。鉴于这个属性,有效及安全的镜像发布将非常便捷。

  可以这么说,容器运行在一个镜像的实例上,Docker使用容器来执行和运行被打包在镜像中的软件。

  你也可以为一个正在运行的容器建立一个Docker镜像,类似为一个EC2实例建立AMI。举个例子,用户可以发布一个容器,并使用类似APT或者YUM的包管理器安装大量的软件,然后将更新提交到一个新的Docker镜像。

  但是这里还存在更有效和灵活的途径来建立镜像,那就是使用DockerFile,它允许声明式的镜像定义。DockerFile语法由一系列的命令组成,我们可以用之安装和配置镜像中包括的各种组件。写一个DockerFile就像茶余饭后使用UserData配置一个EC2实例那么简单。类似一个CloudFormation模板,DockerFile可以使用一个版系统进行跟踪和发布,你可以将DockerFile比作一个镜像的建立文件。

  那么在运动健身移动应用的打造中,Docker又会起到什么样的作用?应用程序架构由下图中的组件构成:

  

  图3

  首先,我们需要建立一个Docker镜像用于发布运行中REST端点的容器。我们可以使用它在笔记本上测试我们的代码,而QA工程师则可以使用它在EC2实例上对应用程序进行测试。REST端点使用Ruby和Sinatra框架建立,因此它们需要被封装到容器中。我们将使用Amazon DynamoDB作为后端,因此,为了保证应用程序在AWS内外都可以使用,Docker镜像同样需要封装DynamoDB数据库。这样一来,DockerFile的代码可能如下所示:

  FROM ubuntu:14.04

  MAINTAINER Nate Slater <slatern@amazon.com>

  RUN apt-get update && apt-get install -y curl wget default-jre git

  RUN adduser --home /home/sinatra --disabled-password --gecos '' sinatra

  RUN adduser sinatra sudo

  RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

  USER sinatra

  RUN curl -sSL https://get.rvm.io | bash-s stable

  RUN /bin/bash -l -c "source /home/sinatra/.rvm/scripts/rvm"

  RUN /bin/bash -l -c "rvm install 2.1.2"

  RUN /bin/bash -l -c "gem install sinatra"

  RUN /bin/bash -l -c "gem install thin"

  RUN /bin/bash -l -c "gem install aws-sdk"

  RUN wget -O /home/sinatra/dynamodb_local.tar.gz https://s3-us-west

  -2.amazonaws.com/dynamodb-local/dynamodb_local_2013-12-12.tar.gz

  RUN tar -C /home/sinatra -xvzf /home/sinatra/dynamodb_local.tar.gz

  DockerFile的内容必须要是自声明的,RUN关键字用以执行命令。默认情况下,命令执行在超级用户权限下。鉴于需要使用RVM来安装Ruby,我们需要使用USER关键字来转换到Sinatra用户权限,因此Ruby相关文件会安装到用户目录下。从USER命令生效起,随后的RUN命令都是使用Sinatra用户权限来执行。这同样意味着,当容器发布后,它也是以Sinatra用户权限来执行命令的。

  Docker守护进程负责管理镜像与运行容器,而Docker客户端通常被用以将命令发送到守护进程。因此在使用上文DockerFile建立镜像时,我们需要执行这个客户端命令:

  $ docker build --tag=”aws_activate/sinatra:v1" .

  在docker.io网站上,我们可以发现完整的Docker客户端命令说明文档。下面,我们着重看一下我们建立镜像所使用的命令。Tag选项用于在镜像上建立识别符,其典型值是owner/repository:version。这样一来,我们可以轻易的识别镜像中所包含的内容,并且可以从注册表中轻易的发现这个镜像的所有权。

  在执行build命令后,我们可以在DockerFile中使用声明来拥有一个配置好的镜像。DockerFile如下:

  $ docker imagesREPOSITORY TAG IMAGE ID CREATED

  VIRTUAL SIZE

  aws_activate/sinatra v1 84b6d4a5a22b

  36 hours ago 942.2 MB

  ubuntu 14.04 96864a7d2df3

  6 days ago 205.1 MB

  毫无疑问,我们可以看到Docker建立好了我们所需的镜像,并给它分配tag中指定的所有权,同时还会拥有一个唯一的镜像ID。现在,我们就可以通过新建立好的镜像来发布容器:

  $ docker run -it aws_activate/sinatra:v1 /bin/bash

  运行这个命令后,容器将成功发布,同时我们将进入Bash shell。在Bash shell中,我们可以像与Linux服务器一样与容器交互。鉴于我们建立的是一个Web应用程序,我们会从Git repository中克隆最新版本到容器,用以运行我们的单元测试,并做好给QA传送的准备。当代码被克隆到容器之后,并且做好了被测试的准备,我们会将运行容器中所做的更新克隆到一个新的镜像。为了完成这个步骤,我们需要确定容器的ID:

  $ docker ps

  CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

  b9d03d60ba89 aws_activate/sinatra:v1 "/bin/bash" 11 minutes ago Up

  11 minutes nostalgic_davinci

  下一步,我们运行提交命令:

  $ docker commit -m “ready for testing” b9d03d60ba89

  aws_activate/sinatra:v1.1

  现在我们在本地注册表中会拥有一个新的容器:

  $ docker imagesREPOSITORY TAG IMAGE ID CREATED

  VIRTUAL SIZE

  aws_activate/sinatra v1.1 40355be9eb8f

  21 hours ago 947.5 MB

  aws_activate/sinatra v1 84b6d4a5a22b

  3 days ago 942.2 MB

  ubuntu 14.04 96864a7d2df3

  8 days ago 205.1 MB

  Version 1.1版本镜像拥有服务我们REST端点所需的Sinatra应用程序。我们可以使用以下命令来运行Web应用程序:

  $ docker run -d -w /home/sinatra -p 10001:4567

  aws_activate/sinatra:v1.1 ./run_app.sh

  上面命令告诉Docker需要做以下的工作:

  1. 从镜像aws_activate/sinatra:v1.1建立一个容器

  2. (-d)表示以分离的形式运行容器

  3. 将工作路径设置为/home/sinatra (-w)

  4. 映射容器端口到主机端口4567——10001

  5. 在容器中执行一个叫做run_app.sh的shell script

  这个shell script会在容器中启动DynamoDB,并且在4567下使用Thin网络服务器的模式发布Sinatra应用程序。现在,如果我们在运行这个Docker容器的笔记本浏览器中指向http://localhost:10001/activity/1,我们将看到以下结果:

  {"activity_id":"1",

  "user_id":" db430d35-92a0-49d6-ba79-0f37ea1b35f7",

  "type":"meal",

  "calories":100,

  "date":"2014-09-26 15:33:58 +0000"}

  我们的端点看起来运行良好——活动记录从本地DynamoDB中取出,并从Sinatra应用程序代码中以JSON的格式返回。

  如果想让这个容器可以给QA工程师做进一步测试,我们可以将之推送给DockerHub这个公用的注册表。类似GitHub,DockerHub提供了公用和私有两个选项,可以满足这个容器不面向所有人的需求。

  QA工程师将在EC2中运行这个实例,这就意味着我们将需要一个配置了Docker守护进程和客户端软件的EC2实例。假设需要使用CloudFormation启动一个EC2实例和CloudFormation表,我们可以借助CloudFormation AWS::EC2::Instance类型的UserData属性,使用Docker软件安装程序中的引导程序。CloudFormation中规定EC2实例的JSON文件可能拥有类似如下代码:

  "DockerInstance": {

  "Type": "AWS::EC2::Instance",

  "Properties": {

  "InstanceType": "t2.micro",

  "ImageId": {"Fn::FindInMap" : ["RegionMap",{"Ref" :

  "AWS::Region"}, "64"]},

  "KeyName": {"Ref": "KeyName"},

  "SubnetId": {"Ref": "SubnetId"},

  "SecurityGroupIds": [{"Ref": "SecurityGroupId"}],

  "Tags": [{"Key": "Name", "Value": "DockerHost"}],

  "UserData": {"Fn::Base64":

  "#include https://get.docker.io" }

  }}

  这样一来,如果QA工程师登入CloudFormation堆栈建立的EC2实例,镜像可以使用如下命令从远程的DockerHub注册表中取出:

  $ docker pull aws_activate/sinatra:v1.1

  这里从镜像中启动容器的命令和上文没太大的区别,有一个区别是环境变量会使用“-e”选项来设置,而Sinatra应用程序则会被配置为“test”环境。这个配置将使用区域端点(regional endpoint)来连接DynamoDB,而不是本地端点:

  $ docker run -d -w /home/sinatra –e “RACK_ENV=test” -p 10001:4567

  aws_activate/sinatra:v1.1 ./run_app.sh

  到这里,QA工程师就可以通过HTTP在公共DNS(名称是EC2实例,端口号是10001)下访问REST端点。当然,前提你还需要设置一个安全组规则,并允许10001端口访问。如果发现任何bug,运行的容器可以提交到一个新的镜像,指定一个合适的版本号,并将之提交到注册表。容器的状态会被完整的保存,因此软件工程师可以便捷的复制QA中发现的问题,检查日志文件并且做常规的排错。

  我们希望通过本文让用户对Docker有一个很好的认识,同时也认识到AWS和Docker的完美兼容。Docker的可移植性让它非常适合开发和测试,因为我们可以在多个团队中非常便捷的共享容器。EC2和CloudFormation完美的支撑了容器在AWS中的运行,但是AWS的便利绝不止于此。AWS ElasticBeanstalk,允许开发者将整个应用程序堆栈部署到Docker容器。经常关注本网站,你将看到更多关于AWS中运行Docker的博客。

时间: 2024-11-01 12:24:43

一个更好的开发/测试体验:在AWS上运行Docker的相关文章

腾讯QQ设计师谈如何构建一个更轻巧的开发流程

网页制作Webjx文章简介:腾讯设计师谈敏捷开发. 腾讯一直推广敏捷开发,也在强调敏捷开发,但你会发现,即便如此,还是会陷入以下情景 又丑又长的讨论会 好像人手永远不够 不切实际的想法 悬而不决的功能点 无穷尽的偏好设置 越来越多纠缠不清的细节 项目依然延期 我们如何构建一个更轻巧的开发流程,让我们更快更好的交付结果?作为一个设计师,如何成为敏捷的一分子?以下是一些心得方法,希望和大家分享 1 界面先行 作为设计师,最简单能让大家明白你的想法就是先把它画出来,不要用晦涩的语言和结构图,毕竟不是所

一个可以让.net程序在非WIN平台上运行的软件Mono_实用技巧

唉,最近只知道埋头写程序,消息实在是不灵通啊,今天偶然发一个开源项目,Mono,一个旨在让.net程序在linux,unix,mac os,solaris等平台的软件,爽啊,期待.... What is Mono?Mono provides the necessary software to develop and run .NET client and server applications on Linux, Solaris, Mac OS X, Windows, and Unix. Spo

android-如何做到在一个平台上运行,另一个平台上显示操作运行界面?

问题描述 如何做到在一个平台上运行,另一个平台上显示操作运行界面? 应用程序是mfc开发的,运行在一个没有显示器的windows系统中,称之为A 在另一个ipad(称之为B)上可以看到A上运行的程序的界面,并且界面的按钮等等都可以操作,就像是直接在A上操作一样 A和B之间通过wifi连接,在A上跑了一个什么server,在B上用html的方式来显示操作A上的程序. 这样的好处似乎是,可以跨平台显示操作他们的程序(mfc开发,只能在windows上运行),例如iOS,android? 具体这是如何

同时撑握几种WEB开发语言不失为一个更好的选择

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 大家一直都在争论学习或者是使用哪种WEB开发语言,于是关于asp/php/net/jsp哪个好的争论一直都不休.通常来说,做为一个项目的决策者,他更在意的是网站的定位,盈利模式以及客户的体验,根本就不会去研究用哪个开发语言,只求结果,不看过程是很多决策者的思维模式. 但是做为开发人员,我想说的是,同时撑握asp/php/.net/jsp不失为

RocketMQ:一个纯java的开源消息中间件--开发测试环境搭建

一.简介     RocketMQ的前身是Metaq,当Metaq3.0发布时,产品名称改为RocketMQ     MetaQ2.x版本由于依赖了alibaba公司内部其他系统,对于公司外部用户使用不够友好,推荐使用3.0版本.      项目地址:https://github.com/alibaba/RocketMQ 二.安装RocketMQ      安装RocketMQ需要jdk1.6, maven,git环境      如果本机没有安装git,请使用如下命令安装      yum in

【开源】用C# .net 在linux下开发了一个论坛,先公开测试一下前台

问题描述 [开源]用C#.net在linux下开发了一个论坛,先公开测试一下前台asp.net+mysql5.2+linux+apache公开测试地址:asp.net+mysql5.2+linux请多指教哦采用的是家用宽带,上行带宽只有512K速度稍微有些慢,请大家谅解!有需要代码的留下邮件地址,和建议本周内可发代码!后台功能请参考,力争下周公测后开源!开发部署:asp.net+mysql5.2+linux+apache请多指教哦 解决方案 解决方案二:挺好的,解决方案三:该回复于2011-11

[译]Angular vs React:谁更适合前端开发

本文讲的是[译]Angular vs React:谁更适合前端开发, 原文地址:Angular vs. React: Which Is Better for Web Development? 原文作者:Brandon Morelli 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m- 译者:龙骑将杨影枫 校对者:Larry.薛定谔的猫.逆寒 大家总在写文章争论,Angular 与 React 哪一个才是前端开发的更好选择(译者:在中国还要加上 vue :P).我

OpenStack开发测试云平台介绍

因此,我们邀请了来自五八同城公司的高级云计算工程师:赵龙,分享了他在企业内部设计.构建以及运维整个 OpenStack 系统的经验,让更多希望能够了解和使用这个优秀的云计算平台的技术人员可以更有效地获得最有实用价值的信息.随着互联网技术的飞速发展和广泛应用, 互联网公司对于产品迭代和技术升级的要求都更为迫切.相应地,研发测试人员对于机器的使用需求量也上了一个台 阶.传统的虚拟化解决方案存在 大量的问题和弊端,已经无法满足企业内部用户按需取用虚拟机资源的需求,运维人员和开发测试人员在虚拟机的使用管

Ajax铺设了更好的开发Web应用道路(图)

ajax|web 页面重载提出了一个在Web应用开发中最大的可用性障碍,对于Java开发来说也是一个重大的挑战.在本文中,作者Philip McCarthy介绍了通过后台通道的方法来创建动态Web应用的经验. Ajax(Asynchronous JavaScript and XML)是一个结合了Java技术.XML.以及JavaScript的编程技术,可以让你构建基于Java技术的Web应用,并打破了使用页面重载的惯例. Ajax,异步JavaScript与XML,是使用客户端脚本与Web服务器