Docker 测试开发之路 (工具篇)--Docker

孙高飞 · 2016年10月17日 · 最后由 孙高飞 回复于 2018年11月16日 · 4020 次阅读
本帖已被设为精华帖!

前言

之前在《环境管理》那一篇分享中介绍了我在管理环境上的一些经验,但是并没有介绍 docker 的使用细节。但有些小伙伴们还是比较感兴趣的。关于 docker 的教程网上其实也是满天飞,各种命令和原理的文章,中文的英文的数不胜数。所以我就不从安装开始,介绍各种命令了。这么讲我觉得我也讲不出什么花来,但是网上的这些教程大多数都是理论层次的。他们告诉你这么命令是干什么的,却没有用一条线把他们穿起来告诉你怎么用他们。所以今天我来用我们在测试中实际遇到的例子给大家穿一条线出来。让没用过 docker 的小伙伴们大概知道 docker 是怎么用的,有多简单,通过例子把大概的概念和理论了解一下。 这样就不会被漫天高大上的专有名字搞懵逼了。

什么是 docker

官网上和各类文章中都对 docker 作出了明确的阐释,但是这些定义过于专业和高大上了。所以他姥爷这个土鳖就用俺们村的大白话给大家说一下。

Docker 这个单词英文原意是码头工人,搬运工的意思,这个搬运工搬运的是各种应用。docker 是一种容器技术。有的小伙伴们不了解什么是容器的话就把它当虚拟机吧。虽然 docker 不是虚拟机,但是大家可以把它当成虚拟机用。我们把各种应用(例如我们测试环境中的各种服务)制作成镜像(镜像制作很简单),docker 这个搬运工要搬运的东西就是这个镜像,它可以启动一个或者 N 个容器并把镜像搬运进去,这就是为什么我在《环境管理》那篇分享中可以一下子启动近 30 套测试环境的原因。只要我有镜像,在任何有 docker 服务的机器中都可以迅速拉起 N 套测试环境来。

在 demo 中学习

干说概念性的东西容易让人懵逼。我们还是像学习编程从 hello world 开始一样,我们先演示一个 demo,从迅速搭建一个 test link 应用开始。

mysql

首先我们需要一个 mysql 服务来存储 test link 的数据。按照上面说的,我们需要一个 mysql 镜像。 那么我们如何制作镜像呢? docker 的好处之一就是共享,他人制作的镜像我们可以下载下来直接使用。怎么做呢? 我们可以去 docker hub 中直接搜寻 mysql 的官方镜像

具体的使用细节官方镜像附带的说明中写的很清楚,很简单。我们来用一下吧。首先是下载 mysql 5.5 的镜像。命令如下:

docker pull mysql:5.5

运行过后我们下载了镜像. docker pull 这条命令就是在 docker hub 上搜寻并下载一个镜像。接下来我们运行一下 docker images | grep mysql 来查看本地下载的 mysql 镜像。docker images 的意思就是列出所有的镜像。

OK,我们有了 mysql 的镜像了,那么我们怎么使用这个镜像呢。 来来来,我们关键的地方到了。请看下面的脚本

export name=testlink_mysql
export ip=172.27.1.221

docker rm -f $name
docker run --name=$name -e MYSQL_ROOT_PASSWORD=root -itd -v /home/testlink_data:/var/lib/mysql --net=none  mysql:5.5

pipework br0 $name $ip/20@172.27.0.1

