2020年7月

Linux 内核批准采用中性的术语

Linus Torvalds 批准了 Linux 内核代码和文档采用中性术语的拉取请求。从现在开始,内核开发者被要求使用新的术语去替换 master/slave 和 blacklist/whitelist。

来源:solidot

拍一拍:你们高兴就好。

Linus Torvalds 对 Linux 内核支持 Rust 的看法:默认可以有效启用

去年就有开发者询问 Linux 内核稳定版维护者 Greg Kroah-Hartman “Linux 有没有想法拥抱 Rust”,Greg 希望 Linux 中的 Rust 支持是以可选的方式存在,而不能全面默认启用。但 Linus 则认为应该在默认情况下可以有效地启用支持,以确保进行广泛的测试,而不是只有某些开发者孤立地在进行疯狂/错误的使用。

来源:开源中国

拍一拍:这个态度要比 Greg 的积极多了。

Android 10 的普及率最快

Google 刚刚宣布:去年 9 月发布的 Android 10 是所有 Android 版本中普及率最快的,发布五个月设备安装量已经达到了一亿。但搜索巨人没有提供安装百分比等数据,它已经完全停止更新不同 Android 版本的占有率数据。相比下,苹果的数据很清晰:它的 iOS 13 安装比例为 81%。苹果完全控制了它的软件和硬件,而 Google 只控制软件。

来源:solidot

拍一拍:但是如果 Android 不采用开源模式,恐怕也不能这样迅速崛起。

物联网(IoT)是一个由智能设备连接起来的网络,并提供了丰富的数据,但是它也有可能是一场安全领域的噩梦。

物联网 Internet of Things (IoT)是一个统称,指的是越来越多不属于传统计算设备,但却连接到互联网接收或发送数据,或既接收也发送的电子设备组成的网络。

现在有数不胜数的东西可以归为这一类:可以联网的“智能”版传统设备,比如说电冰箱和灯泡;那些只能运行于有互联网环境的小设备,比如像 Alexa 之类的电子助手;与互联网连接的传感器,它们正在改变着工厂、医疗、运输、物流中心和农场。

什么是物联网?

物联网将互联网、数据处理和分析的能力带给了现实的实物世界。对于消费者来说,这就意味着不需要键盘和显示器这些东西,就能和这个全球信息网络进行互动;他们的日常用品当中,很多都可以通过该网络接受操作指令,而只需很少的人工干预。

互联网长期以来为知识工作提供了便利,在企业环境当中,物联网也能为制造和分销带来同样的效率。全球数以百万计甚至数十亿计的嵌入式具有互联网功能的传感器正在提供令人难以置信丰富的数据集,企业可以利用这些数据来保证他们运营的安全、跟踪资产和减少人工流程。研究人员也可以使用物联网来获取人们的喜好和行为数据,尽管这些行为可能会严重影响隐私和安全。

它有多大?

一句话:非常庞大。Priceonomics 对此进行了分析:在 2020 年的时候,有超过 50 亿的物联网设备,这些设备可以生成 4.4 泽字节 zettabyte (LCTT 译注:1 zettabyte = 10 9 terabyte = 10 12 gigabyte)的数据。相比较,物联网设备在 2013 年仅仅产生了 1000 亿 千兆字节 gigabyte 的数据。在物联网市场上可能挣到的钱也同样让人瞠目;到 2025 年,这块市场的价值可以达到 1.6 万亿美元到 14.4 万亿美元不等。

物联网的历史

一个联网设备和传感器无处不在的世界,是科幻小说中最经典的景象之一。物联网传说中将 1970 年 卡耐基•梅隆大学的一台连接到 APRANET 的自动贩卖机 称之为世界上第一个物联网设备,而且许多技术都被吹捧为可以实现 “智能” 的物联网式特征,使其颇具有未来主义的光彩。但是“物联网”这个词是由英国的技术专家 Kevin Ashton 于 1999 年提出来的。

一开始,技术是滞后于当时对未来的憧憬的。每个与互联网相连的设备都需要一个处理器和一种能和其他东西通信的方式,无线的最好,这些因素都增加了物联网大规模实际应用的成本和性能要求,这种情况至少一直持续到 21 世纪头十年中期,直到摩尔定律赶上来。

