Anarcat 发布的文章

我最近深入研究了网站归档,因为有些朋友担心遇到糟糕的系统管理或恶意删除时失去对放在网上的内容的控制权。这使得网站归档成为系统管理员工具箱中的重要工具。事实证明,有些网站比其他网站更难归档。本文介绍了对传统网站进行归档的过程,并阐述在面对最新流行单页面应用程序(SPA)的现代网站时,它有哪些不足。

转换为简单网站

手动编码 HTML 网站的日子早已不复存在。现在的网站是动态的,并使用最新的 JavaScript、PHP 或 Python 框架即时构建。结果,这些网站更加脆弱:数据库崩溃、升级出错或者未修复的漏洞都可能使数据丢失。在我以前是一名 Web 开发人员时,我不得不接受客户这样的想法:希望网站基本上可以永久工作。这种期望与 web 开发“快速行动和破除陈规”的理念不相符。在这方面,使用 Drupal 内容管理系统(CMS)尤其具有挑战性,因为重大更新会破坏与第三方模块的兼容性,这意味着客户很少承担的起高昂的升级成本。解决方案是将这些网站归档:以实时动态的网站为基础,将其转换为任何 web 服务器可以永久服务的纯 HTML 文件。此过程对你自己的动态网站非常有用,也适用于你想保护但无法控制的第三方网站。

对于简单的静态网站,古老的 Wget 程序就可以胜任。然而镜像保存一个完整网站的命令却是错综复杂的:

$ nice wget --mirror --execute robots=off --no-verbose --convert-links \
    --backup-converted --page-requisites --adjust-extension \
    --base=./ --directory-prefix=./ --span-hosts \
    --domains=www.example.com,example.com http://www.example.com/

以上命令下载了网页的内容,也抓取了指定域名中的所有内容。在对你喜欢的网站执行此操作之前,请考虑此类抓取可能对网站产生的影响。上面的命令故意忽略了 robots.txt 规则,就像现在归档者的习惯做法,并以尽可能快的速度归档网站。大多数抓取工具都可以选择在两次抓取间暂停并限制带宽使用,以避免使网站瘫痪。

上面的命令还将获取 “页面所需(LCTT 译注:单页面所需的所有元素)”,如样式表(CSS)、图像和脚本等。下载的页面内容将会被修改,以便链接也指向本地副本。任何 web 服务器均可托管生成的文件集,从而生成原始网站的静态副本。

以上所述是事情一切顺利的时候。任何使用过计算机的人都知道事情的进展很少如计划那样;各种各样的事情可以使程序以有趣的方式脱离正轨。比如,在网站上有一段时间很流行日历块。内容管理系统会动态生成这些内容,这会使爬虫程序陷入死循环以尝试检索所有页面。灵巧的归档者可以使用正则表达式(例如 Wget 有一个 --reject-regex 选项)来忽略有问题的资源。如果可以访问网站的管理界面,另一个方法是禁用日历、登录表单、评论表单和其他动态区域。一旦网站变成静态的,(那些动态区域)也肯定会停止工作,因此从原始网站中移除这些杂乱的东西也不是全无意义。

JavaScript 噩梦

很不幸,有些网站不仅仅是纯 HTML 文件构建的。比如,在单页面网站中,web 浏览器通过执行一个小的 JavaScript 程序来构建内容。像 Wget 这样的简单用户代理将难以重建这些网站的有意义的静态副本,因为它根本不支持 JavaScript。理论上,网站应该使用渐进增强技术,在不使用 JavaScript 的情况下提供内容和实现功能,但这些指引很少被人遵循 —— 使用过 NoScriptuMatrix 等插件的人都知道。

传统的归档方法有时会以最愚蠢的方式失败。在尝试为一个本地报纸网站(pamplemousse.ca)创建备份时,我发现 WordPress 在包含 的 JavaScript 末尾添加了查询字符串(例如:?ver=1.12.4)。这会使提供归档服务的 web 服务器不能正确进行内容类型检测,因为其靠文件扩展名来发送正确的 Content-Type 头部信息。在 web 浏览器加载此类归档时,这些脚本会加载失败,导致动态网站受损。