接下来我们讲解一下这些命令。从 docker rm -f 开始把,这条命令是删除一个容器,还记得什么是容器么? 容器是镜像的载体。我们的镜像要放在容器里运行的。所以如果有同名的容器我们先删除它,当然这一步不是必须得。 接下来我们看 docker run 的命令, 这条命令就是用镜像去启动一个容器,命令的最后的那个 mysql:5.5 就是镜像的名称(我们之前用 docker pull 下载的),是不是很简单。这样我们就启动了这个 mysql 的服务了。当然中间有一些参数我来详细的讲解一下。

  1. --name:定义容器的名称。我们可以通过 docker ps 来查看所有容器。
  2. -e: 启动容器时向容器内传递一个环境变量,这个参数可以有多个。 这是非常重要的一个参数,有些时候我们在制作镜像的时候并不清楚一些行为到底要怎么定义,需要在启动容器的时候决定。例如这个例子里我们用-e 向 mysql 容器传递了 root 的密码。mysql 容器在启动的时候会读取这个环境变量并设置 root 密码
  3. -v: 这同样是一个很重要的参数,它是一个挂载的概念。是在主机和容器间共享数据的方式。用:分割,左边是宿主机的文件目录,右边是容器的目录。这个参数在我们做数据备份的时候很有用。在这个例子我把 mysql 存储数据的目录挂载到了主机的一个目录里。这样就算容器被人不小心删除了,数据也不会丢失的。
  4. --net:这个参数指定 docker 的网络模式,我一般设置为 none,因为我要分配固定 ip 最后一个命令,pipework,它是一个第三方的工具,可以给容器分配固定 ip。有兴趣的可以在网上搜一下这个工具的使用。

OK,运行这个脚本后,我们的数据库服务就搭建好了。是不是很简单。你不是运维的同学,你不必懂 mysql 得配置,你只需要下载官方镜像直接使用就可以了。

接下来我们搞一搞 test link 吧。同样现在 docker hub 上搜一下有没有人已经做好了 test link 的镜像。很幸运的我发现也是有的。我们运行一下 docker pull otechlabs/testlink 下载即可。我们同样用下面的命令启动 test link 容器

export name=testlink_new
export ip=172.27.1.220

docker rm -f $name
docker run -itd --name=$name --hostname=$name --net=none -v /home/testlink_upload:/var/testlink testlink

pipework br0 $name $ip/20@172.27.0.1

命令跟上面 mysql 一样,也很简单,唯一需要注意的是我挂载目录的位置是 test link 保存附件的文件夹,testlink 不是所有数据都保存在数据库里的,所以这部分也要挂载出来保存。容器启动后,我们使用 ip 登录 test link,见证奇迹的时刻就到了。剩下的你只需要根据 test link 的页面配置一下数据库了。到这里我们就搭建了一个在测试工作中很常见的用例管理工具。当然到了这里我们还有些不太完美。就是到了这里我们的数据虽然都挂载到宿主机上保存了。但是 test link 的配置缺没有,这是容器启动后,我们在页面上配置的。这部分的信息我们没有保存。所以我们需要修改一下镜像了。如下:

FROM otechlabs/testlink

ADD files /var/www/testlink

这是一个 Dockerfile,制作镜像的语法文件。我们使用 Dockerfile 的语法来扩展一个镜像。 第一行的 FROM 命令大家看到了,说明是继承自另一个镜像的。也就是说我们对 test link 镜像做扩展。熟悉编程的小伙伴们理解起来一定很容易,你就把它当成面向对象语言中的继承就行了。 接下来我们用 ADD 命令,把宿主机中的 files 文件夹下所有的文件都 copy 到镜像中的/var/www/testlink 文件夹中。 这里说一下我把 test link 的 config 文件存在了 files 文件中,所以也就是说 config 文件现在被 copy 到了 test link 容器里了。接下来我们运行一个简单的命令构建镜像。

docker build -t testlink .

这是构建一个惊险的命令,要在 Dockerfile 的目录下执行。这样我们新的镜像就做好了。我们用新的镜像代替之前启动 test link 的旧镜像。一切就 OK 了,完美了。test link 的配置文件也就存到了镜像里了。

这是一个搭建 test link 的简单应用。我们经理了下载官方镜像并使用的过程,扩展镜像满足我们自己需要的过程。 我们可以用这个思想搭建各种基础服务。那下面我们再说复杂一点的场景

更复杂点的场景

