[关闭]
@gzm1997 2018-11-05T12:59:21.000000Z 字数 3382 阅读 1026

基于容器的开发

docker


郭柱明


背景

虚拟化技术在服务端开发中越来越常用 docker就是常用的一种虚拟化技术 docker的虚拟化并不是系统级别的虚拟化 而是进程级别的虚拟化 他把一个进程相关的代码文件 环境变量 第三方包等等相关都打包进一个"容器"之中 可以


一种基于容器的开发模式

花了一个多星期时间 暂时是为了实现以下开发的一种设计模式
微信图片_20180910212550.png-55.1kB
在开发环境 我们只需要按照系统的功能将系统划分为多个模块 分别将这些模块打包为docker镜像 然后推送至远程仓库

在部署和测试环境 只需要安装了go语言 docker 以及封装了docker remote api的go第三方包go docker client 在这边只需要运行我们预先写好的启动文件(这个稍后会详细介绍) 从远程仓库中拉取我们需要的每个小模块的镜像 分别生成容器 运行各个容器 各个容器之间相互协同工作 我们在部署测试这边 我们不需要关注每个容器内部是如何工作的 我们只需要关注在顶层如何调度这些子模块进行协同工作


实现

我现在做的一个demo其实非常简单 就是以mongo为数据库 以beego为框架 写一个简单的用户注册登录页面 登陆之后才有权限浏览一个特殊的页面
gitlab地址

  1. 注册一个新的用户 将用户的名字 id 密码存进mongo的一个表
  2. 登录的时候使用名字和密码进行登录 使用session跟踪用户 session实现方式为借用cookie
  3. 如果登录成功自动跳转到一个display页面 如果没有登录那么提醒用户需要登录

基本逻辑功能实现非常简单了 所以不多说

然后是测试上 在

三个小模块上 都编写了单元测试
注册测试 登录测试 display页面测试(需要登录权限)
以及对上诉各个小模块串联起来测试的集成测试集成测试

煞费苦心写单元测试和集成测试的原因有 我们可以在容器运行的时候让容器自动运行所有的单元测试和集成测试 所有测试都是在容器中进行的 可以借机利用容器可以为我们的测试提供一次性环境的优点来运行测试 试想一下:我们每次在自动化部署项目到服务器之后 肯定是希望我们的单元测试和集成测试都可以自动跑一次 来来检验 这是很方便的 更何况如果是使用容器来运行这些测试 那么测试完成之后 容器被删除 测试过程在持久层产生的数据也会被删除干净 不对整个服务造成其他干扰


打包镜像

根据我们上面的设计 我们可以将整个demo划分为两个模块 一个mongo 一个写好的beego server

mongo已经有人将它打包为镜像 并且推送至远程仓库dockerhub上去了 所以我们可以直接使用 不需要自己打包 那么我们只需要打包上面写好的beego server

docker镜像的打包方式有三种

开发过程中打包镜像推荐使用第一种方式 不推荐使用第二第三种方式 第二第三中方式适合拉取已经构造好的远程镜像到本地生成容器来运行

我们来看一下我们的beego server的Dockerfile配置文件

  1. FROM golang:1.10.3
  2. COPY . /go/src/hello
  3. WORKDIR /go/src/hello
  4. RUN go get github.com/astaxie/beego
  5. RUN go get github.com/smartystreets/goconvey
  6. RUN go get gopkg.in/mgo.v2
  7. RUN go build
  8. RUN tr -d "\r" < run.sh > run.sh
  9. RUN chmod -R 777 run.sh
  10. EXPOSE 8080
  11. EXPOSE 27017
  12. CMD sh run.sh

Dockerfile一些详细的使用可以大家可以看一下旭升之前写的docker入门 这里我只简单说一下我这里的dockerfile的大概含义

FROM golang:1.10.3

基于golang作为基础镜像来构造我们的镜像

COPY . /go/src/hello

将我们这个demo的除了.dockerignore上标记的文件都拷贝到go镜像的/go/src/hello文件夹下