随着 web 向使用浏览器作为执行任意代码的虚拟机转化,依赖于纯 HTML 文件解析的归档方法也需要随之适应。这个问题的解决方案是在抓取时记录(以及重现)服务器提供的 HTTP 头部信息,实际上专业的归档者就使用这种方法。

创建和显示 WARC 文件

互联网档案馆 Internet Archive 网站,Brewster Kahle 和 Mike Burner 在 1996 年设计了 ARC (即 “ARChive”)文件格式,以提供一种聚合其归档工作所产生的百万个小文件的方法。该格式最终标准化为 WARC(“Web ARChive”)规范,并在 2009 年作为 ISO 标准发布,2017 年修订。标准化工作由 国际互联网保护联盟 International Internet Preservation Consortium (IIPC)领导,据维基百科称,这是一个“为了协调为未来而保护互联网内容的努力而成立的国际图书馆组织和其他组织”;它的成员包括 美国国会图书馆 US Library of Congress 和互联网档案馆等。后者在其基于 Java 的 Heritrix crawler(LCTT 译注:一种爬虫程序)内部使用了 WARC 格式。

WARC 在单个压缩文件中聚合了多种资源,像 HTTP 头部信息、文件内容,以及其他元数据。方便的是,Wget 实际上提供了 --warc 参数来支持 WARC 格式。不幸的是,web 浏览器不能直接显示 WARC 文件,所以为了访问归档文件,一个查看器或某些格式转换是很有必要的。我所发现的最简单的查看器是 pywb,它以 Python 包的形式运行一个简单的 web 服务器提供一个像“ 时光倒流机网站 Wayback Machine ”的界面,来浏览 WARC 文件的内容。执行以下命令将会在 http://localhost:8080/ 地址显示 WARC 文件的内容:

$ pip install pywb
$ wb-manager init example
$ wb-manager add example crawl.warc.gz
$ wayback

顺便说一句,这个工具是由 Webrecorder 服务提供者建立的,Webrecoder 服务可以使用 web 浏览器保存动态页面的内容。

很不幸,pywb 无法加载 Wget 生成的 WARC 文件,因为它遵循1.0 规范不一致1.1 规范修复了此问题。就算 Wget 或 pywb 修复了这些问题,Wget 生成的 WARC 文件对我的使用来说不够可靠,所以我找了其他的替代品。引起我注意的爬虫程序简称 crawl。以下是它的调用方式:

$ crawl https://example.com/

(它的 README 文件说“非常简单”。)该程序支持一些命令行参数选项,但大多数默认值都是最佳的:它会从其他域获取页面所需(除非使用 -exclude-related 参数),但肯定不会递归出域。默认情况下,它会与远程站点建立十个并发连接,这个值可以使用 -c 参数更改。但是,最重要的是,生成的 WARC 文件可以使用 pywb 完美加载。

未来的工作和替代方案

这里还有更多有关使用 WARC 文件的资源。特别要提的是,这里有一个专门用来归档网站的 Wget 的直接替代品,叫做 Wpull。它实验性地支持了 PhantomJSyoutube-dl 的集成,即允许分别下载更复杂的 JavaScript 页面以及流媒体。该程序是一个叫做 ArchiveBot 的复杂归档工具的基础,ArchiveBot 被那些在 ArchiveTeam 的“零散离群的归档者、程序员、作家以及演说家”使用,他们致力于“在历史永远丢失之前保存它们”。集成 PhantomJS 好像并没有如团队期望的那样良好工作,所以 ArchiveTeam 也用其它零散的工具来镜像保存更复杂的网站。例如,snscrape 将抓取一个社交媒体配置文件以生成要发送到 ArchiveBot 的页面列表。该团队使用的另一个工具是 crocoite,它使用无头模式的 Chrome 浏览器来归档 JavaScript 较多的网站。

