石墨烯的引入,既能增强、增韧聚氨酯,有效提升聚氨酯涂层的耐磨、耐刮性、耐热性、耐老化性、抗静电性、电磁屏蔽性和阻燃等性能,提升合成革的等级,又不改变传统的工艺和设备,适合多种合成革的制造。
广泛应用在鞋子、箱包、皮带、汽车内用品,家具用品。
1,扫描电镜看的是样品的局部区域,可能你看到的样品区域刚好就没有石墨烯。
2,你的样品为符合才能,可能在复合材料制备过程中,石墨烯的结构已经被破坏,所以看不到。
3,复合材料中的石墨烯含量本身就极少,需要在SEM下找很多区域,也许能看到。
.基于石墨烯的纳米复合材料在能量储存、液晶器件、电子器件、生物材料、传感材料和催化剂载体等领域展现出许多优良性能,具有广阔的应用前景.目前研究的石墨烯复合材料主要有石墨烯/聚合物复合材料和石墨烯/无机物复合材料两类,其制备方法主要有共混法、溶胶-凝胶法、插层法和原位聚合法.本文将对石墨烯的纳米复合材料及其性能等方面进行简要的综述.
一、基于石墨烯的复合物
利用石墨烯优良的特性与其它材料复合可赋予材料优异的性质.如利用石墨烯较强的机械性能,将其添加到高分子中,可以提高高分子材料的机械性能和导电性能;以石墨烯为载体负载纳米粒子,可以提高这些粒子在催化、传感器、超级电容器等领域中的应用.
1.1 石墨烯与高聚物的复合物
功能化后的石墨烯具有很好的溶液稳定性,适用于制备高性能聚合物复合材料.根据实验研究,如用异氰酸酯改性后的氧化石墨烯分散到聚苯乙烯中,还原处理后就可以得到石墨烯-聚苯乙烯高分子复合物.该复合物具有很好的导电性,添加体积分数为1%的石墨烯时,常温下该复合物的导电率可达0.1S/M,可在导电材料方面得到的应用.
添加石墨烯还可显著影响高聚物的其它性能,如玻璃化转变温度(Tg)、力学和电学性能等.例如在聚丙稀腈中添加质量分数约1%的功能化石墨烯,可使其Tg提高40℃.在聚甲基丙烯酸甲酯(PMMA)中仅添加质量分数0.05%的石墨烯就可以将其Tg提高近30℃.添加石墨烯的PMMA比添加膨胀石墨和碳纳米管的PMMA具有更高的强度、模量以及导电率.在聚乙烯醇(PVA)和PMMA中添加质量分数0.6%的功能化石墨烯后,其弹性模量和硬度有明显的增加.在聚苯胺中添加适量的氧化石墨烯所获得的聚苯胺-氧化石墨烯复合物的电容量(531F/g)比聚苯胺本身的电容量(约为216F/g)大1倍多,且具有较大的拉伸强度(12.6MPa).这些性能为石墨烯-聚苯胺复合物在超级电容器方面的应用创造了条件.
看看下面这篇博文吧:(科学网 - 为什么学生不爱科研)N多学生进校时雄心壮志或者单纯朦胧,对于科研一片美好期许,到毕业时,愁容满面,对于科研唉声叹气。两个方面原因:一是制度方面原因。A:跟着导师申请项目,发现原来申请基金就是靠关系。某学生辛辛苦苦6个月写的一个本子被刷了,上去的是一个跟指南上要求的方向八竿子打不着的一个方向上去了,很郁闷,倒是导师很看得开,宽慰他:都这样,人家关系硬,我们来年再说吧;B:写项目原来就是扯淡。老师让写项目书,总是过完年了让通知写,总是赶急赶忙的写,在老师的压力下,三天就可以写好一个本子,那所谓的创新都是那三天硬憋出来的,其实在自己看来就是扯淡,后来终于明白,申请项目更多的在于关系,写固然重要,但是不是最重要的。C:申请项目,有的项目没有任何的前期工作,也没有任何的前期调研,全凭百度和维基上东西凑出来的任务书,提指标的时候老师让学生提,学生说咋提啊,我都没见过那玩意,全是拍脑袋决策,做的时候也是东搞搞西搞搞,各种不理想,想尽方法,都失败,老师却怪学生的不努力,不聪明,学生彻底绝望。D:项目书下来了,学生接过任务书一看:这项目的80%不都已经完成了么?技术很成熟了,数据实验室也早有了,还有什么搞的。内心感叹:搞科研就是骗国家钱啊。E:项目书下来了,学生接过任务书一看:这问题不是早八百年前就解决了,中国学界连这个问题都没解决,那帮科学家都干啥吃的?可是这个项目怎么能下来呢?传统的名词换个新的提法,貌似很高端,其实啥都没变,这就是所谓的科研?这就是神圣的科研?F:项目书下来了,学生接过任务书一看:这里面的有一些东西,稍微内行的人或者有点专业常识的人一看就知道不可能实现的东西,原理上就行不通,咋做,这项目咋通过的?有高人指点说:既然你们老师有本事拿来,就有本事结题,而且还能很顺利,这个不是你担心的。学生直念,阿弥陀佛阿弥陀佛。。G:学生:我们老板说了,国家的钱最好挣,有个项目,一个试验没做,结题了。H:所谓的科研就是炒菜,人家用个猫做实验,你用个狗,这就是创新?这就是科研?二是老师原因:A:老师让他搭建设备,从零件购,到设备选材,设备调试,价格高了,老板还不同意,就这样,折腾了三年,到第四年开题都没法开。B:老师想发高水平论文,就一直压着他,让他攒数据,攒一篇好的,结果攒成心病。C:大老板想冲院士,明文规定:博士第一年上课,不算,硕博连读的前两年不算。D:实际导师啥也不管,名义导师想冲教授,所有稍好一点的论文一作都是他,这样的话自己基本上就没有论文,毕业都发愁。E:天天去工厂下车间,帮导师出差,毕业的东西基本没做。导师源源不断的接项目,做项目,自己的时间都不在自己的课题上,虽然说的挺好,要抓紧时间做论文,可是老师太贪心了,学生是有限的,项目却像无穷多,你说与你课题无关?不做可以么?在人屋檐下啊。F:老师特别抠,一点小钱也要发票凑,凑不着就不给报,一年下来学生搭进去一两千。没有实验材料了,也是拖着不,总是托关系东家要,西家借,学生看着直寒心,有时候真想算了,这试验费自己掏算了。项目三四个,经费四百万,写项目的时候材料费,检测费十几万几十万的写,SEM动不动就写小时,小时,结果呢,一年的材料费满打满算不到1万块钱,却天天喊穷,做了一年SEM(-块钱一个小时)花了一万块钱嫌多。有的老师跟学生算账算得特明白,5块钱也还给学生(要还的话,50不行么?),虽然不算小气,但是不大气。G:老师人品不好,不人性。学生大年初三来给老师干活,食堂和宿舍都没开(没开是有客观原因的),跟老师说没饭吃,老师说你个锅,我给你报;跟老师说:没地方住,老师说:你就在实验室打地铺吧(学校在东北,冬天)。学生的媳妇在待产了,学生要回家,老师打火车站广播找人。上周跟学生说:你把那个XX的一批样品给处理了,今天看见学生在给别人处理样品,忽然来一句:你这一个星期没做实验了,你自己的活不干了啊,学生直接泪奔。就是抓学生干活,一看见某人在电脑桌前就说,谁谁,咋没去做实验呢?H:老师招学生来,都不知道安排学生来干啥,只知道,我现在有项目,要找学生,招学生来就是为了给干活。结果呢,来了之后哪个学生负责哪一块也都瞎搞,你负责ABC,他负责DEF,ABC这一块前后的关联是什么,核心是什么,目标是什么,全都不知道,就是因为我想做这个加上我需要做这个,于是我就让学生做这个。其实全扯淡,想一出是一出,最后看看学生的毕业论文,这一章讲小米的淀粉营养问题,下一章就讲胡萝卜的胡萝卜素对胡萝卜的生长促进,再下一章就是玉米杆的纤维素燃烧。如果再往前看几届,发现基本上他的每一届学生都有这个问题。I:老师啥也不懂,对于学生交上去的报告提不出新东西,改文章都是改错别字,像什么文章结构层次编排,重要观点的突出强化,理论深度的挖掘,都没有。指导学生也不得力,看看学生交上去的报告,都是写:这周上课了,上了这三门课,这周看文献,列表如下,总共一页纸。有做实验的学生就写,这周做试验了,实验照片贴上去,写个结论,老师也提不出什么新东西,都是讲你这个XRD该怎么标,你这个图要摆放整齐,你讲PPT要看着大家等等。至于说你这个实验说明了什么,我们的目标是什么,下一步干啥,通过什么实验来实现等等都不会提,例会每周开,但是从来都不讨论这些东西。J:导师啥也不懂,然后还啥都管,还特别爱面子,还想学生出好东西,实验室啥都没有。要设备没设备,要前期工作没前期工作,问老师,也只知道从百度上找来的东西,每次讲的都是教材上的东西。一切靠自己,从设备选择构建,到材料购,到工艺确定,到最后出东西,都自己一手搞定。然后此间的失败与艰辛换来的是老师的怒斥,一直也出不来东西。想跟老师讨论一些东西吧,却发现他纯粹是个外行,要学生通过红外确定材料的耐热性;遇到任何问题只有默默的去小木虫。K:喜欢忽悠学生或者威胁学生或者给学生极高的期望与许诺,吓到了学生。跟着我好好干,咋地咋地,发nature啊,直接奖励多少钱;我跟啥啥有合作,跟着,到哪哪上班;不干好,这个月扣掉所有补助(还没干呢,就这么说);不干好,别毕业了;你啊,有潜力,有资质,我们这个项目啊,你要好好干,争取达到啥啥;好好干,争取发NS;L:无法真正的指导学生。跟研一的说:你去写个关于非晶合金的综述,这个太大了,能不能详细点,分开点:这个星期跟学生说:你去看两本非晶合金的书,写个总结上来,重点是啥,然后第二周根据前一周的情况,继续发布这样目的明确的任务,让前后的任务相关联,及时发现学生的不足,并且引道学生提出问题。或者想一出是一出,跟研二学生说:你去做XX问题吧(该问题是工程问题,需要长时间,有一定体积效应的时候才会出现的,普通小试片根本无法模拟),但是过一阵又忘了,这就搞得学生无所适从了。或者第二学期开学一个月了,学生知道自己这个学期要开题,师兄问师弟:你这个学期什么安排,你要开题的。师弟茫然不知,因为老师只跟他指定了方向,具体是啥,啥也没说,学生就这样,熬到快开题了,老师却在催开题报告,于是在重压下,加粘贴三天搞定;或者老师明明将师弟交给师兄带,可是老师却经常绕过师兄下达一些任务,搞得师兄的计划就时常不能执行,最后放弃领导。这是我见到的一些同学跟我讲他们导师的恶劣行径。有人说:那是你选导师没选好,大多数导师见到潜在的学生都是和蔼可亲的,问师兄师姐,很难告诉你真话的,因为说导师好吧,你进来发现不是那么回事,怎么办?师兄弟怎么处?说导师不好吧,自己还想活么?导师真正的适不适合自己,自己自己接触之后才真的知道。有人说换导师?那么容易换?我一个同学换导师,怎么换的,先是找到一个年轻的熟识的老师,他需要学生,尤其特别想要一个博士(帮别人带),于是问他该怎么办,于是那老师各种帮他,一个站在学生的角度,一个站在老师的角度互相找理由,互相驳斥,最后我同学找到的理由是:压力大,身体有病,经常产生幻觉,偶尔神经错乱,经常头疼得厉害,于是那同学最后换导师成功,而且是换到帮他出主意的那个老师那里。(他原来的导师,就是属于K种老师,第一个学期还没过呢,就跟学生说要学生造出一个什么什么设备,要史无前例的的突破,将产业更新)换导师不好换啊,许多学生看到是都很好,可是导师跟导师之间的关系,其实挺复杂,尤其是在一栋楼,一个教研室,一个课题组的,不好搞,不好换啊。有人说:学生应该有主动性,主动去做。可是很多博士却有一个共同的心得:如果你完全听从老师的,你将一事无成,如果完全不听导师的,你将死得很惨,怎么办?听导师的话,做自己的事;有想法赶快做,不要坐等靠;如果自己有想法,指望导师批准后再执行,那是大多扯淡,除非遇到那种什么也不管的导师,他的学生倒是经常看见顺利毕业的多。----------------PS1:说到学生学习的主动性,主动性重要么?重要!真的重要么?不重要。多少老师以自己的蛮横否掉学生的想法。而不是讲道理,摆证据。是学生不基于实际,瞎提想法,老师给否掉的么??大多是做的不是老师想要的罢了,有主动性咋样?你必须是老师想要的主动性,不许乱主动的。PS2:我最喜欢两种导师,一种是什么也不管(包括花钱也不管你咋花),就是每学期开学的时候见学生:又开学了,都怎么样啊,学生们讲了讲,完事,从此以后再也看不到导师,即使找他,也是说:OK,OK,你自己做主吧。要么是那种按照严格的科研套路来:真正的直面问题,实打实的调研,该花的时间一天不能少,该花的钱直接说,实验前,方案详细明了完备,经得起推敲,对于潜在的风险及成本有充分的考虑与估算,所有的指标都是有根据的,不是拍脑袋的,所有的工艺也都是有前期基础和有足够的数据支撑其可行性的。然后由定期或者不定期的汇报,总结与讨论,真正的针对问题,解决问题;有困难,老师也积极的参与,与学生一起努力。对于学生交上来的东西,要真正的提出新的问题和导向。当老师也有不会的时候,也要能向学生学习,比如让学生就某一问题做一总结,这就OK。PS3:我有点理想主义情节的,比如PS2中对第二种老师的要求,时常我自己也感觉过分,但是我觉得搞科研就应该实打实的来,带学生就应该真教,每一阶段给他一个目标,引导他到达自己的目标,同时也让他学会自己提出问题,解决问题。给学生安排适当的项目任务,以此为依托,进行扩展以形成其毕业论文,不会将整个项目依托给一个学生,除非是那种前期基础极其扎实的,在不长的时间内(1年)依样画葫芦就可以完成项目的70%,余下30%有难度,通过努力也可以在余下的2年内完成的项目,学生完成任务后让其自己有发挥,做自己想做的,这个时候他也应该能自己做方案,自己实验了,不要给学生无尽的任务,学生的性和想法得不到发挥。对于需要搭建新设备,不会让学生从零部件购,设备材料选择,结构设计等等最原始的地方零基础起步,是要看到原型机,在原型机上仿制,或者在已经设备上进行改造,添加附件等等方式来改造设备,如果我想从零基础搭建设备,我会让一代代的学生做辅助,一代学生做一点,逐步搭建起来,不然学生真的很苦。PS4:有的老师很累,有的老师很轻松。累的老师又很多种,但轻松的老师大多是,在某一领域活跃了很多年,积累得很多,实验室对于实验体系已经程式化了,学生们已经不需要老师费心了,只需要有一个好的助手(或者兄)来辅助维护这一体系就行。前期工作充实,圈子熟了,拿课题也不困难;对于行业状态了解很深,知道方向,目的也很强。有时候当老师真的很悠哉。每次看到那种早上8点钟就来实验室,晚上9点钟走,没有周末节假日的老师,我就在想:那是生活么?那是人么?那是神经病(年轻老师不在此例)。PS5:非常,很,极其想知道各位老师怎么看待研究生上课的重要性问题。在目前的模式下,研究生上课,在我看来就是扯淡。如果说本科生考60分要滴60滴汗,那么硕士考60分,只要30滴就够了,博士大概不到10滴,有人说或许0滴也可以。看看那些研究生第一年,都美其名曰:我们有课,实际呢,跟本科生一样,甚至还不如本科生,上课了夹个本去上课,下课了本子都不知道扔哪去了,期末了,里非常热闹了。学生们最喜欢那种交论文结课的科目,通过谷,粘贴,一个下午完成好几科,一出成绩都是七八十分,都很开心。请问各位老师,你们学校研究生课挂科的比例多少,高于1%么?有没有不毕业的硕士么?当然说到这里也要说一下,有的学校老师对于研究生的课也是不重视的,甚至上一次课之后,留下一个小论文的作业,然后就再也不上课了。因此,我建议把研究生第一年所有的课都集中在第一个学期上。PS6:有的老师认为自己学生是个科研的料,成果丰富,勤奋进取,思维活跃,是自己的得意门生,可是在现实中他可能非常厌恶科研,我见过的有认为科研就是炒菜,太没意思了;有认为科研就是一帮圈子里的人的游戏,自己只能呵呵;有认为科研就是骗人,每次写论文的背景和意义的时候都是闭着眼默念好几分钟:我这个有意义,有意义,有意义,然后才下笔,才写了两句又面红耳赤了;当然也有人认为搞科研的人前五年太穷了,太苦了,不愿意干的。:PS7:我时常想:喧嚣中的孤独和孤独中的喧嚣你选择哪一个?我有资格选么?一直以来我都期待一种内心平静而充实的生活,每天有计划的做着自己的工作,不紧不慢,下班后还有空去健身,陪家人聊聊天,看看书。早上7点起来,喝杯水,翻两页书,吃个早饭再出门。我们接着上篇文章继续讨论,通常情况下我们不希望,也不允许容器和宿主机看到相同的文件系统,那样的话多个容器实例和宿主机会共享相同的文件系统,隔离性就不存在了,因此我们一般情况下通过给每个容器创建独享的mount命名空间来实现文件系统的隔离。
首先我们来通过例子看看如何赋予进程独享的mount命名空间:在自己的机器上运行sudo unshare --mount sh来启动一个新的sh进程,接着创建文件夹source,并在文件夹中创建文件HELLO;然后我们再创建另外一个文件件target,并且通过命令mount --bind source target来将source文件夹bind到target文件夹,如果我们在target文件夹中运行ls -l命令,就可以看到source文件夹中的文件HELLO。如下是在笔者机器上的输出:
vagrant@vagrant:~$ sudo unshare --mount sh
$ mkdir source
$ touch source/HELLO
$ ls source
HELLO
$ mkdir target
$ ls target
$ mount --bind source target
$ ls target
HELLO
上边的输出符合预期,我们接着通过命令findmnt来看看进程sh中具体有哪些mount,命令运行后会输出结果,你可以看到如下这段输出,也就是我们运行mount命令将源文件夹source和目标文件夹target关联在一起:
$ findmnt target
TARGET SOURCE FSTYPE OPTIONS
/home/vagrant/target
/dev/mapper/vagrant--vg-root[/home/vagrant/source]
ext4 rw,relatime,errors=remount-ro,data=ordered
读者可能会想知道,这个bind是否从宿主机可见。我们如果在宿主机上运行相同的命令findmnt,你会发现根本看不到上边的这个mount信息。我们刚才在sh的进程中继续运行命令findmnt,这次不带任何参数,你会发现会返回很长的一个mount列表。如果进程具备隔离性,是不应该看到宿主机上的全部mount信息的,这显然是有问题的。
如果你还记得我们讨论PID命名空间的情况吗,如果只是通过unmount --pid来把进程加入到一个新的PID命名空间中,我们是无法阻止容器看到宿主机的所有进程信息,因为容器进程中运行ps的时候,其实是请求内核读取/proc文件夹,而对于mount命名空间类似,当我们执行findmnt命令的时候,内核读取文件夹/proc/<PID>/mounts文件并返回。
当我们创建进程的时为进程分配了新的mount命名空间,但是在进程中运行findmnt的时候,使用的仍然是宿主机的/proc文件夹,因此返回的mount信息中包含了进程创建时间点之前宿主机上所有的mount信息,我们可以通过cat进程ID对应的文件来验证:cat /proc/<PID>/mounts。
那么我们如何能让新创建的进程有自己专属的文件系统呢?我们可以通过:1,为容器进程创建新的mount命名空间;2,为进程设置新的root文件系统;3,为进程创建新的proc mount,如下边在笔者的机器运行所示:
vagrant@vagrant:~$ sudo unshare --mount chroot alpine sh
/ $ mount -t proc proc proc
/ $ mount
proc on /proc type proc (rw,relatime)
/ $ mkdir source
/ $ touch source/HELLO
/ $ mkdir target
/ $ mount --bind source target
/ $ mount
proc on /proc type proc (rw,relatime)
/dev/sda1 on /target type ext4 (rw,relatime,data=ordered)
熟悉docker的同学一定有过将宿主机上的某个文件夹挂载到容器中的经验,比如我们要在容器中运行某些应用程序或者读取需要的数据,命令docker run -v <宿主机目录>: <容器目录>..., 本质上当容器的root文件夹系统被加载后,会立即创建容器上的目标目录,然后宿主机上的目录被bind到容器中的目录上,由于每个容器都有自己的mount命名空间,因此通过这种方式挂载到容器中的目录,对其他容器不可见。
有了mount命名空间的知识后,我们继续讨论Network命名空间。网络(Network)命名空间赋予容器专属的网络设备接口和路由表。我们可以通过命令行工具lsns来查看机器上的network命名空间。进程启动可以通过--net来创建新的命名空间,如下边命令的输出所示:
vagrant@vagrant:~$ sudo lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531992 net 93 1 root unassigned /sbin/init
vagrant@vagrant:~$ sudo unshare --net bash
root@vagrant:~$ lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531992 net 92 1 root unassigned /sbin/init
4026532192 net 2 28586 root unassigned bash
当进程运行在专属的network命名空间,如果不做任何配置,进程只能看到回路接口(lo)。我们可以通过ip a来验证,如下是在笔者机器上的输出:
vagrant@vagrant:~$ sudo unshare --net bash
root@myhost:~$ ip a
1: lo: <LOOPBACK>mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
只有loopback回路地址也没有啥用,最简单的容器之间进行相互通信都无法实现。为了让容器能够和外界连接,我们需要给容器进程创建virtual Ethernet网络接口,或者严格来说,我们其实创建了一对虚拟以太网接口。
虚拟以太网接口人如其名,就如同办公室中的电缆一样,将容器的网络命名空间和宿主机上的默认网络命名空间连接了起来。我们在保持前边bash进程的前提下,在宿主机上的另外一个控制台窗口上运行命令:root@vagrant:~$ ip link add ve1 netns 32586 type veth peer name ve2 netns 1 来为进程bash创建一对虚拟以太网接口(进程id是32586),其中:
- ip link add命令告诉宿主机我们要增加一个link
- ve1是虚拟以太网这根电缆的容器进程端的名字
- netns 32586表示ve1这一端插入到进程32586这个进程的网络命名空间中
- type veth表示类型,veth表示虚拟以太网
- peer name ve2表示虚拟以太网电缆另外一端的名称为ve2
- netns 1表示ve2插入到进程号1的网络命名空间
上边的命令运行成功后,我们就可以成功的在容器进程中看到ve1(容器端的虚拟以太网接口),如下是在笔者机器上启动的bash进程中运行ip a看到的输出:
root@vagrant:~$ ip a
1: lo: <LOOPBACK>mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ve1@if3: <BROADCAST,MULTICAST>mtu 1500 qdisc noop state DOWN group ...
link/ether 7a:8a:3f:ba:61:2c brd ff:ff:ff:ff:ff:ff link-netnsid 0
不行的是状态DOWN表明这个接口现在无法使用,为了从宿主机到容器来通,我们需要将这个叫ve1@if3的以太网接口激活,这意味着我们需要同时从宿主机上和容器内将这个两端都激活。首先我们在宿主机上,也就是ve2端将虚拟以太网link激活,运行命令:root@vagrant:~$ ip link set ve2 up,接着我们在容器中,也就是ve1端运行相同的命令后,再次通过ip a查看进程的可见网络接口就会发现状态为UP,在笔者的机器上输出如下:
root@vagrant:~$ ip link set ve1 up
root@vagrant:~$ ip a
1: lo: <LOOPBACK>mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ve1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP>mtu 1500 qdisc noqueue state UP ...
link/ether 7a:8a:3f:ba:61:2c brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::788a:3fff:feba:612c/64 scope link
valid_lft forever preferred_lft forever
眼尖的同学会发现ve1@if3这个接口上根本没有ip地址啊,为了容器进程和宿主机IP数据包相互可达,我们需要在以太网的两端设置响应的IP地址,在容器中运行命令:root@vagrant:~$ ip addr add 192.168.1.100/24 dev ve1来为容器端网络端口设置IP段,同样在宿主机上运行命令:root@vagrant:~$ ip addr add 192.168.1.200/24 dev ve1来为宿主机端的以太网设备配置IP地址段。
当我们分别在两端设置好IP地址后,容器的路由表也会插入相应的路由信息,如下的是笔者在bash进程中运行ip route看到的输出:
root@myhost:~$ ip route
192.168.1.0/24 dev ve1 proto kernel scope link src 192.168.1.200
读者可以实际操作一下,这表路由配置信息就允许我们将IP数据包发送到宿主机。
由于我们在前边的文章中详细介绍过cgroup的原理,因此咱这里就不在累述了,简单来说,cgroup让进程只能看到自己专属的cgroup资源控制文件夹。cgroup命名空间和其他的命名空间比起来,被加入到Linux的时间靠后,大部分命名空间是在linux内核版本3.8被引入,而cgroup命名空间知道内核版本v4.6才被引入。
在Linux操作系统中,进程间可以通过共享内存或者消息队列来进行通信,前提是两个进程必须所属相同的IPC命名空间。通常来说,我们不希望一个运行在一个进程中的应用程序访问另外一个进程的内存,因此大部分情况下进程都有自己独享的IPC命名空间。
我们可以通过ipcmk和ipcs来验证,ipcmk用来创建一个共享内存段,而ipcs用来返回IPC的状态,在笔者的机器上输出如下:
$ ipcmk -M 1000
Shared memory id: 98307
$ ipcs
------ Message Queues --------
key msqid owner perms used-bytes messages
48 | Chapter 4: Container Isolation
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0xad291bee 98307 ubuntu 644 1000 0
------ Semaphore Arrays --------
key semid owner perms nsems
0x000000a7 0 root 600 1
我们可以在启动进程的时候,通过unshare --ipc来给进程创建新的IPC命名空间,然后在进程中运行ipcs后,从返回的结果就可以看到这是一个新的IPC命名空间,没有任何进程间通信的结构。
最后我们来说说User命名空间。User命名空间本质上让进程有自己专属的用户(user)和组(group)视图。user命名空间和PID命名空间类似,只是在新的user命名空间中,宿主机上的user和组信息可以有不同的ID。
从安全的角度看,user命名空间是革命性的, 因为我们可以把容器中的0号用户(root用户)映射到宿主机上的非root用户上,这样即便是恶意攻击者从容器中逃逸,那么在宿主机上也只持有一个权限有限的账户。
但是不幸的是,user命名空间目前还不是太被广泛的使用,Docker上默认为开启user命名空间,并且Kubernetes根本就不支持,不过这个命名空间在kubernetes社区正在积极的被讨论是否加入。
我们来实践一下,在自己机器上通过命令unshare --user bash来启动一个新的bash进程,在进程中运行id命令返回用户信息,如下输出所示:
vagrant@vagrant:~$ unshare --user bash
nobody@vagrant:~$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
nobody@vagrant:~$ echo $$
31196
本质上来说,在新的用户命名空间中,宿主机上的用户1000,在宿主机上的ID是nobody,并且ID是65534,具体来说,用户信息从宿主机映射到进程是通过文件/proc/<pid>/uid_map来完成。感兴趣的同学可以研究一下如何在root用户权限下编辑这个文件。
比如我们为进程31196运行命令sudo echo '0 1000 1' >/proc/31196/uid_map后,用户1000在进程中就有了root权限,我们可以通过运行id命令来验证:
nobody@vagrant:~$ id
uid=0(root) gid=65534(nogroup) groups=65534(nogroup)
root用户在容器进程内部有几乎所有的权限,我们可以通过命令capsh --print | grep Current来验证,输出的很长一串capabilities。咱们在前边的文章介绍过Linux操作系统的capabilities机制,在容器内部,内容允许这个“伪”root用户可以干几乎所有的事情,比如创建命名空间,设置网络等。
如果我们在启动进程的时候需要创建多个新的命名空间,那么一般情况下user命名空间是首先会被创建出来,然后用户会具备root权限,比如我们不通过root权限运行unshare --uts bash会出错,但是运行unshare --uts --user bash不会报错并成功。
注:Docker默认情况下并没有turn on 用户命名空间,主要原因是兼容性问题。比如我们的应用程序在容器中以root权限运行,应用无法监听小于1024的端口,主要原因是容器的root权限没有CAP_NET_BIND_SERVICE能力。
从宿主机的角度来看,虽然我们通常把docker运行起来的应用程序称作“容器实例”,但是从宿主机上看到的更多是“容器化的进程”。运行应用程序的容器实例仍然是Linux操作系统上的一个进程,唯一的区别是这些叫容器的进程只能看到宿主机的一部分,只能访问操作系统文件系统的一部分,只能使用机器的部分资源。
笔者想要强调的是,无论怎么看,运行在Docker中的容器实例是操作系统的一个进程,虽说有自己的进程上下文,但是同一台机器上的进程共享底层的操作系统内核。我们可以同时从宿主机上和容器内部看到应用程序进程,唯一的不同就是进程ID。宿主机上可以看到所有容器进程这个事实决定了容器的隔离边界,从安全的角度来看,如果恶意攻击者攻破了宿主机,那么黑客就有能力影响所有运行在这台机器上的应用程序。
通过这篇文章,读者应该很清楚一个事实,容器和宿主机共享同一个操作系统内核,从安全的角度衍生了新的安全问题。笔者强烈建议将容器进程运行在专属的物理机或者虚拟机上(也就是这些机器上不要跑其他业务负载),原因主要是安全的考虑:
- 当我们使用像kubernetes这样的容器编排平台来部署应用程序,意味着运维人员基本不需要直接登陆到宿主机上。这样安全性也就更好,因为宿主机上只需要跑类似于kubelets和kube proxy这样的插件,攻击面被极大的缩减。
- 我们在设计应用的部署架构时,可以考虑Thin OS,这种定制的OS只包含运行容器应用的必要组件,降低了存在安全漏洞的风险。
- 集群中的宿主机做到immutable,当一台机器故障的时候,我们不是修复这台机器,而是替换这台机器,这样所有机器的安全补丁受统一控制,管理更加容易。
好了,咱们这篇文章就这么多了,下篇文章我们继续讨论容器和虚拟机的差异,这是我们理解容器化部署的基石,敬请期待!
欢迎分享,转载请注明来源:夏雨云
评论列表(0条)