一个重要的里程碑是 RFID 标签的大规模使用,这种价格低廉的极简转发器可以被贴在任何物品上,然后这些物品就可以连接到更大的互联网上了。对于设计者来说,无处不在的 Wi-Fi 和 4G 让任何地方的无线连接都变得非常简单。而且,IPv6 的出现再也不用让人们担心把数十亿小设备连接到互联网上会将 IP 地址耗尽。(相关报道:物联网网络可以促进 IPv6 的使用吗?

物联网是如何工作的?

物联网的基本元素是收集数据的设备。广义地说,它们是和互联网相连的设备,所以每一个设备都有 IP 地址。它们的复杂程度不一,这些设备涵盖了从工厂运输货物的自动驾驶车辆到监控建筑温度的简单传感器。这其中也包括每天统计步数的个人手环。为了让这些数据变得有意义,就需要对其收集、处理、过滤和分析,每一种数据都可以通过多种方式进行处理。

采集数据的方式是将数据从设备上传输到采集点。可以通过各种无线或者有线网络进行数据的转移。数据可以通过互联网发送到具有存储空间或者计算能力的数据中心或者云端,或者这些数据也可以分段进行传输,由中间设备汇总数据后再沿路径发送。

处理数据可以在数据中心或者云端进行,但是有时候这不太可行。对于一些非常重要的设备,比如说工业领域的关停设备,从设备上将数据发送到远程数据中心的延迟太大了。发送、处理、分析数据和返回指令(在管道爆炸之前关闭阀门)这些操作,来回一趟的时间可能要花费非常多的时间。在这种情况下, 边缘计算 edge-computing 就可以大显身手了,智能边缘设备可以汇总数据、分析数据,在需要的时候进行回应,所有这些都在相对较近的物理距离内进行,从而减少延迟。边缘设备可以有上游连接,这样数据就可以进一步被处理和储存。

物联网是如何工作的。

物联网设备的一些例子

本质上,任何可以搜集来自于真实世界数据,并且可以发送回去的设备都可以参与到物联网生态系统中。典型的例子包括智能家居设备、射频识别标签(RFID)和工业传感器。这些传感器可以监控一系列的因素,包括工业系统中的温度和压力、机器中关键设备的状态、患者身上与生命体征相关的信号、水电的使用情况,以及其它许许多多可能的东西。

整个工厂的机器人可以被认为是物联网设备,在工业环境和仓库中移动产品的自主车辆也是如此。

其他的例子包括可穿戴设备和家庭安防系统。还有一些其它更基础的设备,比如说树莓派Arduino,这些设备可以让你构建你自己的物联网终端节点。尽管你可能会认为你的智能手机是一台袖珍电脑,但它很可能也会以非常类似物联网的方式将你的位置和行为数据传送到后端服务。

设备管理

为了能让这些设备一起工作,所有这些设备都需要进行验证、分配、配置和监控,并且在必要时进行修复和更新。很多时候,这些操作都会在一个单一的设备供应商的专有系统中进行;要么就完全不会进行这些操作,而这样也是最有风险的。但是整个业界正在向标准化的设备管理模式过渡,这使得物联网设备之间可以相互操作,并保证设备不会被孤立。

物联网通信标准和协议

当物联网上的小设备和其他设备通信的时候,它们可以使用各种通信标准和协议,这其中许多都是为这些处理能力有限和电源功率不大的设备专门定制的。你一定听说过其中的一些,尽管有一些设备使用的是 Wi-Fi 或者蓝牙,但是更多的设备是使用了专门为物联网世界定制的标准。比如,ZigBee 就是一个低功耗、远距离传输的无线通信协议,而 MQTT( 消息队列遥测传输 Message Queuing Telemetry Transport )是为连接在不可靠或者易发生延迟的网络上的设备定制的一个发布/订阅信息协议。(参考 Network World 的词汇表:物联网标准和协议。)

物联网也会受益于 5G 为蜂窝网络带来的高速度和高带宽,尽管这种使用场景会滞后于普通的手机

物联网、边缘计算和云

边缘计算如何使物联网成为可能。

对于许多物联网系统来说,大量的数据会以极快的速度涌来,这种情况催生了一个新的科技领域, 边缘计算 edge computing ,它由放置在物联网设备附近的设备组成,处理来自那些设备的数据。这些机器对这些数据进行处理,只将相关的素材数据发送到一个更集中的系统系统进行分析。比如,想象一个由几十个物联网安防摄像头组成的网络,边缘计算会直接分析传入的视频,而且只有当其中一个摄像头检测到有物体移动的时候才向安全操作中心(SoC)发出警报,而不会是一下子将所有的在线数据流全部发送到建筑物的 SoC。

一旦这些数据已经被处理过了,它们又去哪里了呢?好吧,它也许会被送到你的数据中心,但是更多情况下,它最终会进入云。

对于物联网这种间歇或者不同步的数据来往场景来说,具有弹性的云计算是再适合不过的了。许多云计算巨头,包括谷歌微软亚马逊,都有物联网产品。

物联网平台

云计算巨头们正在尝试出售的,不仅仅是存放传感器搜集的数据的地方。他们正在提供一个可以协调物联网系统中各种元素的完整平台,平台会将很多功能捆绑在一起。本质上,物联网平台作为中间件,将物联网设备和边缘网关与你用来处理物联网数据的应用程序连接起来。也就是说,每一个平台的厂商看上去都会对物联网平台应该是什么这个问题有一些稍微不同的解释,以更好地与其他竞争者拉开差距

物联网和数据

正如前面所提到的,所有这些物联网设备收集了 ZB 级的数据,这些数据通过边缘网关被发送到平台上进行处理。在很多情况下,这些数据就是要部署物联网的首要原因。通过从现实世界中的传感器搜集来的数据,企业就可以实时的作出灵活的决定。

例如,Oracle 公司假想了一个这样的场景,当人们在主题公园的时候,会被鼓励下载一个可以提供公园信息的应用。同时,这个程序会将 GPS 信号发回到公园的管理部门来帮助他们预测排队时间。有了这些信息,公园就可以在短期内(比如通过增加员工数量来提升景点的一些容量)和长期内(通过了解哪些设施最受欢迎,那些最不受欢迎)采取行动。

这些决定可以在没有人工干预的情况作出。比如,从化工厂管道中的压力传感器收集的数据可以通过边缘设备的软件进行分析,从而发现管道破裂的威胁,这样的信息可以触发关闭阀门的信号,从而避免泄漏。

物联网和大数据分析

主题公园的例子可以让你很容易理解,但是和许多现实世界中物联网收集数据的操作相比,就显得小菜一碟了。许多大数据业务都会使用到来自物联网设备收集的信息,然后与其他数据关联,这样就可以分析预测到人类的行为。Software Advice 给出了一些例子,其中包括由 Birst 提供的一项服务,该服务将从联网的咖啡机中收集的咖啡冲泡的信息与社交媒体上发布的帖子进行匹配,看看顾客是否在网上谈论咖啡品牌。

另一个最近才发生的戏剧性的例子,X-Mode 发布了一张基于位置追踪数据的地图,地图上显示了在 2020 年 3 月春假的时候,正当新冠病毒在美国加速传播的时候,人们在 劳德代尔堡 Ft. Lauderdale 聚会完最终都去了哪里。这张地图令人震撼,不仅仅是因为它显示出病毒可能的扩散方向,更是因为它说明了物联网设备是可以多么密切地追踪我们。(更多关于物联网和分析的信息,请点击此处。)

物联网数据和 AI

物联网设备能够收集的数据量远远大于任何人类能够以有效的方式处理的数据量,而且这肯定也不是能实时处理的。我们已经看到,仅仅为了理解从物联网终端传来的原始数据,就需要边缘计算设备。此外,还需要检测和处理可能就是完全错误的数据

许多物联网供应商也同时提供机器学习和人工智能的功能,可以用来理解收集来的数据。比如,IBM 的 Jeopardy!-winning Watson 平台就可以在物联网数据集上进行训练,这样就可以在预测性维护领域产生有用的结果 —— 比如说,分析来自无人机的数据,可以区分桥梁上轻微的损坏和需要重视的裂缝。同时,ARM 也在研发低功耗芯片,它可以在物联网终端上提供 AI 的能力。

物联网和商业

物联网的商业用途包括跟踪客户、库存和重要部件的状态。IoT for All 列举了四个已经被物联网改变的行业:

  • 石油和天然气:与人工干预相比,物联网传感器可以更好的检测孤立的钻井现场。
  • 农业:通过物联网传感器获得的田间作物的数据,可以用来提高产量。
  • 采暖通风:制造商可以监控全国各地的气候控制系统。
  • 实体零售:当顾客在商店的某些地方停留的时候,可以通过手机进行微目标定位,提供优惠信息。

更普遍的情况是,企业正在寻找能够在四个领域上获得帮助的物联网解决方案:能源使用、资产跟踪、安全领域和客户体验。


via: https://www.networkworld.com/article/3207535/what-is-iot-the-internet-of-things-explained.html

作者:Josh Fruhlinger 选题:lujun9972 译者:Yufei-Yan 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

从 Linux 系统的存档中提取文件没有拔牙那么痛苦,但有时看起来更复杂。在这篇文章中,我们将看看如何轻松地从 Linux 系统中可能遇到的几乎所有类型的存档中提取文件。

它们有很多格式,从 .gz 到 .tbz2,这些文件的命名方式都各有一些不同。当然,你可以记住所有从存档中提取文件的各种命令以及它们的选项,但是你也可以将所有经验保存到脚本中,而不再担心细节。

在本文中,我们将一系列提取命令组合成一个脚本,它会调用适当的命令根据文档名提取文件的内容。该脚本首先以一些命令来验证是否已经提供了一个文件名作为参数,或要求运行脚本的人提供文件名。

#!/bin/bash

if [ $# -eq 0 ]; then
    echo -n "filename> "
    read filename
else
    filename=$1
fi

if [ ! -f "$filename" ]; then
    echo "No such file: $filename"
    exit $?
fi

了解了么?如果未提供任何参数,脚本将提示输入文件名,如果存在则使用它。然后,它验证文件是否实际存在。如果不是,那么脚本退出。

下一步是使用 bash 的 case 语句根据存档文件的名称调用适当的提取命令。对于其中某些文件类型(例如 .bz2),也可以使用除 tar 之外的其它命令,但是对于每种文件命名约定,我们仅包含一个提取命令。因此,这是带有各种存档文件名的 case 语句:

 case $filename in
    *.tar)      tar xf $filename;;
    *.tar.bz2)  tar xjf $filename;;
    *.tbz)      tar xjf $filename;;
    *.tbz2)     tar xjf $filename;;
    *.tgz)      tar xzf $filename;;
    *.tar.gz)   tar xzf $filename;;
    *.gz)       gunzip $filename;;
    *.bz2)      bunzip2 $filename;;
    *.zip)      unzip $filename;;
    *.Z)        uncompress $filename;;
    *)          echo "No extract option for $filename"