如果没有提到称做“网站复制者”的 HTTrack 项目,那么这篇文章算不上完整。它工作方式和 Wget 相似,HTTrack 可以对远程站点创建一个本地的副本,但是不幸的是它不支持输出 WRAC 文件。对于不熟悉命令行的小白用户来说,它在人机交互方面显得更有价值。

同样,在我的研究中,我发现了叫做 Wget2 的 Wget 的完全重制版本,它支持多线程操作,这可能使它比前身更快。和 Wget 相比,它舍弃了一些功能,但是最值得注意的是拒绝模式、WARC 输出以及 FTP 支持,并增加了 RSS、DNS 缓存以及改进的 TLS 支持。

最后,我个人对这些工具的愿景是将它们与我现有的书签系统集成起来。目前我在 Wallabag 中保留了一些有趣的链接,这是一种自托管式的“稍后阅读”服务,意在成为 Pocket(现在由 Mozilla 拥有)的免费替代品。但是 Wallabag 在设计上只保留了文章的“可读”副本,而不是一个完整的拷贝。在某些情况下,“可读版本”实际上不可读,并且 Wallabag 有时无法解析文章。恰恰相反,像 bookmark-archiverreminiscence 这样其他的工具会保存页面的屏幕截图以及完整的 HTML 文件,但遗憾的是,它没有 WRAC 文件所以没有办法更可信的重现网页内容。

我所经历的有关镜像保存和归档的悲剧就是死数据。幸运的是,业余的归档者可以利用工具将有趣的内容保存到网上。对于那些不想麻烦的人来说,“互联网档案馆”看起来仍然在那里,并且 ArchiveTeam 显然正在为互联网档案馆本身做备份


via: https://anarc.at/blog/2018-10-04-archiving-web-sites/

作者:Anarcat 选题:lujun9972 译者:fuowang 校对:wxy

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

最近几年,开源项目 Docker (已更名为Moby) 在容器普及化方面建树颇多。然而,它的功能特性不断集中到一个单一、庞大的系统,该系统由具有 root 权限运行的守护进程 dockerd 管控,这引发了人们的焦虑。对这些焦虑的阐述,具有代表性的是 Red Hat 公司的容器团队负责人 Dan Walsh 在 KubeCon + CloudNativecon 会议中的演讲。Walsh 讲述了他的容器团队目前的工作方向,即使用一系列更小、可协同工作的组件替代 Docker。他的战斗口号是“拒绝臃肿的守护进程”,理由是与公认的 Unix 哲学相违背。

Docker 模块化实践

就像我们在早期文献中看到的那样,容器的基础操作不复杂:你首先拉取一个容器镜像,利用该镜像创建一个容器,最后启动这个容器。除此之外,你要懂得如何构建镜像并推送至镜像仓库。大多数人在上述这些步骤中使用 Docker,但其实 Docker 并不是唯一的选择,目前的可替换选择是 rkt。rkt 引发了一系列标准的创建,包括运行时标准 CRI,镜像标准 OCI 及网络标准 CNI 等。遵守这些标准的后端,如 CRI-O 和 Docker,可以与 Kubernetes 为代表的管理软件协同工作。

这些标准促使 Red Hat 公司开发了一系列实现了部分标准的“核心应用”供 Kubernetes 使用,例如 CRI-O 运行时。但 Kubernetes 提供的功能不足以满足 Red Hat 公司的 OpenShift 项目所需。开发者可能需要构建容器并推送至镜像仓库,实现这些操作需要额外的一整套方案。

事实上,目前市面上已有多种构建容器的工具。来自 Sysdig 公司的 Michael Ducy 在分会场中回顾了 Docker 本身之外的 8 种镜像构建工具,而这也很可能不是全部。Ducy 将理想的构建工具定义如下:可以用可重现的方式创建最小化镜像。最小化镜像并不包含操作系统,只包含应用本身及其依赖。Ducy 认为 Distroless, SmithSource-to-Image 都是很好的工具,可用于构建最小化镜像。Ducy 将最小化镜像称为“微容器”。