现在说说我们的测试环境,要搭建测试环境肯定就没有那么成熟的镜像给我们用了。我们需要自己专门定制一个镜像出来,首先我们要做一个基础镜像,解决依赖的问题,例如我们的产品是 java 的项目,那我们要装:maven,jdk,git,ssh 等等。下面看一下 Dockerfile 的例子:

FROM docker.io/ludalex/docker-java7-maven-aws-git
MAINTAINER sungaofei(sungaofei@4paradigm.com)

ADD files /root

RUN apt-get update \
    && apt-get install wget -y \
    && apt-get install -y openssh-server \
    && /etc/init.d/ssh start \
    && apt-get install -y oracle-java7-set-default \
    && cd /tmp \
    && wget http://apache.claz.org/thrift/0.9.3/thrift-0.9.3.tar.gz \
    && tar -zxvf thrift-0.9.3.tar.gz \
    && cd thrift-0.9.3 \
    && ./configure && make \
    && make install \
    && cd /opt \
    && mkdir web \

大家看到首先我还是继承了一个从 docker hub 上下载的基础镜像,通过名字就可以看出来,这个基础镜像里已经有了 maven,git 之类的东西。但还不够,我们需要再下载一点东西。RUN 这个命令就是执行 shell 命令的。 它最大的作用就是安装一些依赖包。在 RUN 里面,最常用的就是 apt-get 了。上面的例子我下载并安装了 ssh 的组件包,jdk7,thrift 的 RPC 框架包等等。然后再运行一个 docker built -t 我们就做好这个基础镜像了,这解决了我们的依赖问题。以后再制作任何 java 镜像我们都可以通过扩展这个基础镜像来做。
接下来我们看一下部署镜像的 Dockerfile

FROM 4paradigm/dango2.0-test-base-new
ADD files /root

ENTRYPOINT ["/root/entrypoint.sh"]

可以看到这个镜像貌似没干什么。但是,恩? ENTRYPOINT 是个什么鬼? 这个很重要,非常重要。大家记住了,这是启动容器后第一个运行的命令。也就是说,它是容器的启动命令,它是容器启动后干的第一个事。我们通常把启动服务的脚本放在这里。我们同 ADD 命令把一些启动脚本放在容器的/root 目录下。然后通过 ENTRYPOINT,运行启动脚本。我们来看一下 entrypoint.sh 这个脚本都干了什么

cd /root
echo "setup is running"

# deploy simba
cd /opt/web

git clone git@git.4paradigm.com:prophet/simba.git


cd /opt/web/simba
git checkout ${simba_branch}

if [ -n ${simba_commit_id} ]
then
    echo "reset to commit_id ${simba_commit_id}"
    git reset ${simba_commit_id}
fi

mvn -DskipTests clean package -U

cd /opt/web
./startserver.sh

中间我删除了一些干扰代码,真实的情况比这个复杂些。看到这个脚本里我们拉取了 git 上的代码。编译并运行了启动脚本。大家注意这里我读取了一些环境变量,例如${simba_branch},这就是通过启动容器的时候(也就是 docker run)的 -e 的参数传递进来的环境变量。 这样我们就做到了容器的参数化。接下来我们运行 docker run 就可以了,我们的这个 java 项目的测试环境的搭建起来了。当然我中间刻意忽略了一些细节免得大家被干扰。但是我们用 docekr 搭建测试环境的流程大概就是这样的了。

总结

今天他姥爷就讲到这里吧,我用了两个在工作中用到 docker 的简单例子来给各位扫一下盲。特别详细的教程他姥爷真的木有时间写了,大家去翻官方文档吧,平时工作比较忙。女王大人还怀孕了,而且女王大人对我这种老是坐在电脑面前码字或者撸代码不管老婆孩子的行为很是不满了。所以各位见谅,我的这个系列文章真的没办法很详细的写个教程。就是带大家入个门,让大家看一下大概怎么做的,做成什么样子。很多细节大家要自己探索和阅读文档了。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 24 条回复 时间 点赞

