Ansible Inventory详解

运维技术采菊篱下 发表了文章 • 0 个评论 • 2037 次浏览 • 2015-10-15 18:50 • 来自相关话题

Inventory文件用来定义你想控制管理的服务器,默认配置文件是/etc/ansible/hosts,如下是一个简单的例子
[test]
10.0.3.56

[zabbix]
10.0.1.30

[web]
10.0.2.57

简要说明

[zabbix],[web]是对服务器分组的名称,指定组名。主机可以直接用ip地址,也可以用域名,还可以用数字和字母指定一批连续的服务器,如:
blog[1:3].jkb.com,相当于blog1.jkb.com blog2.jkb.com blog3.jkb.com我们已经了解到,Ansible默认是通过ssh的方式来远程管理批量服务器的,所以我们这里使用ssh,key加密的方式来进行ssh的认证会更方便,当然,你也可以选择使用Ansible的时候较少-k选项,来通过交互的方式输入密码。
 
Ansible管理主机,已经可以通过密钥的方式管理主机后,我们就可以用Ansible直接来做一些简单的测试,如下:
ansible all -m ping #用于检测所有的主机是否存活如果只想检测某个组的话,可以把all替换成组名,例如:
ansible test -m ping当然也可以直接输入管理主机的ip地址,例如:
ansible 10.0.3.56 -m ping在默认的情况下Ansible是使用root用户来进行远程管理的,在大多数情况下,为了安全起见,一般会使用一个普通账户来管理。 
 
我们可以在所有的被管理的机器上面创建一个ansible的用户,并且可以使用sudo来提升权限到root。当然我们在Ansible主机上面也需要这样一个用户,并且为其生成ssh key。
 
然后通过修改/etc/ansible/ansible.cfg配置文件中的remote_user = ansible以使ansible默认使用ansible用户来进行管理,然后使用 --sudo成熟来获取root权限。
 
 你也可以通过修改/etc/ansible/ansible.cfg 里的remote_port端口来修改默认远程管理的ssh的22端口。 一切完成后你就可以测试了:
ansible all -m ping --sudo
如果多台主机的管理账户各有不同的话,我们也可以在Inventory文件中处理,分割进行设置,例子如下:
[webserver]
10.0.1.3 ansible_ssh_user=root
10.0.2.3 ansible_ssh_user=lucky
10.0.3.3 ansible_ssh_host=10.0.3.3 ansible_ssh_port=36000
[production]
10.0.1.3
10.0.2.3
bjdb0 ansible_ssh_user=work ansible_ssh_private_key_file=/home/work/.ssh/id_rsa

简单说明

ansible_ssh_user--->用于管理远程主机的用户名
ansible_ssh_host--->用于指定被管理主机的端口
ansible_ssh_port---->用于指定ssh连接端口
ansible_ssh_private_key_file--->指定ssh key文件
host_key_checking=False 当你第一次连接远程主机的时候,会提示yes/no,设置为False会跳过这个环节。主机组直接还可以嵌套,需要使用关键字children,示例:
[jkbhost:children]
jkbhost-mysql
jkbhost-web
jkbhost-redis

[jkbhost-mysql]
10.0.1.81
10.0.1.82
10.0.1.88
10.0.1.89
10.0.1.96
10.0.1.107

[jkbhost-web]
10.0.1.104
10.0.1.105

[jkbhost-redis]
10.0.1.181
10.0.1.18我们也可以通过多个Inventory文件来进行主机管理,默认是/etc/ansible/hosts,如果多个管理文件,需要执行ansible命令的时候,通过-i参数来指定:
ansible -i /etc/ansible/hosts2 -m ping关于host就讲到这里,这是用来管理客户端的。 查看全部
Inventory文件用来定义你想控制管理的服务器,默认配置文件是/etc/ansible/hosts,如下是一个简单的例子
[test]
10.0.3.56

[zabbix]
10.0.1.30

[web]
10.0.2.57


简要说明


[zabbix],[web]是对服务器分组的名称,指定组名。主机可以直接用ip地址,也可以用域名,还可以用数字和字母指定一批连续的服务器,如:
blog[1:3].jkb.com,相当于blog1.jkb.com blog2.jkb.com blog3.jkb.com
我们已经了解到,Ansible默认是通过ssh的方式来远程管理批量服务器的,所以我们这里使用ssh,key加密的方式来进行ssh的认证会更方便,当然,你也可以选择使用Ansible的时候较少-k选项,来通过交互的方式输入密码。
 
Ansible管理主机,已经可以通过密钥的方式管理主机后,我们就可以用Ansible直接来做一些简单的测试,如下:
ansible all -m ping #用于检测所有的主机是否存活
如果只想检测某个组的话,可以把all替换成组名,例如:
ansible test -m ping
当然也可以直接输入管理主机的ip地址,例如:
ansible 10.0.3.56 -m ping
在默认的情况下Ansible是使用root用户来进行远程管理的,在大多数情况下,为了安全起见,一般会使用一个普通账户来管理。 
 
我们可以在所有的被管理的机器上面创建一个ansible的用户,并且可以使用sudo来提升权限到root。当然我们在Ansible主机上面也需要这样一个用户,并且为其生成ssh key。
 
然后通过修改/etc/ansible/ansible.cfg配置文件中的remote_user = ansible以使ansible默认使用ansible用户来进行管理,然后使用 --sudo成熟来获取root权限。
 
 你也可以通过修改/etc/ansible/ansible.cfg 里的remote_port端口来修改默认远程管理的ssh的22端口。 一切完成后你就可以测试了:
ansible all -m ping --sudo

如果多台主机的管理账户各有不同的话,我们也可以在Inventory文件中处理,分割进行设置,例子如下:
[webserver]
10.0.1.3 ansible_ssh_user=root
10.0.2.3 ansible_ssh_user=lucky
10.0.3.3 ansible_ssh_host=10.0.3.3 ansible_ssh_port=36000
[production]
10.0.1.3
10.0.2.3
bjdb0 ansible_ssh_user=work ansible_ssh_private_key_file=/home/work/.ssh/id_rsa


简单说明


ansible_ssh_user--->用于管理远程主机的用户名
ansible_ssh_host--->用于指定被管理主机的端口
ansible_ssh_port---->用于指定ssh连接端口
ansible_ssh_private_key_file--->指定ssh key文件
host_key_checking=False 当你第一次连接远程主机的时候,会提示yes/no,设置为False会跳过这个环节。
主机组直接还可以嵌套,需要使用关键字children,示例:
[jkbhost:children]
jkbhost-mysql
jkbhost-web
jkbhost-redis

[jkbhost-mysql]
10.0.1.81
10.0.1.82
10.0.1.88
10.0.1.89
10.0.1.96
10.0.1.107

[jkbhost-web]
10.0.1.104
10.0.1.105

[jkbhost-redis]
10.0.1.181
10.0.1.18
我们也可以通过多个Inventory文件来进行主机管理,默认是/etc/ansible/hosts,如果多个管理文件,需要执行ansible命令的时候,通过-i参数来指定:
ansible -i /etc/ansible/hosts2 -m ping
关于host就讲到这里,这是用来管理客户端的。

WOT软件技术峰会,自动化运维专场现场视频

学习资源OpenSkill 发表了文章 • 0 个评论 • 1247 次浏览 • 2015-10-15 12:34 • 来自相关话题

快乐运维-常景志

运维有人说苦逼,但是我们需要苦中作乐,找到真正的运维乐点!

 

360运维自动化平台之大规模服务监控平台-刘浩

看看大规模的服务监控平台体系,学习大体系服务监控的思路!


