下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

教大家怎样用Dokcer创建开发环境

作者:课课家教育     来源: http://www.kokojia.com点击数:854发布时间: 2017-04-30 16:00:23

标签: Dokcer技术环境搭建Dokcer

  欢迎大家阅读本篇文章,Docker是PaaS提供商dotCloud开源的一个基于LXC的高级容器引擎,源代码托管在Github上,基于go语言并遵从Apache2.0协议开源。Docker让开发者可以打包应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,可以实现虚拟化。2015年9月,此前担任Twitter CFO、风投机构负责人的麦克·古普塔出任Docker的CFO。

     作者在此处使用了Frankenstein一词。Frankenstein,《弗兰肯斯坦》原是英国诗人雪莱的妻子玛丽·雪莱在1818年创作的小说,被认为是世界第一部真正意义上的科幻小说。弗兰肯斯坦来自于此小说,可以理解为怪人;毁灭创造者自己之物。

教大家怎样用Dokcer创建开发环境_Dokcer技术_环境搭建_Dokcer_课课家教育

  知道一个事物和实现这个事物是完全不同的事情。从Docker诞生那天开始,我们就梦想着诸如“15秒部署一个项目”,“版本可控开发环境”,以及时髦的运维用语,如“滚动开发”,“软件定义架构”。处于浪尖的行业人士都在以前所未有的热情参与到将很多名词和工具,例如“编排”,“服务发现”等,定义,重新定义以及商品化大潮中。

  我认为这股大潮的催化剂来自于Docker在应用和基础架构之间带来的美妙接口和抽象。开发者可以在不必知道底层架构情况下谈论基础架构,操作人员也不必花大量时间研究如何安装和管理软件。肯定有什么力量隐藏在看似简单的外表下使得大家生活简化,更加高效。

  现实世界时残酷的,不要想当然认为采用一项新技术只会带来享受。过去几年经过一些项目的磨练,经历过奇怪的环境,我认为Docker也不例外。但是某一个经验一般可以直接应用到项目的下一阶段。要想从Docker获得功力,必须浸淫到实际项目中去磨练。

  过去一年中,我全身心投入去教授我的关于Dokcer基础的书,Docker in Action。

  我注意到几乎所有人开始学习Docker技术时都会纠结于如何创建开发环境,然后才能了解生态系统之内大家的关系。每个人开始都会认为使用Docker会使环境搭建变的简单,也不是完全不对,有很多“容器化”教程都涵盖了创建一个image和如何将某个工具打包到容器(Container)内,但是如何将开发环境Docker化是一个完全不同的事情。

  作为一个踏坑先驱者,我可以分享一下我的经验。

  我曾经是一个资深java使用者,但这个分享的经验不是关于Java的,而是围绕着我使用Go和Node开发应用发生的。我有一定的Go开发经验,主动提高在这一领域的能力。进入一个不熟悉领域迅速上手碰到的主要问题就是如何获得正确的工作流,而且我还比较厌恶在笔记本上不断安装软件,这些都驱使我尝试用Docker做这些工作,或者有时候采用Vagrant。

我曾经是一个资深Java使用者,但这个分享的经验不是关于Java的,而是围绕着我使用Go和Node开发应用发生的。

  我所参与的项目是用Go写一个标准的REST服务,基于gin,依赖Redis和NSQ的某些库和服务。也就是说需要import一些本地运行着的Redis和NSQ实例的库,更有趣的是我还使用了一些服务于NGINX的静态资源。

  对门外汉来说,Go是一种编程语言,实际上还有一种命令行工具也叫“go”。从依赖型管理、编译、测试用例到其它各种任务都使用它。对Go项目来说,除了Git和一个好用的编辑器,剩下就是跟它打交道了。然而还是有一个问题,我不想在笔记本上安装Go,笔记本上我只想安装Git和Docker。这些问题限制了其他环境下的兼容性,并且对新手来说降低了门槛。

  这个项目有运行时依赖,意味着此工具集需要为简单环境定义和编排而包括Docker Compose。 很多人会为此感到不适应,那么我们怎么办?开始创建一个Dockerfile或者docker-compose.yml?好吧,先让我告诉大家我是怎么办的,然后解释为什么这么做。