esac

如果提供给脚本的文件扩展名与脚本已知的扩展名都不匹配,那么会发出 “No extract option for $filename” 的消息。如果缺少你使用的任何存档类型,只需将它们与所需的提取命令一起添加即可。

将 bash 头添加到脚本顶部,使其可执行,然后就可以开始了。

#!/bin/bash

if [ $# -eq 0 ]; then
    echo -n "filename> "
    read filename
else
    filename=$1
fi

if [ ! -f "$filename" ]; then
    echo "No such file: $filename"
    exit $?
fi

case $filename in
    *.tar)      tar xf $filename;;
    *.tar.bz2)  tar xjf $filename;;
    *.tbz)      tar xjf $filename;;
    *.tbz2)     tar xjf $filename;;
    *.tgz)      tar xzf $filename;;
    *.tar.gz)   tar xzf $filename;;
    *.gz)       gunzip $filename;;
    *.bz2)      bunzip2 $filename;;
    *.zip)      unzip $filename;;
    *.Z)        uncompress $filename;;
    *.rar)      rar x $filename ;;
    *)

如果你希望脚本在提取文件时显示内容,请将详细选项(-v)添加到每个命令参数字符串中:

#!/bin/bash

if [ $# -eq 0 ]; then
    echo -n "filename> "
    read filename
else
    filename=$1
fi

if [ ! -f "$filename" ]; then
    echo "No such file: $filename"
    exit $?
fi

case $filename in
    *.tar)      tar xvf $filename;;
    *.tar.bz2)  tar xvjf $filename;;
    *.tbz)      tar xvjf $filename;;
    *.tbz2)     tar xvjf $filename;;
    *.tgz)      tar xvzf $filename;;
    *.tar.gz)   tar xvzf $filename;;
    *.gz)       gunzip -v $filename;;
    *.bz2)      bunzip2 -v $filename;;
    *.zip)      unzip -v $filename;;
    *.Z)        uncompress -v $filename;;
    *)          echo "No extract option for $filename"