游戏虚拟化运维实践-肖力

在这个云计算的时代,虚拟化可谓正值青年。看力哥如何利用虚拟化技术玩转游戏运维!这里推荐一下力哥著作:深度实践KVM:核心技术、管理运维、性能优化与项目实施一书


字节码和网络抓包在应用性能管理中的实践-黄东

网络可谓是运维者必修一课,如果你不了解网络,你不知道攻击你的人,是怎么发起,怎么进入的,那只好等死,抓包就是我们常用的分析手法!查看你应用性能再网络方面的缺陷和可优化之地!


基于Python构建可扩展的自动化运维平台-刘天斯

近几年Python可谓成了运维者必修课程了,随着DevOps再国内的盛行!看大神如何设计、玩转自动化运维之路!



大会PPT资料下载地址:http://pan.baidu.com/s/1o69vgZw
 
OpenSkill.CN 开源技术社区 基于51cto整理分享!
开源技术社区QQ群号:372476089  欢迎加入互相学习
扫码关注微信订阅号:




运维杂谈微信群: 查看全部


快乐运维-常景志


运维有人说苦逼,但是我们需要苦中作乐,找到真正的运维乐点!


 


360运维自动化平台之大规模服务监控平台-刘浩


看看大规模的服务监控平台体系,学习大体系服务监控的思路!



游戏虚拟化运维实践-肖力


在这个云计算的时代,虚拟化可谓正值青年。看力哥如何利用虚拟化技术玩转游戏运维!这里推荐一下力哥著作:深度实践KVM:核心技术、管理运维、性能优化与项目实施一书



字节码和网络抓包在应用性能管理中的实践-黄东


网络可谓是运维者必修一课,如果你不了解网络,你不知道攻击你的人,是怎么发起,怎么进入的,那只好等死,抓包就是我们常用的分析手法!查看你应用性能再网络方面的缺陷和可优化之地!



基于Python构建可扩展的自动化运维平台-刘天斯


近几年Python可谓成了运维者必修课程了,随着DevOps再国内的盛行!看大神如何设计、玩转自动化运维之路!




大会PPT资料下载地址:http://pan.baidu.com/s/1o69vgZw
 
OpenSkill.CN 开源技术社区 基于51cto整理分享!
开源技术社区QQ群号:372476089  欢迎加入互相学习
扫码关注微信订阅号:
opsk.jpg

运维杂谈微信群:
witops.png

HBase file layout needs to be upgraded案例分析

大数据/云计算采菊篱下 发表了文章 • 0 个评论 • 2898 次浏览 • 2015-10-15 01:00 • 来自相关话题

今天在一个内网的测试环境平台,kafka的river插件状态非正常,然后同事只好重建kafka river,river的状态始终无法正常,没有办法,同事对服务还不是很熟悉,我只好帮忙看看了!
 
因为kafka 的river插件作为kafka消息数据的consumers角色,把消费掉的数据,通过Hbase转存储到hdfs中!
如下所示是river对hbase的配置:<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://10.2.2.39:9000/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.master</name>
<value>10.2.2.39:60000</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>10.2.2.56,10.2.2.94,10.2.2.225</value>
</property>
</configuration>从这可以看出river插件是需要hbase的,然后我执行创建river的命令,tail观看到hbase master的hbase-root-master-hbase1.log如下:2015-10-14 17:34:13,980 INFO [master:hbase1:60000] util.FSUtils: Waiting for dfs to exit safe mode...从log中可以看出hbase在等待hdfs退出安全模式,为什么要等Hdfs退出安全模式呢?那下面就具体看看Hdfs的log中有什么线索,查看Hdfs的Namenode的hadoop-root-namenode-had1.log记录如下:2015-10-14 17:33:52,283 ERROR org.apache.hadoop.security.UserGroupInformation: PriviledgedActionException as:root (auth:SIMPLE) cause:org.apache.hadoop.hdfs.server.namenode.SafeModeException: Log not rolled. Name node is in safe mode.运行如下命令等待退出安全模式bin/hadoop dfsadmin -safemode wait发现半分钟后没有反映,然后运行如下命令检查hdfs的健康状态bin/hadoop fsck / 发现有很多corrupt blocks,不过还好备份数大于1.此时,hdfs需要自动的把备份数增加到2,所以需要对数据进行写操作,必须退出安全模式,于是:bin/hadoop dfsadmin -safemode leave关闭之后等待集群把数据备份好,达到2,耐心等待一段时间吧,看数据量的大小,达到2之后,运行:bin/hadoop fsck -move也可以尝试:执行健康检查,删除损坏掉的block。 bin/hdfs fsck  /  -delete 注意: 这种方式会出现数据丢失,损坏的block会被删掉.

把那些破坏的块移到/lost+found这个目录下面,启动Hbase,发现Hmaster启动之后进程又消失了,查看日志:2015-10-14 17:48:29,476 FATAL [master:hbase1:60000] master.HMaster: Unhandled exception. Starting shutdown.
org.apache.hadoop.hbase.util.FileSystemVersionException: HBase file layout needs to be upgraded. You have version null and I want version 8. Consult http://hbase.apache.org/book.html for further information about upgrading HBase. Is your hbase.rootdir valid? If so, you may need to run 'hbase hbck -fixVersionFile'.
at org.apache.hadoop.hbase.util.FSUtils.checkVersion(FSUtils.java:600)
at org.apache.hadoop.hbase.master.MasterFileSystem.checkRootDir(MasterFileSystem.java:462)
at org.apache.hadoop.hbase.master.MasterFileSystem.createInitialFileSystemLayout(MasterFileSystem.java:153)
at org.apache.hadoop.hbase.master.MasterFileSystem.<init>(MasterFileSystem.java:129)
at org.apache.hadoop.hbase.master.HMaster.finishInitialization(HMaster.java:800)
at org.apache.hadoop.hbase.master.HMaster.run(HMaster.java:605)
at java.lang.Thread.run(Thread.java:744)从什么log中可以发现可能是hbase.version文件消失了!我看很多网友的做法是先把/hbase清理调,然后重启就好了,但是以前的数据就丢失了,这有点不科学。于是我:bin/hadoop fs -ls /hbase
发现/hbase/hbase.version确实已经消失了,这才恍然大悟,原来是之前的这个文件可能被损坏了,去/lost+found目录找确实能找到,但是这个文件似乎出了问题,-ls它也看不到。于是想到一个办法,我做了以下操作:bin/hadoop fs -mv /hbase /hbase.bk重启HBase,这时就生成了/hbase/hbase.version文件,然后:bin/hadoop fs -cp /hbase/hbase.version /hbase.bk/

bin/hadoop fs -rmr /hbase

bin/hadoop fs -mv /hbase.bk /hbase这样再次重启HBase,发现Hbase开始splitting hlogs,数据得以恢复。然后再重建river,状态可以正常了! 查看全部
hbase_image.png
今天在一个内网的测试环境平台,kafka的river插件状态非正常,然后同事只好重建kafka river,river的状态始终无法正常,没有办法,同事对服务还不是很熟悉,我只好帮忙看看了!
 