此案中,我希望我的本地包是完全自动的。我不喜欢手动逐条执行步骤,而且我的vim配置文件也很简单。

  此案中,我希望我的本地包是完全自动的。我不喜欢手动逐条执行步骤,而且我的vim配置文件也很简单。我只想从“是否运行”层次控制运行环境。本地化开发环境目标被快速复制,不仅用于提高生产效率,而且用于共享Docker images。 我最终完成了Dockerfile,用来产生包含Go,Node,和我最经常使用的打包工具Gulp的images。 此Dockerfile没有嵌入代码,image也没有嵌入Gulpfile。相反的,在一个建立了的GOPATH(Go workspace的根路径)上定义了一个卷。

  最终,我为此images设置了给gulp提供服务的entrypoint,设置默认命令来监控。输出images肯定不是我称为build artifact的东西,从这个意义上来讲,此环境唯一做的就是提供了一个运行实例,帮助我们判断是否代码运行。对我的场景来说,运行的非常棒。而我将“artifacts”用于称呼另外一个build。

  下一步我用Compose定义本地开发环境。首先定义了在images中用到的所有Docker Hub 中定义的依赖服务,将他们连接到某一个“目标”服务。此服务引用了新Dockerfile从哪里生成,将本地源目录绑定到新image期望输出的挂载点,暴露一些可以测试的端口。然后,添加了一个服务,可以不断地向目标服务循环发起一系列集成测试。最终,我添加了NGINX服务,挂载了有很多配置文件和静态assets的卷。使用卷的好处在于重复使用配置文件和assets而不用重建image。

$ cat ./service/local.df 
 
FROM golang:alpine 
 
RUN apk --update add --no-cache git nodejs 
 
RUN npm install --global gulp 
 
ENV GOPATH=/go PATH=$PATH:/go/bin 
 
VOLUME ["/go/src/github.com/.../myproj", "/go/pkg","/go/bin"] 
 
WORKDIR /go/src/github.com/.../myproj 
 
Bring in dependencies in the imageRUN go get github.com/bitly/go-nsq && \\ 
 
go get github.com/codegangsta/cli && \\ 
 
go get github.com/gin-gonic/gin 
 
CMD ["gulp"] 
 
$ cat ./service/gulpfile.js 
 
var gulp = require('gulp'); 
 
var child = require('child_process'); 
 
var server = null; 
 
gulp.task('default', ['watch']); 
 
gulp.task('watch', function() { 
 
gulp.watch('./**/*.go', ['fmt','build','spawn']); 
 
}); 
 
gulp.task('fmt', function() { 
 
return child.spawnSync('go', ['fmt']); 
 
}); 
 
gulp.task('build', function() { 
 
return child.spawnSync('go', ['install']); 
 
}); 
 
gulp.task('spawn', function() { 
 
if (server) 
 
server.kill(); 
 
server = child.spawn('myproj'); 
 
server.stderr.on('data', function(data) { 
 
process.stdout.write(data.toString()); 
 
}); 
 
server.stdout.on('data', function(data) { 
 
process.stdout.write(data.toString()); 
 
}); 
 
}); 
 
$ cat docker-compose.yml 
 
web: 
 
image: nginx 
 
volumes: 
 
- ./web/assets:/var/www 
 
- ./web/config:/etc/nginx/conf.d 
 
integtest: 
 
build: ./integ 
 
links: 
 
- service 
 
service: 
 
build: ./service 
 
dockerfile: local.df 
 
volumes: 
 
- ./service/src/:/go/src/github.com/.../myproj 
 
links: 
 
- nsqd 
 
- redis 
 
nsqd: 
 
image: nsqio/nsq 
 
... 
 
redis: 
 
image: redis 
 
... 

  所有代码最终会在电脑上生成本地开发环境,当使用:

docker-compose up –d

  时,会启动git clone,然后循环运行;不需要重建image或者重启容器。每当.go文件发生变化,Gulp就会重建,并且在运行的容器中重启我的服务。就这么简单。

  创建此环境很简单吗?不尽然,但是确实实现了。难道不用容器,而在本地直接安装Go,Node,Gulp不是更简单吗?也许在这个场景是,但也只限于用Docker运行此依赖服务。我不喜欢这样。

  我曾经要管理这些工具的不同版本,而产生了复杂的环境变量,到处生成artifacts。我不得不提醒同事们注意这些容易发生冲突的环境变量,他们太缺乏集中版本控制了。

  也许你并不喜欢上面描述的环境,或者对项目有不同的需求。很好,确实是这样,本文并不是让所有工具都运行在Docker中,如果这样就说明并没考虑过要解决什么问题。

  当我设计这个环境时,考虑过下面几个问题,顾虑,以及某些潜在答案。当开始Docker工作环境时,就会发现实际情况可能比自己的回答更糟糕。

  当你考虑打包和环境时,最先考虑的因素是什么?

  这个确实是最重要的问题。在此场景中,有几个选项。我可以使用go直接在容器内编程,看起来如下:

get dependencies$ docker run --rm -v "$(pwd)"/go/src/app golang:1.5 go get -d -v 
 
start the other servicesbuild and link$ docker run --rm -v "$(pwd)":/go/src/app golang:1.5 go install \\ 
 
github.com/allingeek/myproj 
 
run the program stand alone$ docker run --rm -v "$(pwd)"/bin/myproj:/bin/myproj alpine myproj 
 