不错,学习了

敢问一声,孙大师想来杭州发展?跳槽不

#2 楼 @hu_qingen 额,媳妇已然怀孕了~ 这个阶段实在不想折腾了~~

#3 楼 @ycwdaaaa 能理解,我也经历过这个阶段,😀 😀 等孙大师啥时候有想法了,找俺啊,很希望跟你一起共事下😀 😀

#4 楼 @hu_qingen 恩恩 好的~

加精理由: 普及了 docker 这个 devops 依赖的基础知识.

思寒_seveniruby 将本帖设为了精华贴 10月18日 11:45

windows 系统下使用 docker 安装 testlink,数据库启动正常的,账号设置也是正常的,遇到以下报错:

TestLink setup will now attempt to setup the database:

Creating connection to Database Server:Failed!
Please check the database login details and try again.
Database Error Message: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

请问下有遇到过没,怎么解决的?

#8 楼 @jaychang1989 就是连接不上数据库。 你连的 local 的数据库。但是 local 的环境里没有启动数据库的服务

#9 楼 @ycwdaaaa 我在本地连数据库 localhost:32770,数据库是可以连接成功的,testlink 里面也是配置 localhost:32770,就会出现报错,很奇怪

#10 楼 @jaychang1989 你换个远程的试试

#10 楼 @jaychang1989 话说端口号感觉怪怪的呢。。。。mysql 不应该是 3306 么

想问下 docker 可以运行 c++ 的 exe 不 ?

#14 楼 @piaodangdang 这个跟 docker 没关系。。跟操作系统有关系。。 exe 只能 windows 跑吧,所以要在 docker 里启动 windows 的系统。不过在 linux 下的 docker 是不能启动 windows 系统的容器的,因为它不是虚拟机,只是容器而已。 听说微软出的一个产品封装了 docker,可以制作 windows 镜像

#15 楼 @ycwdaaaa 这个我试过了 一个 nanoserver 的基础镜像就 8 个 G 什么都没干 这完全背离了 docker 轻量化的要求 在 segementFault 有人说过可以运行 exe 但是没查到相关资料 后来 segmentfault 不知道为什么访问不了了 看大神的 docker 管理文档 就来问问有木有相关部署经验

#16 楼 @piaodangdang 这个我也木有经验了。 看国外的 docker 大会上说有个程序员妹子把 docker 改了,可以装 windows。但我估计咱们是做不成了

呵呵,文章写的确实不错。很赞👍

不错!

请问一下,你们实际部署的时候 只部署需要测试的服务呢,还是把所有依赖的服务都部署一遍呢?

yes!! 回复

都可以~

pipework is probably never going to work on a Mac. 刚入门 docker,请问除了 pipework 还有给容器分配固定 ip 的工具么?

弗多 回复

那就没听说过了~

孙高飞 回复

意思是 windows 系统上的 docker 只能运行 windows 操作系统以及它的程序?我想在 win10 上启动 win7 或者 win8 系统可行吗?网上的镜像拉取下来启动不起来。还有就是 dockers 和真机环境测试效果一样吗,因为我知道虚拟机和真机测试结果是有差别的。liunx 版 docker 和 window 版 docker 差别有点大哦,window 版 docker 底层要启动一个虚拟机。liunx 版是内核原生支持,那是不是 window 版 docker 跟其实就是虚拟机模拟出来的呢

红客联盟 回复

怎么说呢, 你就记住一句话吧。 目前 docker 只能跑在 linux 内核上。 所以 linux 能做的它能做, linux 做不了的,他绝对做不了。 你再 windows 上看到的一切都是假象。 虽然我听说微软在开发 windows 的 docker,但是还没听说他们搞出来

ABEE ycwdaaaa (孙高飞) 在 TesterHome 的发帖整理 中提及了此贴 01月12日 13:47
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册