因为kafka 的river插件作为kafka消息数据的consumers角色,把消费掉的数据,通过Hbase转存储到hdfs中!
如下所示是river对hbase的配置:
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://10.2.2.39:9000/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.master</name>
<value>10.2.2.39:60000</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>10.2.2.56,10.2.2.94,10.2.2.225</value>
</property>
</configuration>
从这可以看出river插件是需要hbase的,然后我执行创建river的命令,tail观看到hbase master的hbase-root-master-hbase1.log如下:
2015-10-14 17:34:13,980 INFO  [master:hbase1:60000] util.FSUtils: Waiting for dfs to exit safe mode...
从log中可以看出hbase在等待hdfs退出安全模式,为什么要等Hdfs退出安全模式呢?那下面就具体看看Hdfs的log中有什么线索,查看Hdfs的Namenode的hadoop-root-namenode-had1.log记录如下:
2015-10-14 17:33:52,283 ERROR org.apache.hadoop.security.UserGroupInformation: PriviledgedActionException as:root (auth:SIMPLE) cause:org.apache.hadoop.hdfs.server.namenode.SafeModeException: Log not rolled. Name node is in safe mode.
运行如下命令等待退出安全模式
bin/hadoop dfsadmin -safemode wait
发现半分钟后没有反映,然后运行如下命令检查hdfs的健康状态
bin/hadoop fsck / 
发现有很多corrupt blocks,不过还好备份数大于1.此时,hdfs需要自动的把备份数增加到2,所以需要对数据进行写操作,必须退出安全模式,于是:
bin/hadoop  dfsadmin -safemode leave
关闭之后等待集群把数据备份好,达到2,耐心等待一段时间吧,看数据量的大小,达到2之后,运行:
bin/hadoop  fsck -move
也可以尝试:执行健康检查,删除损坏掉的block。 bin/hdfs fsck  /  -delete 注意: 这种方式会出现数据丢失,损坏的block会被删掉.

把那些破坏的块移到/lost+found这个目录下面,启动Hbase,发现Hmaster启动之后进程又消失了,查看日志:
2015-10-14 17:48:29,476 FATAL [master:hbase1:60000] master.HMaster: Unhandled exception. Starting shutdown.
org.apache.hadoop.hbase.util.FileSystemVersionException: HBase file layout needs to be upgraded. You have version null and I want version 8. Consult http://hbase.apache.org/book.html for further information about upgrading HBase. Is your hbase.rootdir valid? If so, you may need to run 'hbase hbck -fixVersionFile'.
at org.apache.hadoop.hbase.util.FSUtils.checkVersion(FSUtils.java:600)
at org.apache.hadoop.hbase.master.MasterFileSystem.checkRootDir(MasterFileSystem.java:462)
at org.apache.hadoop.hbase.master.MasterFileSystem.createInitialFileSystemLayout(MasterFileSystem.java:153)
at org.apache.hadoop.hbase.master.MasterFileSystem.<init>(MasterFileSystem.java:129)
at org.apache.hadoop.hbase.master.HMaster.finishInitialization(HMaster.java:800)
at org.apache.hadoop.hbase.master.HMaster.run(HMaster.java:605)
at java.lang.Thread.run(Thread.java:744)
从什么log中可以发现可能是hbase.version文件消失了!我看很多网友的做法是先把/hbase清理调,然后重启就好了,但是以前的数据就丢失了,这有点不科学。于是我:
bin/hadoop fs -ls /hbase
发现/hbase/hbase.version确实已经消失了,这才恍然大悟,原来是之前的这个文件可能被损坏了,去/lost+found目录找确实能找到,但是这个文件似乎出了问题,-ls它也看不到。于是想到一个办法,我做了以下操作:
bin/hadoop fs -mv /hbase /hbase.bk
重启HBase,这时就生成了/hbase/hbase.version文件,然后:
bin/hadoop fs -cp /hbase/hbase.version /hbase.bk/

bin/hadoop fs -rmr /hbase

bin/hadoop fs -mv /hbase.bk /hbase
这样再次重启HBase,发现Hbase开始splitting hlogs,数据得以恢复。然后再重建river,状态可以正常了!

Linux学习入门vmware虚拟机安装视频教程

学习资源OpenSkill 发表了文章 • 0 个评论 • 904 次浏览 • 2015-10-15 00:01 • 来自相关话题

Linux入门学习者,第一关莫过于安装vmware虚拟机,安装属于自己喜欢的Linux开源系统。下面分享的就是vmware虚拟机安装的教学视频! 查看全部
Linux入门学习者,第一关莫过于安装vmware虚拟机,安装属于自己喜欢的Linux开源系统。下面分享的就是vmware虚拟机安装的教学视频!


网民都是自私的

互联网资讯OpenSkill 发表了文章 • 0 个评论 • 897 次浏览 • 2015-10-14 23:44 • 来自相关话题

 视频演讲人:新媒体营销鼓山文化的CEO铜雀叔叔,这位90后的CEO旗下签约了像同道大叔、小野妹学吐槽、五行属二等知名段子手。

虽然整个演讲主题略微松散了一些,可是,毕竟是实战派人物,有不少干货在里面。分享观看! 查看全部
 视频演讲人:新媒体营销鼓山文化的CEO铜雀叔叔,这位90后的CEO旗下签约了像同道大叔、小野妹学吐槽、五行属二等知名段子手。

虽然整个演讲主题略微松散了一些,可是,毕竟是实战派人物,有不少干货在里面。分享观看!


Python深浅拷贝图解

编程语言koyo 发表了文章 • 1 个评论 • 1727 次浏览 • 2015-10-13 21:50 • 来自相关话题

Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果。
下面本文就通过简单的例子介绍一下这些概念之间的差别。

对象赋值

直接看一段代码:will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = will
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]代码的输出为:




 
下面来分析一下这段代码:首先,创建了一个名为will的变量,这个变量指向一个list对象,从第一张图中可以看到所有对象的地址(每次运行,结果可能不同)然后,通过will变量对wilber变量进行赋值,那么wilber变量将指向will变量对应的对象(内存地址),也就是说"wilber is will","wilber is will"可以理解为,Python中,对象的赋值都是进行对象引用(内存地址)传递第三张图中,由于will和wilber指向同一个对象,所以对will的任何修改都会体现在wilber上这里需要注意的一点是,str是不可变类型,所以当修改的时候会替换旧的对象,产生一个新的地址39758496






浅拷贝

下面就来看看浅拷贝的结果:import copy

will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.copy(will)

print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]代码结果为:




分析一下这段代码:首先,依然使用一个will变量,指向一个list类型的对象然后,通过copy模块里面的浅拷贝函数copy(),对will指向的对象进行浅拷贝,然后浅拷贝生成的新对象赋值给wilber变量浅拷贝会创建一个新的对象,这个例子中"wilber is not will"
但是,对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址),也就是说"wilber is will"当对will进行修改的时候由于list的第一个元素是不可变类型,所以will对应的list的第一个元素会使用一个新的对象39758496
但是list的第三个元素是一个可不类型,修改操作不会产生新的对象,所以will的修改结果会相应的反应到wilber上




总结一下,当我们使用下面的操作的时候,会产生浅拷贝的效果:
[]使用切片[:]操作[/][]使用工厂函数(如list/dir/set)[/][]使用copy模块中的copy()函数[/]

深拷贝

最后来看看深拷贝:import copy

will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.deepcopy(will)

print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]代码的结果为:




分析一下这段代码:首先,同样使用一个will变量,指向一个list类型的对象然后,通过copy模块里面的深拷贝函数deepcopy(),对will指向的对象进行深拷贝,然后深拷贝生成的新对象赋值给wilber变量跟浅拷贝类似,深拷贝也会创建一个新的对象,这个例子中"wilber is not will"
但是,对于对象中的元素,深拷贝都会重新生成一份(有特殊情况,下面会说明),而不是简单的使用原始元素的引用(内存地址)
例子中will的第三个元素指向39737304,而wilber的第三个元素是一个全新的对象39773088,也就是说,"wilber[2] is not will[2]"当对will进行修改的时候由于list的第一个元素是不可变类型,所以will对应的list的第一个元素会使用一个新的对象39758496
但是list的第三个元素是一个可不类型,修改操作不会产生新的对象,但是由于”wilber[2] is not will[2]“,所以will的修改不会影响wilber





