「Docker」- 在测试中使用

更新日期:2019年07月10日
@IGNORECHANGE

#1 测试静态网站(单个容器)

(1)创建Dockerfile并使用该Dockerfile创建镜像。

(2)从该镜像中启动容器。启动时,将本地卷挂载到容器中(通过-v选项)。

(3)修改本地卷中的文件,访问容器来查看。

#2 构建并测试Web应用程序(多个容器)

# 示例一、接收URL参数,并以JSON返回
老路子:使用Dockerfile创建容器。启动一个容器,并使用-v挂载外部卷。访问容器来测试。

# 示例二、连接Redis服务,存储输入的URL参数
创建一个项目,项目中连接Redis服务,Host: db,Post: 6379,并将请求参数写入Redis中。

使用Dockerfile创建一个Redis镜像。从镜像启动容器。使用docker port命令查看端口,使用Redis的客户端工具进行测试。

将应用程序连接到Redis容器,实际上是「组网」,使二者能互相连接。共有三种方法:

	* 使用Docker「内部网络」。不灵活,也不够强大。不推荐使用。
	* 使用Docker「Networing」从Docker 1.9开始,使用docker networking命令。推荐使用的方法。
	* 使用Docker「链接」。是一个抽象层,可以将具体容器链接到一起来进行通讯。在Docker 1.9之前版本推荐使用的方法。

推荐使用「Docker Networking」,而不是「Docker链接」的原因:

	* 「Docker Networking」可以跨宿主机;
	* 「Docker Networking」无需事先创建容器,也不必关心容器的运行顺序;
	* 「Docker Networking」可以在无需更新连接的情况下,对停止、启动或重启容器。而「Docker链接」,则需要更新一些配置,或者重启相应的容器来维护Docker容器之间的链接。

# 内部网络

这属于Docker自身的网络栈。常见的就是把「容器的端口」映射到「宿主机的端口」。还有一种用法就是内部网络。

安装Docker时,会默认创建了docker0网口,它是一个虚拟网桥,连接容器和宿主机,分配私有IP地址,网段172.17.0.0/16,如果被占用,则会在172.16.0.0到172.31.0.0之间选择一个。每个容器都会在这个接口上分配一个IP地址。Docker会为每一个容器创建一个veth*的接口,这个接口一端连接到「容器内的eth0」,一端桥接到「宿主机的docker0」。这样Docker就创建了一个虚拟子网,连通的宿主机器和各个容器,这样它们之间就可以互相操作了。

追踪路由可以发现,流量从「容器内的eth0」到「veth*接口」,到了「docker0」。

实际上,向建立连接还需要另外一部配置 - 防火墙,这允许宿主网络和容器间路由。默认容器是无法被访问到的,但是做了DNAT之后,就可以访问了。更多网络的内容,可以查看「Networking overview」部分。

支持ipv6,不过启动时要使用--ipv6选项。

使用docker inspect命令来查看端口及网络信息。通过映射端口来访问Docker容器中的服务。实际上也可以直接通过IP地址及端口访问容器中的服务。

这种方式有几个问题:

	* 「应用程序」只能硬编码「容器的IP地址」
	* 重启容器后,IP地址会发生变化。也就是说服务可能会无法连接。

而这些问题可以使用Networking来解决。

# Networking

容器间的连接使用网络创建,这被成为Networking,实在1.9之后的新特性。Docker Networing允许用户创建自己的网络,容器通过这个网络通信。

Docker Networing以新的由用户管理的网络补充了现有的docker0。更重要的是可以夸主机通信,并且网络设置可以更灵活的定制。

Docker Networking同时也与Docker Compose及Swarm进行了集成。

Docker Networking也是可插拔的,可以通过增加「网络驱动」以支持来自不同网络设备提供商的特定拓扑和网络框架。

使用Docker Networking,要先创建网络,然后在网络下启动容器:

	# docker network create app # 创建网络
	# docker network inspect app # 查看网络信息
			# 还可以创建overlay类型的网络,可以夸主机通信。参考官方文档。
	# docker network ls # 查看当前网络
	# docker network rm # 删除网络
	# docker run -d --net=app --name db jam/redis # 启动一个容器并加入app网络
	# docker network inspect app # 再次查看网络,将看到网络中的容器的IP地址、MAC地址等信息。
	# docker run -d --net=app --name web jam/static_web # 启动应用容器,同时加入到app网络中。
		# 这两个容器都是在网络中启动的,Docker会将容器的地址保存到本地DNS文件,/etc/hosts,中:
			172.18.0.3 1b9b99609f21	# 当前容器
			127.0.0.1  localhost	# locahost
			172.18.0.3 db		# 网络中其他容器名(另一方方面也可以看出,容器名就是主机名)
			172.18.0.3 db.app	# 网络中其他容器名 + . + 网络名
		# 更重要的是,即使重启后IP地址发生了变化,也会自动在/etc/hosts文件中自动更新。
	# docker network connect app db2 # 将db2加入到app网络中。
	# docker network inspect app # 到目前位置将看到三个容器。三个容器的/etc/hosts中包含了其他容器的host信息。
	# docker network disconnect app db2 # 将容器从网络中移除
		# 同时一个容器可以属于多个网络,可以参考官方的手册来了解更多内容。