WORKDIR /go/src/hello

工作路径为/go/src/hello

RUN go get github.com/astaxie/beego
RUN go get github.com/smartystreets/goconvey
RUN go get gopkg.in/mgo.v2
RUN go build

下载需要的go第三方包 并对demo进行编译 生成了demo名字相同的hello可执行文件

RUN tr -d "\r" < run.sh > run.sh

因为一个Dockerfile文件中只可以有一个CMD命令 我们既需要运行测试文件 又需要运行服务 那么我们只可以将运行服务和测试都写进一个sh脚本里面 然后在dockfile中只需要运行这个sh脚本就可以了 上面的命令只是为了去除脚本的"\r" 使得sh文件中可以cd ..

  1. #!/bin/bash
  2. ./hello &
  3. cd tests && go test -v && cd ..
  4. go test -v -tags integration
  5. wait

正如上面所说 run.sh这个脚本做的内容有

我们可以在dockerfile文件所在的根目录下使用

docker image build -t 镜像名字:标签名字 .

命令来生成打包好的镜像

至此 我们要做的beego server镜像打包好了 我们的镜像根据Dockerfile上所配置的而言:这个镜像被下载到本地 生成容器 之后运行 这个容器会自动运行我们的server服务 并且自动执行所有的单元测试和集成测试

使用

docker push 镜像名字:标签名字

将这个镜像推送至你的远程dockerhub仓库里面(实现需要进行docker login进行登录)

那么 我们已经完成了一半的工作量 如下
微信图片_20180910221816.png-30.6kB


拉取镜像

我们剩下来的一半工作就是编写拉取远程仓库中的镜像到本地 生成相应的容器 协调各个容器之间的工作 使得整个服务运行起来

上面说到 在使用docker的方式中我们有三种

  1. Dockerfile
  2. docker remote api
  3. 封装了remote api的第三包

在拉取镜像这部分 我们是推荐使用第三种方式的 因为设想一下 如果使用这种方式 我们在部署测试的时候只需要那边的环境安装了go和docker以及封装了remote api的第三包 那么需要起这个服务只需要简单de地运行我们写好的这个go启动脚本 那么当给让测试的同学来起我们的服务的时候 他们甚至不需要懂得docker的命令 只需要知道怎么运行go文件就可以了

完整的启动文件startUp.go
对于每一个子模块或者说每一个镜像 我们都需要经历下面的过程 才可以将这个子模块在本地的一个docker容器中进行运行
微信图片_20180910223243.png-9.7kB

  1. 构造Config和HostConfig等等 会定义与镜像和容器相关的配置 Config一般包含基本信息 名字内存等等 HostConfig一般是与ip和端口等相关
  2. PullImage下载远程镜像到本地
  3. CreateContainer根据镜像和上诉的配置构造容器
  4. StartContainer启动容器
  5. InspectContainer监视容器

效果

我们可以来看一下 当我们的环境中只安装了go和docker以及封装了go docker client这个第三方包的时候 运行我们的启动文件startUp.go将整个服务启动起来
微信图片_20180910223809.png-53.5kB

注意上诉运行的本质就是

  1. 拉取mongo远程镜像到本地
  2. 生成一个mongo容器进行运行 返回容器所在的IP地址和端口以备beego server连接mongo数据库
  3. 拉取我们之前打包好的beego server镜像到本地
  4. 生成beego server容器 并且将mongo容器运行返回的IP地址和端口作为环境变量传进beego server容器中以供连接数据库
  5. beego server容器运行之后自动运行所有单元测试和集成测试(这部分已经打包在Dockerfile中了成为镜像本身的一部分)

我们可以看一下这两个容器的运行情况
微信图片_20180910224321.png-25.5kB

在查看一下 我们的beego server容器中自动运行单元测试集成测试的结果输出 需要在docker logs命令中指定容器的名字
微信图片_20180910224438.png-54.7kB


微服务架构

说了这些可能会觉得莫名其妙 为什么要这样做呢 其实觉得这都是为了微服务架构做准备

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注