拷贝的特殊情况

其实,对于拷贝有一些特殊情况:对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有拷贝这一说
也就是说,对于这些类型,"obj is copy.copy(obj)" 、"obj is copy.deepcopy(obj)"如果元祖变量只包含原子类型对象,则不能深拷贝,看下面的例子




总结

 本文介绍了对象的赋值和拷贝,以及它们之间的差异:
[]Python中对象的赋值都是进行对象引用(内存地址)传递[/][]使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.[/][]如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝[/][]对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有被拷贝一说[/][]如果元祖变量只包含原子类型对象,则不能深拷贝,看下面的例子[/]
分享原文地址 查看全部
Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果。
下面本文就通过简单的例子介绍一下这些概念之间的差别。


对象赋值


直接看一段代码:
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = will
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
代码的输出为:
pysq1.jpg

 
下面来分析一下这段代码:
首先,创建了一个名为will的变量,这个变量指向一个list对象,从第一张图中可以看到所有对象的地址(每次运行,结果可能不同)
然后,通过will变量对wilber变量进行赋值,那么wilber变量将指向will变量对应的对象(内存地址),也就是说"wilber is will","wilber is will"
可以理解为,Python中,对象的赋值都是进行对象引用(内存地址)传递
第三张图中,由于will和wilber指向同一个对象,所以对will的任何修改都会体现在wilber上
这里需要注意的一点是,str是不可变类型,所以当修改的时候会替换旧的对象,产生一个新的地址39758496
pysq2.jpg



浅拷贝


下面就来看看浅拷贝的结果:
import copy

will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.copy(will)

print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
代码结果为:
pysq3.jpg

分析一下这段代码:
首先,依然使用一个will变量,指向一个list类型的对象
然后,通过copy模块里面的浅拷贝函数copy(),对will指向的对象进行浅拷贝,然后浅拷贝生成的新对象赋值给wilber变量
浅拷贝会创建一个新的对象,这个例子中"wilber is not will"
但是,对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址),也就是说"wilber is will"
当对will进行修改的时候
由于list的第一个元素是不可变类型,所以will对应的list的第一个元素会使用一个新的对象39758496
但是list的第三个元素是一个可不类型,修改操作不会产生新的对象,所以will的修改结果会相应的反应到wilber上
pysq4.jpg

总结一下,当我们使用下面的操作的时候,会产生浅拷贝的效果:
    []使用切片[:]操作[/][]使用工厂函数(如list/dir/set)[/][]使用copy模块中的copy()函数[/]


深拷贝


最后来看看深拷贝:
import copy

will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.deepcopy(will)

print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
代码的结果为:
pysq5.jpg

分析一下这段代码:
首先,同样使用一个will变量,指向一个list类型的对象
然后,通过copy模块里面的深拷贝函数deepcopy(),对will指向的对象进行深拷贝,然后深拷贝生成的新对象赋值给wilber变量
跟浅拷贝类似,深拷贝也会创建一个新的对象,这个例子中"wilber is not will"
但是,对于对象中的元素,深拷贝都会重新生成一份(有特殊情况,下面会说明),而不是简单的使用原始元素的引用(内存地址)
例子中will的第三个元素指向39737304,而wilber的第三个元素是一个全新的对象39773088,也就是说,"wilber[2] is not will[2]"
当对will进行修改的时候
由于list的第一个元素是不可变类型,所以will对应的list的第一个元素会使用一个新的对象39758496
但是list的第三个元素是一个可不类型,修改操作不会产生新的对象,但是由于”wilber[2] is not will[2]“,所以will的修改不会影响wilber
pysq6.jpg


拷贝的特殊情况


其实,对于拷贝有一些特殊情况:
对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有拷贝这一说
也就是说,对于这些类型,"obj is copy.copy(obj)" 、"obj is copy.deepcopy(obj)"
如果元祖变量只包含原子类型对象,则不能深拷贝,看下面的例子
pysq7.jpg


总结


 本文介绍了对象的赋值和拷贝,以及它们之间的差异:
    []Python中对象的赋值都是进行对象引用(内存地址)传递[/][]使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.[/][]如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝[/][]对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有被拷贝一说[/][]如果元祖变量只包含原子类型对象,则不能深拷贝,看下面的例子[/]

分享原文地址

configure: error: no acceptable C compiler found in $PATH

运维技术采菊篱下 回复了问题 • 3 人关注 • 1 个回复 • 1631 次浏览 • 2015-10-13 19:55 • 来自相关话题

Ansible常用模块介绍

运维技术采菊篱下 发表了文章 • 0 个评论 • 3833 次浏览 • 2015-10-12 19:56 • 来自相关话题

之前文章http://openskill.cn/article/120已经介绍了what is ansible?下面给大家介绍介绍ansible常用的几个模块
 
Ansible通过模块的方式来完成一些远程的管理工作。可以通过ansible-doc -l查看所有模块,可以使用ansible-doc -s module来查看某个模块的参数具体用法,也可以使用ansible-doc help module来查看该模块更详细的信息。
 

setup

可以用来收集远程主机的一些基本信息:
ansible -i /etc/ansible/hosts test -m setup

ping

可以用来测试远程主机的运行状态:
ansible test -m ping

file

设置文件的属性
file模块包含如下选项:
force:需要在两种情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
group:定义文件/目录的属组
mode:定义文件/目录的权限
owner:定义文件/目录的属主
path:必选项,定义文件/目录的路径
recurse:递归的设置文件的属性,只对目录有效
src:要被链接的源文件的路径,只应用于state=link的情况
dest:被链接到的路径,只应用于state=link的情况
state:
directory:如果目录不存在,创建目录
file:即使文件不存在,也不会被创建
link:创建软链接
hard:创建硬链接
touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
absent:删除目录、文件或者取消链接文件
示例:
ansible test -m file -a "src=/etc/fstab dest=/tmp/fstab state=link"
ansible test -m file -a "path=/tmp/fstab state=absent"
ansible test -m file -a "path=/tmp/test state=touch"
ansible test -m file -a "path=/tmp/test state=directory"
ansible test -m file -a "path=/tmp/testd state=directory owner=root group=root mode=777"

copy

复制文件到远程主机
copy模块包含如下选项:
backup:在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no
content:用于替代"src",可以直接设定指定文件的值
dest:必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录
directory_mode:递归的设定目录的权限,默认为系统默认权限
force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes
others:所有的file模块里的选项都可以在这里使用
src:要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync。
validate :The validation command to run before copying into place. The path to the file to validate is passed in via '%s' which must be present as in the visudo example below.
示例:
ansible test -m copy -a "src=/srv/myfiles/foo.conf dest=/etc/foo.conf owner=foo group=foo mode=0644"
ansible test -m copy -a "src=/mine/ntp.conf dest=/etc/ntp.conf owner=root group=root mode=644 backup=yes"
ansible test -m copy -a "src=/mine/sudoers dest=/etc/sudoers validate='visudo -cf %s'"

command

在远程主机上执行命令
command模块包含如下选项:
creates:一个文件名,当该文件存在,则该命令不执行
free_form:要执行的linux指令
chdir:在执行指令之前,先切换到该指定的目录
removes:一个文件名,当该文件不存在,则该选项不执行
executable:切换shell来执行指令,该执行路径必须是一个绝对路径
示例:
ansible test -a "ls /root"

shell