可重现镜像 reproducible container 是指构建多次结果保持不变的镜像。为达到这个目标,Ducy 表示应该使用“宣告式”而不是“命令式”的方式。考虑到 Ducy 来自 Chef 配置管理工具领域,你应该能理解他的意思。Ducy 给出了符合标准的几个不错的实现,包括 Ansible 容器Habitatnixos-容器Simth 等,但你需要了解这些项目对应的编程语言。Ducy 额外指出 Habitat 构建的容器自带管理功能,如果你已经使用了 systemd、 Docker 或 Kubernetes 等外部管理工具,Habitat 的管理功能可能是冗余的。除此之外,我们还要提到从 Docker 和 Buildah 项目诞生的新项目 BuildKit, 它是 Red Hat 公司 Atomic 工程的一个组件。

使用 Buildah 构建容器

 title=

Buildah 名称显然来自于 Walsh 风趣的 波士顿口音; 该工具的品牌宣传中充满了波士顿风格,例如 logo 使用了波士顿梗犬(如图所示)。该项目的实现思路与 Ducy 不同:为了构建容器,与其被迫使用宣告式配置管理的方案,不如构建一些简单工具,结合你最喜欢的配置管理工具使用。这样你可以如愿的使用命令行,例如使用 cp 命令代替 Docker 的自定义指令 COPY 。除此之外,你可以使用如下工具为容器提供内容:1) 配置管理工具,例如Ansible 或 Puppet;2) 操作系统相关或编程语言相关的安装工具,例如 APT 和 pip; 3) 其它系统。下面展示了基于通用 shell 命令的容器构建场景,其中只需要使用 make 命令即可为容器安装可执行文件。

# 拉取基础镜像, 类似 Dockerfile 中的 FROM 命令
buildah from redhat

# 挂载基础镜像, 在其基础上工作
crt=$(buildah mount)
ap foo $crt
make install DESTDIR=$crt

# 下一步,生成快照
buildah commit

有趣的是,基于这个思路,你可以复用主机环境中的构建工具,无需在镜像中安装这些依赖,故可以构建非常微小的镜像。通常情况下,构建容器镜像时需要在容器中安装目标应用的构建依赖。例如,从源码构建需要容器中有编译器工具链,这是因为构建并不在主机环境进行。大量的容器也包含了 psbash 这样的 Unix 命令,对微容器而言其实是多余的。开发者经常忘记或无法从构建好的容器中移除一些依赖,增加了不必要的开销和攻击面。

Buildah 的模块化方案能够以非 root 方式进行部分构建;但mount 命令仍然需要 CAP_SYS_ADMIN,有一个 工单 试图解决该问题。但 Buildah 与 Docker 都有同样的限制,即无法在容器内构建容器。对于 Docker,你需要使用“特权”模式运行容器,一些特殊的环境很难满足这个条件,例如 GitLab 持续集成;即使满足该条件,配置也特别繁琐

手动提交的步骤可以对创建容器快照的时间节点进行细粒度控制。Dockerfile 每一行都会创建一个新的快照;相比而言,Buildah 的提交检查点都是事先选择好的,这可以减少不必要的快照并节省磁盘空间。这也有利于隔离私钥或密码等敏感信息,避免其出现在公共镜像中。

Docker 构建的镜像是非标准的、仅供其自身使用;相比而言,Buildah 提供多种输出格式,其中包括符合 OCI 标准的镜像。为向后兼容,Buildah 提供了一个“使用 Dockerfile 构建”的命令,即 buildah bud, 它可以解析标准的 Dockerfile。Buildah 提供 enter 命令直接查看镜像内部信息,run 命令启动一个容器。实现这些功能仅使用了 runc 在内的标准工具,无需在后台运行一个“臃肿的守护进程”。

Ducy 对 Buildah 表示质疑,认为采用非宣告性不利于可重现性。如果允许使用 shell 命令,可能产生很多预想不到的情况;例如,一个 shell 脚本下载了任意的可执行程序,但后续无法追溯文件的来源。shell 命令的执行受环境变量影响,执行结果可能大相径庭。与基于 shell 的工具相比,Puppet 或 Chef 这样的配置管理系统在理论上更加可靠,因为它们的设计初衷就是收敛于最终配置;事实上,可以通过配置管理系统调用 shell 命令。但 Walsh 对此提出反驳,认为已有的配置管理工具可以在 Buildah 的基础上工作,用户可以选择是否使用配置管理;这样更加符合“机制与策略分离”的经典 Unix 哲学。