esac

总结

虽然可以为每个可能用到的提取命令创建别名,但是让脚本为遇到的每种文件类型提供命令要比自己停下来编写每个命令和选项容易。


via: https://www.networkworld.com/article/3564265/painless-file-extraction-on-linux.html

作者:Sandra Henry-Stocker 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

微软将在 Windows 中放弃对 PHP 的支持

PHP 8.0 将于 11 月发布,但当这个重要的新版本出现时,Windows 将不支持它,原因未知。该公司表示,在 PHP 7.2、7.3 和 7.4 版本的生命周期内,Windows 将继续为其准备错误修复和安全补丁。但当今年晚些时候发布最新版本时,微软将“不为 8.0 及以后的版本以及以任何方式支持 PHP for Windows”。

来源:cnBeta.COM

拍一拍:希望这个决定只是基于用户数量缺乏的考虑。

想替代 C 的 Zig 语言成立了基金会

Zig 语言官方宣布成立 Zig 软件基金会(Zig Software Foundation,ZFS),致力于促进、保护和推进 Zig 编程语言,支持并促进多元化和国际化的 Zig 开发者社区的发展。Zig 是一门通用编程语言,专为稳定性、可维护性和性能而设计,追求替代 C 语言在系统编程上的最佳地位。

来源:开源中国

拍一拍:C:“想取代我的多呢……”

因被黑客滥用 Mozilla 宣布暂停 Firefox Send 文件共享服务

Firefox Send 服务于 2019 年 3 月上线。Firefox Send 在恶意软件社区得到了更广泛的应用。恶意软件作者在 Firefox Send 上传恶意软件的有效文件,这些文件以加密格式存储,然后黑客在给客户的电子邮件中分享该链接。

来源:cnBeta.COM

拍一拍:确实很难防范被滥用,“自由”的代价。

从输出的哈希值反推回输入,这从计算的角度是不可行的。

无论安全从业人员用计算机做什么,有一种工具对他们每个人都很有用:加密 哈希(散列) hash 函数。这听起来很神秘、很专业,甚至可能有点乏味,但是, 在这里,关于什么是哈希函数以及它们为什么对你很重要,我会作出一个简洁的解释。

加密哈希函数,比如 SHA-256 或者 MD5,接受一组二进制数据(通常是字节)作为输入,并且对每个可能的输入集给出一个 希望唯一 hopefully unique 的输出。对于任意模式的输入,给定的哈希函数的输出(“哈希值”)的长度都是一样的(对于 SHA-256,是 32 字节或者 256 比特,这从名字中就能看出来)。最重要的是:从输出的哈希值反推回输入,这从计算的角度是 不可行的 implausible (密码学家讨厌 “ 不可能 impossible ” 这个词)。这就是为什么它们有时候被称作 单向哈希函数 one-way hash function