切换到某个shell执行指定的指令,参数与command相同。
示例:
ansible test -m shell -a "somescript.sh >> somelog.txt"

service

用于管理服务
该模块包含如下选项:
arguments:给命令行提供一些选项
enabled:是否开机启动 yes|no
name:必选项,服务名称
pattern:定义一个模式,如果通过status指令来查看服务的状态时,没有响应,就会通过ps指令在进程中根据该模式进行查找,如果匹配到,则认为该服务依然在运行
runlevel:运行级别
sleep:如果执行了restarted,在则stop和start之间沉睡几秒钟
state:对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded)
示例:
ansible test -m service -a "name=httpd state=started enabled=yes"
ansible test -m service -a "name=foo pattern=/usr/bin/foo state=started"
ansible test -m service -a "name=network state=restarted args=eth0"

cron

用于管理计划任务
包含如下选项:
backup:对远程主机上的原任务计划内容修改之前做备份
cron_file:如果指定该选项,则用该文件替换远程主机上的cron.d目录下的用户的任务计划
day:日(1-31,[i],[/i]/2,……)
hour:小时(0-23,[i],[/i]/2,……)
minute:分钟(0-59,[i],[/i]/2,……)
month:月(1-12,[i],[/i]/2,……)
weekday:周(0-7,*,……)
job:要执行的任务,依赖于state=present
name:该任务的描述
special_time:指定什么时候执行,参数:reboot,yearly,annually,monthly,weekly,daily,hourly
state:确认该任务计划是创建还是删除
user:以哪个用户的身份执行
示例:
ansible test -m cron -a 'name="check dirs" hour="5,2" job="ls -alh > /dev/null"'
ansible test -m cron -a 'name="a job for reboot" special_time=reboot job="/some/job.sh"'
ansible test -m cron -a 'name="yum autoupdate" weekday="2" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=ansible_yum-autoupdate'
ansilbe test -m cron -a 'cron_file=ansible_yum-autoupdate state=absent'

filesystem

在块设备上创建文件系统
选项:
dev:目标块设备
force:在一个已有文件系统的设备上强制创建
fstype:文件系统的类型
opts:传递给mkfs命令的选项

user

管理用户
home:
groups:
uid
password:
name:
createhome:
system:
remove:
state:
shell:
需要特别说明的是,password后面指定的密码不能是明文,后面这一串密码会被直接传送到被管理主机的/etc/shadow文件中,而登陆的时候输入的密码会被hash加密以后再去与/etc/shadow中存放的密码去做对比,会出现不一致的现象。所以需要先将密码字符串进行加密处理:openssl passwd -salt -1 "123456",然后将得到的字符串放到password中即可。

synchronize

使用rsync同步文件
archive
checksum
delete
dest
src
dest_port
existing_only: skip createing new files on receiver
links
owner
mode:(push, pull)
recursive
rsync_path
times:Preserve modification times
示例:
src=some/relative/path dest=/some/absolute/path rsync_path="sudo rsync"
src=some/relative/path dest=/some/absolute/path archive=no links=yes
src=some/relative/path dest=/some/absolute/path checksum=yes times=no
src=/tmp/helloworld dest=/var/www/helloword rsync_opts=--no-motd,--exclude=.git mode=pull

mount

配置挂载点
选项:
dump
fstype:必选项,挂载文件的类型
name:必选项,挂载点
opts:传递给mount命令的参数
passno
src:必选项,要挂载的文件
state:必选项
present:只处理fstab中的配置
absent:删除挂载点
mounted:自动创建挂载点并挂载之
umounted:卸载
示例:
name=/mnt/dvd src=/dev/sr0 fstype=iso9660 opts=ro state=present
name=/srv/disk src='LABEL=SOME_LABEL' state=present
name=/home src='UUID=b3e48f45-f933-4c8e-a700-22a159ec9077' opts=noatime state=present

ansible test -a 'dd if=/dev/zero of=/disk.img bs=4k count=1024'
ansible test -a 'losetup /dev/loop0 /disk.img'
ansible test -m filesystem 'fstype=ext4 force=yes opts=-F dev=/dev/loop0'
ansible test -m mount 'name=/mnt src=/dev/loop0 fstype=ext4 state=mounted opts=rw'

raw

类似command,可以传递管道原文地址:http://devopsh.com/774.html  查看全部
之前文章http://openskill.cn/article/120已经介绍了what is ansible?下面给大家介绍介绍ansible常用的几个模块
 
Ansible通过模块的方式来完成一些远程的管理工作。可以通过ansible-doc -l查看所有模块,可以使用ansible-doc -s module来查看某个模块的参数具体用法,也可以使用ansible-doc help module来查看该模块更详细的信息。
 


setup


可以用来收集远程主机的一些基本信息:
ansible -i /etc/ansible/hosts test -m setup


ping


可以用来测试远程主机的运行状态:
ansible test -m ping


file


设置文件的属性
file模块包含如下选项:
force:需要在两种情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
group:定义文件/目录的属组
mode:定义文件/目录的权限
owner:定义文件/目录的属主
path:必选项,定义文件/目录的路径
recurse:递归的设置文件的属性,只对目录有效
src:要被链接的源文件的路径,只应用于state=link的情况
dest:被链接到的路径,只应用于state=link的情况
state:
directory:如果目录不存在,创建目录
file:即使文件不存在,也不会被创建
link:创建软链接
hard:创建硬链接
touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
absent:删除目录、文件或者取消链接文件
示例:
ansible test -m file -a "src=/etc/fstab dest=/tmp/fstab state=link"
ansible test -m file -a "path=/tmp/fstab state=absent"
ansible test -m file -a "path=/tmp/test state=touch"
ansible test -m file -a "path=/tmp/test state=directory"
ansible test -m file -a "path=/tmp/testd state=directory owner=root group=root mode=777"


copy


复制文件到远程主机
copy模块包含如下选项:
backup:在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no
content:用于替代"src",可以直接设定指定文件的值
dest:必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录
directory_mode:递归的设定目录的权限,默认为系统默认权限
force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes
others:所有的file模块里的选项都可以在这里使用
src:要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用"/"来结尾,则只复制目录里的内容,如果没有使用"/"来结尾,则包含目录在内的整个内容全部复制,类似于rsync。
validate :The validation command to run before copying into place. The path to the file to validate is passed in via '%s' which must be present as in the visudo example below.
示例:
ansible test -m copy -a "src=/srv/myfiles/foo.conf dest=/etc/foo.conf owner=foo group=foo mode=0644"
ansible test -m copy -a "src=/mine/ntp.conf dest=/etc/ntp.conf owner=root group=root mode=644 backup=yes"
ansible test -m copy -a "src=/mine/sudoers dest=/etc/sudoers validate='visudo -cf %s'"


command


在远程主机上执行命令
command模块包含如下选项:
creates:一个文件名,当该文件存在,则该命令不执行
free_form:要执行的linux指令
chdir:在执行指令之前,先切换到该指定的目录
removes:一个文件名,当该文件不存在,则该选项不执行
executable:切换shell来执行指令,该执行路径必须是一个绝对路径
示例:
ansible test -a "ls /root"


shell


切换到某个shell执行指定的指令,参数与command相同。
示例:
ansible test -m shell -a "somescript.sh >> somelog.txt"


service


用于管理服务
该模块包含如下选项:
arguments:给命令行提供一些选项
enabled:是否开机启动 yes|no
name:必选项,服务名称
pattern:定义一个模式,如果通过status指令来查看服务的状态时,没有响应,就会通过ps指令在进程中根据该模式进行查找,如果匹配到,则认为该服务依然在运行
runlevel:运行级别
sleep:如果执行了restarted,在则stop和start之间沉睡几秒钟
state:对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded)
示例:
ansible test -m service -a "name=httpd state=started enabled=yes"
ansible test -m service -a "name=foo pattern=/usr/bin/foo state=started"
ansible test -m service -a "name=network state=restarted args=eth0"