to iterate, make changes and repeat the last two steps 

  其实这个示例中大部分bolierplate可以通过shell别名或者函数隐藏,感觉Go是安装在自己的设备中似的,还可以跟Go工作流联系,创建artifacts。这些特性对非服务项目有益处,但是对库和软件项目就不一定了。

  假设你已经在使用Gulp,make,ant或者其他脚本,那么可以继续,并且使用Dokcer作为这些工具的目标。

  另外一种方法,我可以通过使用Dockerbuild来定义和控制我的build,获得更多面向Docker的经验。代码如下:

$ cat Dockerfile 
 
FROM golang:1.5-onbuild 
 
start the other servicesinstall dependencies, build, and link$ docker build -t local/myproj . 
 
run the program$ docker run --rm local/myprog 
 
to iterate, make changes and repeat the last two steps 

     使用Dokcer来控制build有若干好处。可以使用以前编译好的image,Dockerfilebuilds使用缓存方法,使得编译工作只重复最小的步骤(假设有一个很棒的Dockerfile)。最后,这些builds生成的images也可以跟其他开发者共享。

  这个案例中,我使用golang资源库中的onbuildimage作为基础。其中包括一些很棒的下载依赖包逻辑。这个方法会生成可以方便用于其他非生产环境的Dockerimage。这个方法对于生产级别的image的问题在于,必须有步骤避免大image并且包括某些初始化脚本,用于启动和监控服务前验证状态。

  有意思的是,Docker使用一系列脚本,Makefiles和Dockerfiles。build系统相对很健壮了,负责各种测试,linting等,以及各种操作系统和架构的artifacts。本场景中,容器是用来产生二进制的工具,然而是从一个本地build image中实现的。

  扩充Docker build的选项,可以使用Compose来定义一整套开发环境。

$ cat Dockerfile 
 
FROM golang:1.5-onbuild 
 
$ cat docker-compose.yml 
 
service: 
 
build: . 
 
links: 
 
- redis 
 
- nsq 
 
redis: 
 
image: redis 
 
nsq: 
 
image: nsqio/nsq 
 
install dependencies, build, link, launch dependency services, run$ docker-compose up -d 
 
to iterate, make changes and then$ docker-compose build && docker-compose up -d 

  Compose负责环境管理。如果觉得系统非常干净并不奇怪,Compose把所有事情都联系起来,优化卷管理,当images缺失时自动build,汇总日志输出。我之所以选这些开关是为了简化服务依赖,也因为它能生成我需要的artifacts。

  这个示例是一个运行时容器,Compose或者Docker都有合适的工具做到这点。此场景中,也可能更需要一个分布式image,或者可能希望build可以为本机产生一个二进制文件。

  如果期望获得想要的image,必须确保源码或者预编译库在build时候嵌入image中。build时候没有挂载卷,也即需要每次重复时都要重建image。

  如果希望在容器内部产生某些artifacts,则需要引入挂载卷。使用Docker命令行或者Compose环境可以很容易实现。但是要注意,除非容器在运行,否则build并不工作,也就意味着不能只用dockerbuild。

  知识分享:

  Docker 是 PaaS 提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github 上, 基于 go语言并遵从Apache2.0协议开源。

  Docker自2013年以来非常火热,无论是从 github 上的代码活跃度,还是 Redhat在RHEL6.5中集成对Docker的支持, 就连 Google 的 Compute Engine 也支持 docker 在其之上运行。

  一款开源软件能否在商业上成功,很大程度上依赖三件事 - 成功的 user case, 活跃的社区和一个好故事。 dotCloud 自家的 PaaS 产品建立在 docker之上,长期维护且有大量的用户,社区也十分活跃。

  面对上述几个问题,docker设想是交付运行环境如同海运,OS如同一个货轮,每一个在OS基础上的软件都如同一个集装箱,用户可以通过标准化手段自由组装运行环境,同时集装箱的内容可以由用户自定义,也可以由专业人员制造。这样,交付一个软件,就是一系列标准化组件的集合的交付,如同乐高积木,用户只需要选择合适的积木组合,并且在最顶端署上自己的名字(最后个标准化组件是用户的app)。这也就是基于docker的PaaS产品的原型。

  汇总:

  目前没有Docker方式创建开发环境。Docker是一个可编排工具,不只是圣书。与其使用别人已有的dockerbuild系统,不如花一定时间学习此工具,明确自己的需求,然后创建适合自己的Docker环境。

     小结:相信大家阅读完毕本篇文章后收获不小吧?其实学习这方面的知识的话,还得自己多私下多自学才能了解到更多内容,当然如果大家想更深入的学习并了解这方面的知识的话,请登录课课家教育平台哟~

赞(28)
踩(0)
分享到:
华为认证网络工程师 HCIE直播课视频教程