# 链接

连接容器的另外一个选择,在Docker 1.9以前首选的容器连接方式,并且只在运行1.9之前版本的容器才推荐使用这种方式。

这是一个简单的方式,需要使用到容器的名字:

	# docker run -d --name redis jamtur/redis # 之前说过,容器名是唯一的。
			# 至此,运行了一个Redis容器。但是没有公开任何端口(即没有映射到宿主机器的端口)
	# docker run -p 4567 --name webapp --link **redis:db** -t -i -v /foo:/bar jam/static_web /bin/bash
			# -p 公开4567端口,供外部访问
			# --name 指定容器的命名
			# -v 挂载卷
			# --link 创建了两个容器的链接。一个参数是「容器名」,一个参数是「别名(主机名)」,参数之间使用冒号(:)分隔。「别名」可以用于访问容器,而无需关心底层容器名。

链接让「服务容器」与「客户容器」通信,并能分享一些链接细节,这些细节有助于在应用程序中配置并使用这个链接。

另外一个好处是,启动Redis时,没有使用-p标志公开Redis端口。因为容器之间是直接链接的,所以我们不需要对宿主机公开端口(选项-p公开端口实际上是在宿主机上做了网络映射)。通过链接,客户容器可以访问服务容器的端口,而且只有「使用了链接的客户容器」才能连接到「服务容器」的指定端口(实际上是指的对别名和hosts文件的处理)。这是一个很好的安全模型。!!!可以通过--icc=false来关闭没有链接的容器间的通讯!!!

也可以链接多个容器。多个容器链接到同一个服务容器,也可以指定多次--link选项,来链接到多个服务容器。

但是「链接」只能用于同一台宿主机,多宿主机要使用Docker Networking,或者使用Docker Swarm来完成多台宿主机上的Docker守护进程的编排。

「客户容器」会在两个地方写入链接信息:

	首先,是/etc/hosts文件:链接时会写入「服务容器」的IP地址,链接别名,容器名,ID。当然也可以使用''--hostname''手动指定主机名。当然也可以使用''--add-host=hostname:ip_address''选项来手动指定条目。从Docker 1.3开始,链接的容器被重启后,/etc/hosts文件也会被更新。
	其次,是包含连接信息的环境变量。在容器中执行env命令就可以看到这些环境变量,环境变量是以链接时的容器别名为前缀的。

所以访问服务的方法由两种,一种从环境变量中读取信息,另一种是使用/etc/hosts的信息。

!!!也可以在docker run中加入--dns或--dns-search选项来为容器单独配置DNS。你可以设置本地DNS或搜索域。参考官方文档。如果没有这两个选项,则Docker会根据宿主机的信息来配置DNS解析。查看容器的/etc/resolv.conf文件来查看DNS解析的配置情况。

#3 用于持续集成

在多开发者的「持续集成」测试场景中使用Docker:

没有什么新东西:Jenkins拉代码,使用代码里的Dockerfile构建镜像,运行镜像启动容器,容器中执行测试,使用docker wait获取测试结果,以测试结果为Jenkins的退出码,然后把测试结果生成的文件给Jenkins用。

#4 多配置的Jenkins

加入要在多个平台上测试作业,比如在Ubuntu、Debian、CentOS上测试,可以使用Jenkins的多配置作业。

这是Jenkins的功能,创建「Mult-configuration project」作业,在User-defined Axis中定义「Key」和「Item」,然后在脚本中使用Key即可。

其他方面和之前的例子是类似的。

#5 其他选择

持续集成还可以使用Drone和Shippable工具。Drone是基于Docker开发的CI/CD工具。这里不展开介绍了。


ToC

#1 测试静态网站(单个容器)

#2 构建并测试Web应用程序(多个容器)

# 内部网络

# Networking

# 链接

#3 用于持续集成

#4 多配置的Jenkins

#5 其他选择