cron


用于管理计划任务
包含如下选项:
backup:对远程主机上的原任务计划内容修改之前做备份
cron_file:如果指定该选项,则用该文件替换远程主机上的cron.d目录下的用户的任务计划
day:日(1-31,[i],[/i]/2,……)
hour:小时(0-23,[i],[/i]/2,……)
minute:分钟(0-59,[i],[/i]/2,……)
month:月(1-12,[i],[/i]/2,……)
weekday:周(0-7,*,……)
job:要执行的任务,依赖于state=present
name:该任务的描述
special_time:指定什么时候执行,参数:reboot,yearly,annually,monthly,weekly,daily,hourly
state:确认该任务计划是创建还是删除
user:以哪个用户的身份执行
示例:
ansible test -m cron -a 'name="check dirs" hour="5,2" job="ls -alh > /dev/null"'
ansible test -m cron -a 'name="a job for reboot" special_time=reboot job="/some/job.sh"'
ansible test -m cron -a 'name="yum autoupdate" weekday="2" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=ansible_yum-autoupdate'
ansilbe test -m cron -a 'cron_file=ansible_yum-autoupdate state=absent'


filesystem


在块设备上创建文件系统
选项:
dev:目标块设备
force:在一个已有文件系统的设备上强制创建
fstype:文件系统的类型
opts:传递给mkfs命令的选项


user


管理用户
home:
groups:
uid
password:
name:
createhome:
system:
remove:
state:
shell:
需要特别说明的是,password后面指定的密码不能是明文,后面这一串密码会被直接传送到被管理主机的/etc/shadow文件中,而登陆的时候输入的密码会被hash加密以后再去与/etc/shadow中存放的密码去做对比,会出现不一致的现象。所以需要先将密码字符串进行加密处理:openssl passwd -salt -1 "123456",然后将得到的字符串放到password中即可。


synchronize


使用rsync同步文件
archive
checksum
delete
dest
src
dest_port
existing_only: skip createing new files on receiver
links
owner
mode:(push, pull)
recursive
rsync_path
times:Preserve modification times
示例:
src=some/relative/path dest=/some/absolute/path rsync_path="sudo rsync"
src=some/relative/path dest=/some/absolute/path archive=no links=yes
src=some/relative/path dest=/some/absolute/path checksum=yes times=no
src=/tmp/helloworld dest=/var/www/helloword rsync_opts=--no-motd,--exclude=.git mode=pull


mount


配置挂载点
选项:
dump
fstype:必选项,挂载文件的类型
name:必选项,挂载点
opts:传递给mount命令的参数
passno
src:必选项,要挂载的文件
state:必选项
present:只处理fstab中的配置
absent:删除挂载点
mounted:自动创建挂载点并挂载之
umounted:卸载
示例:
name=/mnt/dvd src=/dev/sr0 fstype=iso9660 opts=ro state=present
name=/srv/disk src='LABEL=SOME_LABEL' state=present
name=/home src='UUID=b3e48f45-f933-4c8e-a700-22a159ec9077' opts=noatime state=present

ansible test -a 'dd if=/dev/zero of=/disk.img bs=4k count=1024'
ansible test -a 'losetup /dev/loop0 /disk.img'
ansible test -m filesystem 'fstype=ext4 force=yes opts=-F dev=/dev/loop0'
ansible test -m mount 'name=/mnt src=/dev/loop0 fstype=ext4 state=mounted opts=rw'


raw


类似command,可以传递管道
原文地址:http://devopsh.com/774.html 

docker与虚拟机性能比较

大数据/云计算Geek小A 发表了文章 • 0 个评论 • 2600 次浏览 • 2015-10-12 19:14 • 来自相关话题

概要

docker是近年来新兴的虚拟化工具,它可以和虚拟机一样实现资源和系统环境的隔离。本文将主要根据IBM发表的研究报告,论述docker与传统虚拟化方式的不同之处,并比较物理机、docker容器、虚拟机三者的性能差异及差异产生的原理。

docker与虚拟机实现原理比较

如下图分别是虚拟机与docker的实现框架。



比较两图的差异,左图虚拟机的Guest OS层和Hypervisor层在docker中被Docker Engine层所替代。虚拟机的Guest OS即为虚拟机安装的操作系统,它是一个完整操作系统内核;虚拟机的Hypervisor层可以简单理解为一个硬件虚拟化平台,它在Host OS是以内核态的驱动存在的。
 虚拟机实现资源隔离的方法是利用独立的OS,并利用Hypervisor虚拟化CPU、内存、IO设备等实现的。例如,为了虚拟CPU,Hypervisor会为每个虚拟的CPU创建一个数据结构,模拟CPU的全部寄存器的值,在适当的时候跟踪并修改这些值。需要指出的是在大多数情况下,虚拟机软件代码是直接跑在硬件上的,而不需要Hypervisor介入。只有在一些权限高的请求下,Guest OS需要运行内核态修改CPU的寄存器数据,Hypervisor会介入,修改并维护虚拟的CPU状态。

Hypervisor虚拟化内存的方法是创建一个shadow page table。正常的情况下,一个page table可以用来实现从虚拟内存到物理内存的翻译。在虚拟化的情况下,由于所谓的物理内存仍然是虚拟的,因此shadow page table就要做到:虚拟内存->虚拟的物理内存->真正的物理内存。

对于IO设备虚拟化,当Hypervisor接到page fault,并发现实际上虚拟的物理内存地址对应的是一个I/O设备,Hypervisor就用软件模拟这个设备的工作情况,并返回。比如当CPU想要写磁盘时,Hypervisor就把相应的数据写到一个host OS的文件上,这个文件实际上就模拟了虚拟的磁盘。
对比虚拟机实现资源和环境隔离的方案,docker就显得简练很多。docker Engine可以简单看成对Linux的NameSpace、Cgroup、镜像管理文件系统操作的封装。docker并没有和虚拟机一样利用一个完全独立的Guest OS实现环境隔离,它利用的是目前Linux内核本身支持的容器方式实现资源和环境隔离。简单的说,docker利用namespace实现系统环境的隔离;利用Cgroup实现资源限制;利用镜像实现根目录环境的隔离。通过docker和虚拟机实现原理的比较,我们大致可以得出一些结论:(1)docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有优势,具体的效率对比在下几个小节里给出。在IO设备虚拟化上,docker的镜像管理有多种方案,比如利用Aufs文件系统或者Device Mapper实现docker的文件管理,各种实现方案的效率略有不同。(2)docker利用的是宿主机的内核,而不需要Guest OS。因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。我们知道,引导、加载操作系统内核是一个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,这个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了这个过程,因此新建一个docker容器只需要几秒钟。另外,现代操作系统是复杂的系统,在一台物理机上新增加一个操作系统的资源开销是比较大的,因此,docker对比虚拟机在资源消耗上也占有比较大的优势。事实上,在一台物理机上我们可以很容易建立成百上千的容器,而只能建立几个虚拟机。

docker与虚拟机计算效率比较

在上一节我们从原理的角度推测docker应当在CPU和内存的利用效率上比虚拟机高。在这一节我们将根据IBM发表的论文给出的数据进行分析。以下的数据均是在IBM x3650 M4服务器测得,其主要的硬件参数是: (1)2颗英特尔xeon E5-2655 处理器,主频2.4-3.0 GHz。每颗处理器有8个核,因此总共有16个核。(2)256 GB RAM.在测试中是通过运算Linpack程序来获得计算能力数据的。结果如下图所示: 



