作为一个运维或者测试,可以不必每天都去关注最新发布的各种开源小工具,但最好了解下docker,因为个人感觉这东西将来可能会对软件的微观和宏观架构产生较大冲击,甚至改变运维和测试目前的工作思维方式。在虚拟化方兴未艾的时代,在云计算的机器海洋里,一个容器时代正在到来。
一、整体结构图
二、测试过程中的几个思考要点
先交代下测试环境:
测试宿主机:Ubuntu 14.04.1 LTS(阿里云服务器)
测试docker版本:1.2
基础镜像:CentOS6.5
由于本人刚接触docker,有些现象,只是记录下来,目前还没理清楚,抛砖引玉。
1、隔离级别。
对于Application Container,从图中可以看到,其隔离级别必然是不如虚拟机的。但是,虽然看上去,docker容器的1号进程与宿主机完全不同,但是还是和宿主机存在联系,比如,在docker容器启动一个apache,会发现宿主机上也多了3个apache进程,而且是完全不同的进程号。这之间是什么关系,目前本人还不清楚。
2、内核参数。
测试发现:
1)、当我们修改宿主机的内核参数的时候,查询docker机上并不受影响。
2)、无法修改docker机的内核参数,如:
[admin@mysql_host2 ~]$ sudo echo 33554432 >/proc/sys/kernel/shmmax
-bash: /proc/sys/kernel/shmmax: Read-only file system
网上爬文,找到了答案,可以用“RUN echo "kernel.shmmax = 68719476736" >> /etc/sysctl.conf”的方式在生成镜像时将内核参数修改固化进去,然后采取-privileged的方式运行容器就ok了,可以看到新的内核参数值。以这种方式运行的容器,也可以动态修改内核参数值,但无法持久化。
参考网文如下:
http://www.kuqin.com/shuoit/20141020/342750.html
3、资源共享。
在docker上,查询cpu和mem信息,与宿主机完全一致。这里也体现了容器与VM的根本差异,VM是从宿主机上显式地分配固定资源的。但发现宿主机第二块盘挂的/data目录,在docker上看不到,docker貌似只继承了宿主机的根目录文件系统。测试在建立镜像的时候,用RUN来mount一下,但提示无法识别我们需要mount的磁盘分区。问题来了,如何让镜像识别宿主机的非系统盘呢?
4、启动多个服务。
网上有人说可以把要启动的服务打包到一个脚本里,然后把这脚本COPY到镜像里,最后用CMD启动即可,俺始终没有试验成功。最后,还是supervisord管用,想拉多少服务都没问题。注意,在centos6.5的基本源里没有supervisord,必须先安装epel
5、IP地址。
运行docker容器的时候,如:
# docker run --name=mysql_contain1 -h=mysql_host1 -d -P docker_mysql
可以设定容器名,可以设定容器主机名,但貌似没法设IP地址?
宿主机有个docker0的虚拟网卡,其地址是192.168.42.1,发现新建的docker容器ip地址就接着后面不断累加。注,要查询一个运行中容器的ip地址,方法如下,其中mysql_contain1是容器名:
# docker inspect mysql_contain1|grep IPAddress
"IPAddress": "192.168.42.235",
6、动态运行容器。
如果我们有了一个mysql镜像,是否可以根据宿主机负载阀值动态启动容器把负载接过去?做了个小实验,当宿主机的mysql连接数超过500的时候,启动一个mysql容器,代码没啥意义,纯属测试:
#!/usr/bin/python
# Filename: db3.py
# Description: a demo to access mysql based on dynamic docker containers
# Python 2.7.6
import MySQLdb
import commands
import os
import random
import time
image_name='docker_mysql'
master_host_ip='127.0.0.1'
prefix_cont='mysql_cont'
num_thread=500
def getDockerip():
i=random.randint(1,10000)
shell='mysqladmin -uroot -proot status|awk \'{print $4}\''
try:
thread = int(commands.getoutput(shell))
except Exception:
print 'get thread number of master sql error'
exit(1)
if ( thread > num_thread ):
str=prefix_cont+'%d' %i
os.environ['cont_name']=str
os.environ['image_name']=image_name
ret=os.system('docker run --name="$cont_name" -d -P $image_name >docker.log 2>&1')
if ( ret <> 0 ):
print 'create docker for mysql error'
exit(2)
shell2='docker inspect "$cont_name"|grep IPAddress|grep -Eo \'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\''
str_ip=commands.getoutput(shell2)
return str_ip
return master_host_ip
def insertData(v):
des_host_ip=getDockerip()
print des_host_ip
print 'begin to insert data to '+des_host_ip
time.sleep(3)
try:
my_conn=MySQLdb.connect(host=des_host_ip,port = 3306,user='root',passwd='root',db ='db_test')
cur = my_conn.cursor()
sql="insert into t(id) values('%d')" %(v)
cur.execute(sql)
cur.close()
my_conn.commit()
my_conn.close()
print 'insert data to '+des_host_ip+' successfully!'
except MySQLdb.Error,e:
print "Mysql Error %d: %s" % (e.args[0], e.args[1])
exit(3)
insertData(2015)
(待续)