但是哈希函数是用来做什么的呢?为什么“唯一”的属性如此重要?

唯一的输出

在描述哈希函数的输出时,“ 希望唯一 hopefully unique ”这个短语是至关重要的,因为哈希函数就是用来呈现完全唯一的输出。比如,哈希函数可以用于验证 下载的文件副本的每一个字节是否和 下载的文件一样。你下载一个 Linux 的 ISO 文件或者从 Linux 的仓库中下载软件时,你会看到使用这个验证过程。没有了唯一性,这个技术就没用了,至少就通常的目的而言是这样的。

如果两个不同的输入产生了相同的输出,那么这样的哈希过程就称作“ 碰撞 collision ”。事实上,MD5 算法已经被弃用,因为虽然可能性微乎其微,但它现在可以用市面上的硬件和软件系统找到碰撞。

另外一个重要的特性是,消息中的一个微小变化,甚至只是改变一个比特位,都可能会在输出中产生一个明显的变化(这就是“ 雪崩效应 avalanche effect ”)。

验证二进制数据

哈希函数的典型用途是当有人给你一段二进制数据,确保这些数据是你所期望的。无论是文本、可执行文件、视频、图像或者一个完整的数据库数据,在计算世界中,所有的数据都可以用二进制的形式进行描述,所以至少可以这么说,哈希是广泛适用的。直接比较二进制数据是非常缓慢的且计算量巨大,但是哈希函数在设计上非常快。给定两个大小为几 M 或者几 G 的文件,你可以事先生成它们的哈希值,然后在需要的时候再进行比较。

通常,对哈希值进行签名比对大型数据集本身进行签名更容易。这个特性太重要了,以至于密码学中对哈希值最常见的应用就是生成“数字”签名。

由于生成数据的哈希值很容易,所以通常不需要有两套数据。假设你想在你的电脑上运行一个可执行文件。但是在你运行之前,你需要检查这个文件就是你要的文件,没有被黑客篡改。你可以方便快捷的对文件生成哈希值,只要你有一个这个哈希值的副本,你就可以相当肯定这就是你想要的文件。

下面是一个简单的例子:

$ shasum -a256 ~/bin/fop
87227baf4e1e78f6499e4905e8640c1f36720ae5f2bd167de325fd0d4ebc791c  /home/bob/bin/fop

如果我知道 fop 这个可执行文件的 SHA-256 校验和,这是由供应商(这个例子中是 Apache 基金会)提供的:

87227baf4e1e78f6499e4905e8640c1f36720ae5f2bd167de325fd0d4ebc791c

然后我就可以确信,我驱动器上的这个可执行文件和 Apache 基金会网站上发布的文件是一模一样的。这就是哈希函数难以发生碰撞(或者至少是 很难通过计算得到碰撞)这个性质的重要之处。如果黑客能将真实文件用哈希值相同的文件轻易的进行替换,那么这个验证过程就毫无用处。

事实上,这些性质还有更技术性的名称,我上面所描述的将三个重要的属性混在了一起。更准确地说,这些技术名称是:

  1. 抗原像性 pre-image resistance :给定一个哈希值,即使知道用了什么哈希函数,也很难得到用于创建它的消息。
  2. 抗次原像性 second pre-image resistance :给定一个消息,很难找到另一个消息,使得这个消息可以产生相同的哈希值。
  3. 抗碰撞性 collision resistance :很难得到任意两个可以产生相同哈希值的消息。

抗碰撞性抗次原像性 也许听上去是同样的性质,但它们具有细微而显著的不同。抗次原像性 说的是如果 已经 有了一个消息,你也很难得到另一个与之哈希值相匹配的消息。抗碰撞性 使你很难找到两个可以生成相同哈希值的消息,并且要在哈希函数中实现这一性质则更加困难。

让我回到黑客试图替换文件(可以通过哈希值进行校验)的场景。现在,要在“外面”使用加密哈希算法(除了使用那些在现实世界中由独角兽公司开发的完全无 Bug 且安全的实现之外),还有一些重要且困难的附加条件需要满足。认真的读者可能已经想到了其中一些,特别需要指出的是:

  1. 你必须确保自己所拥有的哈希值副本也没有被篡改。
  2. 你必须确保执行哈希算法的实体能够正确执行并报告了结果。
  3. 你必须确保对比两个哈希值的实体确实报告了这个对比的正确结果。

确保你能满足这些条件绝对不是一件容易的事。这就是 可信平台模块 Trusted Platform Modules (TPM)成为许多计算系统一部分的原因之一。它们扮演着信任的硬件基础,可以为验证重要二进制数据真实性的加密工具提供保证。TPM 对于现实中的系统来说是有用且重要的工具,我也打算将来写一篇关于 TPM 的文章。


via: https://opensource.com/article/20/7/hash-functions

作者:Mike Bursell 选题:lujun9972 译者:Yufei-Yan 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