图中从左往右分别是物理机、docker和虚拟机的计算能力数据。可见docker相对于物理机其计算能力几乎没有损耗,而虚拟机对比物理机则有着非常明显的损耗。虚拟机的计算能力损耗在50%左右。 为什么会有这么大的性能损耗呢?一方面是因为虚拟机增加了一层虚拟硬件层,运行在虚拟机上的应用程序在进行数值计算时是运行在Hypervisor虚拟的CPU上的;另外一方面是由于计算程序本身的特性导致的差异。虚拟机虚拟的cpu架构不同于实际cpu架构,数值计算程序一般针对特定的cpu架构有一定的优化措施,虚拟化使这些措施作废,甚至起到反效果。比如对于本次实验的平台,实际的CPU架构是2块物理CPU,每块CPU拥有16个核,共32个核,采用的是NUMA架构;而虚拟机则将CPU虚拟化成一块拥有32个核的CPU。这就导致了计算程序在进行计算时无法根据实际的CPU架构进行优化,大大减低了计算效率。

docker与虚拟机内存访问效率比较

内存访问效率的比较相对比较复杂一点,主要是内存访问有多种场景: (1)大批量的,连续地址块的内存数据读写。这种测试环境下得到的性能数据是内存带宽,性能瓶颈主要在内存芯片的性能上; (2)随机内存访问性能。这种测试环境下的性能数据主要与内存带宽、cache的命中率和虚拟地址与物理地址转换的效率等因素有关。以下将主要针对这两种内存访问场景进行分析。在分析之前我们先概要说明一下docker和虚拟机的内存访问模型差异。下图是docker与虚拟机内存访问模型: 



可见在应用程序内存访问上,虚拟机的应用程序要进行2次的虚拟内存到物理内存的映射,读写内存的代价比docker的应用程序高。下图是场景(1)的测试数据,即内存带宽数据。左图是程序运行在一块CPU(即8核)上的数据,右图是程序运行在2块CPU(即16核)上的数据。单位均为GB/s。 







从图中数据可以看出,在内存带宽性能上docker与虚拟机的性能差异并不大。这是因为在内存带宽测试中,读写的内存地址是连续的,大批量的,内核对这种操作会进行优化(数据预存取)。因此虚拟内存到物理内存的映射次数比较少,性能瓶颈主要在物理内存的读写速度上,因此这种情况docker和虚拟机的测试性能差别不大; 内存带宽测试中docker与虚拟机内存访问性能差异不大的原因是由于内存带宽测试中需要进行虚拟地址到物理地址的映射次数比较少。根据这个假设,我们推测,当进行随机内存访问测试时这两者的性能差距将会变大,因为随机内存访问测试中需要进行虚拟内存地址到物理内存地址的映射次数将会变多。结果如下图所示:







1图是程序运行在一个CPU上的数据,右图是程序运行在2块CPU上的数据。从左图可以看出,确实如我们所预测的,在随机内存访问性能上容器与虚拟机的性能差距变得比较明显,容器的内存访问性能明显比虚拟机优秀;但出乎我们意料的是在2块CPU上运行测试程序时容器与虚拟机的随机内存访问性能的差距却又变的不明显。针对这个现象,IBM的论文给出了一个合理解释。这是因为当有2块CPU同时对内存进行访问时,内存读写的控制将会变得比较复杂,因为两块CPU可能同时读写同一个地址的数据,需要对内存数据进行一些同步操作,从而导致内存读写性能的损耗。这种损耗即使对于物理机也是存在的,可以看出右图的内存访问性能数据是低于左图的。2块CPU对内存读写性能的损耗影响是非常大的,这个损耗占据的比例远大于虚拟机和docker由于内存访问模型的不同产生的差异,因此在右图中docker与虚拟机的随机内存访问性能上我们看不出明显差异。

docker与虚拟机启动时间及资源耗费比较

上面两个小节主要从运行在docker里的程序和运行在虚拟机里的程序进行性能比较。事实上,docker之所以如此受到开发者关注的另外一个重要原因是启动docker的系统代价比启动一台虚拟机的代价要低得多:无论从启动时间还是从启动资源耗费角度来说。docker直接利用宿主机的系统内核,避免了虚拟机启动时所需的系统引导时间和操作系统运行的资源消耗。利用docker能在几秒钟之内启动大量的容器,这是虚拟机无法办到的。快速启动、低系统资源消耗的优点使docker在弹性云平台和自动运维系统方面有着很好的应用前景。

docker的劣势

前面的内容主要论述docker相对于虚拟机的优势,但docker也不是完美的系统。相对于虚拟机,docker还存在着以下几个缺点:1.资源隔离方面不如虚拟机,docker是利用cgroup实现资源限制的,只能限制资源消耗的最大值,而不能隔绝其他程序占用自己的资源。2.安全性问题。docker目前并不能分辨具体执行指令的用户,只要一个用户拥有执行docker的权限,那么他就可以对docker的容器进行所有操作,不管该容器是否是由该用户创建。比如A和B都拥有执行docker的权限,由于docker的server端并不会具体判断docker cline是由哪个用户发起的,A可以删除B创建的容器,存在一定的安全风险。 3.docker目前还在版本的快速更新中,细节功能调整比较大。一些核心模块依赖于高版本内核,存在版本兼容问题

原文作者:chenbiaolong
 
 
分享原文地址:http://blog.csdn.net/cbl709/article/details/43955687 查看全部


概要


docker是近年来新兴的虚拟化工具,它可以和虚拟机一样实现资源和系统环境的隔离。本文将主要根据IBM发表的研究报告,论述docker与传统虚拟化方式的不同之处,并比较物理机、docker容器、虚拟机三者的性能差异及差异产生的原理。 


docker与虚拟机实现原理比较


如下图分别是虚拟机与docker的实现框架。
dvk1.png
比较两图的差异,左图虚拟机的Guest OS层和Hypervisor层在docker中被Docker Engine层所替代。虚拟机的Guest OS即为虚拟机安装的操作系统,它是一个完整操作系统内核;虚拟机的Hypervisor层可以简单理解为一个硬件虚拟化平台,它在Host OS是以内核态的驱动存在的。
 
虚拟机实现资源隔离的方法是利用独立的OS,并利用Hypervisor虚拟化CPU、内存、IO设备等实现的。例如,为了虚拟CPU,Hypervisor会为每个虚拟的CPU创建一个数据结构,模拟CPU的全部寄存器的值,在适当的时候跟踪并修改这些值。需要指出的是在大多数情况下,虚拟机软件代码是直接跑在硬件上的,而不需要Hypervisor介入。只有在一些权限高的请求下,Guest OS需要运行内核态修改CPU的寄存器数据,Hypervisor会介入,修改并维护虚拟的CPU状态。 

Hypervisor虚拟化内存的方法是创建一个shadow page table。正常的情况下,一个page table可以用来实现从虚拟内存到物理内存的翻译。在虚拟化的情况下,由于所谓的物理内存仍然是虚拟的,因此shadow page table就要做到:虚拟内存->虚拟的物理内存->真正的物理内存。

