SegmentFault QuanTalk最新的文章
2022-05-02T23:07:22+08:00
https://segmentfault.com/feeds/blogs
https://creativecommons.org/licenses/by-nc-nd/4.0/
ArchLinux Plasma 简洁优雅桌面环境设置
https://segmentfault.com/a/1190000041785884
2022-05-02T23:07:22+08:00
2022-05-02T23:07:22+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<p>一转眼自己使用 ArchLinux 已经 5 年了,期间自己尝试把桌面环境 Plasma 美化了下,用户体验更接近 MacOS。</p><p><img src="/img/bVcZuzX" alt="效果图" title="效果图"></p><h2>预备知识</h2><p>ArchLinux 是 Linux 操作系统的一个发行版,它的特点是简洁、轻量、滚动更新。定制化能力也很高,适合动手能力强的小伙伴。</p><p>而 Plasma 是一个由 KDE 开源社区维护的免费桌面环境,这款桌面环境的定制性也很强,可以自定义主题、应用图标、开机启动画面、窗口样式等。而且大量爱好者贡献了很多优秀插件,直接搜索安装就可以。</p><h2>应用图标</h2><p>最近刚刚换成由设计师 vinceliuice 贡献的图标库 <a href="https://link.segmentfault.com/?enc=uFWQGUXAlqSvGxcYKfmSvA%3D%3D.Hr1ZLppWKznL8DNLOtW0vHNxOt35CTSvXPRP2YR%2BJdzMAZ9D9liNK9QqUYrxDera" rel="nofollow">McmoJave Circles Icon</a>,该图标库模仿了 MacOS 的设计风格,提供了多种配色。而且完全开源,GitHub 链接为 <a href="https://link.segmentfault.com/?enc=rvu%2FNkncT0QyGPyzHeoLDg%3D%3D.sEDOD5IVwXKldVOUXNRCa8QrgffM7kLB4Be%2BONpER1mfU7fMu1AzsnSn6WTv%2FFdR" rel="nofollow">vinceliuice-McMojave-circle</a>。下载该图标库,在<code>设置</code>-<code>外观</code>中选择并应用即可。</p><h2>壁纸</h2><p>自己希望桌面尽可能简洁、壁纸要自然一些,经过 1 个小时的精挑细选,最终选择了下面的图片作为壁纸,<a href="https://link.segmentfault.com/?enc=XpiLdyEIjG49RIDB0RBDkw%3D%3D.Yh7QqfLuXFr7nTOWwNVn6%2FYBrYG%2B0sn6euSauhm3HVOEB0wXECdTYuIlu%2BkC47RU" rel="nofollow">链接在此</a>,需要原图的小伙伴自取。</p><p><img src="/img/remote/1460000041785886" alt="" title=""></p><h2>dock 栏</h2><p>dock 栏使用 KDE 开发的 <a href="https://link.segmentfault.com/?enc=n7DGwAi8aslptn7a8aRBiw%3D%3D.B5pgB6GikPa4VxlDf9Y0%2FhgWvZc6mXIJhKxGZQTS%2FrG3%2FGdzYMiCjEVCvXG0SZwc" rel="nofollow">latte-dock</a>,设置起来也非常方便,我把设置导出到文件中了,方便配置,需要的可以参考 <a href="https://link.segmentfault.com/?enc=BMv4pstt4cqVZ%2FSgwSCiHQ%3D%3D.Ck8o2QC2Ir3i00kro0G6ZKfPM4NuV402boms6huRXmlfpsMKXgNrHgCtTxkq%2F49v" rel="nofollow">我的 dotfiles 仓库</a> 中找到<code>kde-plasma-setting/assets/plasma.layout.latte</code>文件导入到 dock 中即可。</p><p><img src="/img/bVcZuzY" alt="" title=""></p><h2>恢复与备份</h2><p>由于桌面环境设置相对繁琐和复杂,网络不好的话下载安装也很慢。我找到了一个插件 <a href="https://link.segmentfault.com/?enc=ggoWePc5KCTceH1xOnJQwA%3D%3D.0vSaunlpIfFAjW5VFA4lhQvAlKbnxtjwsHenLnJHqcvSAFvBSjR1uKL2BQToUkoB" rel="nofollow">PlasmaConfSaver</a> ,它可以很方便地将 plasma 配置进行备份和恢复,能够在多种配置间动态切换。</p><p><img src="/img/bVcZuz0" alt="" title=""></p><p>只需要安装该控件,然后将我设置好并导出的配置文件<code>dotfiles/kde-plasma-setting/assets/kde-mcmojave-default.tar.gz</code>导入自己的环境即可,大大简化流程,<a href="https://link.segmentfault.com/?enc=TVeq%2B6WpOm02rZBRaqOVVg%3D%3D.ABjSNlxlnef7yX%2B33KNty%2B5aKeP%2FIDSAjGj6tGLlGyDX%2FpgJHJErK6rrJ%2BXeR2Pj" rel="nofollow">PlasmaConfSaver 视频介绍</a>。</p><h2>总结</h2><p>对于软件工程师来说,<strong>笔记本和操作系统是重要的生产力工具</strong>,它可以帮助我们做很多事情。</p><p>本文结合笔者自身 5 年的 Linux 使用经验,从最基本的桌面环境设置入手,为大家提供快速设置 Linux Plasma 桌面环境的方法,希望给想尝试 Linux 的同学一个参考。</p><h2>参考文献</h2><ul><li><a href="https://link.segmentfault.com/?enc=lPFrDSrp%2BiGoT8quhEXUNw%3D%3D.XQbGPMxj1OJZVxkf6M%2BIloHxSNJyYXc4QKduB9b%2B%2FUI%2BA1ewRUJy8Bvd0MQAM%2FJwQ5noJZABQevge2nebEpg6w%3D%3D" rel="nofollow">Kde 桌面的 Mac 化</a></li><li><a href="https://link.segmentfault.com/?enc=KeTXFOuK7s2sjkLCwakvYA%3D%3D.gaKAfc%2FzOzeJZ3BRN%2BfWc1zWKBZJ6s%2BFqTeh2Ft3VpaaTIEfqj9U6FTe1tZ8fRECFOE%2FbhM7lRotZztTPa3eHgDWGqZhp5Rxjz3ySiiOEV56BS6aNRifObAparfyGlRqM3Pi4RRHIRFhxmdVxAqFYQ%3D%3D" rel="nofollow">KDE 桌面美化指南 Part 1</a></li><li><a href="https://link.segmentfault.com/?enc=FcOMT2hMr%2BV9IpDgwUCL6Q%3D%3D.adqx%2BUlX6weKZ%2F7BZEK6TTHErwRjNoJpsp9QpjQGcZc%3D" rel="nofollow">我是如何在 VS Code 上完成写作的</a></li></ul>
如何定制Kubernetes调度算法?
https://segmentfault.com/a/1190000041111313
2021-12-13T20:28:13+08:00
2021-12-13T20:28:13+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<p>随着云计算和容器技术的发展,以docker为核心的容器技术迅速在开发者和科技公司中应用,Kubernetes凭借丰富的企业级、生产级功能成为事实上的容器集群管理系统。可是k8s的<code>通用性</code>削弱了调度算法的<code>定制性</code>,本文将调研定制化调度算法的方法,并且给出一个开源实现Demo。</p><h2>k8s与调度器架构</h2><p>下图1-1是Kubernetes的整体架构图,集群节点分为两种角色:<code>Master节点</code>和<code>Node节点</code>。Master节点是整个集群的管理中心,负责集群管理、容器调度、状态存储等组件都运行在Master节点上;Node节点是实际上的工作节点,负责运行具体的容器。</p><p><img src="/img/bVcWE5n" alt="1-1 Kubernetes整体架构图" title="1-1 Kubernetes整体架构图"></p><p>Kubernetes调度器是独立运行的进程,内部运行过程从逻辑上可以分为多个模块。图1-2展示了默认调度器内部包含的具体模块,配置模块负责读取调度器相关配置信息,并且根据配置内容初始化调度器。</p><ul><li>优先队列模块是一个优先堆数据结构,负责将待调度Pod根据优先级排序,优先级高的Pod排在前面,调度器会轮询优先队列,<a href="https://link.segmentfault.com/?enc=VHCwgVLiHNKKFmD3j5iZ9A%3D%3D.19mM6U2426XJOCZzR0jf6G1fHKX6uxSx0CJvbb71lamuAA3d%2Fz2GfIkWWcPyOFs3" rel="nofollow">当队列中存在待调度Pod时就会执行调度过程</a>。</li><li>调度模块由<code>算法模块</code>、<code>Node缓存</code>和<code>调度扩展点</code>三部分组成,算法模块提供对Node进行评分的一系列基础算法,比如均衡节点CPU和内存使用率的NodeResourcesBalancedAllocation算法,算法模块是可扩展的,用户可以修改和添加自己的调度算法;Node缓存模块负责缓存集群节点的最新状态数据,为调度算法提供数据支撑;调度扩展点由一系列扩展点构成,每个扩展点负责不同的功能,最重要的扩展点是Filter、Score和Bind这三个扩展点。</li><li>最后是绑定模块,负责将调度器选择的Node和Pod绑定在一起。</li></ul><p><img src="/img/bVcWE5o" alt="1-2 Kubernetes调度器架构图" title="1-2 Kubernetes调度器架构图"></p><p>Kubernetes调度器代码采用可插拔的插件化设计思路,包括核心部分和可插拔部分。图1-2中的配置模块、优先队列和Node缓存是核心部分,算法模块、调度扩展点属于可插拔部分。<strong>这种插件化设计允许调度器一些功能通过插件的方式实现,方便代码修改和功能扩展,<a href="https://link.segmentfault.com/?enc=luYMbzhThwDcnSyOOBmu9g%3D%3D.fN7xQA%2BTeNe0vpK5kOycEwdA%2FiwNHZX0SO8MznUlpxIfxg2uYBNQIQSflSPChN84dBRjV4DeqQvTbusV22DdL9LqHuxVm8jGpH4VPuXeQ7VnejmRBEgS1EZwJxZD70gD" rel="nofollow">同时保持调度器核心代码简单可维护</a>。</strong></p><p>下图1-3列出了调度器扩展点模块中包含的具体扩展点。Pod的调度过程分为<code>调度周期</code>和<code>绑定周期</code>,调度和绑定周期共同构成Pod的调度上下文。调度上下文由一系列扩展点构成,每个扩展点负责一部分功能,最重要的扩展点是调度周期中的预选(Filter)和优选(Score)扩展点和绑定周期中的绑定(Bind)扩展点。预选扩展点负责判断每个节点是否能够满足Pod的资源需求,不满足就过滤掉该节点。优选扩展点部分会对每个Pod运行默认的评分算法,并且将最终评分加权汇总,得到最后所有节点的综合评分;调度器会选择综合评分最高的节点,如果有多个节点评分相同且最高,调度器会通过水塘采样算法在多个节点中随机选择一个作为调度结果,然后将该节点上Pod申请的资源用量进行保留操作,防止被其它Pod使用。在绑定周期中,调度器将Pod绑定到评分最高的节点上,这一步本质是修改Pod对象中节点相关的信息,并且更新到存储组件etcd中。</p><p><img src="/img/bVcWE5p" alt="1-3 Kubernetes调度器扩展点架构图" title="1-3 Kubernetes调度器扩展点架构图"></p><h2>定制化算法方案</h2><p>如果要实现自定义调度算法,主要有三种方案:</p><ol><li>修改默认调度器的源代码,加入自己的调度算法,然后重新编译和部署调度器,论文<a href="https://link.segmentfault.com/?enc=Qy3P7bFGhQk%2BZI11p928nA%3D%3D.zmGqlAA%2BNgZqjx%2BeUhVclGfcRW0MwRivyj%2FYWo9pKgk6hN4497RfrcrAIh0ShStV" rel="nofollow">kcss</a>和<a href="https://link.segmentfault.com/?enc=RLzkqk2NKrFA39pbg6o1Jg%3D%3D.laAWPWJ49%2FypnKuEFKFsMw2uX9kFCHvoq8k6IXUB2j4TQRuSSUJyfHwolDetArE8" rel="nofollow">kubecg</a>中的调度器研究基于此方案实现;</li><li>开发自己的调度器,和默认调度器同时运行在集群中;</li><li>基于<a href="https://link.segmentfault.com/?enc=awXEmFeyWtulgv2SI8CBOA%3D%3D.SgoseZJeeEdUkcRtSRxQOKDeZ0Pl2FrpneQJABVwTWlJEI0GA%2Fe7%2B3Kk1eu%2BgH39AA9KEQJRGAxZHJt%2BDpDxUO9tDTXksDsufw2GoEnsmK%2FBOrjzxIdSjrxoDw%2BK%2FEVC6s5TVBQ1edvodrMQnJuTHjvypELlEoGxu1NUFsReM8M%3D" rel="nofollow">Kubernetes Scheduler Extender机制</a>,在扩展调度器中实现自定义算法,论文<a href="https://link.segmentfault.com/?enc=Cu4hlFMnqQhWEBGpISCsBQ%3D%3D.xEJke8QGO%2BCOLHhD%2B4%2B%2FABoVI13DMeEzEkbJAFKKP%2BGPM6aUpOQw5x7FW6HOZfWP" rel="nofollow">dynamic IO</a>中的算法实现基于这种方案。</li></ol><p>上述三种自定义调度算法实现方案的优缺点见表2-1。综合来讲,</p><ul><li>方案1改动最小,但是这样做会破坏开源软件的可维护性,当Kubernetes主干代码更新时,改动后的调度器要和上游代码保持一致,<strong>这会带来大量的维护和测试工作</strong>。</li><li>方案2是实现自己的调度器,并且在集群中运行多个调度器,多个调度器之间没有集群资源数据同步,存在并发调度数据竞争和数据不一致的问题。</li><li>方案3需要默认调度器通过API和Extender交互,新增的网络请求会增加整个调度过程的耗时。</li></ul><p>2-1 自研调度算法方案对比</p><table><thead><tr><th align="left">方案</th><th align="left">优点</th><th align="left">缺点</th></tr></thead><tbody><tr><td align="left">方案1:修改调度器源代码</td><td align="left">改动小</td><td align="left">破坏源代码、不好维护</td></tr><tr><td align="left">方案2:运行多个调度器</td><td align="left">不改动源代码</td><td align="left">存在数据竞争、不一致</td></tr><tr><td align="left">方案3:开发扩展调度器</td><td align="left">不改动源代码</td><td align="left">存在网络耗时</td></tr></tbody></table><p>本文的调度器实现采用方案3,设计并开发符合Scheduler Extender机制和API规范的扩展调度器,将其命名为<strong>Liang</strong>。代码2-1是扩展调度器JOSN格式的策略配置文件,通过配置文件参数将该策略文件传递给Kubernetes默认调度器,其中urlPrefix表示扩展调度器Liang运行后监听的API地址,prioritizeVerb表示优选扩展点在扩展调度器中的路由。当默认调度器在优选扩展点运行完评分插件后会发送HTTP POST网络请求到Liang的API地址,并将Pod和候选节点信息放在HTTP Body中一起传递过去。接收到POST请求后,扩展调度器Liang会根据评分算法对节点进行评分并将结果返回给默认调度器。</p><pre><code class="json">{
"kind": "Policy",
"apiVersion": "v1",
"extenders": [
{
"urlPrefix": "http://localhost:8000/v1",
"prioritizeVerb": "prioritizeVerb",
"weight": 1,
"enableHttps": false,
"httpTimeout": 1000000000,
"nodeCacheCapable": true,
"ignorable": false
}
]
}</code></pre><p>图2-1是带扩展的默认调度器(kube-scheduler)启动过程,通过kube-policy.json配置文件将扩展调度器Liang的配置信息告诉默认调度器。</p><p><img src="/img/bVcWE5q" alt="2-1 扩展调度器通过配置文件传递给默认调度器启动示意图" title="2-1 扩展调度器通过配置文件传递给默认调度器启动示意图"></p><h2>扩展调度器Liang</h2><p>扩展调度器Liang独立于Kubernetes默认调度器,Liang的模块设计和组织架构如图3-1所示,包括多维资源采集存储和API服务两大部分。多维资源数据采集通过在集群中运行Prometheus和node-exporter实现,扩展调度器Liang负责从Prometheus获取多维指标然后运用调度算法,将结果返回给默认调度器。</p><p><img src="/img/bVcWE5s" alt="3-1 扩展调度器Liang整体架构图" title="3-1 扩展调度器Liang整体架构图"></p><ol><li>api server模块,负责实现符合扩展调度器数据格式和传输规范的API接口,Liang接收到Kubernetes的评分请求后,解析得到请求中的Pod和候选节点信息,作为参数传递给内部的调度算法,得到候选节点的评分结果并返回给默认调度器。</li><li>调度算法模块,扩展调度器Liang的核心模块,负责实现自定义的调度算法。得益于扩展调度器机制,Liang中可以实现多个自定义调度算法。本文主要设计并实现了BNP和CMDN两个调度算法。</li><li><p>数据缓存模块,主要功能有两个:</p><ol><li>通过请求Prometheus的API得到整个Kubernetes集群中所有节点的状态数据。</li><li>实现基于内存的指标数据缓存机制,提供指标数据的写入和读取接口,提高算法运行时获取多维指标数据的速度。</li></ol></li></ol><p><strong>Liang使用Go语言开发,代码量约3400行,开源网址为<a href="https://link.segmentfault.com/?enc=B2yRzO%2B73sdkQNJY%2BLJHqg%3D%3D.gRAWFSZVc%2F0ExQ2spkDN1oHsN3fC4cdTLoAKu8X%2ByKO5RXdf3Ms4LYOOlDw8r3ek" rel="nofollow">Liang开源地址</a>。</strong></p><p>表3-1是扩展调度器是否使用缓存机制和默认调度器做出调度决策的耗时对比,调度耗时通过在Kubernetes调度器源代码中打印时间戳的方式获取,分别运行9次然后计算平均值。从表3-1中可以看到,默认调度器做出调度决策的耗时非常小,不到1ms。加上扩展调度器和缓存机制的情况下,平均调度决策耗时为4.439ms,比默认调度器增加了约3ms,增加的时间主要是默认调度器与扩展调度器Liang之间网络请求耗时以及Liang运行调度算法所需的时间。当扩展调度器不加缓存机制时,每次做出调度决策的平均耗时为1110.439ms,调度耗时迅速增加超过100倍,主要是每次做出调度决策都要请求Prometheus计算和获取集群中的指标数据。因此,扩展调度器加上缓存机制可以避免请求Prometheus带来的网络请求时间,降低扩展调度器的决策时间,提升了扩展调度器的性能。</p><p>3-1 不同调度器架构决策耗时</p><table><thead><tr><th align="left">调度类型</th><th align="left">平均决策耗时</th></tr></thead><tbody><tr><td align="left">默认调度器</td><td align="left">0.945ms</td></tr><tr><td align="left">扩展调度器-使用缓存</td><td align="left">4.439ms</td></tr><tr><td align="left">扩展调度器-不使用缓存</td><td align="left">1110.439ms</td></tr></tbody></table><h3>BNP算法</h3><p>BNP算法在Liang中实现,它将网络IO使用情况纳入k8s调度算法的考量,能够均衡集群中的网络IO用量。</p><p>图3-2是实验中默认调度算法和BNP算法中,整个集群中网络IO资源的变化情况,每部署一个Pod统计一次数据,共部署九个Pod。可以明显看到,BNP实验中网络IO资源要比默认调度算法分配更均衡。</p><p><img src="/img/bVcWE5t" alt="3-2 bnp算法网络IO使用率变化情况" title="3-2 bnp算法网络IO使用率变化情况"></p><h3>CMDN算法</h3><p>CMDN算法在Liang中实现,它的目标是让集群中的多维资源分配更加均衡或者更加紧凑,核心步骤是针对CPU、内存、磁盘IO和网络IO以及网卡带宽这五个指标进行综合排序,选择最佳Node部署Pod。图3-3是实验中CPU使用率变化对比情况,可以明显看到,CMDN均衡策略下CPU使用率均衡程度要比默认调度算法分配更均衡。</p><p><img src="/img/bVcWE5u" alt="3-3 cmdn算法均衡策略下CPU使用率变化情况" title="3-3 cmdn算法均衡策略下CPU使用率变化情况"></p><h2>总结</h2><p><strong>Kubernetes调度算法的通用性削弱了算法的定制性</strong>。本文研究了k8s调度器架构和扩展机制,对比了三种定制化调度算法方案,选择扩展方案实现<code>扩展调度器Liang</code>,并在Liang中实现了两个调度算法BNP和CMDN用于展示定制化算法能力。</p><p>扩展方案极大丰富了定制化调度算法的能力,可以满足非常多定制化场景的需求。同时也需要注意,定制调度算法往往需要更多的数据,这就需要在k8s集群中额外部署数据采集模块,增加了运维成本,降低了定制化调度算法的通用性。</p><blockquote><a href="https://link.segmentfault.com/?enc=s0l%2FizkZlgpMicp4dB5Jww%3D%3D.3r%2BYGM4%2Fu0d0AQwsoCArxZZ7wOQ7URiUQB8FLUrqAj4DRDAhC0%2Bh76Yu2uJ%2Bqv0foc305HCbR1IYzqMPULDFhw%3D%3D" rel="nofollow">原文链接</a>,文章持续更新,可以微信搜索「 <strong>机器学习与系统</strong> 」阅读最新内容,回复<strong>资料</strong>、<strong>内推</strong>、<strong>考研</strong>获取相关内容。</blockquote>
机器学习项目是如何开发和部署的?
https://segmentfault.com/a/1190000022781863
2020-05-29T12:31:25+08:00
2020-05-29T12:31:25+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<blockquote>本文以一个小项目带你弄清ML的项目流程</blockquote>
<p>这周做作业查资料时,无意中看到一个GitHub项目<a href="https://link.segmentfault.com/?enc=y2sKnvR8niARVbMFfpWm6Q%3D%3D.KwFvzds3zQmIUxqdo0BCL86lpa8xVCiDak7yHxhrjTRzJb%2FckZGvcte0stADP7Sa" rel="nofollow">ML-web-app</a>,它以PyTorch训练MNIST文字识别模型为例,介绍了从<code>模型训练</code>到<code>部署上线</code>的整个流程。是非常好的学习项目!下图是效果图:</p>
<p><img src="/img/remote/1460000022781866" alt="" title=""></p>
<p>笔者浏览了项目的代码,以学习为目的,简单解读下这个项目。</p>
<h2>模型训练</h2>
<p>模型训练是相对独立的部分,可以由算法工程师来做。总结起来就是调用PyTorch接口,建立一个神经网络,然后利用MNIST数据进行训练,<strong>最后把训练好的模型文件存储起来,后面部署的时候要用到</strong>。</p>
<h2>服务部署</h2>
<p>该项目使用Flask框架部署服务,<strong>为了方便阅读,笔者对代码进行了精简</strong>。</p>
<p>下面的代码中,通过加载预训练好的模型数据,得到模型实例,可以进行预测:</p>
<pre><code class="python"># initialize flask application
app = Flask(__name__)
# Read model to keep it ready all the time
model = MyModel('./ml_model/trained_weights.pth', 'cpu')</code></pre>
<p>核心预测API路由,路径是<code>/predict</code>。</p>
<pre><code class="python">@app.route('/predict', methods=['GET','POST'])
def predict():
results = {"prediction" :"Empty", "probability" :{}}
input_img = BytesIO(base64.urlsafe_b64decode(request.form['img']))
res = model.predict(input_img)
return json.dumps(results)</code></pre>
<h2>请求过程</h2>
<p>默认主页是通过模板渲染的,在index.js中定义了两个核心函数:</p>
<ol><li>
<code>onRecognition</code>函数通过Ajax向<code>/predict</code> API路由发送POST请求,请求中封装了要识别的图片,然后获取模型预测结果。</li></ol>
<pre><code class="javascript">// post data to server for recognition
function onRecognition() {
$.ajax({
url: './predict',
type:'POST',
data : {img : cvsIn.toDataURL("image/png").replace('data:image/png;base64,','') },
}).done(function(data) {
showResult(JSON.parse(data))
})
}</code></pre>
<ol><li>
<code>showResult</code>函数把结果渲染出来。</li></ol>
<pre><code class="javascript">function showResult(resultJson){
// show predict digit
divOut.textContent = resultJson.prediction;
// show probability
document.getElementById("probStr").innerHTML =
"Probability : " + resultJson.probability.toFixed(2) + "%";
}</code></pre>
<h2>总结</h2>
<p>这个项目麻雀虽小,五脏俱全。可以帮助非算法类程序员一窥ML从建模到上线部署整个流程,透过火爆的趋势看清本质。</p>
<p>如果你对人工智能/机器学习感兴趣,给大家准备了福利,赠送三本周志华老师的新书《<strong>机器学习理论导引</strong>》,点击<a href="https://link.segmentfault.com/?enc=yCW3QXRXLySuckfuju3hpg%3D%3D.%2FvZptgR%2F8I5KACJN35XTAdBk73%2Fxr7avE0vGMbjH2QLa4VaPnOntNTcLwTHK8ftVLb5aMePLVzLkmwrmqRnJWA%3D%3D" rel="nofollow">文末送书,周志华领衔撰写,历时4年,宝箱书问世!</a>查看详情,或者点击<a href="https://link.segmentfault.com/?enc=gIh4p%2FZV3E8oU8m45p3q1g%3D%3D.O7vpXss4cidLEEQ6VtqloCM2x9ZdL9A2aol95tlpmYGd%2FSzlc%2B%2BY2Q9cbFKbGcAy5dEYuDV8LPdsvudAHRhzqA%3D%3D" rel="nofollow">某当200-30优惠券,百万好书任你选</a>领取私人订制购书满减券。福利不要错过~</p>
<blockquote>文章持续更新,可以微信搜索「 <strong>机器学习与系统</strong> 」阅读最新内容,回复<strong>资料</strong>、<strong>内推</strong>、<strong>考研</strong>获取我为你准备的惊喜~</blockquote>
操作系统是如何管理物理内存的?
https://segmentfault.com/a/1190000022348403
2020-04-12T20:34:09+08:00
2020-04-12T20:34:09+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<blockquote>本文是<code>操作系统系列</code>第三篇,介绍物理内存管理。操作系统对内存的管理是非常复杂的,和程序的执行、硬件、编译器等密切相关。本文从物理内存入手,介绍内存管理的重要概念,也为后续的虚拟内存管理内容做铺垫。<a href="https://link.segmentfault.com/?enc=EiWKXoCm4cix9Vpek83ODg%3D%3D.DDinjvdTsGpQkLRyQ1Y0S5PaprEsaIc7vWGj2ROvQz6dV6oqjmkeNwGg4Ho3dzLvM8uoQQRfG2k64su0pCq4mw%3D%3D" rel="nofollow">原文链接</a>,更多内容见公号<code>机器学习与系统</code>,欢迎与我互动~</blockquote>
<p><img src="/img/remote/1460000022348408" alt="" title=""></p>
<h2>内存管理的需求</h2>
<ol>
<li>抽象,即给每个程序逻辑地址空间</li>
<li>保护,不同程序的地址空间互相隔离,无法越界访问</li>
<li>共享,对于一些公共函数库,可以只在内存中存一份,其它程序引用这一个库即可</li>
<li>虚拟化,通过逻辑地址和虚拟内存,可以使用更大的地址空间</li>
</ol>
<h2>地址的概念</h2>
<p>地址是用来标志存储资源位置的,在计算机中用一串二进制数据表示。</p>
<p>一. 地址空间</p>
<p>地址空间就是指地址的范围,从最小值到最大值:</p>
<ul>
<li>物理地址空间从0到物理内存的最大值:0~MAX_sys</li>
<li>逻辑地址空间从0到程序虚拟内存范围的最大值:0~MAX_prog</li>
</ul>
<p>下图展示了物理地址空间,进程A、B的逻辑地址空间。</p>
<p><img src="/img/remote/1460000022348406" alt="" title=""></p>
<p>二. 地址生成</p>
<p>物理地址是已经确定的,逻辑地址的生成依赖于<strong>编译器</strong>。</p>
<ol>
<li>编译:将高级语言编译成汇编语言。假设此时此时地址已知,如果起始地址改变,必须重新编译</li>
<li>汇编:将汇编语言翻译长机器能够识别的二进制代码,里面的地址是该程序执行时,对应地址空间中的位置</li>
<li>链接:将程序执行需要的函数库链接到可执行文件中,更新地址空间</li>
<li>
<strong>加载</strong>:将函数加载到内存中时根据程序块在内存中的位置更新<code>逻辑地址空间</code>内的地址(重定位)</li>
<li>执行:执行代码时,程序在内存中可能会移动,这里需要地址转换(映射)支持</li>
</ol>
<p><img src="/img/remote/1460000022348407" alt="" title=""></p>
<p>三. 地址解析</p>
<p>下图是CPU和计算机的基本架构,我们以此图来说明物理/逻辑地址在CPU和计算机中如何被解析处理的。</p>
<ol>
<li>首先,CPU中的算数逻辑单元看到的都是逻辑地址</li>
<li>当CPU需要把数据写入内存或从内存中读取时,MMU会把逻辑地址转换成对应的物理地址</li>
<li>
<p>控制逻辑把数据、操作请求和物理地址发送到总线,分为读请求和写请求</p>
<ul>
<li>写请求,则把数据写入内存</li>
<li>读请求,则把数据从内存中读取发送给CPU</li>
</ul>
</li>
</ol>
<p><img src="/img/remote/1460000022348410" alt="" title=""></p>
<p><strong>在上面的过程中,MMU负责逻辑地址和物理地址之间的转换,操作系统负责建立逻辑地址和物理地址之间的映射关系</strong>。</p>
<h2>连续内存分配</h2>
<h3>基本概念</h3>
<ol>
<li>连续内存分配:给程序分配一块<strong>连续内存区域</strong>
</li>
<li>
<p>内存碎片:内存上一些没有被分配利用的区域</p>
<ul>
<li>内部碎片:某个程序分配的内存没有充分利用。是否产生取决于分配算法,比如<strong>分配的内存大小是否要取整</strong>
</li>
<li>外部碎片:被分配的内存区域之间没的的空闲区域</li>
</ul>
</li>
<li>碎片整理:通过调整进程占用的内存区域位置来减少或避免分区碎片</li>
<li>碎片紧凑:通过移动分配给进程的内存区域,以合并外部碎片。要求运行的程序都可以动态重定位</li>
</ol>
<h3>动态分配</h3>
<p>当程序被加载时,根据进程的实际需要动态分配内存空间,使分配的大小刚好与作业的大小相等。动态分区分配并不预先将内存划分成一块块分区,而是在程序进入内存时,根据程序的大小动态地建立分区,因此系统中分区的大小是可变的,分区的数目也是可变的。</p>
<p>有以下三种分配策略:</p>
<ol>
<li>最先匹配(First-fit):分配N个字节,<code>使用第一个可用空间比N大的内存块</code>。如分配400 byte的内存块,按照从上到下的查找顺序,应该分配<code>1K byte</code>内存区域。如果是从下往上查找,应该分配<code>5K byte</code>的区域。</li>
<li>最佳匹配(Best-fit):分配N字节分区时,<code>查找并使用不小于N的最小空闲分区</code>。如果要分配2800 byte,应该分配<code>3K byte</code>区域。</li>
<li>最差匹配(Worst-fit):分配N字节,<code>使用尺寸不小于N的最大空闲分区</code>。如果分配800 byte,则选择<code>5K byte</code>区域。</li>
</ol>
<p><img src="/img/remote/1460000022348409" alt="" title=""></p>
<p>上述三种分区算法,在释放分区时,都要检查是否能和周围的分区合并。</p>
<h2>非连续内存管理</h2>
<p>连续内存分配会出现内/外部碎片、动态修改比较困难、内存必须连续,而且内存利用率不高。因此提出了非连续内存分配的方法,允许程序使用非连续的内存空间、允许共享代码和数据,以提高内存利用效率和管理的灵活性。</p>
<p>当然,这也带来了挑战:非连续内存分配中,如何有效实现和管理逻辑地址和物理地址间的映射。</p>
<p>下面介绍三种方式:</p>
<ul>
<li>段式存储管理(segmentation)</li>
<li>页式存储管理(paging)</li>
<li>段页式存储管理(上面两者的综合)</li>
</ul>
<h3>段式存储管理</h3>
<p><img src="/img/remote/1460000022348411" alt="" title=""></p>
<p>段(segment)指一类地址空间,一个段就是一个地址连续的内存块,若干个段组成程序的逻辑地址空间。</p>
<p>每个段由0到最大的线性地址序列构成。各个段的长度可以是0到某个允许的最大值之间的一个数。<strong>不同的段的长度可以不同(通常情况下也都不一样),段的长度在运行期间可以动态改变</strong>,比如push数据时,堆栈段的长度会增加,pop时会减少。段也可以被装满,但是通常情况下段的长度很大,这种情况很少发生。</p>
<p>段式存储管理下的逻辑地址组成格式为(s, o),s为<code>段号</code>,o为<code>段内偏移量</code>,段号和对应内存中的物理起始地址由<code>段表</code>记录。寻址时,先根据段号到段表中查到物理起始地址(基址),然后加上偏移量,得到最终的物理地址。</p>
<h3>页式存储管理</h3>
<p>页式存储管理有两个至关重要的概念:</p>
<ol>
<li>物理页帧(Frame | Page Frame | 帧 | 页帧):把物理地址空间分成大小相同的基本单位。大小为2^n,如512/4096等。</li>
<li>逻辑页面(Page | 页):把逻辑地址空间划分为相同大小的基本单位</li>
<li><strong>页帧大小和页面大小必须一致</strong></li>
</ol>
<p>页式存储管理的寻址方式和段式管理类似,逻辑地址格式为(p, o),表示<strong>页</strong>中的地址,其中p表示页号,o表示偏移量。物理地址格式为(f, o),表示<strong>页帧</strong>中的地址,其中f表示页帧号,o表示偏移量,页偏移量和页帧偏移量是相等的。</p>
<p>页和页帧的对应关系使用<strong>页表(Page Table)</strong>来管理。寻址时首先根据页号找到页表中对应的页帧号,然后用得到的页帧号与偏移量组成实际的物理地址。</p>
<p><img src="/img/remote/1460000022348412" alt="该图来自清华大学OS课程PPT,笔者做了适当修改" title="该图来自清华大学OS课程PPT,笔者做了适当修改"></p>
<p>页面和页帧的大小相比分段要小得多,假设系统是32位,页帧大小1024字节,这样有2^32/2^10=2^22条页表记录,查询页表的时间要多很多。下面介绍两个提高性能的方法:</p>
<ol>
<li>使用快表(Translation Look-aside Buffer, TLB):直译为旁路快表缓冲,可以理解为页表缓冲。即在内存和CPU之间搭建页表缓存,寻址时先到TLB中查找,未命中再到内存中的快表查找</li>
<li>多级页表:(p1, p2, o)是两级页表的虚拟地址表示,先根据p1查找页表1中的p2,再根据p2查询真正的页帧号,然后根据偏移地址o查到最终的物理地址</li>
</ol>
<h3>分段和分页的比较</h3>
<p>分页和分段系统有许多相似之处。两者都采用离散分配方式,且都要通过地址映射机构来实现地址变换。但在概念上两者完全不同,主要表现在下述三个方面:</p>
<ol>
<li>页帧是信息的物理单位,分页是为了实现非连续分配,以便解决内存碎片问题, 提高内存的利用率。段是信息的逻辑单位,分段的目的是为了能更好地满足用户的需要。</li>
<li>页的大小固定且由系统决定,由系统把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的,因而在系统中只能有一种大小的页面。而段的长度却不固定,决定于用户所编写的程序,通常由编译程序在对源程序进行编译时,根据信息的性质来划分。</li>
</ol>
<p>段式存储和页式存储都是为了更好管理内存,段式从程序的角度入手,页式从物理底层的角度入手,在理解上,可以结合两者的优缺点进行选择:</p>
<table>
<thead><tr>
<th align="center"> </th>
<th align="center">分段</th>
<th align="center">分页</th>
</tr></thead>
<tbody>
<tr>
<td align="center">优点</td>
<td align="center">段长可动态修改,方便编程,分段共享,分段保护,动态链接,动态增长</td>
<td align="center">非连续分配,减少内存碎片,提高内存利用效率</td>
</tr>
<tr>
<td align="center">缺点</td>
<td align="center">内部碎片,地址计算需要更多硬件支持</td>
<td align="center">需要两次内存访问,页表可能很大</td>
</tr>
</tbody>
</table>
<h3>段页式存储管理</h3>
<p>段页式存储管理充分利用了段式存储在内存保护方面有优势,页式存储在内存利用和优化转移到后备存储方面有优势。</p>
<p>在段式存储管理基础上,给每个段加一级页表。逻辑地址格式为(s, p, o),s为段号,p为页号,o为页内偏移。寻址时,现根据段号s查找段表中的页表地址,然后到页表中查找p对应的起始地址,最后加上偏移o得到最终的物理地址。</p>
<h2>总结</h2>
<p>程序在执行时,CPU看到的是逻辑地址,当CPU读写数据时,由MMU根据逻辑地址找到对应的物理地址,然后到总线上读写数据。通过这种管理机制,可以更好地管理内存,在多道程序执行中做到隔离和共享。</p>
<blockquote>文章持续更新,可以微信搜索「 <strong>机器学习与系统</strong> 」阅读最新内容,回复【内推】【考研】获取我准备的头条内推以及考研信息</blockquote>
<h2>Reference</h2>
<ul>
<li><a href="https://link.segmentfault.com/?enc=In1xVCaCcaEdoXz046%2FmKw%3D%3D.GQIA4eyIFhDvE1LbS0GxMW1uj%2FMpK0dFBrJ9eo8t%2Fho%3D" rel="nofollow">操作系统-精髓与设计原理</a></li>
<li><a href="https://link.segmentfault.com/?enc=2pJ6Sq7AkHWuSuqmS3nmFQ%3D%3D.2DOYRmMp0ywDtaFdi19CbmZn6ndD%2BcgXdE42%2BY5ia2T%2F%2FOKXC%2FmLqaKOVC5OjdOl" rel="nofollow">清华大学OS课程</a></li>
<li><a href="https://link.segmentfault.com/?enc=bp8ROMd3n0z7gqV%2FMmSayQ%3D%3D.fEt4AhpnyK%2Fwh9L7D7ZvKZ1kgTTVjIqP2klQ0ZDyMqG6XwqhBMMmIsqiAmAUH0xl" rel="nofollow">部分配图来自清华大学OS课程PPT</a></li>
<li><a href="https://link.segmentfault.com/?enc=Yj5iKL49Wy6NYdnfZJil%2Bg%3D%3D.KYCXmAytekpc8CQJ0wsbUNpSM8y3RKlY19YvRvav7%2FK7RgvfnqXXo7yyb24iVKCw5T7edJwvRMqoJEXdsNvjdw%3D%3D" rel="nofollow">连续分配方式 -- 动态分区分配</a></li>
<li><a href="https://link.segmentfault.com/?enc=xAb2Dbu%2BZGNvMCtabGsxow%3D%3D.HqR563eJgqjLShrj%2F6lE7Jl0Z9mm9UzrwkjycS8V1BWFAcv351dFIWdUQurj3Uf7oFOIBTKAftj0285rAobaEw%3D%3D" rel="nofollow">学堂在线-操作系统课程</a></li>
<li><a href="https://link.segmentfault.com/?enc=zx79y0LsnzpwYhwHtsz3OQ%3D%3D.%2FqWsDnw4unNM4PZNhvZalZKIaqFldhwUFNnVkXcdEWt%2BWruhDgnB4bZ83CP3B3DHx3EH3hBohJJpyeSZ5MEGvQ%3D%3D" rel="nofollow">分段,分页与段页式存储管理</a></li>
<li><a href="https://link.segmentfault.com/?enc=8bUHXfEQQjtIOIGd6Ll%2Bdw%3D%3D.g4V7aSBZyOBsZRknuu8KzzVwl0f8i2YCVMjpz9wF2WZNwgQdXju4Ymjz2yYZvTS2bcZz0PsjQL%2BCqNdfJy0j0g%3D%3D" rel="nofollow">TLB的作用及工作过程</a></li>
</ul>
只要15美元,畅享O'Reilly所有在线学习资源!
https://segmentfault.com/a/1190000021591385
2020-01-15T16:05:55+08:00
2020-01-15T16:05:55+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
8
<p>O'Reilly是世界著名信息技术图书出版公司,它为读者提供了丰富的在线学习资源,但是<strong>个人会员499美元/年</strong>,是一笔不小的开销。笔者发现通过注册ACM会员,只要<strong>15美元/年</strong>就可以畅享O'Reilly所有学习资料,读完1-2本书,就赚回会员费了!<br><img src="/img/remote/1460000021591389" alt="" title=""></p>
<p>这里分享给大家具体实践方法:主要有两种方式,一个是通过CCF协助注册ACM会员,另一个是在ACM官方网站直接注册。</p>
<h2>CCF协助注册ACM会员</h2>
<p>需要先注册CCF会员(学生50元/年,成人200元/年),然后登录CCF网站,通过CCF网站协助注册ACM会员。<a href="https://link.segmentfault.com/?enc=avZ3XfAbViR74XEI3OsRPA%3D%3D.lyrc7s%2BMbjy6pXYXM0fUP%2BhFjpcZBznd5TiB%2F4hL%2BaBbjgumW%2FngnSsGWZahYODjtu6%2BemLIACxMacjIBY9jfA%3D%3D" rel="nofollow">注册信息</a>如下:</p>
<blockquote>...... <br>交费标准:会员:175元人民币;学生会员:133元人民币 <br>...... <br>会员资格何时生效?<p>根据CCF与ACM达成的协议,CCF会员部每月25日(如遇周末提前至周五或延至周一)将当月交费的会员信息提交给ACM。ACM将在次月10日左右给申请者发送资格生效手续邮件,交费凭证、会员号和会员有效期也将一并发至邮箱。</p>
</blockquote>
<h2>ACM官网直接注册</h2>
<p>官网注册优惠的原理是,ACM针对发展中国家提供了折扣,我国还是发展中国家,<strong>根据2020年1月15号的数据,成人15美元/年、学生8美元/年</strong>。如果有美国信用卡,注册起来会很方便,如果没有的话,可以在某宝上找代付。算下汇率和手续费也比CCF协助注册要划算。注册链接如下:</p>
<ol>
<li>专业会员(非学生)折扣注册链接 <a href="https://link.segmentfault.com/?enc=mRC85PsL6s6s8zlP%2BhrB2w%3D%3D.s55GZ%2Bn8qxLyD84W2ZtaJsytxuYkFT8wQ2Vc2uYbvqFZhXFSeB8oYqbbO%2FWSWGYpt4pVMmNtuHmKzRjrjQj5GNNZUBvoarVufjnthuocvseIE7WB8pCTYBWES9wFvTjtQGSJ%2Fea67kiycN2UMiIHonYJPMv5iML%2FqmlgDvD9NGEGLb87IyuAoT1rKavBVp5%2F" rel="nofollow">https://services.acm.org/publ...</a>
</li>
<li>学生会员注册链接 <a href="https://link.segmentfault.com/?enc=W1%2FiPqAMsekOl%2B12TmiiEg%3D%3D.FXlvgKN%2F0YstBA8474c4vhcj3feimRrdvnPN7ZHV2W0GjxxhP6yC8h5xax4d%2BAkOSeqW5SB9YKDMRDI7HVcLkh4oLCkJRdazyj87PigOBUJorVW5PrTQBB1POeqBYBYtV%2FdmG%2FgTWKNq4KDltwLyFMjRHH5GEtt6AZ6gk%2BZFVx1jvkcDHRsQOmcd%2B%2BppQHp3" rel="nofollow">https://services.acm.org/publ...</a>
</li>
</ol>
<p>填写完信息提交后,ACM会在后台生成数据和收费链接,<strong>这个收费链接要牢记</strong>。<br><img src="/img/remote/1460000021591388" alt="" title=""></p>
<p><strong>可选</strong>:如果需要代付,把收费链接发给代付,付完钱ACM会发送邮件到你的邮箱,根据邮箱中的链接和网页提示激活账号、设置密码等。</p>
<h2>两种方案比较</h2>
<table>
<thead><tr>
<th align="left">比较项</th>
<th align="center">CCF</th>
<th align="center">ACM</th>
</tr></thead>
<tbody>
<tr>
<td align="left">生效时间</td>
<td align="center">每月25号提交给ACM,次月10日生效</td>
<td align="center">立即生效</td>
</tr>
<tr>
<td align="left">价格</td>
<td align="center">成人375元,学生183元</td>
<td align="center">成人15美元,学生8美元</td>
</tr>
<tr>
<td align="left">权益</td>
<td align="center">CCF会员权益+ACM会员权益</td>
<td align="center">ACM会员权益</td>
</tr>
</tbody>
</table>
<p>通过对比可以发现,<strong>如果是已经工作的软件开发人员,直接注册ACM会员是最划算的</strong>。</p>
<h2>进入O'Reilly学习网站</h2>
<p>注册完后,可能会找不到如何用ACM的账号进入O'Reilly的学习资源页面,这里介绍网页、App和ACM官网三种方法。</p>
<h3>网页</h3>
<p>浏览器输入<code>http://learning.oreilly.com/</code>,登录时输入ACM的账号邮箱,会自动跳到ACM的统一认证网页,输入ACM账号密码,成功后进入O'Reilly学习网页。<br><img src="/img/remote/1460000021591392" alt="" title=""><br><img src="/img/remote/1460000021591391" alt="" title=""></p>
<h3>移动端App</h3>
<p>移动端的登录方式和web网页端原理是一样的,登录的时候输入ACM邮箱,O'Reilly会自动跳到ACM统一认证页面,输入ACM账号密码,成功后自动跳回O'Reilly App。</p>
<p><img src="/img/remote/1460000021591393" alt="" title=""><br><img src="/img/remote/1460000021591390" alt="" title=""></p>
<h3>ACM网站跳转</h3>
<p>访问ACM学习中心<a href="https://link.segmentfault.com/?enc=aou%2FbCGBjDoYxLlnuIHobg%3D%3D.6qppS5qBUz7%2FBmxHEhM3%2FzEA4axzFojhnUKKqadEi6U%3D" rel="nofollow">https://learning.acm.org/</a>,点击右上角<strong>O'Reilly</strong>,即可跳转到O'Reilly学习中心。<br><img src="/img/remote/1460000021591394" alt="" title=""></p>
<h2>Reference</h2>
<ul>
<li><a href="https://link.segmentfault.com/?enc=EoLIfZ7LwBpnfULIWUNiBw%3D%3D.%2B0radabnycaXNj6dUBcncrq%2BxaVp5OAwAtaffI6p7AM%3D" rel="nofollow">买了 ACM 的会员,可以看 O'Reilly 的所有书籍和视频,真香</a></li>
<li><a href="https://link.segmentfault.com/?enc=TPlNFqIkJ7cup3rz2%2B1miA%3D%3D.zF9mrjf38%2F8B4ivudtaL1h4FBuFdkTffmyp5SL6kVET%2BAR%2BIAzMdXpcTo%2FOjGIAG" rel="nofollow">O'Reilly Safari Learning Platform 开通指南及概览</a></li>
</ul>
<hr>
<p>欢迎关注公众号<code>QuanTalk</code>,了解更多<code>计算机科学与技术</code>、<code>阅读分享</code>、<code>独立思考</code>内容。</p>
从社区报告看美国未来20年的AI战略
https://segmentfault.com/a/1190000020474243
2019-09-24T07:18:52+08:00
2019-09-24T07:18:52+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<blockquote>2019年8月6号,美国计算社区联盟(CCC)和人工智能促进协会(AAAI)联合发布了美国未来20年AI研究路线图。主要关注如何发挥AI的价值和减轻AI的风险。小编对摘要部分进行翻译梳理,总结后分享给读者。<strong>关注公众号QuanTalk,回复“ai20”,获取完整PDF报告~</strong>。</blockquote>
<h2>概览</h2>
<p><img src="/img/remote/1460000020474246" alt="" title=""></p>
<p>数十年AI研究产生了强大的技术,为工业、政府和社会带来了巨大的收益。现在的AI系统可以做到<code>多语言翻译</code>、<code>识别图片和视频中的物体</code>、<code>简化生产过程</code>以及<code>控制汽车</code>。AI系统的部署不仅创造了万亿美元的产业(这一数字将在3年内翻翻),也暴露了很多问题:<strong>如何让AI系统更加公平、可信、值得信赖和更加安全</strong>。未来的AI系统将能有效地识别它们所处的世界,高效、合乎道德地处理复杂任务,进行有意义的交流并且通过经验提高它们的意识。</p>
<p>如何充分发挥AI技术的潜力呢?这需要对AI研究企业进行根本地变革,并通过大量、持续的投资促进变革。下面的内容是由计算社区联盟和人工智能促进协会社区合作完成的主要建议,目的是<strong>为未来20年的人工智能研究和发展制定路线图</strong>。</p>
<h2>AI带来了哪些社会效益</h2>
<p>AI系统有潜力对社会各个部门产生根本性影响,并带来实质性创新和经济增长。主要有:</p>
<ul>
<li>促进健康和提高生活质量</li>
<li>提供终生学习和培训的机会</li>
<li>重构企业创新和竞争规则</li>
<li>聚合科学发现和技术创新</li>
<li>证据驱动的更科学和合理的社会机会和政策</li>
<li><strong>变革国家防御和安全手段</strong></li>
</ul>
<p>可以看到,AI将对个人、组织、社会产生巨大影响。</p>
<h2>如何实现这些社会效益</h2>
<p>在AI研究上,需要注意以下重点,它能激发社会驱动力:</p>
<ul>
<li>集成智能</li>
<li>有意义的互动</li>
<li>主动学习</li>
</ul>
<h2>社区建议</h2>
<ol>
<li>
<p>开创和运营国家AI基础设施</p>
<ul>
<li>开放AI平台和开放资源建设</li>
<li>社区驱动持续产生AI挑战</li>
<li>建立国家AI研究中心</li>
<li>建立任务导向的AI实验室</li>
</ul>
</li>
<li>
<p>重新定义和培训全面的人工智能员工</p>
<ul>
<li>开发不同层次的AI课程</li>
<li>为高级AI学位创建招聘名额和保留计划</li>
<li>重视少数群体和弱势群体</li>
<li>激励新兴的跨学科AI领域</li>
<li>强调AI道德准则和政策</li>
<li>解决AI和工作新旧更替期间的挑战</li>
<li>训练高水平AI工程师和技术人员</li>
</ul>
</li>
<li>基础人工智能研究的核心项目至关重要</li>
</ol>
<h2>路线图</h2>
<p><img src="/img/remote/1460000020474247" alt="" title=""><br><img src="/img/remote/1460000020474248" alt="" title=""></p>
<h2>总结</h2>
<p>AI被认为是新的<strong>水和电</strong>,是社会发展至关重要的生产力。目前中国和美国在AI领域处于世界领先位置,但是<code>中国以应用为主、美国基础研究实力雄厚</code>,即中国在基础研究上不及美国。</p>
<p>上面的社区研究报告可以给我们参考,决定未来的研究领域,<strong>以更好地实现陶融品性、创获智慧,促进民族和社会的发展</strong>。</p>
全民CS、校训就是搬砖,这所学校计算机顶尖是有原因的
https://segmentfault.com/a/1190000020168509
2019-08-23T18:18:50+08:00
2019-08-23T18:18:50+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<blockquote><a href="https://link.segmentfault.com/?enc=IxnKXkKlwzT7k01Oq1va0w%3D%3D.WC8uOg25D7T0CyZZJllyNdnJfm6t0leBEmR0Ul7dh0t1j%2BBgGH8gYijFS1eWTdghW9f5mkehFUIE6qUJZfTCrQ%3D%3D" rel="nofollow">原文链接</a></blockquote>
<p>卡耐基梅隆大学(下文简称为CMU)的计算机科学享誉全美,被视为该领域的领导者。CMU的计算机科学研究生教育全美最佳,软件工程专业更是遥遥领先于其它名校,本科生的声誉也在雇主中排名第一。</p>
<p><img src="/img/remote/1460000020168512" alt="" title=""></p>
<p>像这样的顶尖大学,本文无法面面俱到,而是从计算机专业培养入手,结合<code>院系</code>、<code>课程</code>、<code>培养方案</code>等角度总结其培养学生的特点,为CS领域或想转行CS的小伙伴提供可借鉴的方法和参考。</p>
<h2>校训</h2>
<p>CMU的校训是卡耐基先生的名言:<strong>My heart is in the work(我心于业)</strong>,即使经历了百年内数次重大革新,这样的信念依旧根深蒂固融于整个大学文化中。</p>
<p>在校训的指引下,卡耐基梅隆大学<strong>对学生的训练异常严格,课业繁重</strong>,在普林斯顿评论(Princeton Review)每年“学生累得像狗的大学排名”中,从来高居前几位,与加州理工学院、麻省理工学院、芝加哥大学、普林斯顿大学等同为美国乃至全世界训练最为残酷的大学。</p>
<h2>最大的学院</h2>
<p>在院系设置上CMU和UC Berkeley、MIT和Stanford都不同,计算机是一个独立的学院-<strong>计算机科学学院,School of Computer Science 下面简称SCS</strong>。SCS是为数不多将计算机科学独立设院的大学,隶属于CMU七大学院之一,是全美乃至全世界最大的计算机学院。因此,CMU的学生戏称自己是全民CS。</p>
<p>SCS下面设置多个部门和研究所,由这些研究所为学生提供专业和培养方案。</p>
<p><img src="/img/remote/1460000020168513" alt="" title=""></p>
<h2>丰富专注的课程</h2>
<p>CMU的课程也是按编号管理的,格式为<code>XX-xxx</code>,前缀<code>XX</code>表示课程由哪个部门开设,计算机科学部的编号是15,后面的<code>xxx</code>是一个三位数,第一位表示课程的难度/水平,一般数字越大,难度和级别越高。</p>
<p>计算机科学学院的课程信息查询有多种方式:</p>
<ul>
<li>课程表。</li>
<li>不同部门开设的课程。</li>
<li>Catalog为学生指引。</li>
</ul>
<h3>课程表</h3>
<p>以学期为单位发布当前学年的<a href="https://link.segmentfault.com/?enc=EVwojP0SfcR8dWA555IiLA%3D%3D.753cOP51RniLounhMobI45JY5WlkNYk8Dd7NvpMqvkeHtR8DjrNBUlv1HmOqTQMhB9Bnxum8w9jLbXDwSWHwXDSH9FGswSolzIY%2FqxgJiLk%3D" rel="nofollow">完整课程表</a>,里面列出当前学年的所有课程,但是只有课程信息、上课地点,没有具体的课程页面,适用于本校学生查询。</p>
<h3>研究所课程</h3>
<p>除了上面的两种方法,在计算机科学学院每个部门、研究所官网上都有详细的课程信息:</p>
<ul>
<li>
<a href="https://link.segmentfault.com/?enc=j0EQ8BOwXQGui3yA1pjx4g%3D%3D.FyPVlbEGbw%2FByfQxheILLFWTM0fYq1MMaEt5w%2Ffrk7t6zeQCT5bvoYu%2BKWp3BiMjn%2BmX95HX%2F93PdXO8VTEqow%3D%3D" rel="nofollow">Computer Science Department Course List</a>:计算机科学学院的课程列表</li>
<li>
<a href="https://link.segmentfault.com/?enc=1nfu4NutGUL%2BYTGN1xHfnA%3D%3D.zMJ9FrWCe6rb7fYE6JZh7dl8oHmCP7HsQhxHs%2Fc2hOzlsopV73m1HAJGe9kQUS3n" rel="nofollow">Machine Learning Department</a>:人工智能系课程</li>
<li>
<a href="https://link.segmentfault.com/?enc=G6pSlo4MYfo8%2BjJBn4xocQ%3D%3D.gIu7ghbBiK%2BBv6OLS6wCp%2FGBfLQ5cRtPKSoJAS3Spex5X4Ho6SKWFix0%2BMb5MqCC" rel="nofollow">Human-Computer Interaction Institute</a>:人机交互研究所课程</li>
<li>
<a href="https://link.segmentfault.com/?enc=G21kqZGBIoKm6uoXQYZ%2FOg%3D%3D.Hbp7MH%2FZIlQYIlQLe4zD91g5R4er97EMOjSp2lEdNt1J4LruX8Ry5oZPoVOSpYpe" rel="nofollow">Robotics Institute</a>:机器人研究所课程</li>
<li>
<a href="https://link.segmentfault.com/?enc=HxcfHMS8XESbz73QDL0leg%3D%3D.rd3SQ1pZcM%2FqeRa1UTFG6u7E6Ji%2F%2BDA3ANh%2BxER24oN9AhDCZv8wNm0SAHlPKftG" rel="nofollow">Language Technologies Institute</a>:语言技术研究所课程</li>
<li>Computational Biology Department下的<a href="https://link.segmentfault.com/?enc=mcsYPo4tDNxZaWr83LpGWg%3D%3D.hJ6E9%2BmWpBpidJxLQRCUD352vsGMthmy%2FZBO7fu7JRB6IlTfu9iLc%2BrzZlLkKolorL6tROO0jq%2FnDa%2BBbKyO7A%3D%3D" rel="nofollow">本科课程</a>和<a href="https://link.segmentfault.com/?enc=S4qou70YVoJdMdLVyjuwHg%3D%3D.VleNeYlO2hV02mDOxwvnaiKlW51T75f9HRlSnZz3Hq%2B59VULM%2BdlLioZ0C2ziuZ%2FFaELVuS4B%2Fsai7uwUogmtg%3D%3D" rel="nofollow">研究生课程</a>
</li>
<li>
<a href="https://link.segmentfault.com/?enc=IATESmrP9S5Efzaa%2BKXl1g%3D%3D.mWLIHsTsqG3SCDL8LjxggRO1kpLsjX4aWOpziFp%2FCXywUyroNuW%2Fj4ynE%2FH9HoGCkMfxklQuLGHbTUze2W7Clw%3D%3D" rel="nofollow">Software Engineering Institute Courses</a>:里面的课程偏向培训</li>
</ul>
<h3>课程目录(Catalog)</h3>
<p>计算机学院大而全,院系和课程都非常多,Catalog是以学院下属的研究所、部门为单位进行细分的:</p>
<ul>
<li><a href="https://link.segmentfault.com/?enc=lJjSVhEPX1z0qG%2BFK%2FxLpw%3D%3D.284WWMrsmjQP5l5frUxL1O7fVgTFLXWZXa%2BU3KcMgJXv%2B4m5PwCh3z9HkJXE5%2B%2FjwpaEZqEpMxUW2qA6wmdl%2F1k5ZcvSbyALoyE2%2BjqLX2TleNUePTuPN8OPsUEL4a5e" rel="nofollow">计算机系全部课程列表</a></li>
<li><a href="https://link.segmentfault.com/?enc=43ncVkNMUwGj9wz28HQjZg%3D%3D.jDS31iJtn26KaQS92dOPI%2Bba7mTTlMGsa8JP1f4%2BlRBsK5F67zmWs6%2BWJpczdUYDrar4aQxXSM%2BTf7%2Bw7bqcHZs2mF5V7OTRyXLAzcmUlOph555AqTctp9QNPNMbT6IL1D4Zt1b5sG430v85E%2FhmrztpQIKr4%2BjXnYGXuw2Pj9Q%3D" rel="nofollow">人工智能专业下的课程</a></li>
<li><a href="https://link.segmentfault.com/?enc=8%2FelW22TyDqyRsJz%2FRs7qw%3D%3D.ChEAN0uT1V117QqgtOyD3ic46NpSOYtEXeVdpwWj7TK5pGQEQ1L8V6tJi1ub0j56cHaN1LsjepX2Q24GSONNENGpPbCRVSy6kgVgtfBjPX9QmbUlXsebQlnl0bvMLUo%2Bn8AQJLf%2BirCoC8HPxcY8Rp5%2FiSmNRNeHd1gB%2F0unlz%2BnK4CVR%2BtzxBwKOkhbtBJv" rel="nofollow">计算机科学专业下的课程</a></li>
<li><a href="https://link.segmentfault.com/?enc=W2c%2B93HU97zFkynoNJ1k4g%3D%3D.9NgPOT2ONcQoRquENICDX0xkrj5vhn%2F7chmdSMAcjwtxIe6L%2FGiqeBhvkp6IEtgmSN%2BrHAA3ILnUMQgoWc31CE7ajbGwDVse24ghGf%2FPFYwdLxL1waGntGAjThFNmcv9XcsaoAEGjXhbKg9VZVKcKzhzNuPDXyglnf314hF1rpw%3D" rel="nofollow">机器学习</a></li>
<li><a href="https://link.segmentfault.com/?enc=f7mpVd%2BeVzpTCyQQNMfZNg%3D%3D.unbfpEKkBo5KYwov%2B1xmDbGmfk2FNOa6NC%2FiLVg8MuWwaKuvQBanh%2B%2F0hWmxEk68%2FMdJZZAEYrDIByUF0gKya3TikovJPgFYNkVq2RqU45swAcas5SM7d%2FZ4zvoNYs%2FA45p2fZ0Le%2FquReM6PZnGoCruZ3%2BEURjgKdsDRzJHsW4WSD77W7a5O7PKF5SzcotJ" rel="nofollow">软件工程</a></li>
<li><a href="https://link.segmentfault.com/?enc=FCs2NcWKLHzmYcjVKmJylg%3D%3D.l1p0WuZ5xOxSpvyhWHENewMlFeat95n5a2V4%2FQDFJIXSV7ysA6Yg084eYPogaZ6zkuqJSn9O86aCas%2FmT2fLlyi9oPQNOEN7A%2FbLlzxG6MVwnRLB5AuJtOOdzRejEl9LyfUsmJVc7oCjiWupbJnbr6dkAI6tW6UQpbzXPjFlnXEwbcdpBy%2Bpqdo90YYPGsv3" rel="nofollow">语言技术</a></li>
</ul>
<p>如果上面的课程让你眼花缭乱,你可以到专门的<a href="https://link.segmentfault.com/?enc=CO95LkR7nuWB%2F1ikClUwJg%3D%3D.rksE4l%2BpOGhznXSMMT1nkl1%2F4I%2B13vg5pw15z25Z%2B8dklbtymN%2ByouOTMmLmj%2By5" rel="nofollow">课程搜索页</a>查询课程。</p>
<p><img src="/img/remote/1460000020168514" alt="" title=""></p>
<p>上面介绍的三种方法可以让你找到自己需要的课程,这里总结几个比较出名的课程:</p>
<ul>
<li>
<a href="https://link.segmentfault.com/?enc=PXWlET%2FC9JhD0rVbJF4fuw%3D%3D.Q9Cyt8gVcplkwE0KRlAXyRRZCzeB4o2WRZdhRk2sbkI7LjA5Vyn3JBH92J9epjZAGaSsmnbO3snP8v4faAkueA9QJwGJtZneZMJz%2BkdJXLQ%3D" rel="nofollow">15-440/640 Distributed Systems</a>,这门课有两个版本,Yuvraj Agarwal和Srini Seshan上的Fall学期,以及Satya和Babu上的Spring学期。Fall的15640用Go语言,更加偏向于应用一些(e.g. 实现mapreduce、比特币挖矿),Spring的15640用C和Java,更加偏系统一些。</li>
<li>
<a href="https://link.segmentfault.com/?enc=CgVrVmHs%2FeMhC%2FXXj7OZMA%3D%3D.9EU3cgSRXRAykwEEak7JwQJFcv7Ksk4ChAVdoAtuD5s%3D" rel="nofollow">Fundamentals of Programming and Computer Science</a>,<a href="https://link.segmentfault.com/?enc=dbtSuL72jf04Pge4UXEYpw%3D%3D.YJrnqWOLDv%2Bp7bsAm5fSEnNzsg6KdlghyWWDsDAM4YaGs1iRaJTZzYASPyPihjHF%2B5PKAm40Ub5IZZkhwTA5dz8uzfrAKewW23pJ1X9rLGuGoK1nXHqZSCdDDXdwOCYW2L5pQq5BpUr1qQiNc7WA2w%3D%3D" rel="nofollow">全美最好的五门计算机课程之一</a>,面向本科生的基础课程,最新课程页面为:<a href="https://link.segmentfault.com/?enc=oy%2Ba7u0oeTMSxh6W%2FdeVYA%3D%3D.mWyr9BzzlyfHOu4fK6r0aB8Ak%2FQpOOEXyjXQVSWVlVY%3D" rel="nofollow">https://www.cs.cmu.edu/~112/</a>,目前还没有更新,感兴趣的小伙伴可以持续关注。</li>
<li>
<a href="https://link.segmentfault.com/?enc=4lyxPnEU%2BPgthCitb1LlIQ%3D%3D.EcXQLk31r06Z%2B9DxXc5%2BRd89yKXw8XxTy4qf0%2BemPX8%3D" rel="nofollow">15-213: Introduction to Computer Systems</a>,该门课程诞生了著名神书<a href="https://link.segmentfault.com/?enc=GHhEfNl180iSROdOUDg2uw%3D%3D.jTzi2ttHD7X1V%2FD7dc%2FupFJx80SV%2BKtKbPjsdAObpBc%3D" rel="nofollow">CSAPP</a>,书和课程配套学习效果最佳!</li>
<li><a href="https://link.segmentfault.com/?enc=04NOJUxHj2noEuUpJhJhuA%3D%3D.mJrbrp6NyYkKYmVRTF8QRGyo9OkGewK62rb4b6mVJs17rKwZ1X%2ByRT8YRG4oYd2LWEr7clTzNVkH0TQtQTzU3CCEff2mPQDo6VI0pZI40p0IWRrWg11Ij8QA2l0e4HxdDP7m926DFrJmAOrxoLROxg%3D%3D" rel="nofollow">10-605 in Fall 2017 Machine Learning with Large Datasets</a></li>
<li><a href="https://link.segmentfault.com/?enc=Kl6Y524cUy4ojNeFzEULEw%3D%3D.SvIzDE6zICWDmSTCxChJarjv4%2FjcEUN1iLL8c2I4T8vvgJCpAY0ZmIelyHDm2oM3" rel="nofollow">17-445/645 Software Engineering for AI-Enabled Systems</a></li>
</ul>
<h2>教育</h2>
<p><img src="/img/remote/1460000020168515" alt="" title=""></p>
<p>SCS的研究生教育和人工智能专业全美排名第一,做到如此成就,在教育上自然有其自身的特点,笔者总结为:<strong>方向丰富、领域专注、提供交叉专业</strong>。</p>
<h3>本科</h3>
<p>因为SCS是一个大学院,下设七个部门,而且有全美顶尖的专业,所以它不仅为本系学生提供了全面的培养体系,也为CMU的所有学生提供了计算机学习机会。SCS的专业设置大概分为以下几个类型:</p>
<ul>
<li>Undergraduate Majors:面向CS系学生的专业</li>
<li>Undergraduate Additional Majors:类似国内双学位,学生可以修两个专业,这里的CS是第二学位</li>
<li>Undergraduate Minors:辅修专业,全校的学生只要符合条件都可以选择</li>
</ul>
<p>基于上面的专业框架,CS系为本科生提供了丰富、灵活的选择:</p>
<ul>
<li>Computer Science:计算机科学专业,也是CS领域的核心</li>
<li>Artificial Intelligence:全美排名第一的人工智能专业</li>
<li>Human-Computer Interaction:人机交互专业</li>
<li>Robotics:机器人专业</li>
<li>Computer Science and the Arts:计算机科学与艺术专业,交叉学科</li>
<li>Music and Technology:音乐与计算理论专业,交叉学科</li>
<li>Computational Biology:计算生物专业,交叉学科</li>
</ul>
<p>丰富的专业下,为了让学生更深入、专注学习某个核心领域,SCS提出了Concentration的概念,让学生能聚焦以下领域:</p>
<ul>
<li>
<a href="https://link.segmentfault.com/?enc=oAulklIFs9IKgjFQLMdUug%3D%3D.vmmc7lZw7a7dJPOS9gF0Xal2jaSBj50KWbDggWTPLCbihh8%2BI6YtIqXGzTacXQVvml6tZhAs6UoJuMB9BgoV153%2B1N87qp1pLt5JAHTo20BvA6JyjnkoLILCdj6VImXU" rel="nofollow">Algorithms & Complexity</a>:算法与复杂性,学生学完应该达到申请博士项目的水平。</li>
<li>
<a href="https://link.segmentfault.com/?enc=VXkIYRIYIZz8NA8kjAf%2BKg%3D%3D.wBelzPccTJsrd6G30wG7UArE%2BuqMVRlyAHnv3WEApBU07AOBmnOBPv%2Fuiisi%2BjWbf3FLv4Yzox%2F4Wv0oK%2Bv0t1TghSfPBlfANwjD%2BDrsdeM%3D" rel="nofollow">Computer Systems</a>:计算机系统,学生能够理解系统的设计和开发,<strong>比如内核开发、编译器优化、分布式系统设计等</strong>,达到申请博士水平或工业界同等水平。</li>
<li>
<a href="https://link.segmentfault.com/?enc=uJ5Rt4P%2BZX2wg6Lu69Rt9Q%3D%3D.GZ2%2F1hM5cBCNIOWK%2F4fnX1aimtLofKF0RyjHCvmYFcPC4QnomSWxD2760TQF7%2FIVUp52Gsx4hgG4eIbRzxN%2FJA%3D%3D" rel="nofollow">Security and Privacy</a>:安全和隐私。</li>
<li>
<a href="https://link.segmentfault.com/?enc=LZsu6cURI3ZN%2BDt62pZu8w%3D%3D.GyLdT95oyrzDMxUOeuy62OYq5E0bnc8OY%2F%2BbrHj5NIRx5NJJW%2F2%2BvOcKYDlQUKQlEejypqcuSA%2B7l93aYU5bfAr0nhddyz8aa1RO4BK6l90%3D" rel="nofollow">Software Engineering</a>:教授高效开发现代大规模软件的技巧和知识。</li>
<li><a href="https://link.segmentfault.com/?enc=jGAphGvCpcXGJ3JhdnjQMA%3D%3D.tpMuYH81EDe08TpdKCiZwmfvadYC4Svs4ChVF%2FTras4kthbBBeJJQ4mtIcyJhdWERY6vgVB2ltjp7iQPhhLLJlJSdDX%2FCufzIZelsNQmkwxuPmZ8UscszmJbPMG6CFOTO3IjbXOQK7CvDQM5jqzPyA%3D%3D" rel="nofollow">Computational Biology</a></li>
</ul>
<p>老师们考虑周到,在提供丰富、灵活选择的同时,为避免由此带来的<code>广而不精</code>,为学生们提供了核心领域,让他们能够专注学习,做到<code>广而精</code>,成为T型人才。</p>
<h3>研究生</h3>
<p>硕士学位分布在上文提到的7个部和研究所中,这些研究所负责提供学位、培养学生。<a href="https://link.segmentfault.com/?enc=drOq8w5Hr1vr7%2BldoSOYoQ%3D%3D.hwVvlNVJrVpTbJZSrWm1P7G3L4YY7Ih9544Nvnaeptl8AGsFrfS3MejPTLd5Dkx7" rel="nofollow">硕士专业和方向</a>网站上一共有20个专业,非常多!这里笔者列举几个和计算机相关的:</p>
<ul>
<li>Computer Science</li>
<li>Machine Learning</li>
<li>Computer Vision</li>
<li>Product Management</li>
<li>Computational Data Science</li>
<li>Artificial Intelligence and Innovation</li>
<li>Intelligent Information Systems</li>
<li>Language Technologies</li>
<li>Robotics</li>
</ul>
<p>每个专业都有专门的培养方案和要求,相关信息都列举在各个专业详细网页里面。</p>
<h2>总结</h2>
<p>CMU的计算机是单独设院的,并且是全美最大的计算机学院。在向学生提供广泛方案的同时,还帮助学生聚焦在某个领域深入学习,同时提供交叉学科培养方案,使学生成为广而精的顶尖人才。</p>
<p>因此,作为开发者,要能做到<strong>致广大而尽精微</strong>:广泛阅读学习的同时,要能专注于某个领域。</p>
<h2>Reference</h2>
<ul>
<li><a href="https://link.segmentfault.com/?enc=EN60mooJW7qhoOJYhQzNKw%3D%3D.GmMvUGC%2Bwkyu%2FlqqT3HIzeS0Tkf0%2Fu8EEG2T73b5yVzdHygmvmzCyor17QlDLQlg" rel="nofollow">CMU 计算机选课上有什么特别好的课程推荐?</a></li>
<li><a href="https://link.segmentfault.com/?enc=OBj8XSR3R0EkUczpEPDSyg%3D%3D.VwQivm0IWcrwXqOdw4m3gNL89vPkAkCqah1jswR4pTe3bkzE87APHeH3thvTP6Aw" rel="nofollow">在卡耐基梅隆大学(CMU)学习计算机是怎样的体验?</a></li>
<li><a href="https://link.segmentfault.com/?enc=K2a5o3a0xA76EKAab2qLsw%3D%3D.FuEk9i0nSfcQOMSDifjwynntdhxJNgSH8YVu1zm%2BsNqYomfTKrWbhE98aR9urDFRbxJ%2Bz6pWu9AYF92zc7k7fmoN7F0l786T5oQlJaOtCfIJ6HoZ40ZFdBCO6adt6UmGC0fuNm96QOBDxlfttWmUHQ%3D%3D" rel="nofollow">百度百科-卡耐基梅隆大学</a></li>
</ul>
Grail:Uber是如何管理大规模基础设施的
https://segmentfault.com/a/1190000020143897
2019-08-21T17:50:01+08:00
2019-08-21T17:50:01+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<p><img src="/img/remote/1460000020143900?w=1433&h=614" alt="" title=""></p>
<ul>
<li><a href="https://link.segmentfault.com/?enc=YF5Lw87XLHn0I1I92AnXJg%3D%3D.N78VLZkBda7%2Bh274DISUMYJNFbQ56Mo%2Fs4w6pwCH2X0%3D" rel="nofollow">翻译:@AdolphLWQ</a></li>
<li><a href="https://link.segmentfault.com/?enc=0zdKuIUp44qDevVyiS6dBA%3D%3D.0HHjKrLslrr%2BJKAQ%2FlBMxBK6BNb3DDmHB9gzW7m2cjUKcsOkJzZfNoPEJuqhzIHZ" rel="nofollow">项目地址</a></li>
<li>用时: 10h</li>
</ul>
<blockquote>本文介绍Uber存储平台团队是如何管理自己的存储基础设施的。他们把基础设施抽象成图模型,以此收集状态,然后根据这些信息执行运维任务、制定决策。</blockquote>
<p>易于获取当前系统状态对于规模化构建、维护基础设施至关重要。由于Uber的商业持续扩张,我们的基础设施在规模和复杂性上不断增加,使得我们必要时获取所需信息变得很困难。</p>
<p>为了解决这个问题,我们开发了Grail,一个聚合状态信息并在一个全局视图中展示、横跨多个<a href="https://link.segmentfault.com/?enc=%2BjUcxWZn4N7BqbMThfNUbg%3D%3D.lVNpxL%2B6nxvPiPRu0%2BV%2B%2FwhxFL8Yiu2lEQ6aOfSJk%2B9P6IrhExaHZb8VFxKj%2F17i%2FxDJiJfn8BZqi4tx9614RQ%3D%3D" rel="nofollow">数据中心和区域</a>的平台。有了Grail,我们可以更容易地开发快速、健壮的运维工具。</p>
<p>继续阅读以了解Grail如何通过图模型,根本性地改变Uber工程部门操作存储的方式,使团队更容易缝合不同源头的数据。</p>
<h2>设计简单的管理方式</h2>
<p>2016年末,为了支撑不断增加的负载,我们把所有数据库主机从旋转式硬盘更新到固态硬盘。有一步很重要,就是依然能够鉴别和追踪使用旧硬件的成千上万数据库。</p>
<p>那时候我们没有容易的方式获取设备的当前状态,并且还要追踪大量脚本和任务。这驱使我们寻找不同的方法来开发大规模运维工具,需求如下:</p>
<ol>
<li>持续收集整个基础设施的状态。</li>
<li>唯一的全局视图。</li>
<li>低延迟从所有数据源获取所有数据。</li>
<li>关联所有数据源的数据。</li>
<li>简单添加和删除数据源。</li>
</ol>
<h2>Grail简介</h2>
<p>不像<a href="https://link.segmentfault.com/?enc=3d%2FI2BA9hLyuvyOmBRQEEw%3D%3D.R2QAfJQK62mtZJZq0O9dB502n9Zf1jkG5ZdLo5nFd7p3Ml3OrNOyKt%2FgZ2whPl%2BAqCydpvCTfpUGBWrX0RLOdA%3D%3D" rel="nofollow">Metricbeat</a>和<a href="https://link.segmentfault.com/?enc=NGybAKPHGdMSJbFivDpG0A%3D%3D.N71xJYKagPQUsktMbCFxfcqkxURcUTruomMQQidN7pQ%3D" rel="nofollow">osquery</a>等类似信息收集系统,Grail不收集特定领域的信息,它的角色是一个平台,以高可用和响应式的方式聚合、链接和查询来自不同数据源的数据,例如主机、数据库、部署和所有权等信息。它高效隐藏了实现细节。</p>
<p><img src="/img/remote/1460000020143901?w=768&h=387" alt="" title=""></p>
<p>此外,你可以接近实时的方式,快速获取下面问题的答案:</p>
<ol>
<li>哪些主机当前空闲空间超过4TB?</li>
<li>某个团队的数据库使用多少磁盘空间?</li>
<li>哪些数据库运行在旋转磁盘上?</li>
</ol>
<p>如果你的服务和主机很少,这些问题就不重要。你只需要写一个脚本,在需要的时候直接收集信息就行了。但是以Uber的规模,当你有一堆服务和数十万主机时,这种方法就失效了。节点太多响应就会慢,查询完后数据关联会出错,结果也不能反映真实情况了。大规模场景下很难及时收集状态。</p>
<p>一个关键结论是“不存在唯一的真理来源”。数据中心和系统的信息总是分布在多个地方,只有把它们关联起来才能做决策。更复杂的是这些状态一直在变:主机的空闲磁盘空间在变、供应新的存储集群、并行发生的其它事件。整个系统的状态不可能实时获取,只能接近它。</p>
<h2>规模化维护</h2>
<p>Uber的存储平台团队开发维护的存储系统支撑了拍字节的关键任务数据,我们的运维工具有一套标准的自我修复范式,有三个简单步骤:首先我们收集系统状态,然后和正常状态比较,最后处理异常数据。</p>
<p><img src="/img/remote/1460000020143902?w=728&h=554" alt="我们构建的所有操作工具都经过这个循环,直到系统状态收敛于正常状态" title="我们构建的所有操作工具都经过这个循环,直到系统状态收敛于正常状态"></p>
<p>如前文所述,在大规模场景下,不使用Grail这样的聚合平台是很难收集状态。举个例子,当我们想获取所有运行主机当前状态时,比如trips数据。首先我们要先找出哪些主机包含这个数据。接下来我们要连接到这些主机并收集当前状态。最后转换并展示结果。</p>
<p>有了Grail,我们只需要运行一条查询语句,就可以获得需要的信息:</p>
<pre><code>TRAVERSE datastore:trips (
SCAN cluster (
SCAN db (
SCAN host (
FIELD HostInfo
)
)
)
)</code></pre>
<p>结果以json文档的形式返回,与查询结构非常相似,对代码友好。下面的代码片段展示了运行上面查询语句的精简版结果:</p>
<pre><code class="json">{
"__id": "datastore:trips",
"cluster": [{
"__id": "cluster-trips-us1-44",
"db": [{
"__id": "cluster-trips-us1-44-db26",
"host": [{
"__id": "host:database862-sic1",
"HostInfo": {
"cpuCount": 24,
"puppetRole": "database",
"memory": {
"freeBytes": 1323212425,
"totalBytes": 137438953472
},
"disk": {
"freeBytes": 48289601723,
"totalBytes": 1598689906787
}
}
}]
}]
}]
}</code></pre>
<h2>拼接数据</h2>
<p>Grail围绕对Uber基础设施的两项观察进行设计。第一,基础设施中节点和节点间的联系可以很自然地建模为图。</p>
<p><img src="/img/remote/1460000020143903?w=768&h=325" alt="有了Grail,基础设施被表示成相互连接的节点图" title="有了Grail,基础设施被表示成相互连接的节点图"></p>
<p>模型图中的节点通过唯一的键进行标识,键由类型和名字以<code>type:name</code>的形式构成。数据源使用节点键将包括属性和连接的数据附加到节点上,因此数据就好像被节点键标识一样。节点的键空间是全局的,而属性和连接的键空间相对于节点是局部的。</p>
<p>Grail的对象模型是这样的,建模图中的节点由数据源生成的属性和连接隐式定义,这意味着下面条件至少满足一条节点A存在:</p>
<ol>
<li>数据源产生的数据有A的属性。</li>
<li>数据源将节点A与至少一个其它节点关联。</li>
<li>数据源至少将其它一个节点与A关联。</li>
</ol>
<p>第二点是单个基础设施概念,比如主机或数据库的信息是去中心化的。这意味着获取完整数据视图需要结合不同系统的信息。</p>
<p>Grail的方法是让每个数据源提供自己所属子图来解决去中心化问题。这些子图可能会有重叠,因为数据源可能把属性和连接附加到同一个节点。</p>
<p><img src="/img/remote/1460000020143904?w=768&h=361" alt="图4:每个数据源提供它们自己的子图,并且将数据附加到节点键上。查询时将这些子图结合起来,提供整个基础设施的视图" title="图4:每个数据源提供它们自己的子图,并且将数据附加到节点键上。查询时将这些子图结合起来,提供整个基础设施的视图"></p>
<p>上图最上面展示了三个子图。实线和颜色表示子图由哪些数据源提供,虚线表示整个图。下面的图表示从Grail用户的角度看到的视图。</p>
<p>通过方法,我们可以自动更新数据源的所有数据。对不同数据源,我们能够以不同的速度并行更新数据。</p>
<p><img src="/img/remote/1460000020143905?w=768&h=433" alt="" title=""></p>
<p>上图中,数据源1在键<code>HostInfo</code>下附加属性,数据源2键<code>ServiceInfo</code>下附加属性,并将此节点和关联类型<code>Service</code>下的一系列服务建立联系。</p>
<h2>数据导航</h2>
<p>随着设计的实施,我们需要一种简单的方法,能够在图中执行特定遍历。我们调研的技术中没有能很好符合需求的。比如,<a href="https://link.segmentfault.com/?enc=kJ%2BPDOauQ34UIoCT5%2FI5lg%3D%3D.%2B4ZuigPmVyQMepYUyin7gebkmuG9XUAjj45Jsw4vflU%3D" rel="nofollow">GraphQL</a>需要定义模式,且不支持映射和节点间命名关联。<a href="https://link.segmentfault.com/?enc=DzyDE86Z6%2ByxAHQ6i1aqHg%3D%3D.iUgZesLZ8F1qsnn12gGUIJ9jSybJ9PWRnH7dMCCEy%2FrB6RFRfyFXPTDzTIZrO0lxgeEwa3LijwYwvmQC8BKv9Q%3D%3D" rel="nofollow">Gremlin</a>)似乎可以,但实现并单独使用它非常复杂。所以我们开发了自己的方案。</p>
<p>我们的查询语言YQL,用户只需要指定一个开始节点集,然后通过后面的条件遍历图,同时与沿图属性中的字段交互。举个例子,下面的查询语句列出了所有满足条件的主机:空闲内存大于40G、剩余磁盘空间大于100G且是SSD:</p>
<pre><code>TRAVERSE host:* (
FIELD HostInfo
WHERE HostInfo.disk.media = “SSD“
WHERE HostInfo.disk.free > (100*1024^3)
WHERE HostInfo.memory.free > (40*1024^3)
)</code></pre>
<h2>迁移到内存</h2>
<p>从发布起Grail的架构经历多次迭代。起初,它是我们之前数据库运维工具的内部组件。第一版迭代受<a href="https://link.segmentfault.com/?enc=3VEf1hoQCgOAjbhum0cRew%3D%3D.d8CRKtyxE6J1QI1FBQkxWYK3ROmObGnNCWEaUrdZ2wFwoihDh1QwpQJjL5FoFvaQp%2F9tuci1WaMxW8%2BIntbRh%2BTbOOJiN2GnWoamdm93xowAFq8aOpur7C23th9r7GS6p%2FdjNX5S5Ysc%2BWTi2Bh79A%3D%3D" rel="nofollow">TAO</a>启发,基于Python开发,使用redis存储图。当它变得低效时,我们决定把它作为一个单独服务用Go重写,使用共享的ElasticSearch集群存储。但是随着时间的推移,我们发现这个方案在快速、有效摄取和查询所需信息时,缺少伸缩性和低延迟。</p>
<p>我们重新思考它的架构,把之前存到共享ElasticSearch集群中的数据迁移,改为直接存储到每个查询节点上定制的内存数据库里。</p>
<p>当前Grail的高层架构包含三个组件:</p>
<ol>
<li>
<em>Ingesters</em>,从配置的数据源收集数据。</li>
<li>
<em>Coordination</em>,确保严格的数据更新顺序。</li>
<li>
<em>Query Nodes</em>,为数据获取提供水平扩展能力</li>
</ol>
<p><img src="/img/remote/1460000020143906?w=768&h=405" alt="" title=""></p>
<p>Ingesters周期性从预配置的数据源中收集数据,然后通过Coordination集群传输,最后存储到每一个查询节点上的datastore中。Coordination由定制的内存<a href="https://link.segmentfault.com/?enc=NIpGmXzlzq%2F6aoZ6xvHRdQ%3D%3D.kffSEUBLeEv53LNexZcT1%2BBcEhm2R%2B0aZnIrTHeV1Nk%3D" rel="nofollow">Raft集群</a>实现,基于<a href="https://link.segmentfault.com/?enc=BGjhNlzv1BKHpgkkTyowHA%3D%3D.IT1KOv9ZMxRpFgRYfNb5c4YtUf1ydGqchzgJ%2FbpEbXYQEKffaUEe4STDlyOF67BW" rel="nofollow">etcd Raft库</a>开发。Raft协议确保数据更新和被存储到datastore的顺序,同时确保重启后数据一致。<code>Coordination Nodes</code>和<code>Query Nodes</code>都包含了存储在datastore中的每个数据源最新数据更新。当Raft-logs被截断时,Coordination Nodes只使用datastore中的数据来创建当前数据的快照。</p>
<p>datastore是一个简单的键/值抽象,数据源的名字作为键,不同的键下面存储每个数据源最新的数据更新。所有数据源的数据分开存储,只有在执行查询时才聚合起来。</p>
<p>Grail通过在每个区域运行各自的实例,为我们提供基础设施的全局视图。每个实例负责从本地主机和服务收集数据。查询节点根据配置追踪本地和远程区域上的raft-log。当执行查询时,查询引擎把本地和远程信息结合起来。</p>
<p>为了扩展Grail,我们可以部署多个coordination集群、扩展查询引擎来支撑分布式查询,以便将来可以增加数据吞吐量和大小。</p>
<h2>处理精确问题</h2>
<p>在与分布式系统交互时,考虑到信息不准确非常重要。不管数据如何提供,来自聚合平台或直接来自源头,在系统变化时不可避免会有延迟。分布式系统不是事务的,你不能用一致的快照获取它。不管基础设施规模如何,这些条件都是对的。</p>
<p>我们的运维工具使用Grail的信息做决策。当这些决策需要改变系统时,在应用改变之前,我们总是确保双重检查源头的信息。举个例子,当主机端的代理程序被分配任务时,代理程序在执行任务前会先检查先决条件是否满足,比如判断主机是否有足够的磁盘空间。</p>
<h2>关键点</h2>
<p>正如前面所讨论的,高效基础设施管理需要深刻洞察系统状态。当规模很小时这很简单,你只需要按需查询数据即可。但是这个方法不适用大规模系统,这时你要将信息聚合到一处。正如我们在实践中学到的,当有数十万主机和许多系统时,快速获取合理且最新的系统状态很重要。</p>
<p>最后Grail的优势可以总结为三点:</p>
<ol>
<li>所有数据都被聚合到支持通用查询API的单一共享模型。</li>
<li>低延迟查询所有地区当前状态。</li>
<li>团队可以附加自己特定领域的概念,并将它们与来自其它领域的相关概念关联起来。</li>
</ol>
<p>目前,Grail服务我们存储方案的大多运维工具,并且对基础设施的各个方面都有几乎无数的使用案例。事实上随着信息范围不断增加,会有更多的使用案例。</p>
<p><img src="/img/bVborL3" alt="图片描述" title="图片描述"><br>欢迎关注公众号<strong>QuanTalk</strong>,专注于计算机科学与技术、独立思考、阅读分享,开发者认知、学习、成长平台。</p>
黑客图标
https://segmentfault.com/a/1190000018180609
2019-02-17T15:55:11+08:00
2019-02-17T15:55:11+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<p>Linux社区有他们的<a href="https://link.segmentfault.com/?enc=YnJI2NMg%2BWM5GRuVm5O1fA%3D%3D.6fwx7oJgZ0VwVw7t8sAylc%2BS7lgsNTipEtZ62hNs5laD0gMhNtsqRJdBlrIMJQAS" rel="nofollow">企鹅Logo</a>,BSDers有他们的<a href="https://link.segmentfault.com/?enc=d1zfd6D%2B0m3u9TmdXrycIA%3D%3D.szKllZhk1XbLnjSS4EkffqekHJ55NZLOhMfm3i2WUnbTCmYjH0RggBcknOBBzV5d" rel="nofollow">Daemon Logo</a>。Perl有<a href="https://link.segmentfault.com/?enc=8rG1h9dEWS6ApBbeMfGjrw%3D%3D.AU0kH8w46pNeoF2X%2F%2FC55qUiE%2Bf9zX1%2Bo6y0s4oUut0%3D" rel="nofollow">骆驼Logo</a>,FSF粉丝有他们的<a href="https://link.segmentfault.com/?enc=2npKVyTAyAmMPb3aKeom%2Bw%3D%3D.5cyDwY8JH5ufg4VcAgNc0Paj5Qf3mfGEgV1o4gVwCZre4G5nK29hUwUMEA1kc%2Bsr" rel="nofollow">gnu</a>和OSI有一个<a href="https://link.segmentfault.com/?enc=sjEVWrYxvoYyHSshPSt2Jg%3D%3D.EO9s1KbCjBokMWL%2FEARHcMSZxoE6D2qohrImxqgZMjc5CbwlM4tMlpb8GIgLruf%2BszJP%2Bk4xYdryvLmD0L0%2Bm67GEYdeU4Y43Bqf5651WXc%3D" rel="nofollow">开源徽标</a>。从历史上看,我们所没有的是一个代表整个黑客社区的标志,标志是所有这些组织的一部分。这是一个我们采用的提议 - 灵感来游戏<a href="https://link.segmentfault.com/?enc=%2BQ%2FsHyYNI1dm8dhFy8WZvw%3D%3D.4Awd%2FsCw4WSUhjYhFF6cg%2BhG%2FC6ESj1mQezuIbLv8Tkli8mFYW2rAJ7xZc5Bis8kSwGZ%2F4ALaIYgmn%2BA26jfOQ%3D%3D" rel="nofollow">Game of life</a>的Glider pattern。</p>
<p>在alpha测试中,大约一半的黑客看到这个想法后立刻说说“哇!酷!”,无需测试者进一步解释。如果你不知道Glider pattern是什么,或者为什么它会成为一个好的标志,或者如果你对可能的标志感到怀疑,请阅读<a href="https://link.segmentfault.com/?enc=d%2F%2FUUqwWG44T61xV5oudYg%3D%3D.KW2QcnGS4TaCUvDdzHChaO3z%2F%2BYPfjFygX5tAQo%2FHQyS79ZFai%2FxgjEJdDh%2FjgT4" rel="nofollow">FAQ</a>页面。</p>
<p>我在2003年10月首次提出这个标志。从那以后,它已经广泛应用,你可以从左边的国际翻译数量看出来。Glider标志的成功并不是绝对的,因为许多黑客原则上反对徽章的想法。</p>
<h2>如果我展示它,意味着什么?</h2>
<p>当你将Glider标志放在网页上、或将其印在衣服上、或以其他方式展示时,你就会明显地将自己与黑客文化联系起来。这与声称自己是黑客并不完全相同--因为黑客是一种荣誉称号,通常<a href="https://link.segmentfault.com/?enc=OgtxUWJFkAeMNu5zpACkCQ%3D%3D.LvT0IkutvtoJH4Pfgs1uxa1EeSvVaNYMalt9NM56ounqlUw%2FoYgbdzseIWWeQp5NaGIjF91wNF5VO5vJYZf02w%3D%3D" rel="nofollow">必须由他人授予</a>,而不是自我假设。但是通过使用这个标志,你表达了对黑客目标、黑客价值观和黑客生活方式的认同。有关详细信息,请阅读<a href="https://link.segmentfault.com/?enc=n73PNCY7RSthR11Bfe9Txg%3D%3D.4ycAvpn4f8681UCPaOWqD2m4NfkuT6QVDGjvjzFnFaTEibuaMUFK2AX3Y0FHjS9x" rel="nofollow">FAQ</a>页面。</p>
<p>是的,在提案发布后仅仅四天,就有杯子和T恤周边。但请注意,我与此无关并且不发表评论;事实上,收益将转移到Electronic Frontier Foundation(电子前沿基金会)。另一个早期的商品已经消失,但<a href="https://link.segmentfault.com/?enc=F%2BOT7Ag1ee4Fs7FmBfCQWA%3D%3D.vbqG7pX2f16rcEew%2Frz8c1bxTbJAM1eE575MiPNld9Pr6QpzT3P0d8Rl2Vri%2FfwZ" rel="nofollow">其他商品</a>已经填补了这个空白。</p>
<h2>谁不应该使用这个标志?</h2>
<p>如果你认为黑客攻击是入侵他人的计算机,那么我们这些提出此标志的人不希望你展示它。去发明你自己的徽章。如果与我们混为一谈,我们会找到一些拒绝公开的方法羞辱你。</p>
<p>我曾经禁止将Glider用于商业。一些固执的人认为这是不切实际且不公平。但我认为要保持它的初心,否则你会引火烧身。</p>
<h2>如何使用它?</h2>
<p>Glider不受版权保护也没有注册商标。推荐在网页上使用它,图像和链接返回到此页面或直接指向<a href="https://link.segmentfault.com/?enc=2HvVZayk3dzmhCbM2p5YKw%3D%3D.No5XvtBuPgHPXIqVPyDB8Mn767t%2F8%2BommiG5m87s%2BpZz0p08sgAhYAu13q1G96u7" rel="nofollow">如何成为黑客</a>。 以下是你可以粘贴到页面中的XHTML片段。</p>
<pre><code class="html"><a href='http://www.catb.org/hacker-emblem/'>
<img src ='http://www.catb.org/hacker-emblem/glider.png'alt ='黑客会徽'/> </a></code></pre>
<p>你可以随意放大或缩小图像。此PNG文件是从<a href="https://link.segmentfault.com/?enc=GWCBJaOkABeT9KwIffFd9A%3D%3D.y%2F%2Fd3vTw17kRbrS9RkKGv8w3eL0sRVcqiJnx%2Fnnfikn3A2nWXwKreSeRdfmKv2BU" rel="nofollow">PIC源</a>生成的,尺寸减半。你还可以下载<a href="https://link.segmentfault.com/?enc=bUCUoX8uN12%2BK5ep5qXqwQ%3D%3D.771O4hoM7qgtj5eNUfUPyZMDVmGGXRg%2FQksbBMdMsk3rJvzV02StLWN4ClHdSv%2Fa" rel="nofollow">SVG版本</a>,可<a href="https://link.segmentfault.com/?enc=Hx7vvmTZX6ntT8jWckEGGQ%3D%3D.ST%2BmqIC7G2aAX4wtV%2BPWbb8QQ2D8ke0%2BZpUQ00kI4Kz4jK6scVqaAd23yba8X019" rel="nofollow">内联的SVG版本</a>,<a href="https://link.segmentfault.com/?enc=gL%2BZtshhEylPvvP4mE8UVA%3D%3D.hWq3oY8LSZGHT0%2FcOiAP4D6zsdkYfCoHKmUJ3SIWKCQkrs0QlgydeTXTvrMkuhD6" rel="nofollow">封装的PostScript版本</a>,甚至<a href="https://link.segmentfault.com/?enc=D22520de7gcMCyBTovoqHw%3D%3D.IjLGgxyaHoCHSPwmz6Op9E63gKNL8gIiAG0mGSY1gA12j4a2rmRg%2F8Yh4n%2Fn9Df4" rel="nofollow">TEX源</a>。</p>
<h2>买图标的地方?</h2>
<p>我与这些地方无任何关联,这里列出来是方便大家,而不是认可。链接可能随时过期,使用风险由你自己承担。你的邮费可能会改变。</p>
<ul>
<li><a href="https://link.segmentfault.com/?enc=BPKvAvaXbQ7PRbC7TsUC1g%3D%3D.ZFAPByPwdGyTNCLDKzTF2LS8tii4a%2BVoUVmSTzVY2lSxurWorqKyATehEd2i6ipa4BRYLl8YLgeIPItYWCIuUA%3D%3D" rel="nofollow">Zazzle上的Zortmeister</a></li>
<li><a href="https://link.segmentfault.com/?enc=ajM%2F50Yu6liG6u%2BtUqbp0g%3D%3D.GNM9axIhDrhSOGyRyk4aMqzDdy1CePdHI1gGe0c5oqM%3D" rel="nofollow">hackerlogo.com</a></li>
</ul>
<h2>变种</h2>
<p>在制作自己的变体之前,请阅读<a href="https://link.segmentfault.com/?enc=W%2F%2FvD3uuMjzyTSZ6762RWw%3D%3D.%2Fo23Pi9eZ3vVDoRbyOcw9RRPlEPJgr1swo4qNCJzQ4G8XOW4lm7aHeXu08eZwMmY" rel="nofollow">FAQ</a>页面。以下是我发送过的一些内容:</p>
<p><div align='center'><img alt="hacker emblem" src="<a href="https://link.segmentfault.com/?enc=5Vn0i5NoowTwYtp1FrFzNQ%3D%3D.mII0GaPo9U7KKwJ48%2F4cDLbKDmBUcCST58dH3l6YZY7MqidjDtfFGD0k6ha8DoDC1F9dI8oMxf1B9BJOiuVH5Q%3D%3D" rel="nofollow">http://www.catb.org/hacker-em...</a>;><img alt="hacker emblem" src="<a href="https://link.segmentfault.com/?enc=wiflrp2UCQ4OOfl%2FlgWRQQ%3D%3D.p3OyKipL4bDuKi0lQcyCRCAQmbuX1m8smigDw1K4LZCWewqCREMgchyyGx3ftQTkrHr9KeBlbfIddrxY10FPfA%3D%3D" rel="nofollow">http://www.catb.org/hacker-em...</a>;></div></p>
<pre><code class="shell">.O.
..O
OOO
| _ | 0 | _ |
| _ | _ | 0 |
| 0 | 0 | 0 |
.
.
. . .</code></pre>
<p>这是一个<a href="https://link.segmentfault.com/?enc=NGVY5%2B6rrgL%2Fidf8L98NHQ%3D%3D.Wb2Oam8CmnzSoop7OLsfDxRnHJBZkMtfH%2FqAm62cwhGOVZGZQ6wC2p0yIIXkYXIrU2sABeoudD4U7ujEv6EGzg%3D%3D" rel="nofollow">karamba主题</a>,用于在KDE桌面上显示Glider标志。</p>
<p>这是一个<a href="https://link.segmentfault.com/?enc=q1LtqfJysWXZD6P5214www%3D%3D.Wm7DFU%2B%2BMaB0vkq3dPiR7dTriDzsuoBrIEwZpIfBv5QOPGAU4AWWterIFz2HjGiC" rel="nofollow">ico</a>版本,这是<a href="https://link.segmentfault.com/?enc=CrJakOgU4fY35EKf6%2FQgDw%3D%3D.kIWYqKxQCV9MNExsdKxxfgJGf92b%2F3xWV79J1gdEI6p0F1hElaxjhRbznc6fWV%2F2" rel="nofollow">另一个版本</a>。如果你将其中一个命名为favicon.ico并将其放在网站的文档根目录中,它将成为你的网站图标。</p>
<p>这些纹身<a href="https://link.segmentfault.com/?enc=FjPAsUfFunYofb0EBQPkrQ%3D%3D.ZHKWqnLjATQ4K93YV71c20AZ82NLlXgM3B2OGaB50VkH3wIpDb9UVa9ZTeKkmAgs" rel="nofollow">图像1</a>和<a href="https://link.segmentfault.com/?enc=%2Beq2vb%2FPr6XSaWOMUh3f%2FA%3D%3D.bWCDejXgXoMW8gxVdqvfAr8kPAA8kZ64vKPoTgYoIQqKmZ0aFTITINV7sNVo80knpPE3dEYS45ieklLB1qCAUw%3D%3D" rel="nofollow">图像2</a>令人印象深刻,但也许有点过了。</p>
<h2>说明</h2>
<ul>
<li><a href="https://link.segmentfault.com/?enc=nEEKi68XS3SscTjAVEWEQw%3D%3D.wG8r14kV5gm6fKmvFEUG59qxVMy4qhOsZHGyI2Ef3L8%3D" rel="nofollow">翻译:@AdolphLWQ</a></li>
<li><a href="https://link.segmentfault.com/?enc=sGGhGgxdVA78Mj%2FlA2ZUcg%3D%3D.VtrdkzMFKlt3yZ5sK77RQWyrkXgBXu1LDR57sFLc9P6rTOm8evejyes3T%2BH4QiD0" rel="nofollow">项目地址</a></li>
<li>
<a href="https://link.segmentfault.com/?enc=C3u94b4r8aLlsRsY9F%2BPLQ%3D%3D.GejJtvmKiQVXCHV4BBWV1xk5WxaHcAFoIXREP655zu0%3D" rel="nofollow">tt</a>:自动生成翻译模板</li>
<li><img src="/img/remote/1460000018180612?w=344&h=344" alt="QuanTalk" title="QuanTalk"></li>
<li>2019翻译任务:7/52</li>
</ul>
AutoML:自动设计自动驾驶机器学习模型
https://segmentfault.com/a/1190000018020663
2019-01-25T12:35:10+08:00
2019-01-25T12:35:10+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<h2>译者说</h2>
<p>本人介绍了谷歌自动驾驶子公司Waymo在AutoML领域的研究成果。自动驾驶对神经网络模型的准确性和延迟要求,这要求工程师手动调优不同的神经网络架构,这不仅花费了大量的时间,而且能够调优的数量是有限的。因此,Waymo和Google AI的研究员合作,自动生成神经网络架构并训练评估,即AutoML,以便节约时间并寻找最佳模型。本文介绍了他们的初步研究成果,从取得的进展来看,未来可期。</p>
<h2>正文</h2>
<p>By: Shuyang Cheng and Gabriel Bender</p>
<p>在Waymo,机器学习几乎在我们自动驾驶系统的每个模块都起着关键作用。它可以帮助我们的汽车看清周围的环境、感知世界、预测其他人的行为,并决定自己下一步最佳移动。</p>
<p>采取感知:我们的系统组合多个神经网络,使车辆能够解释传感器数据以识别物体,并随着时间的推移跟踪它们,以便车辆能够深入理解周围的世界。创建这些神经网络通常是一项耗时的任务; 我们要优化神经网络架构,以使网络的质量和速度满足在自动驾驶汽车上运行,这是一个复杂的微调过程,一项新任务的调优通常花费工程师数月时间。</p>
<p>现在,我们与Brain团队的Google AI研究员合作,将前沿研究付诸实践来自动生成神经网络。更重要的是,这些自动生成的神经网络比工程师手动调优的网络具有更高的质量和更快的速度。</p>
<p>为了把我们的自动驾驶技术带到不同的城市和环境,我们需要以极快的速度优化我们的模型以适应不同的场景。AutoML让我们做到这一点,它提供了大量的有效且持续的ML解决方案。</p>
<h2>迁移学习:使用现有的AutoML架构</h2>
<p>我们的合作始于一个简单的问题:<strong>AutoML能否为汽车生成高质量和低延迟的神经网络</strong>?</p>
<p>质量衡量神经网络的准确性。延迟衡量神经网络的速度,它也称为推理时间。由于驾驶是一项需要车辆实时反馈、系统足够安全的关键活动,因此我们的神经网络需要低延迟运行。我们大部分直接运行在车辆上的神经网络提供结果的延迟小于10ms,这比在数据中心数千台服务器上运行的许多神经网络快。</p>
<p>在他们的<a href="https://link.segmentfault.com/?enc=22KhxiW3P4FuDX0f0lEDMg%3D%3D.SJuuOZ1%2Bm4ar73QOd%2B4QcqBgkm%2F1kAFgKUFS6BexHSpwp%2FPs%2FAiqBfkNBhM5pyP8" rel="nofollow">初版AutoML论文</a>中,我们的Google AI同事能够自动探索超过12000种架构来解决经典的CIFAR-10图像识别任务:将小图像识别为十个类别中的一个,例如汽车、飞机、狗等。在一篇<a href="https://link.segmentfault.com/?enc=LYhL6%2FIUOtam99rPAQLnNA%3D%3D.h79fz%2FGTJw3DvCO4urwSWWuXGPlTAhg6qjCKfEFgZKqSrTElnA%2B8hvP5FaFMpxlN" rel="nofollow">后续文章</a>中,他们发现了一组神经网络构建模块,称之为NAS单元,对于CIFAR-10和类似的任务,NAS单元自动构建的神经网路比手工调优的要好。通过这次合作,我们的研究人员决定使用这些单元自动构建针对自动驾驶任务的新模型,从而将在CIFAR-10上学到的知识迁移到自动驾驶领域。我们的第一个实验是语义分割任务:将LiDAR点云中的每个点标识为汽车、行人、树等。</p>
<p><img src="/img/remote/1460000018020666" alt="" title=""></p>
<blockquote>One example of a NAS cell. This cell processes inputs from the two previous layers in a neural net.</blockquote>
<p>为此,我们的研究员编写了一个自动搜索算法,在卷积网络架构(CNN)中探索数百种不同的NAS单元组合,训练和评估我们的LiDAR分割任务模型。当我们的工程师手工微调这些神经网络时,他们只能探索有限数量的架构,但通过这种方法,我们自动探索了数百个架构。我们发现新的模型在以下两方面优于以前手工调优的模型:</p>
<ul>
<li>质量相似,但延迟显着降低。</li>
<li>延迟相似,但质量更高。</li>
</ul>
<p>鉴于初步尝试取得的成功,我们将相同的搜索算法应用于两个与交通车道的检测和定位相关的附加任务。迁移学习技术也适用于这些任务,并且我们能够在汽车上部署三个新训练和改进的神经网络。</p>
<h2>端到端搜索:从头开始的新搜索架构</h2>
<p>我们受到这些初步结果的鼓舞,因此决定寻找可以提供更好结果和更广泛应用的全新架构。通过无限制组合已发现的NAS单元,我们可以更直接地寻找满足严格的延迟要求的架构。</p>
<p>进行端到端搜索通常需要手动探索数千种架构,会带来大量的计算成本。探索单一架构需要在具有多个GPU的数据中心计算机上进行数天的训练,这意味着单个任务找到理想的架构需要数千天的计算。因此我们设计了一个代理任务:缩小的LiDAR分割任务,可以在几小时内完成训练。</p>
<p>团队必须克服的一个挑战是找到一个类似于我们原始分割任务的代理任务。在我们能够确定新任务架构的质量与原始任务中架构的质量之间的关联之前,我们尝试设计了几个代理任务。然后,我们启动了类似于<a href="https://link.segmentfault.com/?enc=uLAM%2FwbRZkkzLt7pYZHASQ%3D%3D.pNMOyqaesWnl1aIQLrkjC%2FEN1y%2Frz9UrnnASGsvnxxX%2BklfDA2SW5C5c292zLrWp" rel="nofollow">初版AutoML论文</a>中的搜索算法,但现在用在代理任务上进行搜索:代理端到端搜索。这是该概念首次应用于LiDAR数据。</p>
<p><img src="/img/remote/1460000018020667" alt="" title=""></p>
<blockquote>Proxy end-to-end search: Explore thousands of architecture on a scaled-down proxy task, apply the 100 best ones to the original task, validate and deploy the best of the best architectures on the car.</blockquote>
<p>我们使用了几种搜索算法来优化质量和延迟,因为这对车辆至关重要。我们查看不同类型的CNN架构并使用不同的搜索策略,例如随机搜索和强化学习,我们为代理任务探索10000多种不同的架构。通过使用代理任务,原来在Google TPU集群上需要一年多计算时间的任务现在只需要两周时间。我们刚开始迁移NAS单元时就发现了比以前更好的神经网络:</p>
<ul>
<li>延迟降低20-30%,质量相同。</li>
<li>质量更高,错误率降低8-10%,与之前的架构具有相同的延迟。</li>
</ul>
<p><img src="/img/remote/1460000018020668" alt="" title=""><img src="/img/remote/1460000018020669" alt="" title=""></p>
<blockquote>1) The first graph shows about 4,000 architectures discovered with a random search on a simple set of architectures. Each point is an architecture that was trained and evaluated. The solid line marks the best architectures at different inference time constraints. The red dot shows the latency and performance of the net built with transfer learning. In this random search, the nets were not as good as the one from transfer learning. <br>2) In the second graph, the yellow and blue points show the results of two other search algorithms. The yellow one was a random search on a refined set of architectures. The blue one used reinforcement learning as in [1] and explored more than 6,000 architectures. It yielded the best results. These two additional searches found nets that were significantly better than the net from transfer learning.</blockquote>
<p>搜索中发现的一些网络架构显示了卷积、池化和反卷积操作的创造性组合,如下图所示。这些架构最终适用于我们最初的LiDAR分割任务,并将部署在Waymo的自动驾驶车辆上。</p>
<p><img src="/img/remote/1460000018020670" alt="" title=""></p>
<blockquote>One of the neural net architectures discovered by the proxy end-to-end search.</blockquote>
<h2>下一步呢?</h2>
<p>我们的AutoML实验只是一个开始。对于我们的LiDAR分割任务,迁移学习和代理端到端搜索都提供了比手工调优更好的神经网络。我们现在有机会将这些机制应用于新类型的任务,这可以改善许多神经网络。</p>
<p>这一发展为我们未来的ML工作开辟了新的令人兴奋的途径,并将改善我们自动驾驶技术的性能和能力。我们期待与Google AI进一步工作,敬请期待!</p>
<h2>致谢</h2>
<p>Waymo和Google之间的合作由Waymo的Matthieu Devin和Google的Quoc Le发起和赞助。这项工作由Waymo的Shuyang Cheng和Google的Gabriel Bender以及Pieter-jan Kindermans执行。特别感谢Vishy Tirumalashetty的支持。</p>
<p><img src="/img/remote/1460000018020671" alt="" title=""></p>
<blockquote>Members of the Waymo and Google teams (from left): Gabriel Bender, Shuyang Cheng, Matthieu Devin, and Quoc Le</blockquote>
<h2>说明</h2>
<ul>
<li><a href="https://link.segmentfault.com/?enc=xSpge5NjVmRBzAFsIzuBiw%3D%3D.dYqg6JO6oNPd0M%2BA8uuWRE%2FtyHZhRXrmDLz84P1XkGc%3D" rel="nofollow">翻译:@AdolphLWQ</a></li>
<li><a href="https://link.segmentfault.com/?enc=tukChBjNgQ3eZy5UoibMhA%3D%3D.V2k%2FqN5YGpSSraMygAQiW3sy2EFfWDhs3IFYXKpgzfy7toR6Q2bPo4%2B10EsN0oLZ" rel="nofollow">项目地址</a></li>
<li>
<a href="https://link.segmentfault.com/?enc=uKyGE4%2BbDsNqzFsjTU0JVA%3D%3D.EzSKR8lb6cmYUfdpo043sjXth1axJrK%2Fv6Wt%2Fj7KnVw%3D" rel="nofollow">tt</a>:自动生成翻译模板</li>
<li>用时: 2.5h(人机混合)</li>
<li>2019翻译任务:3/52</li>
</ul>
<h2>参考文献</h2>
<ul>
<li>Barret Zoph and Quoc V. Le. Neural architecture search with reinforcement learning. ICLR, 2017.</li>
<li>Barret Zoph, Vijay Vasudevan, Jonathon Shlens, Quoc V. Le, Learning Transferable Architectures for Scalable Image Recognition. CVPR, 2018.</li>
</ul>
如何像程序员一样思考 - 解决问题的经验与教训
https://segmentfault.com/a/1190000017872902
2019-01-13T17:19:20+08:00
2019-01-13T17:19:20+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
6
<p><img src="/img/remote/1460000017872905" alt="" title=""></p>
<p>如果你对编程感兴趣,你可能看过这句话:</p>
<blockquote>“这个国家的每个人都应该学习计算机编程,因为它会教你思考。” - Steve Jobs</blockquote>
<p>你很可能想知道这句话是什么意思?以及如何做到?本质上讲,这句话是关于<strong>更高效解决问题的方法</strong>。</p>
<p>在这篇文章中,我的目标是教会你这种方法。读完本文,你将明确知道要采取哪些步骤来成为更好的问题解决者。</p>
<h2>为什么这很重要?</h2>
<p><strong>解决问题是元技能</strong>。</p>
<p>我们都面临问题。大的和小的。有时,我们处理它们的方式,呃......很随意。</p>
<p>你需要有一个系统方法,这可能是你“解决”问题的方式(我开始编程时就是这么做的):</p>
<ol>
<li>尝试一个方案。</li>
<li>如果这不起作用,请尝试另一个。</li>
<li>如果还不起作用,请重复步骤2直到解决。</li>
</ol>
<p>可能你运气好解决了问题。但这是最糟糕方法!浪费大量的时间。</p>
<p>最佳方法是:a)有一个框架, b)练习掌握这个框架。</p>
<blockquote>“几乎所有雇主都优先考虑解决问题的技能。<p>相比编程语言的熟练程度、调试和系统设计,解决问题的技能几乎是雇主寻求的最重要的技能。</p>
<p>展示计算思维或将大型、复杂问题拆分的能力与工作所需的基线技能一样有价值(如果不是更多)。” - Hacker Rank(<a href="https://link.segmentfault.com/?enc=StxSbFanHl9lzQZGF3gpww%3D%3D.1Ks7vDrr3qkkKTEUi9fVV2q%2F6rapZA%2BLH7d4BF7ABHZTID3d8XxsmyGPh6YP3rUCtyN0gS9lxRzqzg%2BtOQMggg%3D%3D" rel="nofollow">2018年开发人员技能报告</a>)</p>
</blockquote>
<h2>拥有一个框架</h2>
<p>为了找到合适的框架,我参考了Tim Ferriss关于学习的书<a href="https://link.segmentfault.com/?enc=cBIEMRhd6ribpRLeYNBeSA%3D%3D.OMvE5jL93Cvz%2B7nAehyqsYqRkn6%2BDZJYjLbItAjTOQbG%2F0iQFF5MbpB03V9W%2FFbgXdzQP7FNYE%2FGcowc7GlLTA%3D%3D" rel="nofollow">《The 4-Hour Chef》</a>中的建议。</p>
<p>这让我采访了两个人,他们非常令人印象深刻:<a href="https://link.segmentfault.com/?enc=Mzx%2BtGUVm%2BU0WwtRDmRoJw%3D%3D.vVfj6JQjZBeTmjM3wMlExR6lNFUglYi5kP0B2axF77CvDj5AZyKUDPg2X8Ue9t%2Bu" rel="nofollow">C.Jordan Ball</a>(在<a href="https://link.segmentfault.com/?enc=OvQymchT1jfn0qeIMcwHRg%3D%3D.8xEfQxyjWh3RhxJaC1QaIyWlWt%2BVoj957cqHNUcA%2ByU%3D" rel="nofollow">Coderbyte</a>的65000多名用户中排名第一或第二)和<a href="https://link.segmentfault.com/?enc=xKLjC2IWesS%2Bq5ZB3Sa%2F9A%3D%3D.vKTV1GlWcmj56roc15IBf3sBoXDpPTFlaprGNslnosA%3D" rel="nofollow">V.Anton Spraul</a>(<a href="https://link.segmentfault.com/?enc=3Mt9gIoFXq6RvsTFyPNxaw%3D%3D.wpGgTdVv7iPmoj2pFSZoOEvZXNrEv24LJcYFtaTA9j6GglZDPXaa3DxWwRTsWqEOY%2FX%2BWr%2FqXDe08VZCg6HoHg%3D%3D" rel="nofollow">《像程序员一样思考:解决创造性问题导论》</a>一书的作者“)。</p>
<p>我问他们同样的问题,猜猜结果如何? 他们的回答非常相似!</p>
<p>很快,你也会认识他们。</p>
<p>旁注:这并不意味着他们对待每件事都用同样的方式。每个人都是不同的,你也和大家不一样。但是如果你遵从我们都认可的原则,你会更快进步。</p>
<blockquote>“我看到新程序员犯下的最大错误就是专注于学习语法,而不是学习如何解决问题。” - <a href="https://link.segmentfault.com/?enc=B%2Bsk%2BlYRf9ppaHw6wAahVw%3D%3D.KIu%2BhqKD%2B2JEqOpiNk9kHifzBFRa7wwp6S9e%2Bae06nY%3D" rel="nofollow">V.Anton Spraul</a>
</blockquote>
<p>那么,当遇到新问题你该应该怎么做?</p>
<p>下面是步骤:</p>
<h3>1. 理解你的问题</h3>
<p>明确被问的问题是什么。大多数问题很难是因为你不理解它们(因此这是第一步)。</p>
<p><strong>如何确定你理解了问题?当你能用简单的语言准确描述它,你就理解了这个问题了</strong>。</p>
<p>你还记得曾经被困在一个问题上,你尝试描述它,却立即发现之前没有考虑到的逻辑漏洞?</p>
<p>大多数程序员都知道这种感觉。</p>
<p>这就是为什么你应该写下你的问题、画画涂鸦,或告诉别人你的问题(或者有些人使用<a href="https://link.segmentfault.com/?enc=gGq%2FXrP3ff3qRRj7Nz7RKg%3D%3D.CrqSr0jCAh5%2FW6Fl6fi1iXZJqRYIrUnNU2UbRonkBhMI4iZuw9Eh8BMmpUvwjgn2nDKynbMLGLgbodHpTYGMVA%3D%3D" rel="nofollow">橡皮鸭调试法</a>)。</p>
<blockquote>“如果你不能用简单的术语来解释某事,那你还没理解它。” - Richard Feynman</blockquote>
<h3>2. 做好计划</h3>
<p>没有计划前就不要开始解决问题。你需要计划你的解决方案。</p>
<p>如果你不能写下明确的步骤,别人就没法帮你。</p>
<p>在编程中,这意味着不要立即开始hacking。给大脑时间来分析问题和处理信息。</p>
<p><strong>要想获得一个好的计划,请回答这个问题:“给定输入X,返回输出Y所需的步骤是什么?”</strong></p>
<h3>3. 分割问题</h3>
<p>请注意,这是最重要的一步。不要试图解决一个大问题,你会哭的。相反,将其分解为子问题。这些子问题更容易解决。</p>
<p>然后,逐个解决每个子问题。从最简单的开始。最简单意味着你知道答案(或者很接近答案),还意味着要解决的这个子问题不依赖于其它问题。</p>
<p>一旦解决了每个子问题,请连接所有“子解决方案”,你就得到原始问题的解决方案了。恭喜!</p>
<p>这种方法是解决问题的基石。务必记住它(如果有必要,这个步骤要多读几遍)。</p>
<blockquote>“如果我能教会每个初学程序员解决问题的技巧,那就是'减少问题的技巧性'。<p>例如,假设你是一名程序员新手,被要求编写一个程序:读取十个数字,确定第三大的数字。对于一个全新的程序员来说,这可能是一个艰难的任务,即使它只需要基本的编程语法。</p>
<p>如果你遇到困难,你应该把问题简化为更简单的问题。找到最大的那个数,而不是第三大的数字。还是太难了?那找到三个数字中最大的一个呢?或者两个数中较大的一个?</p>
<p>将问题简化到你知道如何解决,然后写下解决方案。然后稍微扩展问题并重写解决方案以匹配,并继续扩展直到你回到起点。“ - <a href="https://link.segmentfault.com/?enc=nWRsGHuxIGpGl9sghopOmw%3D%3D.tjxR6eSA3Y6tHbqIgBwgk0Ky%2FaR0RPbJy6fMVoKMOUU%3D" rel="nofollow">V.Anton Spraul</a></p>
</blockquote>
<h3>4. 卡住了?</h3>
<p>到现在为止,你可能正坐在那里思考“嘿理查德......这很酷,但是如果我被困住,甚至无法解决一个子问题怎么办?”</p>
<p>首先,深吸一口气。其次,这很公平。因为每个人都会遇到这个情况!</p>
<p>不同之处在于,最好的程序员/问题解决者面对bug/错误时,他们很感兴趣而不是恼火。</p>
<p>事实上,面对打击时可以尝试以下三件事:</p>
<h4>调试</h4>
<p>逐步执行你的解决方案,尝试找到出错的地方。程序员称这为调用(事实上,这都是调试器做的)。</p>
<blockquote>“调试的艺术是弄清楚你真正告诉程序要做什么,而不是你认为你告诉它要做的事情是什么。” - Andrew Singer</blockquote>
<h4>重新评估</h4>
<p>退后一步,换个角度看问题。是否有地方可以被抽象为更一般的方法?</p>
<blockquote>“有时我们会在问题的细节上迷失方向,而忽略了在更一般的层面上解决问题这个原则。<br>当然,这个经典的例子是连续整数求和,1 + 2 + 3 + ... + n,非常年轻的高斯很快就认识到结果是n(n + 1)/ 2,从而避免了冗余计算。“ - <a href="https://link.segmentfault.com/?enc=KeeV83QLA9Q0ngwEUeWJrw%3D%3D.evaFNJJQxF%2FqomYfAqFbYiD9UU4Y7gFlQF%2FfuQbNrsZ1T9A%2F0MloKkSeOhB5NYqj" rel="nofollow">C.Jordan Ball</a>
</blockquote>
<p>旁注:另一种重新评估方式是重新开始。删除所有内容,然后重新开始。我是认真的,你会惊讶于这个方法很有效。</p>
<h4>研究</h4>
<p>啊,尝试谷歌。不管你遇到什么问题,有人可能已经遇到并解决了,你要找到那个人/解决方案。事实上,即使你已经解决了问题,也要这样做!(你可以从其他人的解决方案中学到很多东西)。</p>
<p><strong>警告:</strong>不要寻找解决这个大问题的方法,只寻找子问题的解决方案。为什么? 因为除非你挣扎(甚至一点点),否则你将无法学到任何东西。如果你什么都不学,那就浪费了你的时间。</p>
<h2>练习</h2>
<p>不要指望练习一周后就变得更好。如果你想成为一个好的问题解决者,你需要解决很多问题!</p>
<p>实践。实践。实践。在你意识到“这个问题可以通过某个方法解决前”,你需要大量时间来练习。</p>
<p>如何练习?你有很多问题可以选择:国际象棋谜题、数学问题、数独、围棋、大富翁、视频游戏、加密......</p>
<p>事实上,成功人士的共同点是他们有练习“解决微观问题”的习惯。例如,Peter Thiel下棋、Elon Musk玩视频游戏。</p>
<blockquote>“Byron Reeves说:'如果你想看看三到五年里的商业领导力是什么样的,那就看看在线游戏中正在发生什么。'<p>回到今天,Elon Musk、Reid Hoffman、Mark Zuckerberg和其他许多人都认为游戏是他们在建立公司方面取得成功的基础。” - Mary Meeker(<a href="https://link.segmentfault.com/?enc=6wvDFSkxFM2TFyCCl9FWgw%3D%3D.9qtJEAa9pHMtlST%2BJ2LAJtCGWp7T6OzVACefEC1TygKyHzaSksXsLHCcH9xENGBp6NxcVJDYNQcMs9QyGnaNHInSdcHjTz3AVguXOIDdPuKk1ej08qVunhviH3s5IdkGphuX1L5Pf6mjKrpnWyd4bw%3D%3D" rel="nofollow">2017年互联网趋势报告</a>)</p>
</blockquote>
<p>这是否意味着你应该只玩视频游戏?当然不。<strong>但是视频游戏到底带给人们什么?解决问题!</strong></p>
<p>所以,你应该做的是找到练习的方法。可以让你解决许多微观问题的东西(理想情况下,是一些你喜欢的东西)。</p>
<p>例如,我喜欢编程挑战。每天,我都尝试解决至少一个问题(通常在Coderbyte上)。</p>
<p>就像我说的,所有问题都有相似的模式。</p>
<h2>结论</h2>
<p>现在,你更清楚理解什么是“像程序员一样思考”。你也意识到解决问题的能力是一项需要培养的令人难以置信的技能(元技能)。这好像这还不够,请记住如何练习解决问题的能力!</p>
<blockquote>“就在你认为自己已成功驾驭一个问题时,另一个问题出现了。但生活也因此而变得有趣。<p>生活是突破这些障碍的过程 - 我们也必须突破。</p>
<p>每一次,你都会学到一些。</p>
<p>每一次,你都锻炼力量、智慧和观点。</p>
<p>每一次,竞争会减少一点,直到最后剩下的就是你:最好的你。” - Ryan Holiday(<a href="https://link.segmentfault.com/?enc=h9TffRb1oi%2BR3NwhFyIBVg%3D%3D.lI%2B1wFJakSw6uqK7p3xSoVxtBn8aMJBAx0pE%2BvBDjEQsy49FJf%2FBmItO6SDgE4LYk8Lj05JPHB0JeAZGkAxg%2BQ%3D%3D" rel="nofollow">《The Obstacle is the Way》</a>)</p>
</blockquote>
<p>现在,去解决问题吧,祝你好运。</p>
<h2>译者说</h2>
<p>本文以“像程序员一样思考”为题,介绍了如何成为合格、优秀的程序员。作者结合两位顶尖程序员的回答、参考一些关于学习的书籍,认为最重要的是<strong>培养解决问题的能力/技能</strong>,分享了培养这个能力的方法:形成思维框架,然后在实践中不断练习。笔者理解为多刷OJ。</p>
<h2>说明</h2>
<ul>
<li><a href="https://link.segmentfault.com/?enc=YBFTtRhsiucIfsCOO25RxQ%3D%3D.ZESIbo27aL3Nb%2FzexNGTbq9aQGdd1VOwVBvK4FB9QEPv7SCiOWG0Ootl%2B6e8r1%2BEZUe7Nhr331gb5gW3apMhwsff%2FYuBrJGfsekSRLEZW7Oq9IdswsKMyQlu7KpXaY0q6FhckKceUXnu7vKr2tD9yw%3D%3D" rel="nofollow">原文链接</a></li>
<li><a href="https://link.segmentfault.com/?enc=h5w2OzLa3S7ungcLIXhBMQ%3D%3D.S2r3DLHcP%2FgM7PuVfrNoJhz6TRXXXmlyFH4KmH5ED5M%3D" rel="nofollow">翻译:@AdolphLWQ</a></li>
<li><a href="https://link.segmentfault.com/?enc=SzKXC0gsgsaEiUBOSs1Meg%3D%3D.0FA3wD65K%2BjgY3qXZCl8CT0KjZOLMDYuZ0UGlT3M%2BN0ca19jjWIWRUey4TkIz8NJ" rel="nofollow">项目地址</a></li>
<li>
<a href="https://link.segmentfault.com/?enc=A7CVmcGffBsera9VYQIgSQ%3D%3D.aKN06hgRm7g6G0L8wlxZ5ni7iLPj3PABB%2BicIF9qMnE%3D" rel="nofollow">tt</a>:自动生成翻译模板</li>
<li>用时: 3h (人机混合)</li>
</ul>
<p><img src="/img/bVbm9IL?w=1080&h=1080" alt="图片描述" title="图片描述"></p>
2018AI最佳应用回顾
https://segmentfault.com/a/1190000017785038
2019-01-06T22:53:15+08:00
2019-01-06T22:53:15+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<h2>译者说</h2>
<p>AI商业化迅猛发展,即便如此,普通大众对AI仍然缺少专业性、科学性的认识。作者在本文中精选了7篇2018年关于AI应用的文章,并对内容做了简短、启发性的介绍,旨在帮助公众了解AI能做的事情,帮助大家了解AI在未来能达到的成就。本文还是更偏向学术性,内容比较前沿,对科研人员了解行业应用帮助较大。</p>
<p>毫无疑问,人工智能正在飞速发展,2019年很可能带来许多新的、意想不到的飞跃,比如开发出具有真实、类似人类的<a href="https://link.segmentfault.com/?enc=WqfB5fDHjeoZeavn6GyPHw%3D%3D.mL4OSjsCvSnNRai4y%2FqjAvMQgse%2BN5ZFzoy3J2IVPzqh1czsJmdnxH%2F0kEMWdQFrNin5Aon1Qr1eaTbFhEHHpw%3D%3D" rel="nofollow">通用人工智能机器</a>。我们知道我们远未到达这一目标,但是由于那里有大量与人工智能相关的故事,我们很难跟上过去一年里我们取得的成就,以便了解我们将来能实现的目标。话虽如此,这里列出了过去一年中人工智能和机器学习这个不断发展的世界的一些亮点。</p>
<h2>读心AI</h2>
<p>去年众多有趣进展中的一个便是AI可以“阅读”你的想法。虽然乍一看这可能令人不安,但另一方面,这些技术可能会帮助残障人士更好地沟通或观察,甚至帮助改善图像搜索(想象一下仅通过可视化来查找特定图像)。为了展示这种可能性,一个来自日本京都大学的团队开发了一种重建算法,它能够解码和优化人们观察物体形成脑电波中的视觉信息,让我们离“机器能精确读取人们想法”更进一步。</p>
<p>详情见:<a href="https://link.segmentfault.com/?enc=TxgpVzxbLST2VlvK1FhYEg%3D%3D.9u5YMuShJ8d1POqWExRMlQazTrnbesK1wZkBbDW2blPuO%2B%2Fau%2ByOzqN9v5vsKI3Y%2FaHsf2QZq9oLVEY5XSv66MlVAoG7MSQ0t5dHJVbZzsFcxrgZC3EWI5ijkLufg4WJ" rel="nofollow">Mind-Reading AI Optimizes Images Reconstructed from Your Brain Waves</a></p>
<h2>具备“视觉预见”的机器</h2>
<p><a href="https://link.segmentfault.com/?enc=wP0eVsqB8gQmWvhaNRpM4w%3D%3D.sgFmf3EIxQFtFxJblxMS8S6yw%2FMjvVNGfVO1086hiAYXj3M%2F3ES%2FrKfMXIn%2FW9IkgbjehFwZRPkXZXBXqCwpcA%3D%3D" rel="nofollow">深度学习</a>是机器学习的一个特殊子领域,它启发于生物大脑的结构和功能,旨在开发更好的人工神经网络,这些网络将成为像人一样学习和思考的机器的基础。今年早些时候,<a href="https://link.segmentfault.com/?enc=n46PgxQGWPkudL7%2FJOroEQ%3D%3D.KyryAgAZUrWwJ0xDOemVvfKevULYrLiqpo%2FqZZtslepqPkd1Jxialhd9UYkEdzyC" rel="nofollow">加州大学伯克利分校人工智能研究实验室</a>(BAIR)的研究人员创造了一种能够直观可视化未来的机器,使用他们所谓的“视觉预见”。灵感来自人类婴儿,婴儿在环境中实验和操纵的倾向,以便学习然后将这些知识应用到新的未知情境中,这对人类而言理所当然,但实际上机器难以掌握。这样的研究可以为机器“视觉想象能力”铺平道路,使它们能够自主地与周围环境进行交互。</p>
<p>详情见:<a href="https://link.segmentfault.com/?enc=li5rH3Ix92DyfVqLhvucFA%3D%3D.QnbFNq%2BwmSXx8ZioSaLsCpnNLD8KIfUZuMQHDwDkO%2BhyXjAMj%2FrtEXvx1p7cvyjktHwrjOLfr5SvNDCMIxzT2C350ES6cJXFDyhTcJD6nTE%3D" rel="nofollow">This Robot Can Visualize Its Immediate Future with Deep Learning</a></p>
<h2>具备社交技能的合作机器</h2>
<p>人们可能会认为合作和社交技能是只有人类才具备的领域,但最近的实验表明,机器也可以被赋予一套人的社交技能,使它们能够与其它类型的机器以及人协作。 在为机器合作的社交技能创建一个算法过程中,一个国际团队的研究人员指出:“最终目标是我们理解与人合作背后的数学知识以及人工智能发展社交技能需要具备的属性。AI需要回应人类并清楚地表达它正在做什么事情。它必须能够与人互动。”</p>
<p>详情见:<a href="https://link.segmentfault.com/?enc=SVSHrsjYNovvHpQAsaUEhA%3D%3D.uGbDXyHYcQitH2aFGf7iF9l8r0GfILWa2crA6i8hmsm4GQfxp3eymdm0VlW%2FnydWaKehc3vBnW0mtGoptvRuXAfzT3NBjNk7Jywhat0G%2F5Q%3D" rel="nofollow">AI Algorithm with ‘Social Skills’ Cooperates Better Than Humans</a></p>
<h2>从错误中学习的AI</h2>
<p>没有什么比从错误中吸取教训让我们更像人。人们可能会在机器的<a href="https://link.segmentfault.com/?enc=RJoSWZdT004OpUVCERCc1A%3D%3D.XtUfCvPz%2FnZvKkHJikDGDl5lIdaxB216FDXDdL8B%2FyBQgi7l9acm9UUuutgZdKNd2%2BQasqHNCckIxIAtbxJhqg%3D%3D" rel="nofollow">强化学习</a>中找到类似的结论,但OpenAI的研究人员指出,设计强化学习模型背后的奖励系统可能会越来越非常复杂,实际上可能会抑制机器探索超出任务目标的可能性。相反,这个团队提出了一个开源替代方案,他们称之为<a href="https://link.segmentfault.com/?enc=6y1eXwS2Ad2%2Bdd40vugXQA%3D%3D.HOIZv2EgTr07RSW%2Bm90%2BfXGAElKYYh%2FXaUx8cj1qQRwICfVefuz5Uq0cBDcGWMJG" rel="nofollow">Hindsight Experience Replay</a>(HER)。</p>
<p>详情见:<a href="https://link.segmentfault.com/?enc=z3er9KC9vP4j88e4kv3ZuQ%3D%3D.D1gepMNu6YTkTBVmJ2H%2BQLm3leQPwl%2FZ0rmN%2FwZWur5FV4ZqWnkie1FJS9V13pPLgLJvGORmZnT1gVxxcIeQc9uIE3nVj6H9Vj2PdntpXQw%3D" rel="nofollow">OpenAI Algorithm Allows AI to Learn from Its Mistakes</a></p>
<p><img src="https://cdn.thenewstack.io/media/2018/04/704c218b-display-dummy-915135_1280.jpg" alt="" title=""></p>
<h2>自我复制AI</h2>
<p>传递成功经验的能力是生物有机体区别其它事物的决定性特征。今年早些时候,来自哥伦比亚大学的两位研究人员找到了将这一原理应用于人工智能系统的方法-创建称为“<a href="https://link.segmentfault.com/?enc=h9HqXBc%2BarQv3PWOacWGHg%3D%3D.9SGc5v8BuLZu%2FsOTAOq1h%2BwdlwE%2Bc%2BI%2FK7LLIa9l2EutQYg5CxUkieMcku6F17Lm" rel="nofollow">quines</a>)”的自我复制神经网络。自我复制、自我进化的AI可以自动采用前几代的成功经验,这个想法非常诱人,具有许多潜在有用的应用场景。</p>
<p>详情见:<a href="https://link.segmentfault.com/?enc=BjhVyMaFs3ep9pVbHccG7g%3D%3D.XKi78X0gZr5Oxg6kOVeOCC7KzMQJm0IQbcOj2LcDm771823f1zqAzjDfXIr7LIhk66NUV0TWZ0dT%2FF5VIp42li8ZWGQlJBseFCuE2ZwvoXc%3D" rel="nofollow">AI Researchers Create Self-Replicating Neural Network</a></p>
<h2>AI中的文化偏见</h2>
<p>冷血机器的绝对可靠性是一个容易被人接受的谬误。但正如专家所言,我们的算法中存在大量<a href="https://link.segmentfault.com/?enc=a1MrY0cFY0Chg9dLddQlXQ%3D%3D.5ctSlGr006ITuz%2FaDdleeRrk%2F7MJ5u%2F1ATXXQOKMRBSW96OK5WWL9oGdhvI7YAmf" rel="nofollow">隐秘的文化和性别偏见</a>,当这些算法用于自动化决策系统时,会影响人们的生活。例如人力资源部门或刑事司法系统。在2019年开展AI工作时,我们必须找到解决这种<a href="https://link.segmentfault.com/?enc=c8tL6PsHwrsixZM8vBw5jw%3D%3D.7LjCUAMGrgK1veIgWm48qaXeFnzrZa24s34f3GFgP%2Fm%2FzZC0UF3Okcu%2Bd3d%2FIL%2B2" rel="nofollow">算法偏见</a>的方法,这样才能避免长期存在的偏见和社会不公正现象延续到机器中。</p>
<p>详情见:<a href="https://link.segmentfault.com/?enc=YLTrvkfF6dWraDbXk6UheQ%3D%3D.UoiJthqjbGEYDI4rg6xW4574z3DBUnP1kPHXgX7yJejaUaF2MQDBfb1zOs4jNhspafL2GEBjatw%2FD9pCLRjmZYMhDCOyKNWXHecCn8lRCng%3D" rel="nofollow">Cultural Bias in Artificial Intelligence</a></p>
<h2>AI辅助自动化</h2>
<p>当然,人工智能的讨论绕不过一些事实,即人工智能正在帮助各行各业进一步实现自动化,无论是<a href="https://link.segmentfault.com/?enc=1Kt%2BHzI36vuJ3Iwe1PxHEg%3D%3D.dQE0keD35kU1DSvIty7du9D1%2BEKRHzxXTXq8gQ2TP4RWg5EOtcQ%2B2EDb3aFB0KcJ1aD6b4gJ2pu8w9366Wjz96Jq9aC7SimeopBqH%2F0fqxYkmFouBJuG5UJjt%2B6uvJEE" rel="nofollow">制造业</a>,<a href="https://link.segmentfault.com/?enc=llJfkiJPvOVKGXvaYZexTg%3D%3D.jL0MIW1xw4TjO2fVR5%2Ba%2Be0SbcHX2C%2FMeQrKMxW1azCN8qxOlnnABr%2Fpqu%2BLscamo6yo8O%2Fs32pnJp06t6Cb6A%3D%3D" rel="nofollow">物流</a>还是<a href="https://link.segmentfault.com/?enc=gOFDIGPR9xTeHNFXmp5vFA%3D%3D.%2Fn1G5ILTV%2BMtsBGTgpZefFs%2Ff90m8vcKAo7XIT03PnMKrcJiNfCPCNb3XkyN7wucXRgCA7pjNX2gmG6Qq4XrIQ%3D%3D" rel="nofollow">金融</a>等白领领域。虽然更智能的AI系统导致工人失业,但是仍然可以期待一些积极的事情。例如使用人工智能帮助自动预测新药物相互作用中的危害或者自动化游戏设计--拯救生命或制造更多娱乐性。</p>
<p>详情见:<a href="https://link.segmentfault.com/?enc=0lu0vnVAwfqiS9gt6PYDtw%3D%3D.9jA7PtA7nxd%2FxZTm%2FOh7X37EBxc3xpwPZ8JUli43mXa11sBSaAPDpVgVNMtSgQAYCCNPt%2BYT0Okd5j2HvEH%2BOBA7z6zGJkngnMkxpe733ZM%3D" rel="nofollow">Decagon AI Predicts New And Dangerous Drug Interactions</a> && <a href="https://link.segmentfault.com/?enc=AroBMQXGzEIJtIcInIjsQg%3D%3D.wmkhGTsfd6UKW6Vp1lLn%2Bh5ZPBNEyCCsGLw25fQRUzUOfipvyPgiNRgpl8Fucdlgx4r2jIFQQakCYMk0pbzyRvEdtxP5Y2ehrg%2B2oZh%2B0ErG%2FPmAkfe6Iv%2Bf%2F6hd9%2FSs" rel="nofollow">AI Automates Video Game Design With ‘Conceptual Expansion’</a></p>
<h2>说明</h2>
<ul>
<li><a href="https://link.segmentfault.com/?enc=gN%2FJKN%2BWoqpDIbC2pX55gQ%3D%3D.PwzK1TcldNKBoi%2Bu06yWrpmWfTIK84RKRw%2F%2B02TCc90%3D" rel="nofollow">翻译:@adolphlwq</a></li>
<li><a href="https://link.segmentfault.com/?enc=7hyWahBx3NWasukHYYa%2B0Q%3D%3D.FBpQkigKovRwxTR%2F6Gxxp0izIvkN6r76sHF86Iub85sPvBElyL73Dk%2BgnZrXGDLW" rel="nofollow">项目地址</a></li>
<li>
<a href="https://link.segmentfault.com/?enc=VZsKUNB%2BX2TMr2lrKeQjgQ%3D%3D.wpsOgTTG56ZD2%2BSd5mReG2AGq91KhGcoadPtzUHfUPs%3D" rel="nofollow">tt</a>:自动生成翻译模板</li>
<li>用时: 3h(人机混合翻译)</li>
</ul>
<p><img src="/img/bVbmMRU" alt="图片描述" title="图片描述"></p>
Linux环境下载百度网盘文件
https://segmentfault.com/a/1190000015719430
2018-07-21T22:43:01+08:00
2018-07-21T22:43:01+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
5
<p><img src="/img/bVbd7vf?w=1919&h=1007" alt="图片描述" title="图片描述"></p>
<p><a href="https://link.segmentfault.com/?enc=NyNG72SwjmL6IOpaWyNEVg%3D%3D.sWK6N0RhkjuJop61D5idZPJYFdRrLgddKI4Br7xYWgq%2BEzx%2F0BgA2oDRBx9OF1kllLUZSoslPrs7BYGaUwk%2F5g%3D%3D" rel="nofollow">原文链接</a></p>
<p>Linux中使用浏览器下载百度网盘的文件,如果文件很大或者下载的是文件夹,则会默认打开网盘客户端,但是Linux下没有官方的网盘客户端,这就导致无法下载。虽然有开源bcloud,但是已经不维护了,笔者试了下发现存在很多问题,这里不推荐。</p>
<p>摸索几个方案后,找到一个相对好一点的方案,这里记录下来分享之。</p>
<h2>Overview</h2>
<ul>
<li>
<a href="https://link.segmentfault.com/?enc=i9S%2F8mtoFP9KqrhWc4Tz2Q%3D%3D.M5b4wR%2FmaqbzvV%2BxfaqpOLwMovNzjIC9ZqSmpkYqfjA%3D" rel="nofollow">aria2</a> 命令行下载工具,负责下载百度文件</li>
<li>
<a href="https://link.segmentfault.com/?enc=vrLGBm8unqdqhhs8QVL4Hg%3D%3D.jnqva%2BapQ3qEZyQT1zayoiMzwvNdEPCjcYHDKlxNzfWH6s3qIqhsL7dAYqRDKLWn" rel="nofollow">BaiduExporter</a> 浏览器插件,能够把选中的云盘文件/文件夹下载地址导出到aria2,支持Chrome和Firefox</li>
<li>
<a href="https://link.segmentfault.com/?enc=q5my255WZN606B4TCJSCPg%3D%3D.2qDQcXMmNCW0LJxeCcFQxqTVtY17643DZ%2FAUC2858gZi5vNjugLkxqzaCwPsP6yy" rel="nofollow">webui-aria2</a> webui,可视化aria2下载进度</li>
</ul>
<p>原理就是先运行aria2服务端,监听6800端口。浏览器安装BaiduExporter插件后,选中下载项,页面会多出一个tab(下文详细列出),点击“下载地址导出到aria”,aria就会开始下载。然后运行webui查看下载过程。</p>
<p>下面以ArchLinux为例简介配置过程</p>
<h2>Install</h2>
<h3>aria2</h3>
<pre><code class="shell">sudo pacman -S aria2</code></pre>
<h3>BaiduExporter</h3>
<p>这个插件很重要,没有她就没办法生成文件的下载地址。参考<a href="https://link.segmentfault.com/?enc=yzabgef07OIgLk6CsU61EA%3D%3D.PfjTB6gwrmVq9EDSbdpK56A0IDbQ3IppbQyfQHzJOHVfvz4d2xfwTTIt%2BYhAH04Z" rel="nofollow">官网安装教程</a>:</p>
<ol>
<li>下载crx插件文件,下载后浏览器可能会提示文件有风险,建议删除(Discard),忽略这条提示</li>
<li>chrome打开chrome://extensions,将下载的crx文件拖到浏览器里面</li>
</ol>
<h3>webui-aria2</h3>
<ol><li>clone project</li></ol>
<pre><code class="shell">git clone https://github.com/ziahamza/webui-aria2</code></pre>
<ol><li>启动webui服务</li></ol>
<pre><code class="shell">cd webui-aria2
node node-server.js</code></pre>
<p>浏览localhost:8888</p>
<h2>下载文件</h2>
<ol><li>先运行aria2</li></ol>
<pre><code class="shell">aria2c --enable-rpc --rpc-listen-all</code></pre>
<ol><li>选择要下载的文件/文件夹,导出到aria2 rpc</li></ol>
<p><img src="/img/bVbd7vh?w=817&h=492" alt="图片描述" title="图片描述"></p>
<ol><li>启动webui-aria2,浏览localhost:8888查看</li></ol>
<p><img src="/img/bVbd7vf?w=1919&h=1007" alt="图片描述" title="图片描述"></p>
<h2>Reference</h2>
<ul>
<li><a href="https://link.segmentfault.com/?enc=1mbqyAtuNtCs76NmXJH26g%3D%3D.J7pSok0gxzOAva8fFZeQ0U75ZG2ff6BEji%2FnmMxU2rk05HTqhxyY4KkZA5skhCd%2B06aawhX1GajQkuRqNHJKAxrJE5nOMOApwU%2FlRGXIoInbpjRrPKhQb13t%2BXYskrLfhTREgeUymj%2BR%2F5VCBxlpB556Hl3GUTL52kL4DcGYqB30BBFrGBRGpP8qLp3qSiB%2BCo%2BpGQvNyzcrEgXxTlyjKOebAi2RydnGGFUAIKmSMOng0LpI3hoRTO7KZ%2Bw%2FVU4V" rel="nofollow">百度网盘第三方下载工具“Aria2”使用教程</a></li>
<li><a href="https://link.segmentfault.com/?enc=O6DnOfcIsusQ5Qj%2Be%2Bgupg%3D%3D.FwpNpGjU8o%2Fqwfxvb467oUCMqpLU1VsAjCo7z9UJN6sy%2FEKWhMkIPNrtAHb9eJ5W0D1c9uvi%2B8cXAgEdmNh5gQ%3D%3D" rel="nofollow">BaiduExporter:百度网盘下载 Chrome插件图文介绍</a></li>
</ul>
搭建Gitea服务
https://segmentfault.com/a/1190000015718403
2018-07-21T19:47:10+08:00
2018-07-21T19:47:10+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<p><img src="/img/bVbd7wY?w=1920&h=1007" alt="图片描述" title="图片描述"></p>
<p><a href="https://link.segmentfault.com/?enc=w44T78OiYu1exvJ9pKBSiw%3D%3D.d3KraFQ2H5h4KJiyYJCgYmtvLHSseKc1ftNjZQwwhhhCmyYt66BIBZIyVtBv80T4" rel="nofollow">原文链接</a></p>
<h2>Overview</h2>
<ol>
<li>使用容器部署</li>
<li>Sqlite DB</li>
<li>shell script</li>
<li>mail config</li>
</ol>
<h2>脚本</h2>
<pre><code class="shell">#! /bin/bash
docker run -d --name=gitea --restart=always \
-p 32722:22 -p 32780:3000 \
-v /var/lib/gitea:/data \
gitea/gitea:latest</code></pre>
<h2>配置</h2>
<p>因为Gitea的文档还不是很完整,所以很多地方需要摸索实验,所以这个是重点,防止少踩坑。</p>
<h3>基本项</h3>
<ul>
<li>SSH Server Domain:git.example.com # git服务域名</li>
<li>Gitea Base URL:<a href="https://link.segmentfault.com/?enc=OtrYPjDL%2FAB5Nr0upGGWwA%3D%3D.KcRZrTaiv9b9ypk86V6qHWMmB2KjBh8pDdpn3v%2Bc4Cs%3D" rel="nofollow">http://git.example.com</a> # 配置后gitea自动跳转到这个页面</li>
</ul>
<h3>Mail</h3>
<p>邮件的配置Gitea文档没有详细列出,这里参考<a href="https://link.segmentfault.com/?enc=MF6OeWPt7Vu7ZcOb0v3mAA%3D%3D.8o%2FRrh0icHHIU6OLqA9EJSR23iC6W%2Fce5taDRf3tmogQty14pVboLJrNiXGSu90XJkaWy%2B6ueeESKLrVO7v5Cw%3D%3D" rel="nofollow">GitLab的配置</a></p>
<ul>
<li>SMTP Host: smtp.mailgun.org:587</li>
<li>Send Email As: Adolphlwq <name@server.com></li>
<li>SMTP Username: your name</li>
<li>SMTP Password: your password</li>
</ul>
<h2>Local git config</h2>
<p>Gitea sshd服务运行在容器中,暴露在主机10022端口,这样需要修改本地的ssh配置才能防止git使用默认的22端口。</p>
<pre><code class="txt">Host git.example.com
HostName git.example.com
Port 32722</code></pre>
<h2>问题</h2>
<p>测试发现使用Mailgun的邮件服务发送给网易邮箱会被当垃圾邮件过滤掉。参考:<a href="https://link.segmentfault.com/?enc=wEcE2QTA9Wx47uh26E6Z8Q%3D%3D.DXMZPh3PZTbi9vjXkrLmf4yKX9qORd4KepPVRiZO6gD63n2cGV2rRQ6XfzuJw8sc" rel="nofollow">http://mail.163.com/help/help...</a></p>
<h2>Reference</h2>
<ul>
<li><a href="https://link.segmentfault.com/?enc=QoeuS98PLJaULQYDzh4srg%3D%3D.D7ZHGalNtA%2BsqEFrFeDEU3EEln%2B5ZLXYyl%2BLxxAFfrOoVOHSiSrMRAk3CUpeEBzrESvogNnOUL6fJ3aaPcnaWg%3D%3D" rel="nofollow">从Docker安装Gitea</a></li>
<li><a href="https://link.segmentfault.com/?enc=pzd0Pzwg6ZWXYlH5UHg4wA%3D%3D.1kWM8wPADvcgiymvgGDmH03h2ExlgDJ8xGZMlfVJ5UUd1VwYJYzeR8gQIKdHYEl8LvOtsAwTq%2Bbs0ZcIJ19CeA%3D%3D" rel="nofollow">GitLab的配置</a></li>
<li><a href="https://link.segmentfault.com/?enc=CNmT5SPXgxZtD3saPRm8IQ%3D%3D.Plx5nCFEdFCmRpqA2OlvkJIMAZ80uj%2FZmAtYnu3x2ww9Ov3KR2tuUgPfKJKj9UNw" rel="nofollow">修改了SSH默认端口之后,如何配置git</a></li>
</ul>
kde5与archlinux环境下配置libinput-gestures多手势操作
https://segmentfault.com/a/1190000011327776
2017-09-23T22:23:12+08:00
2017-09-23T22:23:12+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
7
<h2>初衷</h2>
<p>自己的笔记本是archlinux+kde plasma5的环境,看到同事的macbook pro支持很多<code>手势操作(gestures)</code>,自己也希望在archlinux和kde的环境下配置方便的手势操作。</p>
<p>查询资料后发现<a href="https://link.segmentfault.com/?enc=0RJd74DJXPhq2Nchm7PJdw%3D%3D.l1pUHTzitgNCwMYnNQY3OLXkMenGofVAyIpAjkRV%2BzT7wm99QZsl8LqTmgcmklM7" rel="nofollow">touchegg</a>和<a href="https://link.segmentfault.com/?enc=tzH%2FhpjBtdZJvxY9QfH1aw%3D%3D.vEoBgIfQ%2FzNq4nfmZ5EwPdtjPFyb3HCK1%2FY4TOBlIcdkyZAJZZuGa6Mt8AbP3L%2Fb" rel="nofollow">libinput-gestures</a>都可以满足需求,但是在实际配置过程中,touchegg存在很多问题一直都没能解决,而libinput-gestures基本没有太大的问题。所以本文主要介绍如何配置libinput-gestures。</p>
<h2>预备知识</h2>
<ol>
<li><a href="https://link.segmentfault.com/?enc=VpHWwL8JBXcCfE%2Ff96b9YQ%3D%3D.FbScfVEZy%2BqyCtPX5b2m9hqNLSzGp4M9J9XI7UNb%2BmgOEfl7vhZRJoNKLqj3S60K0sUN1DNBF7yCBG4%2FZ2tWTg%3D%3D" rel="nofollow">计算机窗口管理器</a></li>
<li>kde是X.Org桌面环境,<a href="https://link.segmentfault.com/?enc=Wv3acmHe%2BFqG3kt8vJHeUA%3D%3D.aljACIfARg5k7ZRLUOb35TqXobV7aXx9l2tLhBQt0bI%3D" rel="nofollow">aur</a>上维护了一个基于X.Org Server的驱动<a href="https://link.segmentfault.com/?enc=6EjxeVvzQKSkXV8pK6p1Qg%3D%3D.GusBmrWRvN%2BuAKYEjp%2FlyFdeEsdTqECiRbxNrMgwGcQlUnD7xwsLducCtREWmB5LDyBQDlY6RUEsDQ9MfwFJ5g%3D%3D" rel="nofollow">xf86-input-libinput-git</a>,很方便。它们间的关系如下:</li>
</ol>
<p><img src="/img/remote/1460000011327779" alt="" title=""><br>X11 client在我这里就是kde plasma5。</p>
<ol><li>驱动程序libinput,linux生态提供了很多驱动,本文使用的驱动是<a href="https://link.segmentfault.com/?enc=SYQHfCMOF33mAoI4n00vkQ%3D%3D.5k4g3ZEKapYx6BybaqqI3t24UEAalOj924PIp%2FBH%2B9iTH9pdZ%2FRaemal7MJ2QNi8nxCO2On7v2PdGm3I5AcWRw%3D%3D" rel="nofollow">libinput</a>,它负责分析内核从输入设备得到的数据,发送给桌面环境,桌面环境根据不同的数据进行反馈。</li></ol>
<h3>术语解释</h3>
<ul>
<li>touchpad:通常意义上的触摸板。</li>
<li>clickpad:指底部没有按钮的touchpad,参考<a href="https://link.segmentfault.com/?enc=gaB1NmKVfXAhNlrtf0SjBQ%3D%3D.Zht%2FALH5TrmsBSpOLdV0iytmhoN02VCqscLVAsFXDof1qHTBJ94zBqd0L2Db6Mcn8EV%2F%2FK68mHhZtTYMoQfGeNKeUwtY6zi7x5sVd3%2FqVlU%3D" rel="nofollow">clickpad</a>。clickpad中通过不同手指数量的点击行为来<strong>模拟</strong>鼠标左键、中键、右键点击。这些都可以配置或者关闭。</li>
<li>click:点击,本文语境中之物理按钮的“按压”和“释放”。</li>
<li>Clickpad software button behavior:clickpad上软按钮的行为,详情见<a href="https://link.segmentfault.com/?enc=F5ygoESXHUlZb8RE8H5GoQ%3D%3D.1Vm9TnJyE5LxBZ9fLy7MsH7bYv6wOj66vshoXvIJekmcfNH1JI6e1pHVyf8x3sdxUoHIxWS3hpIXg3pbyYERN1CCN1s9ZDQJNa9Rgw84vs8%3D" rel="nofollow">Clickpad software button behavior</a>。</li>
</ul>
<h2>libinput</h2>
<h3>安装</h3>
<ol><li>install basic libinput and xf86-input-libinput</li></ol>
<pre><code class="shell">sudo gpasswd -a $USER input
sudo pacman -S libinput xf86-input-libinput</code></pre>
<h3>配置</h3>
<p>libinput有两种配置方式:</p>
<ul>
<li>使用配置文件的永久配置方式</li>
<li>使用xinput命令行工具,针对运行时(runtime)进行实时配置,主要用来调试。</li>
</ul>
<h4>配置文件</h4>
<p>libinput安装后默认的配置文件在<code>/usr/share/X11/xorg.conf.d</code>目录下,如何你安装多个驱动,会存在多个文件:</p>
<pre><code class="shell">➜ xorg.conf.d ll
total 12K
-rw-r--r-- 1 root root 1.4K Aug 14 05:40 10-quirks.conf
-rw-r--r-- 1 root root 964 May 5 20:24 40-libinput.conf
-rw-r--r-- 1 root root 1.8K Nov 18 2016 70-synaptics.conf</code></pre>
<p>笔者这里安装了3个驱动,所以有3个配置文件,<strong>默认情况下,kde会根据文件前缀数字的大小决定优先使用哪个配置文件,数字越大,优先级越高。</strong></p>
<p>我们需要把默认配置文件复制到<code>/etc/X11/xorg.conf.d/</code>目录下:</p>
<pre><code class="shell">sudo cp /usr/share/X11/xorg.conf.d/40-libinput.conf /etc/X11/xorg.conf.d/40-libinput.conf</code></pre>
<p>下面是文件中touchpad部分的配置:</p>
<pre><code class="shell">Section "InputClass"
Identifier "touchpad"
MatchIsTouchpad "on"
MatchDevicePath "/dev/input/event*"
Driver "libinput"
Option "Tapping" "on"
Option "ButtonMapping" "1 3 0 4 5 6 7"
Option "TappingButtonMap" "lmr"
Option "DisableWhileTyping" "on"
Option "TappingDrag" "on"
EndSection</code></pre>
<p>详细参数和解释见<a href="https://link.segmentfault.com/?enc=yx34h6RbbeBjeKHz9NIaRQ%3D%3D.Yg8UWBfVhnhLAe7VbiuZQNiL%2FFZcdu08ytmMuInl0ebvPO7XN%2FfgBYz5nFh6GYRglHy3ZrLb2h9nAC5Jp%2FWhSw%3D%3D" rel="nofollow">libinput man page: based on X.Org input dirver</a>,解释下几个重要的配置参数:</p>
<ul>
<li>Option "Tapping" "on":手指点击touchpad发送鼠标点击事件</li>
<li>Option "TappingButtonMap" "lmr":1个手指点击对应<code>鼠标左键</code>,2个手指点击对应<code>鼠标中键</code>,3个鼠标点击对应<code>鼠标右键</code>。</li>
<li>Option "ButtonMapping" "1 3 0 4 5 6 7",按钮映射,详情见<a href="https://link.segmentfault.com/?enc=PGe%2BxN6FrpWfhWuuw5IeKw%3D%3D.jPJYqvNpTblM11YmaQRgWKobWOzmsX4YShEHGWGqfjKZZiTursDDrljs0QUt406cLUvZMUQN2MOYnxt41CR9vg%3D%3D" rel="nofollow">libinput#Button_Mapping</a>,这里笔者关闭了3指对应的左键。</li>
<li>Option "DisableWhileTyping" "on":打字时不检测touchpad事件,防止用户不小心触碰touchpad引起不必要的影响。</li>
<li>Option "TappingDrag" "on":开启点击拖拽。</li>
</ul>
<h4>调试</h4>
<ol><li>确定touchpad设备</li></ol>
<pre><code class="shell">➜ ~ xinput list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ SynPS/2 Synaptics TouchPad id=13 [slave pointer (2)]
⎜ ↳ TPPS/2 IBM TrackPoint id=16 [slave pointer (2)]
......</code></pre>
<ol><li>查看touchpad的详细配置</li></ol>
<pre><code class="shell">➜ ~ xinput list-props "SynPS/2 Synaptics TouchPad"
Device 'SynPS/2 Synaptics TouchPad':
Device Enabled (142): 1
Coordinate Transformation Matrix (144): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
libinput Tapping Enabled (295): 1
libinput Tapping Enabled Default (296): 0
libinput Tapping Drag Enabled (297): 1
libinput Tapping Drag Enabled Default (298): 1
libinput Tapping Drag Lock Enabled (299): 0
libinput Tapping Drag Lock Enabled Default (300): 0
libinput Tapping Button Mapping Enabled (301): 0, 1
libinput Tapping Button Mapping Default (302): 1, 0
libinput Accel Speed (277): 0.000000
libinput Accel Speed Default (278): 0.000000
libinput Natural Scrolling Enabled (282): 0
libinput Natural Scrolling Enabled Default (283): 0
libinput Send Events Modes Available (262): 1, 1
libinput Send Events Mode Enabled (263): 0, 0
libinput Send Events Mode Enabled Default (264): 0, 0
libinput Left Handed Enabled (284): 0
libinput Left Handed Enabled Default (285): 0
libinput Scroll Methods Available (286): 1, 1, 0
libinput Scroll Method Enabled (287): 1, 0, 0
libinput Scroll Method Enabled Default (288): 1, 0, 0
libinput Click Methods Available (303): 1, 1
libinput Click Method Enabled (304): 1, 0
libinput Click Method Enabled Default (305): 1, 0
libinput Middle Emulation Enabled (291): 0
libinput Middle Emulation Enabled Default (292): 0
libinput Disable While Typing Enabled (306): 1
libinput Disable While Typing Enabled Default (307): 1
Device Node (265): "/dev/input/event10"
Device Product ID (266): 2, 7
libinput Drag Lock Buttons (293): <no items>
libinput Horizontal Scroll Enabled (294): 1</code></pre>
<p>这里面有一个值很重要<strong>Device Node (265): "/dev/input/event10"</strong>,后面使用libinput命令行时会用到这个路径。</p>
<ol><li>使用libinput debug-events 监控touchpad事件</li></ol>
<pre><code class="shell">➜ ~ libinput debug-events --device /dev/input/event10
-event10 DEVICE_ADDED SynPS/2 Synaptics TouchPad seat0 default group1 cap:pg size 100x56mm tap(dl off) left scroll-nat scroll-2fg-edge click-buttonareas-clickfinger dwt-on
event10 GESTURE_SWIPE_BEGIN +2.82s 3
event10 GESTURE_SWIPE_UPDATE +2.82s 3 0.00/ 0.44 ( 0.00/ 3.63 unaccelerated)
event10 GESTURE_SWIPE_UPDATE +2.84s 3 0.00/ 3.43 ( 0.00/19.38 unaccelerated)
event10 GESTURE_SWIPE_UPDATE +2.87s 3 0.00/ 5.00 ( 0.00/19.38 unaccelerated)
event10 GESTURE_SWIPE_UPDATE +2.89s 3 0.00/ 3.33 ( 0.00/10.90 unaccelerated)
event10 GESTURE_SWIPE_UPDATE +2.92s 3 0.00/ 2.74 ( 0.00/ 8.48 unaccelerated)</code></pre>
<ol><li>使用libinput debug-gui 监控touchpad事件</li></ol>
<pre><code class="shell">➜ ~ libinput debug-gui --device /dev/input/event10
info: event10 SynPS/2 Synaptics TouchPad added</code></pre>
<p>这时会出现一个GUI画面帮助检测。<br><img src="/img/remote/1460000011327780" alt="kde-libinput-gestures-001" title="kde-libinput-gestures-001"></p>
<h2>libinput-gestures</h2>
<p>配置好touchpad和手势后,下面利用<code>libinput-gestures</code>来解析touchpad的数据,然后执行相关的操作。这里主要用到<a href="https://link.segmentfault.com/?enc=20gzDsiz1pz3OpiRmGh2iA%3D%3D.Ue%2FCDOja8%2FNnpGFYKKuWsK%2Fa1tIpCkgjuvsERu53D1W%2FNIyFi%2FpbU8EDz8CEohxQ" rel="nofollow">xdotool</a>,xdotool是模拟键盘/鼠标输入和窗口管理等的命令行工具。libinput-gestures依赖xdotool。</p>
<p>libinput-gestures安装后会有默认的配置,位置在<code>/etc/libinput-gestures.conf</code>,用户可以在<del><code>~/libinput-gestures.conf</code></del> <code>$HOME/.config/libinput-gestures.conf</code>配置自己的配置。笔者根据自己的需要修改了相关配置,如下:</p>
<pre><code class="shell"># Switch to next desktop
gesture swipe right 4 xdotool key ctrl+F1
# Switch to prev desktop
gesture swipe left 4 xdotool key ctrl+F2
# Present windows (current desktop)
gesture swipe down 3 xdotool key ctrl+F9
# Present windows (all desktop)
gesture swipe down 4 xdotool key ctrl+F10
# Show desktop
gesture swipe up 3 xdotool key super+d
# Show desktops grid
gesture swipe up 4 xdotool key ctrl+F8</code></pre>
<p><strong>主要思想是针对不同的手势触发相关的快捷键</strong>,快捷键的配置则可以在系统偏好设置-->快捷键中设置。下图是笔者在plasma5中的切换桌面的快捷键配置:<br><img src="/img/remote/1460000011327781" alt="kde-libinput-gestures-002" title="kde-libinput-gestures-002"></p>
<h3>Demo</h3>
<ol><li>四指横向滑动切换桌面:</li></ol>
<p><img src="/img/remote/1460000011327782" alt="kde-gestures-demo-1-min" title="kde-gestures-demo-1-min"></p>
<ol><li>四指上下滑动显示所有桌面和所有活动窗口:</li></ol>
<p><img src="/img/remote/1460000011327783" alt="kde-gestures-demo-2-min" title="kde-gestures-demo-2-min"></p>
<h2>TODOs</h2>
<h3>通过捏和(pinch in/pinch out)来放大/缩小网页(对标macbook)</h3>
<p><code>$HOME/.config/libinput-gestures.conf</code>中添加如下内容(方向可以自己定义):</p>
<pre><code class="vim"># back history of chromium/chrome
gesture swipe right 3 xdotool key alt+Left
gesture swipe left 3 xdotool key alt+Right</code></pre>
<h3>网页的前进/后退(对标macbook)</h3>
<p><code>$HOME/.config/libinput-gestures.conf</code>中添加如下内容</p>
<pre><code class="vim"># pinch
gesture pinch in 2 xdotool key ctrl+minus # 2指捏: 缩小
gesture pinch out 2 xdotool key ctrl+plus # 2指张: 放大</code></pre>
<h2>总结</h2>
<p>本文从想法到配置好前前后后花了大约1个月时间,大部分时间用在了理解输入驱动、配置驱动以及配置调试toucgegg和libinput-gestures上了。</p>
<p>笔者在配置好自己的archlinux 手势后,机缘巧合用了一个星期的macbook pro,体会了苹果下面的手势操作。总体感觉苹果的手势操作更流畅,识别更准确。毕竟苹果是自己的生态系统,可以针对自己的macOS系统进行封装和调试。而在Linux生态中,因为存在多个Linux发行版和桌面环境,手势操作很难兼容所有发行版,这就要求用户要有较强的动手能力和理解能力。可以说两者都能实现丰富的手势操作,而且Linux的扩展性更强一些,但是需要更专业的知识和动手能力。</p>
<h2>相关参考</h2>
<ul>
<li><a href="https://link.segmentfault.com/?enc=di4ktP5EDPR2hS9HHtDeXA%3D%3D.qUbwHWOIMjqqhGw9eJIsBGns1KGHgs58OhTqYzDxwUwcbAnHvwDnOetqsWtgTBtWQza1IMtZwfTJJ5gaHOofjGLp%2FK9fQmZwdfhQiWhfZ0g%3D" rel="nofollow">原文链接</a></li>
<li><a href="https://link.segmentfault.com/?enc=ZXxTdRTt6LttxmNYx%2BqlgQ%3D%3D.JyraSSVrLUbRbzW82QIVy5i3ga7h6ELal%2BsUEYFU3lQnB%2Bpo9YPLsM46V%2BPKF%2BSK" rel="nofollow">GitHub: libinput-gestures</a></li>
<li><a href="https://link.segmentfault.com/?enc=im8X5zNr1s%2Ft6TDp0iAqxg%3D%3D.vbnUPMe3haLdUhxjm8oyxTss6T50Yfp%2FdTxqbEHKDkdr9BgAbpjE9jXgrIof%2BNTU" rel="nofollow">arch wiki: libinput</a></li>
<li><a href="https://link.segmentfault.com/?enc=fajO372h1Qf1%2FHBuncjnmg%3D%3D.yOTESlJsNpZ4iI0h6HoUgfmAYMVT6IdPMqdA%2Bb8UCwBjlka4kxTngu52xENEmUj2MDRBmDJfF%2F%2BIDN7jbGn5YQ%3D%3D" rel="nofollow">libinput official doc: related pages</a></li>
<li><a href="https://link.segmentfault.com/?enc=eEhVasNBl0S7RB37gxRD3Q%3D%3D.z31EZADSKxd75KVOrFuaHU3Qxh6s4%2FqmVUx45Y1HtJVBMM2BXfxxO2TRIH%2B5e%2F8Tss1VFgls6j%2BfYDxywJ4suA%3D%3D" rel="nofollow">libinput man page</a></li>
<li><a href="https://link.segmentfault.com/?enc=6aoiyIvPowB1UYULZQrR1A%3D%3D.5ALeGNkCzk04js33s7sWF16pnxLN0eom23UvrWaaFLVraimZSRCk9RzHWoz%2FRrndCBZU4TpgSprsozFM%2FQyXfw%3D%3D" rel="nofollow">libinput man page: based on X.Org input dirver</a></li>
<li><a href="https://link.segmentfault.com/?enc=%2B6YuGSY%2FC82cjjnASmBktA%3D%3D.2YWuguIF7HSwmUSa7RsqwWt7WvfoHj%2FynpUR78Aw7MFxzDxo1jMZSrEkoMWEk24evYwGLwhIdp2g21f06hR4Qw%3D%3D" rel="nofollow">Archlinux: 优化触摸板配置</a></li>
</ul>
install wireless firmware on archlinux
https://segmentfault.com/a/1190000008211455
2017-01-24T21:27:47+08:00
2017-01-24T21:27:47+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<p><strong>编者按</strong>:这篇文章介绍了笔者解决archlinux+kde plasma环境无法链接无线网的问题。笔者通过查阅archlinux wiki与Google定位问题,重新安装Linux无线网卡固件解决了问题。</p>
<h2>背景介绍</h2>
<ul>
<li><p><a href="https://link.segmentfault.com/?enc=DndhcyXAMRBT%2FxAS59rC1A%3D%3D.zqw33l0v1VfuI3ExAslrWxriZbeK7rNd0JVhDmidAoA%3D" rel="nofollow">hp440</a>,i54200U 64bit.</p></li>
<li><p>archlinux 20170101.iso</p></li>
<li><p>kde5 plasma</p></li>
</ul>
<h2>问题描述</h2>
<p>安装NetworkManager(负责提供网络功能的服务,简称<code>nm</code>)和<a href="https://link.segmentfault.com/?enc=LzGDxJEVRKQ6nGu40BjOWg%3D%3D.IiS8XWAXq0O58jFHshc6Y4nuwis3Oh7RoG6V8qN5KyAMhZqHel8XbVDHeLih65gwcD5Wo8Uge3S9R8cdMRU5Jw%3D%3D" rel="nofollow">network-manager-applet</a>,network-manager-applet适用于使用plasma桌面的场景,它是一个托盘程序,通过图形化的界面管理计算机的网络,下面简称<code>nm-applet</code>,正确启动nm后,点击nm-applet图标后只显示<strong>有线链接</strong>,不显示可用的无线网列表。</p>
<p><img src="/img/remote/1460000008211458?w=499&h=541" alt="" title=""></p>
<p>即使自己手动添加的<code>linkernetworks2</code>也无法激活。</p>
<h2>解决步骤</h2>
<h3>参考archlinux wiki cn</h3>
<p><a href="https://link.segmentfault.com/?enc=b2UZOIg8Klp%2FHVM0qoiAVw%3D%3D.sXL0Us7ufQ0h80fK2coCcNUilVuw8Wri0Li63FAJjrNLhbA%2B%2BIV2H9zlaa%2BWln6NkpQVAjXNyP%2FSReI3irOdVDCGnUAQl7%2BjJzBDfeZPaDYltUXrdAjUrH4M%2FCCb%2BjcB" rel="nofollow">archlinux wiki-NetworkManager (简体中文)</a>)主要介绍了:</p>
<ul>
<li><p>archlinux上NetworkManager的安装与使用</p></li>
<li><p>GUI的安装</p></li>
</ul>
<p>这部分信息适合安装archlinux后配置基本的网络链接。不适用无线网络的debug。</p>
<h3>archlinux上无线网络的配置</h3>
<p>先在<a href="https://link.segmentfault.com/?enc=IO5F3BLLiwvNYZGPfqwCuA%3D%3D.LFjJsLOMINYnwTyKA8ye1SMnnTPxMuGXpdQ42Op0IXuVtgfcn9p9vW6d5OOTDHRT" rel="nofollow">kde-cn频道</a>上提问并没有解决自己的问题。</p>
<p>又参考<a href="https://link.segmentfault.com/?enc=B7vxzbXQPxT99uQ20nhYSg%3D%3D.vE35KbiaYHLQ%2FcM%2Bcy8LAP0wip9K%2F54ZLSLWaehn7Tk5SMM%2FpE3rPV5BQu6r7nC0YBkr8zNNullqabsHpV3RmlGQWjoE48iK5%2FnAU0haSuolEKctF9tM2tsJbyijvDQLSLENzrrnOuMK9hFyoVg2cQ%3D%3D" rel="nofollow">Wireless network configuration (简体中文)</a>)</p>
<ul><li><p>查看pci设备没发现问题</p></li></ul>
<pre><code class="bash">$ lspci -k
09:00.0 Network controller: Broadcom Limited BCM43228 802.11a/b/g/n
Subsystem: Broadcom Limited Device 05e2
Kernel driver in use: bcma-pci-bridge
Kernel modules: bcma
</code></pre>
<ul><li><p>查看网卡设备,发现没有无线网卡的信息。</p></li></ul>
<pre><code>$ ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp8s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 5c:b9:01:f6:3b:18 brd ff:ff:ff:ff:ff:ff</code></pre>
<p>以上两步发现没有无线网卡的设备信息。猜测有两个:</p>
<ol>
<li><p>无线网卡设备没有开启,(在笔记本上)手动开启</p></li>
<li><p>无线网卡坏了</p></li>
</ol>
<p>自己尝试在<a href="https://link.segmentfault.com/?enc=8kMfTX80cuqxRtROl0m7Pw%3D%3D.h0Zxdbjzn5uuCysECJ44APaSnNVHsnAR7vXL4GOAUqkYcWN5rnS4I5Ss0Q4tANxi" rel="nofollow">hp上开启网线网卡</a>发现没用。<strong>这是我有点慌,难道网卡坏了?宝宝刚申请的笔记本就坏了无线网卡,蓝瘦香菇!</strong></p>
<p>安装archlinux就像堆积木,许多东西都需要自己适配,并且这时我发现了[archlinuxcn-bbs找不到无线网卡[已解决]](<a href="https://link.segmentfault.com/?enc=Dw28oyBYSggzFK5C7Kvtmw%3D%3D.YssQvxRbFOnz3CLexHk3AVU%2BDKRSFbrtMERi6qHNGaNyjo%2F7mivsF6CwwPgq5UfHero%2B6RUL04hkBaIj4xZ%2F6g%3D%3D" rel="nofollow">https://bbs.archlinuxcn.org/v...</a>,参考对方的解决方案感觉是自己没安装对固件(firmware)。</p>
<p>最后定位了自己的问题:<strong>内核中无线网卡固件和无线网卡硬件不一致</strong>。找到问题后参考wiki中的链接正确安装固件后重启笔记本解决问题。</p>
<h2>有用的参考</h2>
<ul>
<li><p><a href="https://link.segmentfault.com/?enc=Rg5nnsBZGQWB2y5N3xYjQg%3D%3D.m0BwPzMTPjaHk%2BrxBoO2d6TklTBwDClF4OoYlNp%2F4xCPr%2BnGy6djP%2Fb2PN4QDmih0pnaGXSTtsvfEdHkT8h4MZWmEnm8bf9FopGQ3jpCZiOpU2Ao4DEKPjzIdf9TZ%2Fi42EWjVmElMUHtNEFs1ch8Lg%3D%3D" rel="nofollow">Wireless network configuration (简体中文)</a>)</p></li>
<li><p>[archlinuxcn-bbs找不到无线网卡[已解决]](<a href="https://link.segmentfault.com/?enc=mNZ%2BxuK1MvPlZfkNzIBewQ%3D%3D.BmKVNBDQE%2BiHH4%2FotJtAC8veTwTxJPd14ywRFdAvVbQf7FusiaVOk5%2B4CAaQ7HydPVVq307Jefl%2Fa5NnLUtWng%3D%3D" rel="nofollow">https://bbs.archlinuxcn.org/v...</a></p></li>
<li><p><a href="https://link.segmentfault.com/?enc=zb2xzZsngpOCao8SowSCKQ%3D%3D.ZLlBUHmuJWq7MEGAzMF3%2F9vYOP6zfIDO6X9KNLNV1nStPVANghC0hFX6N8fK87nbKs7vv3oDKcvj8Ngx8mBYMQ%3D%3D" rel="nofollow">Linux wireless b43 firmware-archive</a> 这个链接<strong>详细介绍</strong>在Linux上安装和硬件版本一致的firmware的过程。</p></li>
<li><p><a href="https://link.segmentfault.com/?enc=KmOYcSWp1rf2Ly37IDgCAA%3D%3D.mWm%2BS6D5gLpH60fDHDpmLibVls%2BxuyGqcZPb%2Fahkt8hsgpnRXc6ZV6pkAxluz2EkV6KuMF7fXg3aBAQ1zjqt2g%3D%3D" rel="nofollow">Linux wireless b43 firmware</a></p></li>
</ul>
<h2>小推广</h2>
<p><a href="https://link.segmentfault.com/?enc=VtltId%2FXao3zYUyHlhL76Q%3D%3D.2RJXHyBuQEFCwwGJGqooTWgiYmbspqtXT0IgPvmm2ZD1eusDA%2FUwVbbbaG0jgpAXXkpuigvYGPADSMQAbbPSmuRHsuElolSQj1KYE5D2X50%3D" rel="nofollow">原文地址</a><br>欢迎关注我的公众号 泉Talk,介绍Spark、Python、读书笔记等内容:</p>
<p><img src="https://segmentfault.com/img/remote/1460000008041692?w=430&h=430" alt="" title=""></p>
install virtualbox on centos server
https://segmentfault.com/a/1190000008161464
2017-01-18T22:25:23+08:00
2017-01-18T22:25:23+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<p><strong>摘要:</strong>本文介绍在<code>centos 7.2 server</code>上下载安装<code>virtualbox</code>,记录遇到的问题:"CentOS 内核版本与<code>yum install kernel-devel</code>版本不一致",以及自己解决问题的过程。</p>
<p>核心在于<strong>下载和主机内核版本一致的源码,然后安装virtualbox</strong>。</p>
<p><a href="https://link.segmentfault.com/?enc=jU9u8Wf34BLrxUioZuJ46A%3D%3D.h9APSxoFf%2FbGPRv2kFi6Wo5YCALpX51eS4lqS8c11pM%2FVx7WpQdWGuMka5pVMnL91y25Q3eD3V87sX8t4ChIvw%3D%3D" rel="nofollow">原文:QuanTalk</a></p>
<h2>Env</h2>
<ul><li><p>CentOS 7.2-1511(笔者利用U盘镜像安装在物理机)</p></li></ul>
<h2>Add repo url</h2>
<pre><code>cd /etc/yum.repos.d
wget http://download.virtualbox.org/virtualbox/rpm/rhel/virtualbox.repo</code></pre>
<h2>Install denpendiencies</h2>
<pre><code>yum --enablerepo=epel install dkms</code></pre>
<h2>Install epel</h2>
<pre><code>CentOS/RHEL 7, 64 Bit (x86_64):
# rpm -Uvh http://epel.mirror.net.in/epel/7/x86_64/e/epel-release-7-8.noarch.rpm
CentOS/RHEL 6, 64 Bit (x86_64):
# rpm -Uvh http://epel.mirror.net.in/epel/6/x86_64/epel-release-6-8.noarch.rpm</code></pre>
<p>这一步报错:找不到url,笔者自己复制url到浏览器发现确实没有这个链接。但是我在仓库下找到另一个链接:</p>
<pre><code>http://epel.mirror.net.in/epel/7/x86_64/e/epel-release-7-9.noarch.rpm</code></pre>
<p>替换一下就好了。</p>
<h2>Install kernel-devel</h2>
<pre><code>sudo yum install kernel-devel</code></pre>
<p><code>kernel-devel</code>是kernel(内核)源码,默认会安装到<code>/usr/src/kernels</code>目录下面。之所以需要内核源码。是因为<strong>virtualbox需要结合内核源码编译特定内核版本的模块</strong>。</p>
<p>笔者遇到的问题是<code>yum install kernel-devel</code>的版本和CentOS上的内核版本不一致。如下(下面的结果是笔者解决了所有问题后列出来的,可以看到没安装的版本3.10.0-514.2.2.el7和主机版本不一致):</p>
<pre><code>➜ alpine uname -r
3.10.0-327.36.3.el7.x86_64
➜ alpine sudo yum list kernel-devel
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: mirror.0x.sg
* epel: mirror.smartmedia.net.id
* extras: mirror.0x.sg
* updates: mirror.0x.sg
Installed Packages
kernel-devel.x86_64 3.10.0-327.36.3.el7 installed
Available Packages
kernel-devel.x86_64 3.10.0-514.2.2.el7 updates</code></pre>
<p>这就导致编译安装的virtualbox模块和主机内核版本不一致,无法运行。</p>
<p>现在解决方案有两大类:</p>
<ul>
<li><p>下载和主机内核版本一直的源码。</p></li>
<li><p>升级内核版本到3.10.0-514.2.2.el7,深思后觉得这个方法不妥,因为升级内核后会导致<code>软件不兼容问题</code>。后续的工作量很大。</p></li>
</ul>
<p>最后还是决定下载版本一直的内核源码。步骤如下:</p>
<ul><li><p>Google <code>kernel-devel-3.10.0-327.36.3.el7.x86_64</code><br>成功找到内核源码的<a href="https://link.segmentfault.com/?enc=9fvSkwX6UAe1xAvBqB5iWw%3D%3D.%2FjPpyn9LiTPI9ZAVUZgtNAOicoRSINPevlJY92lQJuKj1BBLIg5WzLywQzhxxK%2FQjHo1n9wpHuHaV0Oc2EOktu6Dk2utukuS%2FW7V41ENWF%2B3P%2Bd5q7Yg%2FtLuC%2BQ%2FTJiBAhjJNvNnMb1RaNjW55VgKOYdCHRzK1Cf5Q5AoedYGAU%3D" rel="nofollow">有效地址</a>,果断下载。</p></li></ul>
<p><a href="https://link.segmentfault.com/?enc=CFt6o8qWXGODQt4M%2F81hjg%3D%3D.J91sBd9JKiaN28PCUB68N5i6553xMU8MYkIqaZbgQxrSt9wQYqP8T92Vf8vAIJrKafJCFSwuJAeS9jWHLvFkPdd3vcNyc8esrv5X%2BvDzcsRehqwBlOlLM02mnslr%2B6iIuAmYhUCcFkpcI%2FbL35AZMg%3D%3D" rel="nofollow">参考</a></p>
<ul><li><p>安装</p></li></ul>
<pre><code>sudo yum install kernel-devel-3.10.0-327.36.3.el7.x86_64.html</code></pre>
<ul><li><p>添加源码到环境变量</p></li></ul>
<pre><code># export KERN_DIR=/usr/src/kernels/3.10.0-327.36.3.el7.x86_64</code></pre>
<ul><li><p>安装virtualbox(见下一步)</p></li></ul>
<h2>List pkg</h2>
<pre><code>~ yum search virtualbox
Loaded plugins: fastestmirror
Determining fastest mirrors
* base: centos.usonyx.net
* epel: mirrors.tuna.tsinghua.edu.cn
* extras: centos.usonyx.net
* updates: centos.usonyx.net
virtualbox 31/31
VirtualBox-4.3.x86_64 : Oracle VM VirtualBox
VirtualBox-5.0.x86_64 : Oracle VM VirtualBox
VirtualBox-5.1.x86_64 : Oracle VM VirtualBox</code></pre>
<h2>Install</h2>
<pre><code>yum install VirtualBox-5.1</code></pre>
<h2>Reference</h2>
<ul>
<li><p><a href="https://link.segmentfault.com/?enc=LLuEcJtDwWA7vgZ%2FtclVMg%3D%3D.shw%2FhQYA8aELy%2BKoOJdBsBYGtuuBzauhKvWOTp9E9V0mtmP02Xguldq1LO8Hwi6bUaXDqKoHT7RWRhO8JYUyIeruvJmO0UPZjVSu2cfxsWQ4T%2FhY42QtpxmBlsdJueIz0mj5ndUQnJLiFy0UdHkwKA%3D%3D" rel="nofollow">Centos cn wiki:在 CentOS 上安装及使用 VirtualBox</a></p></li>
<li><p><a href="https://link.segmentfault.com/?enc=ByFTVN%2BIhSXRA9hcrFa%2BAQ%3D%3D.%2BdkX6bS4SdqyM1a%2BKUYgl9WOh0Py7Bn0T2WlEgCc3M3hixDqQW0IaO3kq3LMIQ113gQAfy72%2B89P%2FYkeK6dQpaArxFpHe%2F%2Bi4e2CjlNpAPc%3D" rel="nofollow">How to Install Oracle VirtualBox 5.1 on CentOS/RHEL 7/6 and Fedora 23/22</a></p></li>
</ul>
sbt编译Spark App依赖问题
https://segmentfault.com/a/1190000008041689
2017-01-07T14:24:49+08:00
2017-01-07T14:24:49+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<h2>背景简介</h2>
<p>Spark App(用Spark APIs编写的)需要submit到Spark Cluster运行,对于Scala编写的代码,提交之前要用sbt或者maven把以下内容:</p>
<ul>
<li><p>源代码</p></li>
<li><p>依赖的jar包</p></li>
</ul>
<p>全部打包成一个大的jar文件,这样代码就不会因为没有依赖无法在集群中运行。</p>
<h2>问题</h2>
<p>我司用Scala编写<a href="https://link.segmentfault.com/?enc=Bb7j%2Fa1%2ByHgWnRmriYGT5Q%3D%3D.5ureQFsiBp%2BWEgm5Jz8LsNgARXXMINgsV8Or27YSuIy0ag%2BHts8Vv%2FqkAXpoBzbn5nwqyqEqODTJk2zyDJrycQ%3D%3D" rel="nofollow">Spark streaming应用</a>,实现读取Kafka数据,处理后存储到cassandra集群中。这里需要用到一个包<code>spark-streaming-kafka</code>,之前用的<code>spark1.6.0</code>的版本。sbt中的配置如下:</p>
<pre><code>libraryDependencies ++= Seq(
// Spark dependency
"com.eaio.uuid" % "uuid" % "3.2",
"org.apache.spark" %% "spark-core" % "1.6.0" % "provided",
"org.apache.spark" %% "spark-sql" % "1.6.0" % "provided",
"org.apache.spark" %% "spark-streaming" % "1.6.0" % "provided",
"org.apache.spark" %% "spark-streaming-kafka" % "1.6.0",
"com.datastax.spark" %% "spark-cassandra-connector" % "1.6.0-M2",
// Third-party libraries
"com.github.scopt" %% "scopt" % "3.4.0"
)</code></pre>
<p>升级到Spark 2.0.0后需要更新软件包版本,于是将sbt构建配置中的依赖部分改为:</p>
<pre><code>libraryDependencies ++= Seq(
// Spark dependency
"com.eaio.uuid" % "uuid" % "3.2",
"org.apache.spark" %% "spark-core" % "2.0.0" % "provided",
"org.apache.spark" %% "spark-sql" % "2.0.0" % "provided",
"org.apache.spark" %% "spark-streaming" % "2.0.0" % "provided",
"org.apache.spark" %% "spark-streaming-kafka" % "2.0.0",
"com.datastax.spark" %% "spark-cassandra-connector" % "2.0.0-M2",
// Third-party libraries
"com.github.scopt" %% "scopt" % "3.4.0"
)</code></pre>
<p>本以为这样修改后重新构建就没问题了。但是我太天真了,构建后报错,提示:</p>
<pre><code>[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: org.apache.spark#spark-streaming-kafka_2.10;2.0.0: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn]
[warn] Note: Unresolved dependencies path:
[warn] org.apache.spark:spark-streaming-kafka_2.10:2.0.0 (/home/linker/workspace/linkerwp/linkerStreaming/build.sbt#L12-23)
[warn] +- Linker Networks Inc.:linker-streaming_2.10:0.0.1
sbt.ResolveException: unresolved dependency: org.apache.spark#spark-streaming-kafka_2.10;2.0.0: not found</code></pre>
<p>说明这个包是不存在的,于是马上到<strong>maven repo</strong>上去找。常见的Maven公共repo有:</p>
<ul>
<li><p><a href="https://link.segmentfault.com/?enc=deHMY2Mc76ZV6AUv5qZhcw%3D%3D.qiz6jktJ69xCYFi08skiWWZ7TwF55U5lIO8tFnegujw%3D" rel="nofollow">search.maven.org</a>...用于搜索你的依赖包。</p></li>
<li><p><a href="https://link.segmentfault.com/?enc=Gn%2B4NQejCaGcgvrhbk8YyQ%3D%3D.YfdGRdCC2yvoVhirXK7XVgErXsUIC3nFMlFtQ4BpDDc%3D" rel="nofollow">https://mvnrepository.com/</a>...maven仓库。</p></li>
</ul>
<p>进入网址输入<code>spark-streaming-kafka</code>搜索后数来好几和选项,前面4个结果都是不支持Spark 2.0.0的,这让我误以为<strong>Spark 2.0.0还不支持Kafka</strong>,这个想法被前面几个搜索结果误导了。因为对于2.0.0的Spark,Kafka添加了具体的版本号!<code>spark-streaming-kafka</code>--><code>spark-streaming-kafka-0-8</code>就可以找到了(实际上这个版本也在maven repo的搜索结果,因为靠后我没有去看)!!</p>
<h2>总结</h2>
<ul>
<li><p>对于Java/Scala的编译问题,我曾经特别抗拒,因为maven和sbt的配置文件很冗杂,没有Python的简洁明了。Python里20行的依赖文件在maven/sbt里至少200行,而且只要有一个地方没写正确就无法正确编译。</p></li>
<li><p>现在发现要想正确编译,保证源代码没问题的情况下,就需要指定<strong>正确的依赖包和格式</strong>。这个需要到maven的仓库上去搜索,确认无误后再添加到配置文件中。</p></li>
<li><p>要学会发散、拓展思考。当看到sbt编译失败的时候就应该根据报错信息推测出问题的原因:“依赖包版本不正确”,然后把版本指定正确就可以了。</p></li>
</ul>
<h2>广告</h2>
<p><a href="https://link.segmentfault.com/?enc=pwn2AdFaWqlLZiIds%2Fb6WQ%3D%3D.akyBMfnilPPEY7pL7E6l7G98D%2FdSWq4pcLpE648Oj8sKKEcmEgmF45OCZ0c18ThzJYYqGrrqEbbFrxq9T8Ew2g%3D%3D" rel="nofollow">sbt编译Spark App依赖问题</a><br>欢迎关注我的公众号 泉Talk,介绍Spark、Python、读书笔记等内容:<br><img src="/img/remote/1460000008041692?w=430&h=430" alt="" title=""></p>
docker image 实践之容器化 ganglia
https://segmentfault.com/a/1190000004373097
2016-01-27T14:24:00+08:00
2016-01-27T14:24:00+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<h2>基础镜像</h2>
<p>单播模式下检测效果</p>
<p><img src="http://7xl2jw.com1.z0.glb.clouddn.com/ganglia_demo.gif" alt="" title=""></p>
<p>使用centos:6作为基础镜像,因为centos:7没有使用systemd作为系统服务管理工具.这在后面启动ganglia进程的时候会带来很多麻烦,但是有解决方案(由dockone社区微信群大神给出的解决方案,个人并未尝试):</p>
<ul>
<li><p>使用supervisor来统一管理进行</p></li>
<li><p>runt管理进程</p></li>
</ul>
<h2>Dockerfile</h2>
<pre><code class="language">FROM centos:6
MAINTAINER wlu wlu@linkernetworks.com
RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
RUN yum install -y php-common php-cli php-gb php
# install ganglia server
RUN yum install -y rrdtool rrdtool-devel ganglia-web ganglia-gmetad \
ganglia-gmond ganglia-gmond-python httpd apr-devel zlib-devel \
libconfuse-devel expat-devel pcre-devel
# install ganglia client
#RUN yum install -y ganglia-gmond
RUN mkdir -p /var/lib/ganglia && \
chown nobody:nobody /var/lib/ganglia && \
chmod 777 /var/lib/ganglia
ADD supervisord.conf /etc/supervisord.conf
RUN yum install -y python-setuptools && \
easy_install supervisor && \
yum clean all
RUN yum install -y vim && \
ln -f -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"]</code></pre>
<p><strong>注意:</strong>这里可以把多个指令合并以<code>减少镜像层数</code>.</p>
<h2>ganglia的配置</h2>
<h3>原理图:</h3>
<p><img src="http://7xl2jw.com1.z0.glb.clouddn.com/ganglia_db_01.svg" alt="" title=""></p>
<p>ganglia可以监控整个集群的信息.这里有两个概念:</p>
<ul>
<li><p>ganglia 中央机器...对应<code>gmetad</code>进程.对应配置信息在<code>/etc/ganglia/gmetad.conf</code>(centos6下)</p></li>
<li><p>ganglia client...对应<code>gmond</code>进程.对应配置信息在<code>/etc/ganglia/gmond.conf</code>(centos6下)<br>有点类似于master和slave的关系.</p></li>
</ul>
<p>在集群中需要有一个<code>中央机器</code>来统一接收其它机器上收集到的监控信息(也可以包括中央机器自身),在这个中央机器上运行<strong>gmetad</strong>进程.</p>
<p>在其它机器上运行<strong>gmond</strong>进程,用来收集机器上的监控信息.</p>
<h3>ganglia的两种模式</h3>
<h4>单播模式</h4>
<p>这种模式下client上的数据会发送给中央机器,下面看下client(即gmond)的配置(只摘取部分需要的配置项):</p>
<h5>gmond.conf</h5>
<pre><code class="language">......
cluster {
name = "unspecified"
owner = "unspecified"
latlong = "unspecified"
url = "unspecified"
}
......
udp_send_channel {
#bind_hostname = yes # Highly recommended, soon to be default.
# This option tells gmond to use a source address
# that resolves to the machine's hostname. Without
# this, the metrics may appear to come from any
# interface and the DNS names associated with
# those IPs will be used to create the RRDs.
mcast_join = 239.2.11.71
port = 8649
ttl = 1
}
......
/* You can specify as many udp_recv_channels as you like as well. */
udp_recv_channel {
mcast_join = 239.2.11.71
port = 8649
bind = 239.2.11.71
retry_bind = true
# Size of the UDP buffer. If you are handling lots of metrics you really
# should bump it up to e.g. 10MB or even higher.
# buffer = 10485760
}
......</code></pre>
<ol>
<li><p>cluster name,这个必须指定并且相同集群使用相同的name</p></li>
<li><p>udp_send_channel,因为单播模式下各个client把数据以<code>udp</code>协议发给中央机器,所以需要配置中央机器的ip,配置后的结果:</p></li>
</ol>
<pre><code class="language">udp_send_channel {
#bind_hostname = yes # Highly recommended, soon to be default.
# This option tells gmond to use a source address
# that resolves to the machine's hostname. Without
# this, the metrics may appear to come from any
# interface and the DNS names associated with
# those IPs will be used to create the RRDs.
#mcast_join = 239.2.11.71
host = host_ip
port = 8649
ttl = 1
}</code></pre>
<p>这条需要注释:#mcast_join = 239.2.11.71,ganglia默认是<code>多播</code>.</p>
<ol><li><p>注释掉多播的配置:</p></li></ol>
<pre><code class="language">udp_recv_channel {
#mcast_join = 239.2.11.71
port = 8649
#bind = 239.2.11.71
retry_bind = true
# Size of the UDP buffer. If you are handling lots of metrics you really
# should bump it up to e.g. 10MB or even higher.
# buffer = 10485760
}</code></pre>
<p><strong>note:</strong>这里注释掉多播和绑定的ip.我还不是太明白,<a href="https://link.segmentfault.com/?enc=J%2FIBop5qutpDQ%2F6CXYy6hg%3D%3D.UtIagj0%2FAARPiIqb4%2F5XIPrK8oX7U%2BXLgg8d4mM6JgMATKirD5AgaL40O23iLI52" rel="nofollow">详情参考这里</a></p>
<p>配置好后就可以通过<code>service gmond start</code>来启动client上的gmond进程了.</p>
<h5>gmetad.conf</h5>
<pre><code class="language">data_source "my cluster" localhost</code></pre>
<p>改为</p>
<pre><code class="language">data_source "your cluster name" host_ip #host_ip指中央机器的配置</code></pre>
<p>配置好后就可以通过<code>service gmetad start</code>来启动中央机器上的gmetad进程了.</p>
<h4>多播模式</h4>
<p><img src="http://7xl2jw.com1.z0.glb.clouddn.com/ganhlia_gmond.svg" alt="" title=""></p>
<p>多播的特点:</p>
<ul>
<li><p>集群中的每个client把自己的数据发送给<strong>集群中的其它client</strong></p></li>
<li><p>中央机器指定一个client作为数据源.</p></li>
</ul>
<p>个人觉得这种方式很浪费,<strong>因为单播模式下数据传输次数要少</strong></p>
<h2>参考连接</h2>
<p><a href="https://link.segmentfault.com/?enc=uI4olWKawQv9tr77GSpk5Q%3D%3D.4W0PswiB1VyiEPsfw1lKzxPnLX3%2FpTDNyUbrr9OzfHqFitXZ3RPWAYqhzITab61L" rel="nofollow">reference 1</a><br><a href="https://link.segmentfault.com/?enc=YVQwZrEMTZ4gnwMhqWTDoA%3D%3D.mjYGrTn%2BnPiH4DTyU43iQVZyLd%2FUfkTtPR7WKQnU0q6lfOlJRnNl%2BEGaCAHEkiw0" rel="nofollow">reference 2</a><br><a href="https://link.segmentfault.com/?enc=4%2FZyDf%2FB0ulpFnCs8sUnHg%3D%3D.6%2FMWIfsP%2FVNJlF5BewcUOhbCymV0VZrtHAZma%2BGfihQpsqz%2BaSRQb25%2BNLXR2ZbF" rel="nofollow">本项目对应的GitHub地址</a><br><a href="https://link.segmentfault.com/?enc=v6JT1rsFvePtW%2BsBUThVxw%3D%3D.uj7IfGSGi2W7eqxQNFWINfcMnlYdg1m%2FBsk%2F9p1BmdkAGf3bHnC278rfxrZlnGiO6kstfCddM3mfppUYZhc%2BWmatNBiI2wHduG4qrX%2BCzlQ%3D" rel="nofollow">httpd访问控制问题</a></p>
<h2>ps</h2>
<p>南京docker meetup已经于2015年3月份成立,将于2016年开始举办线下技术分享.诚挚欢迎各位对docker及容器技术感兴趣的同学加入<a href="https://link.segmentfault.com/?enc=hu3%2FKo%2B1lrXQZbWHSFHUWA%3D%3D.F3fR%2B%2BlucAgZyNbwp%2Bbbh%2B9GINgv91EGFfjVAj0p4LNG8NSSm4une%2BEKLA6YoHWY" rel="nofollow">Docker Nanjing meetup</a></p>
Kafka文档阅读笔记(一)
https://segmentfault.com/a/1190000003912925
2015-10-27T11:20:35+08:00
2015-10-27T11:20:35+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<blockquote><p>老大让我用Kafka+Spark Streaming搭建<code>简单的</code>数据处理平台,以下记录我在学习中的一些要点。目前我的整理基于<a href="https://link.segmentfault.com/?enc=woY7RTmYWoiigLayHdleaQ%3D%3D.4Z6WdMXJlesZWzyVB8BE4zuh8bgQu7ywTGWRmNJn8PYZHY8%2BkDUD%2FLnO2vIqKheW" rel="nofollow">Kafka 0.8.22 documentation</a>的文档。</p></blockquote>
<h2>入门指南</h2>
<h3>overview</h3>
<p>Kafka中有几个概念很重要:<code>partition</code>、<code>topic</code>、<code>producer</code>、<code>consumer</code>。partition要深入了解,因为它和msg order guarantee, fault tolerace关系很大!</p>
<h3>简介</h3>
<p>Kafka is a <code>distributed</code>, <code>partitioned</code>, <code>replicated</code> commit log service.像官方介绍的那样,Kafka是分布式、分区、可复制的提交日志服务。它采用<code>独特的设计</code>来实现<code>消息服务系统</code>。</p>
<h4>回顾一些术语</h4>
<ul>
<li><p>topics...maintains feeds of messages in categories(维护目录中的消息源)</p></li>
<li><p>producers...发布消息到Kafka<code>topic</code>的<strong>进程</strong></p></li>
<li><p>consumers...订阅topic中消息与处理源(feeds)中<code>发布过</code>消息的<strong>进程</strong></p></li>
<li><p>broker...运行一个或多个服务的Kafka集群</p></li>
</ul>
<p>概念图见下:<br><img src="http://kafka.apache.org/images/producer_consumer.png" alt="" title=""></p>
<p>clients与servers端使用TCP协议通信</p>
<h3>Topics&Logs</h3>
<p>Topic是目录或订阅源的名字,用来接受发布过的消息。对于每个topic,Kafka维护一个分区日志,看起来如下:</p>
<p><img src="http://kafka.apache.org/images/log_anatomy.png" alt="" title=""></p>
<p>每个分区有序,不断附加不可变的消息,称之为<code>a commit log</code>,每个分区中的消息被分配<code>连续的数字</code>称之为<code>offset</code>,<strong>每个分区中消息的offset不同</strong></p>
<p>Kafka集群维护所有已经发布的消息。当然我们可以配置时间来决定集群维护消息的时间长短。在可用时间内消息都可以被消费者消费,超过这个时间消息会被删除来节省时间。<code>Kafka's performance is effectively constant with respect to data size so retaining lots of data is not a problem</code>:Kafka的性能是一个相对高效常亮,不管数据量多少,所以它维护大量的数据不是问题。</p>
<p>每个消费者维护一个元数据:它指消费者读取的消息在日志中的位置,即<code>offset</code>。它由consumer控制。随着读取消息,offset会线性递增。<code>consumer可以按照任意顺序消费消息</code>。<strong> For example a consumer can reset to an older offset to reprocess.</strong></p>
<p>以上特性的组合使得consumer的代价很小。consumer数量可以增加或减少而对整个集群影响很小。例如在不影响consumers和消费内容的情况下从topic尾部内容读取消息。</p>
<h3>分区 && Distribution</h3>
<p><strong>partitions</strong>意义重大:</p>
<ul>
<li><p>First, they allow the log to scale beyond a size that will fit on a single server. Each individual partition must fit on the servers that host it, but a topic may have many partitions so it can handle an arbitrary amount of data.</p></li>
<li><p>Second they act as the unit of parallelism—more on that in a bit.</p></li>
</ul>
<p>Each partition is replicated across a configurable number of servers for fault tolerance.每个分区(内容)都是课重复的,需要在承载分区的服务器上配置。<strong>这是实现容错的一种方案</strong>。</p>
<p>每个分区都有1个<code>server</code>作为<strong>leader</strong>,0/多个server作为<code>followers</code><br>leader处理分区的读写请求,followers服从leader,复制leader的操作。<br>若leader故障,自动选取followers为新的leader</p>
<blockquote><p>Each server acts as a leader for some of its partitions and a follower for others so load is well balanced within the cluster.</p></blockquote>
<h3>Producer</h3>
<p>选择发送什么消息给哪个topic的哪个分区。[从这个角度看producer角色也很厉害]<br> This can be done in a round-robin fashion simply to balance load or it can be done according to some semantic partition function (say based on some key in the message). More on the use of partitioning in a second.</p>
<h3>Consumers</h3>
<p>传统上有2中处理消息的方法:队列和发布/订阅机制。</p>
<ul>
<li><p>队列模式下,消费者池从一台服务器上读取消息,并且<code>每条消息只能发送给消费者池中的一个消费者</code></p></li>
<li><p>发布/订阅模式下,消息广播到所有的消费者。</p></li>
</ul>
<p>consumer group,给一组consumers打标签,标签名即组名</p>
<blockquote><p>Consumers label themselves with a consumer group name, and each message published to a topic is delivered to one consumer instance within each subscribing consumer group. Consumer instances can be in separate processes or on separate machines.</p></blockquote>
<p>结合这张图理解 </p>
<p><img src="http://kafka.apache.org/images/consumer-groups.png" alt="" title=""></p>
<p>大致意思是:每个发送到topic的消息都会被发送给<code>订阅这个topic的</code>consumer group中的<strong>一个consumer</strong>。consumer实例可以在不同的进程或机器中。</p>
<p>当所有consumers属于一个group,这时的发布/订阅模式等同于队列模式。</p>
<p>当所有的consumer都属于不同的group时,这就是典型的发布/订阅模式,topic的消息发送给所有的consumer。</p>
<p>更一般的情况是每个topic有少量的groups,每个group都是topic的“逻辑订阅者”。此时每个group有多个consumer实现扩展性和容错。这里订阅者是sonsumer集群而不是单个进程。这里依然符合发布/订阅语义。</p>
<p>相比传统的消息系统,Kafka有健壮的顺序保证。</p>
<p>Kafka提出了<code>分区</code>的设计,将不同topics下的不同分区的消息分配给sonsumer group下的consumers,确保每个分区都能够被<code>唯一一个</code>consumer按消息发送的顺序处理消息数据。根据情况设计多个分区实现负载均衡。<strong>note:consumer数量不能超过partition数量</strong></p>
<p>Kafka只保证每个分区内的顺序,不同的分区间无法保证消息的顺序性。如果你需要所有的消息都按照顺序,那么只能设置一个分区,一个consumer实例。<strong>这时注意负载均衡和扩展性就无法保证了</strong></p>
<h3>guarantee</h3>
<ul>
<li>
<p>order</p>
<ul>
<li><p>对于1个分区,早发送到分区的offset<后发送到分区的offset</p></li>
<li><p>对于存放在log中的内容按照存储的先后顺序读取</p></li>
</ul>
</li>
<li><p>如果replication factor为N,最多允许<code>N-1</code>台server故障</p></li>
</ul>
<h3>Use Cases(使用案例)</h3>
<ul>
<li><p>Website Activity Tracking(网站活动跟踪)</p></li>
<li><p>Metrics</p></li>
<li><p>Log Aggregation(日志聚合)</p></li>
<li><p>Stream Processing</p></li>
</ul>
<p><a href="https://link.segmentfault.com/?enc=umMt%2FuTIZwLdxDRtxdC1UQ%3D%3D.CTBX%2FHbBPIKh1x94Q4cOPmC2ly5tA477j3tZfqv42MSNrTWujg1lSM0phBT8rbOVqKSBivZ%2BqUQT0V8ABqBqYw%3D%3D" rel="nofollow">原文连接</a></p>
Working with Docker Hub
https://segmentfault.com/a/1190000003710249
2015-09-06T09:39:34+08:00
2015-09-06T09:39:34+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<h2>Working with Docker Hub</h2>
<p>到目前为止我们已经学习了如何使用命令行在主机上运行Docker。你已经学习了如何下载镜像,如何从已经存在的镜像运行容器,以及如何创建你自己的镜像。</p>
<p>下一步,你将学习如何使用Docker Hub来简化和加强你的Docker工作流。</p>
<p>Docker Hub是由Docker公司维护的公共注册仓库。你可以利用它:</p>
<ul>
<li><p>下载超过15000的镜像来构建容器</p></li>
<li><p>身份验证、工作组织结构以及像<code>webhooks</code>和<code>trigger</code>这样的工作流工具</p></li>
<li><p>一些私人工具,比如私人仓库用来存放你不想和他人分享的镜像</p></li>
</ul>
<h4>Docker commands and Docker Hub</h4>
<p>Docker本身提供了一些命令用于获取Docker Hub服务:</p>
<ul>
<li><p>docker login</p></li>
<li><p>docker search</p></li>
<li><p>docker pull</p></li>
<li><p>docker push</p></li>
</ul>
<h4>Account creation and login</h4>
<p>要想使用Docker Hub的服务,首先要有Docker Hub的账号并且登录。你可以在Docker Hub上注册或者通过命令:</p>
<pre><code class="language">docker login</code></pre>
<p>这条命令后会提示输入用户名,<strong>会成为你公共仓库的共有命名空间</strong>,如果已经有了用户名,Docker会提示你输入密码和邮箱,然后自动登录。登录成功后你就可以向Docker Hub上自己的仓库中推送自己的镜像了。</p>
<blockquote><p>注意:你的身份验证信息会被存在用户目录的<code>.dockercfg</code>认证文件中</p></blockquote>
<h4>Searching for images</h4>
<p>我们可以通过Docker自己的search接口或者是命令行中的接口来查找Docker Hub中的镜像。关键字可以是镜像名,用户名甚至是镜像的描述信息。</p>
<pre><code class="language">$ sudo docker search centos
NAME DESCRIPTION STARS OFFICIAL TRUSTED
centos Official CentOS 6 Image as of 12 April 2014 88
tianon/centos CentOS 5 and 6, created using rinse instea... 21
...</code></pre>
<p>其中有两个结果:<code>centos</code>,<code>tianon/centos</code>。第二个<code>tianon/centos</code>表示它来自于一位叫<code>tianon</code>的用户的仓库。第一个结果没有显示列出仓库则意味着它是受信任的官方顶级名称空间存储库。<code>/</code>将仓库名和镜像名分割开。</p>
<p>找到镜像后<code>pull</code>下载镜像</p>
<pre><code class="language">docker pull [imagename]</code></pre>
<h4>Contributing to Docker Hub</h4>
<p>任何人都可以从Docker Hub下载镜像,但是如果你想向Docker Hub推送镜像,首先要注册</p>
<h4>Pushing a repository to Docker Hub</h4>
<p>为了将仓库推送到<code>register</code>中,你需要已经命名的镜像或者把你的容器保存为命名的镜像,详情见<a href="https://link.segmentfault.com/?enc=wz6e7emuFNVfS4ozA9jiNg%3D%3D.3PIs0VqqSDmkwLCDNxQgNKp%2FSzuvpFw3Nv3GUVPNZRM%2BHUg06miBUjB0730hSoom" rel="nofollow">这里</a></p>
<pre><code class="language"> docker push yourname/newimage</code></pre>
<h4>Features of Docker Hub</h4>
<p>现在我们就来看看Docker Hub有哪些特性,更多信息见<a href="https://link.segmentfault.com/?enc=C1bY0u%2F1ABa8EdPDg2lcgw%3D%3D.GG%2FoH1SmI4%2BuKquvdBeaQiWtxBJ5c3%2FiTQ1GV%2Bf9WN6TQGF8KAajftFV%2ByR8YAtg" rel="nofollow">这里</a></p>
<ul>
<li><p>私人仓库</p></li>
<li><p>组织和团队</p></li>
<li><p>自动构建</p></li>
<li><p>webhooks</p></li>
</ul>
<h6>Private Repositories</h6>
<p>如果你有镜像不想公开或和他人分享,Docker允许你拥有自己的私人仓库</p>
<h6>Organizations and teams</h6>
<p>私人仓库的一个好处是你可以把里里面的镜像分享给组织或团队里的人。Docker Hub允许你创建自己的组织,在组织里你可以和同伴一起工作,以及管理自己的仓库。详情见<a href="https://link.segmentfault.com/?enc=OsbP1%2F3qw%2BASTAifR8OTxQ%3D%3D.ddV7H3zPH9ugHTsuJdthbePb24Uzym9KdG%2B%2FGBWiz01tTZtlGfxx2X6x9lgSI4Hvub0R9Sqe3N7gudJ%2B1Z6jIg%3D%3D" rel="nofollow">这里</a></p>
<h6>Automated Builds</h6>
<p>自动构建和更新github和bitbuckets中的镜像,这些工作直接在Docker Hub中进行(不是本地)。它的工作方式是这样的:在你选中的github或bitbucket中添加<code>hook</code>,当你更新仓库时会触发构建和更新操作。</p>
<p>自动构建的步骤:</p>
<ul>
<li><p>创建账号并登录</p></li>
<li><p>连接github或bitbucket的账号</p></li>
<li><p>配置自动构建的选项</p></li>
<li><p>选中github或bitbucket中带有<code>Dockerfile</code>的项目</p></li>
<li><p>选择分支</p></li>
<li><p>命名</p></li>
<li><p>分配可选的Docker标签</p></li>
<li><p>指定Dockerfile文件的位置,默认是<code>/</code>目录</p></li>
</ul>
<p>在<a href="https://link.segmentfault.com/?enc=HzkFDfP1Kd0MzecsMHpHDw%3D%3D.K4njdHHZGPrnfXMP2BKlxKA5Lr0HELwdTI4rRJ%2BqIsbbpZZioxmKUvPHxSaN7IzW" rel="nofollow"> Automated Builds page</a>查看自己自动构建的项目 </p>
<p>不能对自动构建的仓库使用<code>docker push</code>命令。只能通过向github或bitbucket更新代码来管理自己的镜像。</p>
<p>你也可用为同一个项目的不同分支创建多个自动构建的项目。</p>
<h6>Webhooks</h6>
<p>webhooks附着到你的仓库并且在你更新镜像或者push操作时触发事件。通过webhook,push镜像时,你可以指定一个目标URL或者JSON负载均衡。</p>
Apply custom metadata
https://segmentfault.com/a/1190000002779151
2015-05-19T20:15:15+08:00
2015-05-19T20:15:15+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<p><img src="http://7xizmp.com1.z0.glb.clouddn.com/docker-wallpaper-grey.jpg" alt=""></p>
<blockquote>
<p>你可以用过<code>LABEL</code>把元数据应用到你的镜像,容器或者是守护进程中。元数据可以服务于广泛的用途。使用标签可以给镜像添加注释或者是许可信息,还可以用来标志你的主机</p>
</blockquote>
<p>标签是<code><key></code> / <code><value></code>键值对,Docker以字符串的方式存储标签。你可以指定多个标签但是每一个<code><key></code> / <code><value></code>必须不同防止对已经存在的键值对覆盖。如果你给同一个<code>key</code>指定了多个不同的值,新的值会把之前的值覆盖掉。记住,对于相同的<code>key</code>,Docker只会应用你提供的最后一个值。</p>
<blockquote>
<p><strong>注意</strong>:Docker1.4.1之后的版本才支持daemon-labels,对标签和容器的标签支持是1.6.0中的新特性。</p>
</blockquote>
<h2>Label keys (namespaces)</h2>
<blockquote>
<p>标签的<code>键</code>,(也就是命名空间)</p>
</blockquote>
<p>Docker对你创建的标签中的键没有什么硬性的限制,但是简单的键也有可能冲突。例如,你通过<code>architecture</code>标签来给你的镜像分类:</p>
<pre><code>language</code><code>LABEL architecture="amd64"
LABEL architecture="ARMv7"
</code></pre>
<p>而且用户也可以通过不同风格的标签来给镜像打标签:</p>
<pre><code>language</code><code>LABEL architecture="Art Nouveau"
</code></pre>
<p>为了防止命名冲突,Docker的命名空间标签键使用<code>反向域名</code>表示。参考下面来命名你的键:</p>
<ul>
<li>所有的(第三方)工具都用反向域名前缀+标签的方式来命名,这个反向域名要和工具作者提供的域名一致,如<code>com.example.some-label</code>,<code>com.example.some-auther="root"</code>
</li>
<li>
<code>com.docker.*</code>, <code>io.docker.*</code>和<code>com.dockerproject.*</code>保留给Docker内部使用</li>
<li>键只能是小写字母,数字,点和<code>-</code>表示,及<code>[a-z0-9-.]</code>
</li>
<li>键名的开始和结束只能是字母和数字</li>
<li>不能包含连续的<code>-</code>和点</li>
<li>没有名称空间的标签保留给<code>CLI</code>,这就允许最终用户给容器和镜像添加元数据而不必在终端输入繁琐的命令</li>
</ul>
<p>上面列举的都是准则且Docker严格遵守执行。如果你没有遵守这些准则有可能导致标签名的冲突。如果恰巧你也在使用标签构建工具的话,赶快为你的标签和键使用名称空间吧</p>
<h2>Store structured data in labels</h2>
<blockquote>
<p>在标签中存储结构化数据</p>
</blockquote>
<p>标签中的值可以包含任何能被存储为字符串的值,例如下面的JSON格式的数据:</p>
<pre><code>shell</code><code>{
"Description": "A containerized foobar",
"Usage": "docker run --rm example/foobar [args]",
"License": "GPL",
"Version": "0.0.1-beta",
"aBoolean": true,
"aNumber" : 0.01234,
"aNestedArray": ["a", "b", "c"]
}
</code></pre>
<p>要想把这个结构存储在标签中,首先你要把它序列化为字符串:</p>
<pre><code>language</code><code>LABEL com.example.image-specs="{\"Description\":\"A containerized foobar\",\"Usage\":\"docker run --rm example\\/foobar [args]\",\"License\":\"GPL\",\"Version\":\"0.0.1-beta\",\"aBoolean\":true,\"aNumber\":0.01234,\"aNestedArray\":[\"a\",\"b\",\"c\"]}"
</code></pre>
<p>虽然可以在标签中存储结构化的数据,但是Docker把它(结构化的数据)看作是普通的字符串。这意味着Docker本身并不提供基于嵌套属性的查询(过滤器)。如果你的工具需要通过嵌套属性来过滤,那么你的工具本身要实现这个功能,二不要让Docker去做。</p>
<h2>Add labels to images; the LABEL instruction</h2>
<blockquote>
<p>使用<code>LABEL</code>指令给镜像添加标签</p>
</blockquote>
<pre><code>language</code><code>LABEL [<namespace>.]<key>[=<value>] ...
</code></pre>
<p>LABEL指令用来给镜像添加标签,可选择设置它的值。对于使用<code>空格</code>的标签,要用<code>双引号</code>或者<code>反斜杠</code>。<br>
e.g.</p>
<pre><code>language</code><code>LABEL vendor=ACME\ Incorporated
LABEL com.example.version.is-beta
LABEL com.example.version="0.0.1-beta"
LABEL com.example.release-date="2015-02-12"
</code></pre>
<p><strong>注意:</strong>上面的第二行中只有键,没有值。<br>
LABEL指令支持在一个<code>LABEL</code>下设置多个<br>
e.g.</p>
<pre><code>language</code><code>LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"
</code></pre>
<p>Docker允许使用反斜杠<code>\</code>,将1行指令分割为多个行</p>
<pre><code>language</code><code>LABEL vendor=ACME\ Incorporated \
com.example.is-beta \
com.example.version="0.0.1-beta" \
com.example.release-date="2015-02-12"
</code></pre>
<p><strong>Docker更推荐你在一个LABEL指令中设置多个标签</strong>,每个标签都用指令单独设置的话会让你的镜像很<code>低效</code>,这是因为每一个Dockerfile中的LABEL指令都会产生1个镜像层(怒了,这个解释直达本质啊)!!!</p>
<p>我们可以使用<code>docker inspect</code>来查看镜像或者容器的标签</p>
<h2>Query labels</h2>
<blockquote>
<p>查询标签</p>
</blockquote>
<p>标签除了可以用来存储元数据,还可以用来过滤镜像和容器。下面的命令将会列出所有包含<code>com.example.is-beta</code>标签并且运行这的容器:</p>
<pre><code>language</code><code>docker ps --filter "label=com.example.is-beta"
</code></pre>
<p><code>color</code>标签且值为<code>blue</code>的运行中的容器</p>
<pre><code>language</code><code>docker ps --filter "label=color=blue"
</code></pre>
<p>包含<code>vendor</code>和<code>ACME</code>的镜像</p>
<pre><code>language</code><code>docker images --filter "label=vendor=ACME"
</code></pre>
<h2>Daemon labels</h2>
<blockquote>
<p>守护标签</p>
</blockquote>
<p><code>docker info</code>这条命令的解释是:<code>Display system-wide information(显示全部信息)</code><br>
下面是我电脑上的结果:</p>
<pre><code>language</code><code>adolph@geek:~$ docker info
Containers: 7
Images: 44
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 58
Dirperm1 Supported: false
Execution Driver: native-0.2
Kernel Version: 3.13.0-52-generic
Operating System: Ubuntu 14.04.2 LTS
CPUs: 4
Total Memory: 7.687 GiB
Name: geek
ID: HGR7:UGWW:VQVV:WYMF:CSEE:KJ4C:QS4U:IRIU:LREB:M4YC:GDJY:YPI5
Username: adolphlwq
Registry: [https://index.docker.io/v1/]
WARNING: No swap limit support
</code></pre>
<p>可以看出里面主要是关于Docker daemon的信息,这里并没有关于它的标签信息。但是我们可以通过``docker -d label=value`的方式给Docker daemon本身添加标签:</p>
<pre><code>language</code><code>docker -d \
--dns 8.8.8.8 \
--dns 8.8.4.4 \
-H unix:///var/run/docker.sock \
--label com.example.environment="production" \
--label com.example.storage="ssd"
</code></pre>
Dockerfile 基础实战:构建基础的 ubuntu14.04 镜像
https://segmentfault.com/a/1190000002778704
2015-05-19T17:22:59+08:00
2015-05-19T17:22:59+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
0
<blockquote>
<p>我们可以从Docker Hub上下载官方仓库中的镜像,我自己就下载了ubuntu镜像,只有<code>188M</code>左右,很小巧了。但是看了下,里面的软件源还是官方的,而且没有安装<code>vim</code>,所以就打算自己写一个<code>Dockerfile</code>,用它来构建适合自己的ubuntu基础镜像。</p>
</blockquote>
<pre><code>language</code><code>deb http://archive.ubuntu.com/ubuntu/ trusty main restricted
deb-src http://archive.ubuntu.com/ubuntu/ trusty main restricted
...................
</code></pre>
<h2>构建上下文</h2>
<p><code>build context</code>,一个自定义的文件夹,里面放置Dockerfile和一些需要的文件。比如我的:</p>
<ul>
<li>Dockerfile...这个是必须的</li>
<li>sources.list...自己在官方社区找的<a rel="nofollow" href="http://wiki.ubuntu.org.cn/Template:14.04source">ubuntu14.04</a>的源</li>
<li>vimrc...安装好vim后用到的配置文件。我事先配置好的,都是些基础的配置。</li>
</ul>
<pre><code>language</code><code>.
├── baseimage
│ ├── Dockerfile
│ ├── README.md
│ ├── sources.list
│ └── vimrc
</code></pre>
<h2>Dokerfile</h2>
<p>制作image有两种方法:</p>
<ul>
<li>从现有容器通过<code>commit</code>命令创建<br><br><ul>
<li>dockerfile中不方便的操作可以在容器中操作然后提交</li>
<li>没有批量启动容器的需要</li>
<li>自己学、习练习,不需要移植</li>
</ul>
</li>
<li>利用Dockerfile构建<br><br><ul>
<li>方便,灵活,可移植</li>
<li>适合部署大量的镜像和容器</li>
</ul>
</li>
</ul>
<h3>Dockerfile基础</h3>
<ul>
<li>'#'表示注释,一般Dockerfile第一行注释容器的基本信息和版本。</li>
<li>Dockerfile以<code>命令:参数</code>为基本构建语句,命令全部大写,后面的参数视命令而定</li>
<li>
<p>FROM,必须是第一个命令项,表示我的镜像是以哪个镜像为基础构建的</p>
<pre><code>language</code><code>FROM ubuntu
</code></pre>
</li>
<li>
<p>MAINTAINER,后面接构建这的姓名和邮箱,方便联系</p>
<pre><code>language</code><code>MAINTAINER adolphlwq <kenan3015@gmail.com>
</code></pre>
</li>
<li>
<p>LABEL,用键值对的方式来指定image的元数据</p>
<pre><code>language</code><code>LABEL Description="it is used as a basic image for DuoHuoStudio and my study.I will update and install vim." Vendor="Basic image"
</code></pre>
</li>
<li>
<p>ADD,在构建时向Docker daemon传递文件</p>
<pre><code>language</code><code>ADD sources.list /etc/apt/
</code></pre>
</li>
<li>
<p>RUN,接操作和命令<code>sudo apt-get install -y vim</code>等</p>
<pre><code>language</code><code>ADD sources.list /etc/apt/
</code></pre>
</li>
<li>
<p>CMD,构建成功的镜像第一次启动时默认启动的命令</p>
<ul>
<li>CMD只有1条,一般默认在Dockerfile的最后</li>
<li>如果有多个CMD,只有最后一个起作用</li>
<li>CMD会被<code>docker run ..</code>后面的命令覆盖</li>
</ul>
<pre><code>language</code><code>CMD ["/bin/bash"]
</code></pre>
</li>
<li>
<p>ENV,设置环境变量</p>
<pre><code>language</code><code>ENV REFRESHED_AT 2015-05-18
</code></pre>
</li>
</ul>
<h3>构建命令</h3>
<pre><code>language</code><code>cd baseimage(构建上下文文件夹)
docker build -t="duohuosrudio/ubuntu:14.04_64_base_image" .
</code></pre>
<p><code>docker build</code>中<code>-t</code>表示容器的名字<br><code>duohuosrudio/ubuntu</code>中<code>duohuostudio</code>表示仓库名(不允许大写),<code>ubuntu</code>表示镜像名。<br><code>ubuntu:14.04_64_base_image</code>后的<code>14.04_64_base_image</code>是标签,如果没有指定,默认的是<code>latest</code></p>
<p>构建过程:</p>
<p><img src="http://7vihfm.com1.z0.glb.clouddn.com/2015-05-19-base-image.gif" alt=""></p>
<h3>实践中遇到的错误</h3>
<ul>
<li>
<code>apt-get upgrade</code>和<code>apt-get install vim</code>都要加上** -y**选项,不然会报错</li>
<li>ADD后面必须接两个参数,<code>ADD <src>... <dest></code>表示要添加的文件,表示文件添加到哪里。</li>
<li>ADD添加的文件必须以<code>构建上下文</code>为根目录来找,不能超出构建上下文的范围。</li>
</ul>
<p>如果除错停止构建了也不要担心,Docker会把构建过程中的文件都缓存起来,再次构建时会从缓存的地方开始,节省时间。</p>
<p>除错停止后<code>docker images</code>会出现一个只有<code>IMAGE ID</code>的镜像,这个就是构建失败后留下的缓存,我们可以通过image id来运行这个镜像,然后执行除错的命令来检查为什么出错!(下图的最后1行)</p>
<pre><code>language</code><code>adolph@geek:~/programs/DockerWorkspace/dockerfile/baseimage$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
test/ubuntu 14.04_64_base_image e9390454465c 14 hours ago 269.1 MB
test2/ubuntu 14.04_64_base_image e9390454465c 14 hours ago 269.1 MB
duohuostudio/ubuntu 14.04_64_base_image e9390454465c 14 hours ago 269.1 MB
<none> <none> f6efc4dac25a 16 hours ago 269.1 MB
</code></pre>
<h2>总结</h2>
<pre><code>language</code><code>docker build -t="duohuostudio/ubuntu:14.04_64_base_image" .
</code></pre>
<p>这条命令的<strong>最后一个参数是用来指定Dockerfile的路径</strong>,千万不要忘记。</p>
<p>dockerfile已经上传到 <a rel="nofollow" href="https://github.com/adolphlwq/DockerfileHub">github 地址</a></p>
<p>镜像也已经上传到<code>Docker Hub</code>上了,可以通过下列命令下载镜像</p>
<pre><code>docker pull adolphlwq/ubuntu
</code></pre>
Managing Data in Containers
https://segmentfault.com/a/1190000002774628
2015-05-18T12:19:56+08:00
2015-05-18T12:19:56+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<blockquote>
<p>前面已经介绍了许多基础的知识,现在我们来一起学习如何管理Docker容器里面以及容器之间的数据</p>
</blockquote>
<p>先介绍两种原始的方法来管理Docker中的应用:</p>
<ul>
<li>Data volumes</li>
<li>Data volume container</li>
</ul>
<h2>Data volumes</h2>
<blockquote>
<p><code>data volumns</code>是专门设计的工具,它绕过了UFS直接工作于一个或多个容器。它为数据持久和分享提供了许多功能:</p>
</blockquote>
<ul>
<li>容器被创建时,卷(volumn)被初始化。如果基础镜像在指定的挂载点包含数据,这些数据也会被复制到新容器的卷中。</li>
<li>数据卷可以在多个容器间分享和复用</li>
<li>可以直接更改卷里面的数据</li>
<li>更新镜像时对容器数据卷的更改将不会被包含到新的镜像中</li>
<li>即使容器被删除,数据卷依然存在</li>
</ul>
<p>数据卷的设计被用来持久化数据,让数据能够独立于容器的生命周期。因此当删除容器时Docker也不会自动删除数据卷。</p>
<h3>Adding a data volume</h3>
<blockquote>
<p>增加数据卷</p>
</blockquote>
<p><code>docker create -v</code>和<code>docker run -v</code>中的<strong>-v</strong>标记来给容器添加数据卷,我们可以在一条命令中多次使用<code>-v</code>标记来添加多个数据卷,下面的例子挂载了一个数据卷在我们的web应用容器中。</p>
<pre><code>language</code><code>docker run -d -P --name web -v /webapp training/webapp python app.py
</code></pre>
<p>这条命令执行后会在容器中创建一个新的卷<code>webapp</code></p>
<h3>Mount a Host Directory as a Data Volume</h3>
<blockquote>
<p>为数据卷挂在主机目录</p>
</blockquote>
<p>除了使用-v标记来创建卷之外,你还可以挂载Docker守护进程主机的目录到容器中。</p>
<blockquote>
<p><span>注意:</span>如果你使用Boot2Docker,那么你的Docker守护进程只能被限制访问OSX/windows特定的文件目录。Boot2Docker会努力自动分享OSX中的<code>/users</code>目录和windows中的<code>C:users</code>目录。因此你可以通过<code>docker run -v /Users/<path>:/<container path></code> ... (OSX)或者<code>docker run -v /c/Users/<path>:/<container path ...</code>(Windows).来挂在文件或目录。所有的其它路径(不是/users和C:users)都来自Boot2Docker虚拟机中的文件系统。</p>
</blockquote>
<pre><code>language</code><code>docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
</code></pre>
<p>上述命令会把主机的<code>/src/webapp</code>目录挂在到容器中的<code>/opt/webapp</code>下</p>
<blockquote>
<p><span>注意:</span>如果<code>/opt/webapp</code>目录已经存在与容器的镜像中,那么<code>/opt/webapp</code>中的内容会被主机上的<code>/src/webapp</code>中的数据替换,这个和mount命令是一致的。</p>
</blockquote>
<p>数据卷挂在数据对测试非常有用,比如我们可以把源代码挂在到容器中,然后修改代码看看应用会发生什么。主机上的目录必须是绝对路径,如果这个目录不存在Docker会自动去创建1个。</p>
<blockquote>
<p><span>注意:</span>不能在<code>Dockerfile</code>中来配置挂载目录,因为<code>Dockerfile</code>的目的是更方便的来一直和分享镜像,而主机目录依赖于主机,(对于一个目录,在不同的主机上可能绝对路径不一致)所以Dockerfile中目录挂载不会适用于所有的主机</p>
</blockquote>
<p>挂载的数据卷默认是可读写的,当然我们可以通过命令标记来让它<code>只读</code></p>
<pre><code>language</code><code>docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py
</code></pre>
<p>上述命令中我们通过<code>ro</code>选项来让数据卷只读</p>
<h3>Mount a Host File as a Data Volume</h3>
<blockquote>
<p>挂载主机文件作为数据卷</p>
</blockquote>
<p><code>-v</code>标记还可以用来挂在来自主机的文件,而不仅仅是目录</p>
<pre><code>language</code><code>docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
</code></pre>
<p>上述命令会带你到一个新容器的shell界面,你会有来自主机的bash历史。因为容器和主机共享了一个<code>.bash_history</code>文件,所以你在容器中的命令历史和主机中的历史都会记录到<code>.bash_history</code>中,这样当你退出容器中时,你在容器中的命令历史被保存下来了,在主机的shell历史记录中仍然能够看到容器中的历史。</p>
<p><img src="/img/remote/1460000006877144?w=615&h=426" alt=""></p>
<blockquote>
<p><span>注意:</span>人们会使用很多工具来编辑文件,<code>vi</code>,<code>sed --in-place</code>,这些都会导致文件的索引节点改变。Docker 1.1.0之前,文件修改会报如<code>sed: cannot rename ./sedKdJ9Dy: Device or resource busy</code>这样的错误。但是在Docker 1.1.0之后,挂载文件让文件修改变得非常简单而不需要再去挂在包含这个文件的父目录了。</p>
</blockquote>
<h2>Creating and mounting a Data Volume Container</h2>
<blockquote>
<p>创建一个专门防数据的数据卷容器</p>
</blockquote>
<p>如果你有一些持久化的数据需要在容器之间共享,或者想从非持久化容器使用持久化数据。最好的办法是创建名为<code>Data</code>的卷容器,把数据都挂在到Data容器里<br>
我们创建一个能分享数据的命名容器,他不运行任何应用,它重复使用<code>training/postgres</code>镜像以便所有的容器使用同一个层,这样可以节省磁盘空间。</p>
<pre><code>language</code><code>docker create -v /dbdata --name dbdata training/postgres /bin/true
</code></pre>
<p>我们使用<code>--volumes-from</code>标记来绑定<code>/dbdata</code>卷到另一个容器</p>
<pre><code>language</code><code>docker run -d --volumes-from dbdata --name db1 training/postgres
</code></pre>
<p>或者</p>
<pre><code>language</code><code>docker run -d --volumes-from dbdata --name db2 training/postgres
</code></pre>
<p>在是上述的例子中,我们在容器中挂在了<code>/dbdata</code>卷,如果恰巧镜像<code>training/postgres</code>中也有<code>/dbdata</code>这个目录,那么容器会隐藏<strong>镜像的目录,而让容器中的/dbdata目录可见</strong>,新建多个数据容器同样是隐藏镜像的文件而显示容器中的文件,这种机制实现了数据卷的数据共享。<br>
你可以在一条命令中使用多个<code>--volumes-from</code>标记参数把多个容器的数据卷绑定在一起。<br>
上述的代码中db1和db2是挂载dbdata这个容器来扩展的,你也可以挂载db1或者db2来扩展你的数据卷。</p>
<pre><code>language</code><code> docker run -d --name db3 --volumes-from db1 training/postgres
</code></pre>
<p>如果你想删除包含挂载数据卷的容器,甚至是初始化的容器<code>dbdata</code>,或者是由<code>dbdata</code>扩展的db1和db2,容器会删除,但是数据卷会留下。使用<code>docker rm -v</code>来删除容器的数据卷。</p>
<blockquote>
<p><span>注意:</span>当你删除容器没有使用<code>-v</code>标记的时候,Docker不会提示警告。没有使用<code>-v</code>标记删除容器,会让残留的<code>volumns</code>变得“无家可归”(就是没有容器再引用这个数据卷)。这样的卷很难删除而且会占用很多空间,我们正在努力改善数据卷的管理,你可以通过<code>pull request #8484</code>来跟进我们的进程。</p>
</blockquote>
<h2>Backup, restore, or migrate data volumes</h2>
<blockquote>
<p>我们可以利用数据卷来有效的备份、恢复和迁移数据</p>
</blockquote>
<pre><code>language</code><code>docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
</code></pre>
<p>命令中我们启动了一个新的容器,它共享了来自<code>dbdata</code>容器的数据卷。然后我们挂在了一个本地主机的目录<code>/backup</code>。最后我们使用<code>tar</code>命令把<code>/dbdata</code>中的数据压缩成<code>dbdata.jar</code>放到<code>/backup</code>中。执行结束我们就完成了数据卷的数据备份工作。</p>
<p>数据恢复</p>
<pre><code>language</code><code>docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
</code></pre>
<p>创建一个新的容器<code>dbdata2</code>,解压文件到新的容器的数据卷。</p>
Linking Containers Together
https://segmentfault.com/a/1190000002767022
2015-05-14T22:21:30+08:00
2015-05-14T22:21:30+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
2
<p><img src="/img/remote/1460000004868696" alt="" title=""></p>
<blockquote><p>Docker container中services/applications与主机或者其它containers之间通信的两种方式</p></blockquote>
<ul>
<li><p>port mapping(端口映射)</p></li>
<li><p>container linking(容器连接)</p></li>
</ul>
<h2>Connect using Network port mapping</h2>
<blockquote><p>使用端口映射来连接</p></blockquote>
<p>常用的命令(以<code>training/webapp</code>为例):</p>
<pre><code class="language">docker run -d -P traning/webapp ...
docker run -d -p traning/webapp ...</code></pre>
<h3>
<code>-P</code>flag</h3>
<ul>
<li><p>当container被创建并且运行时,-P标记立刻生效</p></li>
<li>
<p>它container内部的任意端口映射到docker host的port</p>
<ul>
<li><p>Docker host的port是随机的</p></li>
<li><p>它的生命力是短暂的(容器停止后端口映射就会失效)</p></li>
</ul>
</li>
</ul>
<p>e.g.</p>
<pre><code class="language">adolph@geek:~$ docker run -d -P training/webapp python app.py
3f30e81a01cdf9895a70828beebea32910f848ac00f92303e6af77faeee1db0a
adolph@geek:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3f30e81a01cd training/webapp:latest "python app.py" 8 seconds ago Up 8 seconds 0.0.0.0:32769->5000/tcp agitated_hawking</code></pre>
<p>内部的5000端口映射到外部的主机的<code>32769</code>端口</p>
<h3>
<code>-p</code>flag</h3>
<p>可以指定container内外的端口<br>内外的5000端口映射</p>
<pre><code class="language">docker run -d -p 5000:5000 training/webapp python app.py
adolph@geek:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf6bd021034d training/webapp:latest "python app.py" 4 seconds ago Up 2 seconds 0.0.0.0:5000->5000/tcp compassionate_lalande </code></pre>
<blockquote><p>这样做的不好的地方在于你只把congtainer内外的5000端口映射在一起,container内的其它端口被抛弃了</p></blockquote>
<p>映射到主机的××端口</p>
<pre><code class="language">docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py</code></pre>
<p>映射到主机的某个随机端口</p>
<pre><code class="language">docker run -d -p 127.0.0.1::5000 training/webapp python app.py</code></pre>
<p>注意<code>127.0.0.1:</code>有个冒号</p>
<p>-p参数使用的次数很多,主要用来配置多个端口</p>
<h2>Connect with the linking system</h2>
<blockquote><p>Docker有自带的<code>linking system</code>用来连接多个container,并且允许从一个container发送信息到另一个。发送信息的称为<code>source container</code>,接收信息的称为<code>recipient container</code>,recipient container智能看到一些经过筛选的关于source container的某些信息</p></blockquote>
<h3>The importance of naming</h3>
<blockquote><p>Docker依赖于容器的名字来建立连接,Docker启动容器时会自动给它起个名字,当然你也可以自己命名</p></blockquote>
<p>命名有两个非常棒的好处:</p>
<ul>
<li><p>告知container的作用或者属于哪种类型,如<code>traning/webapp</code>可以看出是webapp的container</p></li>
<li><p>方便Docker通过name指定container</p></li>
</ul>
<p>在运行container时通过<code>--name</code>标记来命名新的container</p>
<pre><code class="language">adolph@geek:~$ docker run -d -P --name web training/webapp python app.py
1be7fc1ca8f9b683a8c309a1f6315c65819db15e8105ddd1b198e50c4082842f
adolph@geek:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1be7fc1ca8f9 training/webapp:latest "python app.py" 4 seconds ago Up 3 seconds 0.0.0.0:32770->5000/tcp web
adolph@geek:~$ docker inspect -f "{{.Name}}" 1be7f
/web</code></pre>
<p><span style="color:red;"><strong>注意:</strong></span>container的name必须是唯一的,比如说刚才的<code>web</code>,如果你想给另一个容器起名为<code>web</code>,那只能把原来的<code>web</code>container删除(docker rm [-f])。另外,<code>docker run --rm --name..</code>会在容器停止运行后立即删除</p>
<h3>Communication across links</h3>
<blockquote><p>通过连接通信</p></blockquote>
<p>links允许容器发现对方并且建立安全的信息传输通道,link创建好后容器间通信的通道就建立好了。</p>
<p>注意事项:</p>
<ol>
<li><p>需要运行的两个容器不能重名</p></li>
<li><p>不能和其它已经存在的(不管有没有运行)容器重名</p></li>
<li><p><code>docker ps -a</code>查看所有容器的信息</p></li>
<li><p><code>docker rm [container name]</code>删除容器</p></li>
</ol>
<p>link代码</p>
<pre><code class="language">--link <name or id>:alias</code></pre>
<p><code>name or id</code>指我们要连接的container的名字</p>
<p>shell1的代码(我在一个shell中运行这些命令总会有1个容器在启动后就<code>EXIT(0)</code>)</p>
<pre><code class="language">adolph@geek:~$ docker run -i -t --name db adolph/ubuntu:14.04
root@a1bb409128b9:/#</code></pre>
<p>shell2</p>
<pre><code class="language">adolph@geek:~$ docker run -d -P --name web --link db:db training/webapp python app.py
09fed08b63e709e61d17f698ccec55a6d04ddb6e33c1aea3879f78d1970451ce
adolph@geek:~$ docker inspect -f "{{.HostConfig.Links}}" web
[/db:/web/db]</code></pre>
<blockquote><p>we can see that the <code>web</code> container is now linked to the <code>db</code> container <code>web/db</code>. Which allows it to access information about the db container.</p></blockquote>
<table>
<thead><tr>
<th>recipient container</th>
<th>source container</th>
</tr></thead>
<tbody><tr>
<td>web</td>
<td>db</td>
</tr></tbody>
</table>
<p>为了做到容器间的通信,Docker没有使用端口,而是自己建立了<code>tunnel</code>(隧道),使用<code>link</code>连接容器的好处是我们不需要将<code>source container</code>的端口暴露给网络,Docker的tunnel使用两种方式实现连接:</p>
<ul>
<li><p>Environment variables(环境变量)</p></li>
<li><p>Updating the /etc/hosts file(更新<code>/etc/hosts</code>文件)</p></li>
</ul>
<h4>环境变量</h4>
<blockquote><p>当我们连接容器是Docker会创建很多环境变量,并且它会在目标容器自动基于<code>--link</code>后面的参数创建环境变量。Docker会公开来自<code>source container</code>的所有环境变量,这些变量包括:</p></blockquote>
<ul>
<li><p>the ENV commands in the source container's Dockerfile(源容器Dockerfile中的<code>ENV</code>命令)</p></li>
<li><p>the <code>-e</code>, <code>--env</code> and <code>--env-file</code> options on the docker run command when the source container is started(容器运行时<code>run</code>后面的<code>-e</code>, <code>--env</code> 和 <code>--env-file</code>参数)</p></li>
</ul>
<p>这些环境变量允许我们通过编程从目标容器发现来自源容器的信息</p>
<blockquote><p>警告:理解docker link连接容器的机制很重要,link允许所有目标容器获得源容器的指定数据和信息,所以从安全性的角度,不建议在源容器中存储敏感的数据</p></blockquote>
<h5>一些环境变量</h5>
<p><code><alias>_NAME</code></p>
<pre><code class="language">docker run -d -P --name web --link db:db training/webapp python app.py</code></pre>
<p>这个变量是为目标容器建立的,如上,<code>--link db:db</code>后<code>web</code>容器被链接到<code>db</code>容器,这是Docker会在<code>web</code>容器中创建DB_NAME=/web/db</p>
<p><code><name>_PORT_<port>_<protocol></code><br>Docker为每一个源容器暴露的每一个端口。</p>
<ul>
<li><p><name>指--link中指定的目标容器的别名</p></li>
<li><p><port>源容器暴露的端口号</p></li>
<li><p><protocol> TCP或UDP</p></li>
</ul>
<p>Docker使用不同的前缀格式来规定3种不同的环境变量:</p>
<ul>
<li><p><code>prefix_ADDR</code>来自URL的ip地址。例如:WEBDB_PORT_8080_TCP_ADDR=172.17.0.82.</p></li>
<li><p><code>prefix_PORT</code>来自URL的端口。例如:WEBDB_PORT_8080_TCP_PORT=8080.</p></li>
<li><p><code>prefix_PROTO</code>来自URL的协议。例如:WEBDB_PORT_8080_TCP_PROTO=tcp.</p></li>
</ul>
<p>每一组环境变量对应一个端口,如果容器公开多个端口(比如3个),Docker就会创建9个环境变量,每个端口3个。<br>此外,Docker还会为<code>源容器</code>第一个公开的端口创建<code><alias>_PORT</code>,这里的<code>第一个</code>指的是具有<code>lowest port</code>的端口。例如:<code>WEBDB_PORT=tcp://172.17.0.82:8080</code>,如果它吗满足tcp和udp,那指的是tcp</p>
<p>最后,Docker还会创建这样一个变量:<code><alias>_ENV_<name></code>,用来连接源容器和目标容器的桥梁。Docker使用这个值来启动源容器。</p>
<p>e.g:</p>
<pre><code class="shell">adolph@geek:~$ sudo docker run --rm --name web2 --link db:db training/webapp env
[sudo] password for adolph:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=20fb0166d9c6
DB_NAME=/web2/db
HOME=/</code></pre>
<p>我的电脑上并没有看到环境变量!可能因为我的db容器和官网例子上的容器不一直吧,而且我的db容器中并没有安装数据库。<br>Docker创建的这些变量有助于我们用来连接和配置源容器里的工具,比如连接数据库...</p>
<h5>Updating the /etc/hosts file</h5>
<blockquote><p>更新<code>/etc/hosts</code>文件</p></blockquote>
<p>这部分自己有不懂的地方,以后慢慢看吧。</p>
<h2>总结</h2>
<h3>连接容器的两种方法</h3>
<h4>
<code>-p</code>,<code>-P</code>标记</h4>
<h4>link system</h4>
<ul>
<li>
<p>容器的命名是唯一的,不能重复。可以更改容器的名字</p>
<ul><li><p><code>docker rename oldname newname</code></p></li></ul>
</li>
<li><p>--link <name or id>:alias,name指要连接的容器,alais指目标容器/简称</p></li>
<li><p>能够清除代码中那个是目标容器,哪个是源容器,资源开放共享的方向</p></li>
</ul>
<pre><code class="language">docker run -d -P --name web --link db:webdb training/webapp python app.py</code></pre>
<p>这条命令中<code>db</code>是要连接的容器,是源容器,web是目标容器,webdb是web的别称</p>
<pre><code class="language">adolph@geek:~$ docker inspect -f "{{.HostConfig.Links}}" web
[/db:/web/webdb]</code></pre>
<p>都是个人理解,可能有错误,还请指正。</p>
Working with Docker Images
https://segmentfault.com/a/1190000002763168
2015-05-13T16:59:16+08:00
2015-05-13T16:59:16+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<p><img src="http://7vihfm.com1.z0.glb.clouddn.com/2015-4-18-javagroup-5.jpg" alt=""></p>
<h2>目标</h2>
<ul>
<li>本地主机管理镜像</li>
<li>创建自己的镜像</li>
<li>上传镜像到<code>Docker Hub registry</code>
</li>
</ul>
<h2>Listing images on the host</h2>
<blockquote>
<p>列出主机的镜像</p>
</blockquote>
<pre><code>shell</code><code>adolph@geek:~$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu 14.04 07f8e8c5e660 12 days ago 188.3 MB
hello-world latest 91c95931e552 3 weeks ago 910 B
training/webapp latest 31fa814ba25a 11 months ago 278.8 MB
</code></pre>
<p>镜像来自的仓库,标签和Id这些信息都很重要,来自相同的仓库我们通过<code>标签</code>来指定要运行的镜像</p>
<pre><code>language</code><code>docker run -i -t ubuntu:14.04 /bin/bash
docker run -i -t ubuntu:latest /bin/bash (不加标签默认是`latest`)
</code></pre>
<blockquote>
<p>个人觉得标签的好处是对于来自相同的仓库通过标签来告诉docker我要运行的是哪个镜像</p>
</blockquote>
<h2>Finding images</h2>
<blockquote>
<p>寻找镜像</p>
</blockquote>
<pre><code>language</code><code>docker search [image name]
docker pull [image name]...找到合适的后直接拉下来
</code></pre>
<h2>Creating our own images</h2>
<blockquote>
<p>创建和定制自己的镜像</p>
</blockquote>
<ul>
<li>更改现有镜像并提交(保存)</li>
<li>使用<code>Dockerfile</code>来制作镜像</li>
</ul>
<h3>Updating and committing an image</h3>
<pre><code>language</code><code>docker run -i -t ubuntu:14.04 /bin/bash
root@5bc673e32e0a:/#apt-get install git
root@5bc673e32e0a:/#exit
sudo docker commit -m "install git" -a "adolph" 0b2616b0e5a8 adolph/ubuntu:14.04
output:4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c
</code></pre>
<h3>Building an image from a Dockerfile</h3>
<pre><code>language</code><code>mkdir ubuntu
cd ubuntu
touch Dockerfile
vim Dockerfile
content:
#this is my fiest image created by dockerfile
FROM ubuntu:14.04
MAINTAINER adolph <test@126.com>
RUN apt-get update
#RUN apt-get install git
</code></pre>
<p>结果:</p>
<pre><code>language</code><code>adolph@geek:~/ubuntu$ sudo docker build -t adolph-dockerfile/ubuntu:14.04 .
Sending build context to Docker daemon 2.048 kB
Sending build context to Docker daemon
Step 0 : FROM ubuntu:14.04
---> 07f8e8c5e660
Step 1 : MAINTAINER adolph <nalan3015@126.com>
---> Running in 241ad7c398c3
---> 10d866905c1a
Removing intermediate container 241ad7c398c3
Step 2 : RUN apt-get update
---> Running in 826db7ff28e6
Ign http://archive.ubuntu.com trusty InRelease
Ign http://archive.ubuntu.com trusty-updates InRelease
。。。。。。。。。
</code></pre>
<p>sudo docker build -t adolph-dockerfile/ubuntu:14.04 <strong><span>.</span></strong></p>
<p><strong>注意上述命令有个<code>.</code>用来指定Dockerfile文件的位置</strong></p>
<h2>Setting tags on an image</h2>
<blockquote>
<p>给镜像添加标签</p>
</blockquote>
<pre><code>language</code><code>docker tag [image id] [username]/[repository]:[tag name]
</code></pre>
<h2>Push an image to Docker Hub</h2>
<blockquote>
<p>需要登录Docker Hub账号</p>
</blockquote>
<p><code>docker push [image name]</code></p>
<h2>Remove an image from the host</h2>
<p><code>docker rmi [image name]</code></p>
<h2>总结</h2>
<pre><code>language</code><code>docker images...查看docker镜像
docker search [images name]...查找镜像
</code></pre>
<p><code>sudo docker commit -m "install git" -a "adolph" 0b2616b0e5a8(old image id) adolph/ubuntu:14.04(new image name with tag 14.04)</code><br>
这条命令很重要和难记,<code>-m</code>和<code>git commit -m</code>的作用类似,<code>-a</code>指定作者,id指<code>更改过的image的id</code>,<code>adolph/ubuntu</code>是新的image的名字</p>
<pre><code>language</code><code>docker build -t adolph-dockerfile/ubuntu:14.04 .
后面要指定dockerfile的地址
docker tag [image id] [username]/[repository]:[tag name]
docker push [image name]
docker rmi [image name]
</code></pre>
Working with Containers
https://segmentfault.com/a/1190000002761949
2015-05-13T11:22:27+08:00
2015-05-13T11:22:27+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<p><img src="http://7vihfm.com1.z0.glb.clouddn.com/2015-3-28-weekly-summary.jpeg" alt=""></p>
<h2>先回顾之前学习过的一些命令</h2>
<pre><code>shell</code><code>docker run -i...交互式运行
docker run -d...background运行`daemon`守护进程
docker ps...Lists containers.(容器列表)
docker logs...Shows us the standard output of a container.(显示容器的标准输出)
docker stop...Stops running containers.
</code></pre>
<p>docker命令格式:</p>
<pre><code>shell</code><code>[sudo] docker [command] [flags] [arguments]...
</code></pre>
<h2>Seeing what the Docker client can do</h2>
<blockquote>
<p>docker client能干什么</p>
</blockquote>
<p><code>[sudo] docker</code>...显示docker后能执行的命令</p>
<h2>Seeing Docker command usage</h2>
<blockquote>
<p>docker 命令使用</p>
</blockquote>
<pre><code>language</code><code>docker command --help...查看特定命令的使用方式
</code></pre>
<h2>Running a Web Application in Docker</h2>
<blockquote>
<p>docker中运行一个web应用</p>
</blockquote>
<pre><code>language</code><code> sudo docker run -d -P training/webapp python app.py
</code></pre>
<p><code>-P</code>参数表示将容器内部要用到的网络端口映射到主机</p>
<pre><code>language</code><code>docker ps -l -a
</code></pre>
<p><code>-l</code>显示容器的详细信息,<code>-a</code>表示显示所有的容器信息(包含以前运行的)</p>
<pre><code>language</code><code>docker run -d -P training/webapp python app.py
docker run -d -p 5000:5000 training/webapp python app.py
</code></pre>
<p><code>-P</code>表示将<code>image</code>镜像的任何端口映射到我们自己的主机<br><code>-p</code>自己指定<code>image</code>的网络端口和主机的端口</p>
<p><strong>实战:</strong><br>
命令行输入</p>
<pre><code>language</code><code>docker run -d -P training/webapp python app.py
docker ps -l -a
out:
adolph@geek:~$ docker ps -a -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1179c34ac0e0 training/webapp:latest "python app.py" 2 minutes ago Up 2 minutes 0.0.0.0:32769->5000/tcp elegant_curie
</code></pre>
<p><span>这里重要的是port下面的值:0.0.0.0:32769->5000/tcp</span>,我的理解是:这条命令把<code>0.0.0.0:32769</code>这个自己主机的端口映射到容器里的<code>5000</code>端口,所以当你在自己的浏览器输入<code>0.0.0.0:32769</code>是它会映射到images的<code>5000</code>端口从而访问app.py的网页</p>
<h2>A Network Port Shortcut</h2>
<blockquote>
<p>网站端口<code>Shortcut</code></p>
</blockquote>
<pre><code>language</code><code>docker port [container id|container name]
</code></pre>
<p>这条命令表示输出容器的端口和映射端口,</p>
<pre><code>language</code><code>5000/tcp -> 0.0.0.0:32769
adolph@geek:~$ docker port 1179c 5000
0.0.0.0:32769
</code></pre>
<h2>Viewing the Web Application's Logs</h2>
<blockquote>
<p>查看web应用的logs</p>
</blockquote>
<pre><code>language</code><code>adolph@geek:~$ docker logs -f elegant_curie
* Running on http://0.0.0.0:5000/
172.17.42.1 - - [12/May/2015 17:49:25] "GET / HTTP/1.1" 200 -
172.17.42.1 - - [12/May/2015 17:49:26] "GET /favicon.ico HTTP/1.1" 404 -
</code></pre>
<p><code>-f</code>功能类似于<code>tail -f</code>而且我们可以看到标准输出的信息</p>
<h2>Looking at our Web Application Container's processes</h2>
<blockquote>
<p>查看web应用容器的进程</p>
</blockquote>
<p>使用<code>docker top</code>命令</p>
<pre><code>language</code><code>adolph@geek:~$ docker top elegant_curie
UID PID PPID C STIME TTY TIME CMD
root 32280 2150 0 01:48 ? 00:00:00 python app.py
</code></pre>
<h2>Inspecting our Web Application Container</h2>
<blockquote>
<p>检查web应用容器</p>
</blockquote>
<pre><code>language</code><code>docker inspect comtainer name
</code></pre>
<p>以<code>Json</code>格式输出信息</p>
<h2>Stopping&Start&Remove our Web Application Container</h2>
<blockquote>
<p>停止和启动我们的web容器</p>
</blockquote>
<pre><code>language</code><code>adolph@geek:~$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1179c34ac0e0 training/webapp:latest "python app.py" 25 minutes ago Up 25 minutes 0.0.0.0:32769->5000/tcp elegant_curie
adolph@geek:~$ docker stop elegant_curie
elegant_curie
adolph@geek:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
adolph@geek:~$ docker start elegant_curie
elegant_curie
adolph@geek:~$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1179c34ac0e0 training/webapp:latest "python app.py" 26 minutes ago Up 7 seconds 0.0.0.0:32770->5000/tcp elegant_curie
adolph@geek:~$ docker stop elegant_curie
elegant_curie
adolph@geek:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
adolph@geek:~$ docker rm elegant_curie
elegant_curie
</code></pre>
<h2>命令总结</h2>
<pre><code>shell</code><code>docker...显示docker的命令
docker command --help...显示某个命令的帮助
docker ps -a -l...显示所有的容器信息
docker run -d -P ...-P映射容器的5000端口到主机的任意端口[32768-61000]
docker run -d -p ...-p自己指定映射端口
docker port [comtainer id|container name]...查看容器的端口情况
docker logs -f [container name|id] ...输出容器标准输出
docker inspect [container name]...输出json格式的容器的详细信息
docker top [container name...查看容器的进程
docker stop|start|rm [container name]...停止|开始|删除容器
</code></pre>
Docker学习笔记-Docker化你的应用
https://segmentfault.com/a/1190000002760996
2015-05-13T01:18:52+08:00
2015-05-13T01:18:52+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
2
<h2>Docker化你的应用</h2>
<p>使用<code>docker run</code>命令在容器中运行应用</p>
<blockquote>
<p>如果你使用的是远程Docker 进程(daemon),使用<code>sudo docker run</code></p>
</blockquote>
<h3>Hello world</h3>
<pre><code>shell</code><code>sudo docker run ubuntu:14.04 /bin/echo 'Hello world'
</code></pre>
<p>执行这条命令Docker首先会在本地的Docker主机上找image:ubuntu:14.04,如果没找到,Docker会到Docker Hub上下载这个镜像<br>
Docker容器仅仅在你指定的命令激活时才运行,在上面的命令中,当输出<code>hello world</code>后,容器就停止。</p>
<h3>An Interactive Container(交互式容器)</h3>
<pre><code>shell</code><code>$ sudo docker run -t -i ubuntu:14.04 /bin/bash
root@af8bae53bdd3:/#
</code></pre>
<p><code>docker run</code>启动镜像ubuntu14.04,<code>-t</code>在启动的容器中使用<code>终端</code>,<code>-i</code>表示允许我们建立交互式的连接,通过获取容器的标准输入[stdin]<br><code>exit</code>或者ctrl+D退出终端</p>
<h3>A Daemonized Hello world(将命令守护进程化)</h3>
<pre><code>language</code><code>$ sudo docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
eb643329659cb6b6830b70b87ef9576e0da1913682d4972d8ab904fb709072b7
</code></pre>
<p><code>-d</code>表示后台运行容器<br><code>/bin/sh -c "while true; do echo hello world; sleep 1; done"</code>无限输出<code>hello world</code><br>
返回一个<code>a bit long</code>表示<code>container ID</code></p>
<blockquote>
<p>Note: The container ID is a bit long and unwieldy and a bit later on we'll see a shorter ID and some ways to name our containers to make working with them easier.</p>
</blockquote>
<pre><code>language</code><code>adolph@geek:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eb643329659c ubuntu:14.04 "/bin/sh -c 'while t 2 minutes ago Up 2 minutes clever_hypatia
</code></pre>
<blockquote>
<p>docker会自动命名我们启动的container,当然你也可以自己重新命名</p>
</blockquote>
<p>查看容器日志并且返回它的输出</p>
<pre><code>language</code><code>docker logs container_name[clever_hypatia]
</code></pre>
<p>停止容器</p>
<pre><code>language</code><code>adolph@geek:~$ sudo docker stop clever_hypatia
clever_hypatia
adolph@geek:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
</code></pre>
<h3>总结</h3>
<ul>
<li>docker ps</li>
<li>sudo docker run [image name] [command]</li>
<li>sudo docker run ubuntu:14.04 /bin/echo 'Hello world'</li>
<li>sudo docker -t -i run [image name] [command]...交互式操作(有自己的命令行)</li>
<li>sudo docker run -t -i ubuntu:14.04 /bin/bash</li>
<li>sudo docker run -d [iamge name] [command]</li>
<li>sudo docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"</li>
<li>sudo docker logs [container name]...查看容器日志和输出信息</li>
<li>docker logs clever_hypatia </li>
<li>docker stop [container name] ...停止容器</li>
</ul>
<p><a rel="nofollow" href="https://docs.docker.com/userguide/dockerizing/">原文链接</a></p>
了解什么是 Docker
https://segmentfault.com/a/1190000002756858
2015-05-11T13:14:09+08:00
2015-05-11T13:14:09+08:00
陆道峰
https://segmentfault.com/u/adolphlwq
1
<pre><code class="shell"> _ _ _ _
__ _____| | | __| | ___ _ __ ___ | |
\ \ /\ / / _ \ | | / _` |/ _ \| '_ \ / _ \ | |
\ V V / __/ | | | (_| | (_) | | | | __/ |_|
\_/\_/ \___|_|_| \__,_|\___/|_| |_|\___| (_)
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
| |
__ | __ __ | _ __ _
/ \| / \ / |/ / _\ |
\__/| \__/ \__ |\_ \__ |
</code></pre>
<h2>What is Docker?</h2>
<p>Docker是一个为开发者和系统管理员<code>构建</code>,<code>部署</code>,<code>运行</code>分布式应用的开源平台。包括:Docker Engine,可移植的轻量运行环境和包管理工具,及<code>Docker Hub</code>。Docker Hub是为分享应用和自动化工作流服务的云服务。Docker能够做到apps快速从组件装配并且消除开发,质量评估和产品环境间的冲突。因此,它可以在不改变文件的情况下,在电脑上,数据中心虚拟机,任何云上运行同一款app</p>
<h2>Why do developers like it?</h2>
<p>有了Docker,开发者可以用任何语言,使用任何工具链构建任何应用。Docker化的应用完全可移植,并且到处运行:OS x,windows,云上的ubuntu或者是RED HAT上的产品数据中心虚拟机</p>
<p>Docker Hub上有13000+的apps,帮助开发者快速的开始开发。由Docker来管理,跟踪变化和依赖关系。系统管理员可以很容易地理解由开发者开发的app是如何工作的。有了Docker Hub,开发者可以自动构建他们自己的管道或者和合伙人通过<code>共有</code>或者<code>由repositories</code>来发布他们的产品</p>
<p>Docker帮助开发者开发,部署,快速的高质量应用。</p>
<h2>Why do sysadmins like it?</h2>
<p>系统管理员为他们(development, QA, and production teams)减少<code>在自己电脑上运行</code>带来的调整时间。通过Docker化app平台和app的依赖环境,系统管理员抽象的剥离了操作系统发行版本和底层的基础设施之间的差异。</p>
<p>此外,<code>Docker Engine</code>模块的标准化并以此作为部署单元使系统管理员更灵活的调整工作量。无论是否是空的物理机,或者data center VMs或者公共云,在基础架构技术的帮助下,<code>workload deployment</code>会更加的灵活。workload deployment会被企业的政策和次序来驱动。另外,Docker Engine的轻量运行环境允许快速的上架和下架以此响应需求的快速变化。</p>
<p>总的来说,Docker帮助系统管理员快速,稳定地在任何基础设施上部署和运行任何应用。</p>
<h2>How is this different from Virtual Machines?</h2>
<h3>Virtual Machines</h3>
<p><img src="/img/bVlJlu" alt="图片描述" title="图片描述"></p>
<p>每个运行在虚拟机里的应用本身大小的数量级在<code>MB</code>,而再加上应用依赖的包和二进制库以及运行应用的虚拟机后,整个系统的大小就会达到惊人的<code>GB</code>级别</p>
<h3>Docker</h3>
<p><img src="/img/bVlJly" alt="图片描述" title="图片描述"></p>
<p>Docker引擎容器仅仅包含一个用和它的依赖项,它作为一个孤立的进程运行在操作系统的用户空间,和其它容器共享内核。因此,它享有特定的资源和虚拟机易部署的优势,但更加便捷和高效。</p>
<h2>try it</h2>
<pre><code class="shell">docker version
docker search imageName
docker pull image(<username>/<repository>)
docker run [image name] [command]
docker run [image name] [apt-get install -y ping]</code></pre>
<blockquote><p>Save your change for image</p></blockquote>
<p>保存更改使你下次使用这个镜像时能够从这个点开始运行镜像<br>docker中用来保存状态的操作叫做<code>commit</code></p>
<pre><code class="shell">docker ps -l 查看要保存的进程ID
docker commit id [new image name]
docker commit 698a learn/ping
docker run learn/ping ping www.baidu.com
docker inspect [image id] 查看image的详细信息</code></pre>
<blockquote><p>push you images to Docker Hub</p></blockquote>
<pre><code class="language">docker images....查看当前主机上有多少个镜像
docker push [image name]</code></pre>