目前 Buildah 处于测试阶段,Red Hat 公司正努力将其集成到 OpenShift。我写这篇文章时已经测试过 Buildah,它缺少一些文档,但基本可以稳定运行。尽管在错误处理方面仍有待提高,但它确实是一款值得你关注的容器工具。

替换其它 Docker 命令行

Walsh 在其演讲中还简单介绍了 Red hat 公司 正在开发的另一个暂时叫做 libpod 的项目。项目名称来源于 Kubernetes 中的 “pod”, 在 Kubernetes 中 “pod” 用于分组主机内的容器,分享名字空间等。

Libpod 提供 kpod 命令,用于直接检查和操作容器存储。Walsh 分析了该命令发挥作用的场景,例如 dockerd 停止响应或 Kubernetes 集群崩溃。基本上,kpod 独立地再次实现了 docker 命令行工具。kpod ps 返回运行中的容器列表,kpod images 返回镜像列表。事实上,命令转换速查手册 中给出了每一条 Docker 命令对应的 kpod 命令。

这种模块化实现的一个好处是,当你使用 kpod run 运行容器时,容器直接作为当前 shell 而不是 dockerd 的子进程启动。理论上,可以直接使用 systemd 启动容器,这样可以消除 dockerd 引入的冗余。这让由套接字激活的容器成为可能,但暂时基于 Docker 实现该特性并不容易即使借助 Kubernetes 也是如此。但我在测试过程中发现,使用 kpod 启动的容器有一些基础功能性缺失,具体而言是网络功能(!),相关实现在活跃开发过程中。

我们最后提到的命令是 push。虽然上述命令已经足以满足本地使用容器的需求,但没有提到远程仓库,借助远程仓库开发者可以活跃地进行应用打包协作。仓库也是持续部署框架的核心组件。skopeo 项目用于填补这个空白,它是另一个 Atomic 成员项目,按其 README 文件描述,“包含容器镜像及镜像库的多种操作”。该项目的设计初衷是,在不用类似 docker pull 那样实际去下载可能体积庞大的镜像的前提下,检查容器镜像的内容。Docker 拒绝加入 检查功能,建议通过一个额外的工具实现该功能,这促成了 Skopeo 项目。除了 pullpush,Skopeo 现在还可以完成很多其它操作,例如在,不产生本地副本的情况下将镜像在不同的仓库中复制和转换。由于部分功能比较基础,可供其它项目使用,目前很大一部分 Skopeo 代码位于一个叫做 containers/image 的基础库。Pivotal、 Google 的 container-diffkpod pushbuildah push 都使用了该库。

kpod 与 Kubernetes 并没有紧密的联系,故未来可能会更换名称(事实上,在本文刊发过程中,已经更名为 podman),毕竟 Red Hat 法务部门还没有明确其名称。该团队希望实现更多 pod 级别的命令,这样可以对多个容器进行操作,有点类似于 docker compose 实现的功能。但在这方面,Kompose 是更好的工具,可以通过 复合 YAML 文件 在 Kubernetes 集群中运行容器。按计划,我们不会实现类似于 [swarm] 的 Docker 命令,这部分功能最好由 Kubernetes 本身完成。

目前看来,已经持续数年的 Docker 模块化努力终将硕果累累。但目前 kpod 处于快速迭代过程中,不太适合用于生产环境,不过那些工具的与众不同的设计理念让人很感兴趣,而且其中大部分的工具已经可以用于开发环境。目前只能通过编译源码的方式安装 libpod,但最终会提供各个发行版的二进制包。

本文最初发表Linux Weekly News

via: https://anarc.at/blog/2017-12-20-docker-without-docker/

作者:Anarcat 译者:pinewall 校对:wxy

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