对于IO设备虚拟化,当Hypervisor接到page fault,并发现实际上虚拟的物理内存地址对应的是一个I/O设备,Hypervisor就用软件模拟这个设备的工作情况,并返回。比如当CPU想要写磁盘时,Hypervisor就把相应的数据写到一个host OS的文件上,这个文件实际上就模拟了虚拟的磁盘。
对比虚拟机实现资源和环境隔离的方案,docker就显得简练很多。docker Engine可以简单看成对Linux的NameSpace、Cgroup、镜像管理文件系统操作的封装。docker并没有和虚拟机一样利用一个完全独立的Guest OS实现环境隔离,它利用的是目前Linux内核本身支持的容器方式实现资源和环境隔离。简单的说,docker利用namespace实现系统环境的隔离;利用Cgroup实现资源限制;利用镜像实现根目录环境的隔离。
通过docker和虚拟机实现原理的比较,我们大致可以得出一些结论:
(1)docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有优势,具体的效率对比在下几个小节里给出。在IO设备虚拟化上,docker的镜像管理有多种方案,比如利用Aufs文件系统或者Device Mapper实现docker的文件管理,各种实现方案的效率略有不同。
(2)docker利用的是宿主机的内核,而不需要Guest OS。因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。我们知道,引导、加载操作系统内核是一个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,这个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了这个过程,因此新建一个docker容器只需要几秒钟。另外,现代操作系统是复杂的系统,在一台物理机上新增加一个操作系统的资源开销是比较大的,因此,docker对比虚拟机在资源消耗上也占有比较大的优势。事实上,在一台物理机上我们可以很容易建立成百上千的容器,而只能建立几个虚拟机。


docker与虚拟机计算效率比较


在上一节我们从原理的角度推测docker应当在CPU和内存的利用效率上比虚拟机高。在这一节我们将根据IBM发表的论文给出的数据进行分析。以下的数据均是在IBM x3650 M4服务器测得,其主要的硬件参数是: 
(1)2颗英特尔xeon E5-2655 处理器,主频2.4-3.0 GHz。每颗处理器有8个核,因此总共有16个核。
(2)256 GB RAM.
在测试中是通过运算Linpack程序来获得计算能力数据的。结果如下图所示: 
dvk2.png
图中从左往右分别是物理机、docker和虚拟机的计算能力数据。可见docker相对于物理机其计算能力几乎没有损耗,而虚拟机对比物理机则有着非常明显的损耗。虚拟机的计算能力损耗在50%左右。 
为什么会有这么大的性能损耗呢?一方面是因为虚拟机增加了一层虚拟硬件层,运行在虚拟机上的应用程序在进行数值计算时是运行在Hypervisor虚拟的CPU上的;另外一方面是由于计算程序本身的特性导致的差异。虚拟机虚拟的cpu架构不同于实际cpu架构,数值计算程序一般针对特定的cpu架构有一定的优化措施,虚拟化使这些措施作废,甚至起到反效果。
比如对于本次实验的平台,实际的CPU架构是2块物理CPU,每块CPU拥有16个核,共32个核,采用的是NUMA架构;而虚拟机则将CPU虚拟化成一块拥有32个核的CPU。这就导致了计算程序在进行计算时无法根据实际的CPU架构进行优化,大大减低了计算效率。


docker与虚拟机内存访问效率比较


内存访问效率的比较相对比较复杂一点,主要是内存访问有多种场景: 
(1)大批量的,连续地址块的内存数据读写。这种测试环境下得到的性能数据是内存带宽,性能瓶颈主要在内存芯片的性能上; 
(2)随机内存访问性能。这种测试环境下的性能数据主要与内存带宽、cache的命中率和虚拟地址与物理地址转换的效率等因素有关。
以下将主要针对这两种内存访问场景进行分析。在分析之前我们先概要说明一下docker和虚拟机的内存访问模型差异。下图是docker与虚拟机内存访问模型: 
dvk3.png
可见在应用程序内存访问上,虚拟机的应用程序要进行2次的虚拟内存到物理内存的映射,读写内存的代价比docker的应用程序高。
下图是场景(1)的测试数据,即内存带宽数据。左图是程序运行在一块CPU(即8核)上的数据,右图是程序运行在2块CPU(即16核)上的数据。单位均为GB/s。 
dvk4.png

dvk5.png
从图中数据可以看出,在内存带宽性能上docker与虚拟机的性能差异并不大。这是因为在内存带宽测试中,读写的内存地址是连续的,大批量的,内核对这种操作会进行优化(数据预存取)。因此虚拟内存到物理内存的映射次数比较少,性能瓶颈主要在物理内存的读写速度上,因此这种情况docker和虚拟机的测试性能差别不大; 
内存带宽测试中docker与虚拟机内存访问性能差异不大的原因是由于内存带宽测试中需要进行虚拟地址到物理地址的映射次数比较少。根据这个假设,我们推测,当进行随机内存访问测试时这两者的性能差距将会变大,因为随机内存访问测试中需要进行虚拟内存地址到物理内存地址的映射次数将会变多。
结果如下图所示:
dvk6.png

dvk7.png
1图是程序运行在一个CPU上的数据,右图是程序运行在2块CPU上的数据。从左图可以看出,确实如我们所预测的,在随机内存访问性能上容器与虚拟机的性能差距变得比较明显,容器的内存访问性能明显比虚拟机优秀;但出乎我们意料的是在2块CPU上运行测试程序时容器与虚拟机的随机内存访问性能的差距却又变的不明显。
针对这个现象,IBM的论文给出了一个合理解释。这是因为当有2块CPU同时对内存进行访问时,内存读写的控制将会变得比较复杂,因为两块CPU可能同时读写同一个地址的数据,需要对内存数据进行一些同步操作,从而导致内存读写性能的损耗。这种损耗即使对于物理机也是存在的,可以看出右图的内存访问性能数据是低于左图的。2块CPU对内存读写性能的损耗影响是非常大的,这个损耗占据的比例远大于虚拟机和docker由于内存访问模型的不同产生的差异,因此在右图中docker与虚拟机的随机内存访问性能上我们看不出明显差异。


docker与虚拟机启动时间及资源耗费比较


上面两个小节主要从运行在docker里的程序和运行在虚拟机里的程序进行性能比较。
事实上,docker之所以如此受到开发者关注的另外一个重要原因是启动docker的系统代价比启动一台虚拟机的代价要低得多:无论从启动时间还是从启动资源耗费角度来说。docker直接利用宿主机的系统内核,避免了虚拟机启动时所需的系统引导时间和操作系统运行的资源消耗。利用docker能在几秒钟之内启动大量的容器,这是虚拟机无法办到的。快速启动、低系统资源消耗的优点使docker在弹性云平台和自动运维系统方面有着很好的应用前景。


docker的劣势


前面的内容主要论述docker相对于虚拟机的优势,但docker也不是完美的系统。相对于虚拟机,docker还存在着以下几个缺点:
1.资源隔离方面不如虚拟机,docker是利用cgroup实现资源限制的,只能限制资源消耗的最大值,而不能隔绝其他程序占用自己的资源。
2.安全性问题。docker目前并不能分辨具体执行指令的用户,只要一个用户拥有执行docker的权限,那么他就可以对docker的容器进行所有操作,不管该容器是否是由该用户创建。比如A和B都拥有执行docker的权限,由于docker的server端并不会具体判断docker cline是由哪个用户发起的,A可以删除B创建的容器,存在一定的安全风险。 
3.docker目前还在版本的快速更新中,细节功能调整比较大。一些核心模块依赖于高版本内核,存在版本兼容问题


原文作者:chenbiaolong
 
 
分享原文地址:http://blog.csdn.net/cbl709/article/details/43955687


怎么限制docker容器的磁盘和带宽

大数据/云计算Ansible 回复了问题 • 2 人关注 • 1 个回复 • 2658 次浏览 • 2015-10-12 18:10 • 来自相关话题