像主流云提供商的处理方式一样,在家中添加机器到你的私有云。

Cloud-init 是一种广泛使用的行业标准方法,用于初始化云实例。云提供商使用 Cloud-init 来定制实例的网络配置、实例信息,甚至用户提供的配置指令。它也是一个可以在你的“家庭私有云”中使用的很好的工具,可以为你的家庭实验室的虚拟机和物理机的初始设置和配置添加一点自动化 —— 并了解更多关于大型云提供商是如何工作的信息。关于更多的细节和背景,请看我之前的文章《在你的树莓派家庭实验室中使用 Cloud-init》。

 title=

运行 Cloud-init 的 Linux 服务器的启动过程(Chris Collins,CC BY-SA 4.0

诚然,Cloud-init 对于为许多不同客户配置机器的云提供商来说,比对于由单个系统管理员运行的家庭实验室更有用,而且 Cloud-init 解决的许多问题对于家庭实验室来说可能有点多余。然而,设置它并了解它的工作原理是了解更多关于这种云技术的好方法,更不用说它是首次启动时配置设备的好方法。

本教程使用 Cloud-init 的 NoCloud 数据源,它允许 Cloud-init 在传统的云提供商环境之外使用。本文将向你展示如何在客户端设备上安装 Cloud-init,并设置一个运行 Web 服务的容器来响应客户端的请求。你还将学习如何审查客户端从 Web 服务中请求的内容,并修改 Web 服务的容器,以提供基本的、静态的 Cloud-init 服务。

在现有系统上设置 Cloud-init

Cloud-init 可能在新系统首次启动时最有用,它可以查询配置数据,并根据指令对系统进行定制。它可以包含在树莓派和单板计算机的磁盘镜像中,也可以添加到用于 配给 provision 虚拟机的镜像中。对于测试用途来说,无论是在现有系统上安装并运行 Cloud-init,还是安装一个新系统,然后设置 Cloud-init,都是很容易的。

作为大多数云提供商使用的主要服务,大多数 Linux 发行版都支持 Cloud-init。在这个例子中,我将使用 Fedora 31 Server 来安装树莓派,但在 Raspbian、Ubuntu、CentOS 和大多数其他发行版上也可以用同样的方式来完成。

安装并启用云计算初始服务

在你想作为 Cloud-init 客户端的系统上,安装 Cloud-init 包。如果你使用的是 Fedora:

# Install the cloud-init package
dnf install -y cloud-init

Cloud-init 实际上是四个不同的服务(至少在 systemd 下是这样),这些服务负责检索配置数据,并在启动过程的不同阶段进行配置更改,这使得可以做的事情更加灵活。虽然你不太可能直接与这些服务进行太多交互,但在你需要排除一些故障时,知道它们是什么还是很有用的。它们是:

  • cloud-init-local.service
  • cloud-init.service
  • cloud-config.service
  • cloud-final.service

启用所有四个服务:

# Enable the four cloud-init services
systemctl enable cloud-init-local.service
systemctl enable cloud-init.service
systemctl enable cloud-config.service
systemctl enable cloud-final.service

配置数据源以查询

启用服务后,请配置数据源,客户端将从该数据源查询配置数据。有许多数据源类型,而且大多数都是为特定的云提供商配置的。对于你的家庭实验室,请使用 NoCloud 数据源,(如上所述)它是为在没有云提供商的情况下使用 Cloud-init 而设计的。

NoCloud 允许以多种方式包含配置信息:以内核参数中的键/值对,用于在启动时挂载的 CD(或虚拟机中的虚拟 CD);包含在文件系统中的文件中;或者像本例中一样,通过 HTTP 从指定的 URL(“NoCloud Net” 选项)获取配置信息。

数据源配置可以通过内核参数提供,也可以在 Cloud-init 配置文件 /etc/cloud/cloud.cfg 中进行设置。该配置文件对于使用自定义磁盘镜像设置 Cloud-init 或在现有主机上进行测试非常方便。

Cloud-init 还会合并在 /etc/cloud/cloud.cfg.d/ 中找到的任何 *.cfg 文件中的配置数据,因此为了保持整洁,请在 /etc/cloud/cloud.cfg.d/10_datasource.cfg 中配置数据源。Cloud-init 可以通过使用以下语法从 seedfrom 键指向的 HTTP 数据源中读取数据。

seedfrom: http://ip_address:port/

IP 地址和端口是你将在本文后面创建的 Web 服务。我使用了我的笔记本电脑的 IP 和 8080 端口。这也可以是 DNS 名称。

创建 /etc/cloud/cloud.cfg.d/10_datasource.cfg 文件:

# Add the datasource:
# /etc/cloud/cloud.cfg.d/10_datasource.cfg

# NOTE THE TRAILING SLASH HERE!
datasource:
  NoCloud:
    seedfrom: http://ip_address:port/

客户端设置就是这样。现在,重新启动客户端后,它将尝试从你在 seedfrom 键中输入的 URL 检索配置数据,并进行必要的任何配置更改。

下一步是设置一个 Web 服务器来侦听客户端请求,以便你确定需要提供的服务。

设置网络服务器以审查客户请求

你可以使用 Podman 或其他容器编排工具(如 Docker 或 Kubernetes)快速创建和运行 Web 服务器。这个例子使用的是 Podman,但同样的命令也适用于 Docker。

要开始,请使用 fedora:31 容器镜像并创建一个容器文件(对于 Docker 来说,这会是一个 Dockerfile)来安装和配置 Nginx。从该容器文件中,你可以构建一个自定义镜像,并在你希望提供 Cloud-init 服务的主机上运行它。

创建一个包含以下内容的容器文件:

FROM fedora:31

ENV NGINX_CONF_DIR "/etc/nginx/default.d"
ENV NGINX_LOG_DIR "/var/log/nginx"
ENV NGINX_CONF "/etc/nginx/nginx.conf"
ENV WWW_DIR "/usr/share/nginx/html"

# Install Nginx and clear the yum cache
RUN dnf install -y nginx \
      && dnf clean all \
      && rm -rf /var/cache/yum

# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout ${NGINX_LOG_DIR}/access.log \
    && ln -sf /dev/stderr ${NGINX_LOG_DIR}/error.log

# Listen on port 8080, so root privileges are not required for podman
RUN sed -i -E 's/(listen)([[:space:]]*)(\[\:\:\]\:)?80;$/\1\2\38080 default_server;/' $NGINX_CONF
EXPOSE 8080

# Allow Nginx PID to be managed by non-root user
RUN sed -i '/user nginx;/d' $NGINX_CONF
RUN sed -i 's/pid \/run\/nginx.pid;/pid \/tmp\/nginx.pid;/' $NGINX_CONF

# Run as an unprivileged user
USER 1001

CMD ["nginx", "-g", "daemon off;"]

注:本例中使用的容器文件和其他文件可以在本项目的 GitHub 仓库中找到。

上面容器文件中最重要的部分是改变日志存储方式的部分(写到 STDOUT 而不是文件),这样你就可以在容器日志中看到进入该服务器的请求。其他的一些改变使你可以在没有 root 权限的情况下使用 Podman 运行容器,也可以在没有 root 权限的情况下运行容器中的进程。

在 Web 服务器上的第一个测试并不提供任何 Cloud-init 数据;只是用它来查看 Cloud-init 客户端的请求。

创建容器文件后,使用 Podman 构建并运行 Web 服务器镜像:

# Build the container image
$ podman build -f Containerfile -t cloud-init:01 .

# Create a container from the new image, and run it
# It will listen on port 8080
$ podman run --rm -p 8080:8080 -it cloud-init:01

这会运行一个容器,让你的终端连接到一个伪 TTY。一开始看起来什么都没有发生,但是对主机 8080 端口的请求会被路由到容器内的 Nginx 服务器,并且在终端窗口中会出现一条日志信息。这一点可以用主机上的 curl 命令进行测试。

# Use curl to send an HTTP request to the Nginx container
$ curl http://localhost:8080

运行该 curl 命令后,你应该会在终端窗口中看到类似这样的日志信息:

127.0.0.1 - - [09/May/2020:19:25:10 +0000] "GET / HTTP/1.1" 200 5564 "-" "curl/7.66.0" "-"

现在,有趣的部分来了:重启 Cloud-init 客户端,并观察 Nginx 日志,看看当客户端启动时, Cloud-init 向 Web 服务器发出了什么请求。

当客户端完成其启动过程时,你应该会看到类似的日志消息。

2020/05/09 22:44:28 [error] 2#0: *4 open() "/usr/share/nginx/html/meta-data" failed (2: No such file or directory), client: 127.0.0.1, server: _, request: "GET /meta-data HTTP/1.1", host: "instance-data:8080"
127.0.0.1 - - [09/May/2020:22:44:28 +0000] "GET /meta-data HTTP/1.1" 404 3650 "-" "Cloud-Init/17.1" "-"

注:使用 Ctrl+C 停止正在运行的容器。

你可以看到请求是针对 /meta-data 路径的,即 http://ip_address_of_the_webserver:8080/meta-data。这只是一个 GET 请求 —— Cloud-init 并没有向 Web 服务器发送任何数据。它只是盲目地从数据源 URL 中请求文件,所以要由数据源来识别主机的要求。这个简单的例子只是向任何客户端发送通用数据,但一个更大的家庭实验室应该需要更复杂的服务。

在这里,Cloud-init 请求的是实例元数据信息。这个文件可以包含很多关于实例本身的信息,例如实例 ID、分配实例的主机名、云 ID,甚至网络信息。

创建一个包含实例 ID 和主机名的基本元数据文件,并尝试将其提供给 Cloud-init 客户端。

首先,创建一个可复制到容器镜像中的 meta-data 文件。

instance-id: iid-local01
local-hostname: raspberry
hostname: raspberry

实例 ID(instance-id)可以是任何东西。但是,如果你在 Cloud-init 运行后更改实例 ID,并且文件被送达客户端,就会触发 Cloud-init 再次运行。你可以使用这种机制来更新实例配置,但你应该意识到它是这种工作方式。

local-hostnamehostname 键正如其名,它们会在 Cloud-init 运行时为客户端设置主机名信息。

在容器文件中添加以下行以将 meta-data 文件复制到新镜像中。

# Copy the meta-data file into the image for Nginx to serve it
COPY meta-data ${WWW_DIR}/meta-data

现在,用元数据文件重建镜像(使用一个新的标签以方便故障排除),并用 Podman 创建并运行一个新的容器。

# Build a new image named cloud-init:02
podman build -f Containerfile -t cloud-init:02 .

# Run a new container with this new meta-data file
podman run --rm -p 8080:8080 -it cloud-init:02

新容器运行后,重启 Cloud-init 客户端,再次观察 Nginx 日志。

127.0.0.1 - - [09/May/2020:22:54:32 +0000] "GET /meta-data HTTP/1.1" 200 63 "-" "Cloud-Init/17.1" "-"
2020/05/09 22:54:32 [error] 2#0: *2 open() "/usr/share/nginx/html/user-data" failed (2: No such file or directory), client: 127.0.0.1, server: _, request: "GET /user-data HTTP/1.1", host: "instance-data:8080"
127.0.0.1 - - [09/May/2020:22:54:32 +0000] "GET /user-data HTTP/1.1" 404 3650 "-" "Cloud-Init/17.1" "-"

你看,这次 /meta-data 路径被提供给了客户端。成功了!

然而,客户端接着在 /user-data 路径上寻找第二个文件。该文件包含实例所有者提供的配置数据,而不是来自云提供商的数据。对于一个家庭实验室来说,这两个都是你自己提供的。

你可以使用许多 user-data 模块来配置你的实例。对于这个例子,只需使用 write_files 模块在客户端创建一些测试文件,并验证 Cloud-init 是否工作。

创建一个包含以下内容的用户数据文件:

#cloud-config

# Create two files with example content using the write_files module
write_files:
 - content: |
    "Does cloud-init work?"
   owner: root:root
   permissions: '0644'
   path: /srv/foo
 - content: |
   "IT SURE DOES!"
   owner: root:root
   permissions: '0644'
   path: /srv/bar

除了使用 Cloud-init 提供的 user-data 模块制作 YAML 文件外,你还可以将其制作成一个可执行脚本供 Cloud-init 运行。

创建 user-data 文件后,在容器文件中添加以下行,以便在重建映像时将其复制到镜像中:

# Copy the user-data file into the container image
COPY user-data ${WWW_DIR}/user-data

重建镜像,并创建和运行一个新的容器,这次使用用户数据信息:

# Build a new image named cloud-init:03
podman build -f Containerfile -t cloud-init:03 .

# Run a new container with this new user-data file
podman run --rm -p 8080:8080 -it cloud-init:03

现在,重启 Cloud-init 客户端,观察 Web 服务器上的 Nginx 日志:

127.0.0.1 - - [09/May/2020:23:01:51 +0000] "GET /meta-data HTTP/1.1" 200 63 "-" "Cloud-Init/17.1" "-"
127.0.0.1 - - [09/May/2020:23:01:51 +0000] "GET /user-data HTTP/1.1" 200 298 "-" "Cloud-Init/17.1" "-

成功了!这一次,元数据和用户数据文件都被送到了 Cloud-init 客户端。

验证 Cloud-init 已运行

从上面的日志中,你知道 Cloud-init 在客户端主机上运行并请求元数据和用户数据文件,但它用它们做了什么?你可以在 write_files 部分验证 Cloud-init 是否写入了你在用户数据文件中添加的文件。

在 Cloud-init 客户端上,检查 /srv/foo/srv/bar 文件的内容:

# cd /srv/ && ls
bar foo
# cat foo
"Does cloud-init work?"
# cat bar
"IT SURE DOES!"

成功了!文件已经写好了,并且有你期望的内容。

如上所述,还有很多其他模块可以用来配置主机。例如,用户数据文件可以配置成用 apt 添加包、复制 SSH 的 authorized_keys、创建用户和组、配置和运行配置管理工具等等。我在家里的私有云中使用它来复制我的 authorized_keys、创建一个本地用户和组,并设置 sudo 权限。

你接下来可以做什么

Cloud-init 在家庭实验室中很有用,尤其是专注于云技术的实验室。本文所演示的简单服务对于家庭实验室来说可能并不是超级有用,但现在你已经知道 Cloud-init 是如何工作的了,你可以继续创建一个动态服务,可以用自定义数据配置每台主机,让家里的私有云更类似于主流云提供商提供的服务。

在数据源稍显复杂的情况下,将新的物理(或虚拟)机器添加到家中的私有云中,可以像插入它们并打开它们一样简单。


via: https://opensource.com/article/20/5/create-simple-cloud-init-service-your-homelab

作者:Chris Collins 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出