V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhuang
V2EX  ›  DevOps

一点运维经验,以及运维眼中的发行版

  •  1
     
  •   zhuang · 2015-07-28 02:39:21 +08:00 · 5790 次点击
    这是一个创建于 3402 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    这是一篇以问答形式针对 linux 运维技术中“一致性”问题的总结。

    适合的读者包括一般运维人员和全栈工程师,以及希望了解运维技术的 IT 工作人员。

    本文重点在于软件层面的抽象方法,而不涉及硬件层面的网络拓扑。

    尺度上说,以测试集群 10~100 机器为例,我也没有更大规模的运维经验。生产集群取决于开发人员配备,而生产集群取决于业务类型。以测试集群来衡量更容易体现运维方法的合理性和可扩展性。

    基础问与答

    什么是“一致性”问题?

    简单说,“一致性”问题是运维工作中,为保持开发、测试和生产集群的环境一致所涉及的难点以及解决方法,包括但不限于硬件、网络、操作系统和软件环境。

    为什么要保持一致?

    目的在于在保证可用性的前提下,简化从开发到测试再到部署的时间以及人力成本。

    不能保证一致性的情况下,可用性也不能保证,由此带来的人力和时间成本浪费也非常严重。

    “一致性”的最终目标是什么?

    无论底层实现如何,最终产品运行状态呈现保证二进制的一致性(byte-identical),同时此种保持一致性的方法具有可重现性(reproducible),以方便移植和二次部署。

    对于软件构建而言,一致性的目标是:对于确定的输入来源给出二进制一致的构建结果。

    为什么要追求二进制的一致性?

    • 二进制一致具有天然的一致性保证。
    • 二进制发行(相对于源码发行)具有极佳的可移植性。
    • 二进制发行可以方便地集成到以现代密码学为基础的数字加密体系中。

    “一致性”问题的难点在哪里?

    一般来说,硬件和网络的一致性不强求。硬件仅仅需要 cpu 架构一致即可,而网络一般以部署时参数作为一致性控制手段。

    操作系统的一致性强调内核、工具链、运行时依赖和包管理工具等方面,不强调发行版本身。(尽管多数情况下,发行版决定了一致性的众多因素的选择范围,但选择发行版并不足以保证一致性。)

    软件环境的一致性通常依赖版本控制系统实现,偏向开发范畴。以二进制形式发布可以减少对于操作系统一致性的依赖。(比如采用容器技术)

    从硬件基础到最终的产品呈现,有着过多的层级和变量,维持每个层级的一致和由此引入的管理复杂度都是难点所在。

    实际生产中,最大的非一致来源是操作系统层面的。

    进阶问与答

    操作系统的不一致来源有哪些?

    确定性的来源有:

    • 最大的不一致来源是发行版:在不替换发行版内建组件的前提下,几乎没有办法保证二进制的一致性,即使有,由此带来的人力成本增加也不值得。
    • 内核版本与参数配置:除去硬件支持相关的部分,某些内核参数如 ASLR 会影响到运行时的二进制状态。
    • 工具链:编译器、编译依赖的版本以及编译参数是都会影响到被编译程序的最终二进制表达。
    • 运行时依赖:动态链接的程序实际运行状态会受动态链接库版本的影响。
    • 包管理:某些程序会在编译时获取系统信息,由于包管理对于操作系统基础组件的版本管理不同,也会造成最终的不一致。

    不确定性的来源也很多:

    • 非常多的应用会在编译时引入编译时间等参数,并输出到最终二进制文件中,如常见的 openssl 等等,这需要手动控制编译参数,或者使用官方源提供修改后的编译包。使用发行版官方的二进制源也可以,但考虑到安全策略,并非所有的情形下都可以使用二进制来源。

    如何解决操作系统层面的不一致?

    首先确定发行版,以及发行版的版本。

    内核可以以内核配置文件的形式保持一致,在官方内核源的基础上进行编译。

    工具链系统可以依赖 Bootstrapping) 进行二次构建。

    运行时依赖主要依靠发行版提供的工具进行切换,或者需要手工介入。动态链接库靠 LD_ 相关参数来调节,动态解释器如 python 通过环境变量等调节。

    包管理需要提供基于源代码的构建方式,最好有官方源支持。当然也可以人工操作,只是在大规模集群的管理上,工作量可能不亚于重新实现一套包管理系统。

    使用容器技术可以封装包括工具链、运行时依赖以及包管理工具在内的系统组件,可以大大简化生产系统二进制发布的一致性问题。但仍然需要一整套具有一致性的开发和测试系统来生成具有一致性的容器本身。

    主流发行版对于一致性构建的支持如何?

    简单总结是:基于二进制的发行版目前连自身官方源的一致性都不能解决。

    Debian ReproducibleBuilds

    Debian 这个可能是应用最广泛的发行版仅仅从 2014 年底才开始重视一致性构建,经过两次大规模重构之后,约有 75% 的官方二进制包符合一致性构建标准。(即还有 25% 的二进制包不能确定是由官方源生成。)

    目前仅在 unstalbe 分支进行工具链相关的一致性构建测试。由于一般 Debian 用户会由于稳定性原因使用 stable 分支,依赖 Debian 官方二进制源的一致性构建还需要运维人员自行解决。

    openSUSE open-build-service

    open-build-service 是一套构建平台,Reproducible 是它的特性之一,该项目的应用相对广泛。

    主要适用于纯二进制程序发布,后端实现是脚本化的一致性构建流程,依赖非常复杂。

    官方构建平台的二进制源可用性和可靠性尚可,但不解决运维层面的一致性问题。

    Fedora(RHEL, CentOS) BuildId

    提出了一套“记录-重现-构建-验证”的流程,但并没有在官方源大规模应用。

    该流程建立在可信工具链的基础上,对于运维来说,依旧不解决问题。

    Arch

    无官方支持,官方源依赖 openSUSE 的构建平台

    工程实践

    容器技术

    尽管容器技术是近一年才成为主流,而且容器技术的主要目标并非解决一致性问题,但它确实从另一个角度解决了 linux 集群运维的问题。

    传统解决办法是将“操作系统--工具链--运行依赖--软件”中的除了软件的部分全部交给运维,结果是无论效率还是可靠性都不能保证。

    使用容器技术可以将一致性问题重新解构,运维的工作变成“操作系统--容器宿主--一致容器“,软件自身依赖交给开发人员。

    容器技术解决了一个问题:即使无法重建完全一致的依赖,也可以将当前状态以容器的形式进行二进制发布。而运维层面,解决可重建问题比起解决一致性问题要容易得多。

    基于源代码的发行版

    真正具有生产意义的基于源代码的发行版,可能仅有 Gentoo 一家。

    基于源代码的发行版,天然地解决了“操作系统--工具链--运行依赖”的一致性问题。

    Gentoo 系统的构建相当于在单一系统上完成了一次交叉编译,最终系统的工具链、基础系统和运行依赖全部由本地参数控制生成。假如系统中任何一个环节需要更新安全补丁,可以在任何时间重建从内核到编译器到二进制软件的全部依赖。

    一致容器

    基于 Gentoo+docker 的一致性构建引入了一个新的问题:如何构建具有一致性的容器本身?

    Docker 一直没有解决的一个问题是 Nested builds,通常用来解决一致性问题的办法就是,在 docker 容器中运行 docker,换句话说是构建一个“可以生成其它容器的”容器。

    不得不说,这种办法引入的问题和管理复杂度不比它解决的问题少。

    使用 Gentoo 有一个相对优雅的解决方案,既然 Gentoo 可以非常容易地构建一个一致的系统,也可以构建一个一致的 Gentoo 容器。这个容器既可以作为构建平台,也可以作为生产平台。

    更进一步,这个构建平台可以持久化,保留构建缓存,有其它项目需要构建容器的时候可以重用。另外生产平台可以除去用不到依赖以减小体积,而生产平台的内容可以以二进制的形式直接嵌入到生产平台中,而不需要任何改动。

    wking/dockerfile 就是这样一种思想下的实践。

    edannenberg/gentoo-bb 在前者的基础上针对生产环境做了前述的优化。

    补充

    NixOS 也可以作为 Gentoo 替代。

    相比 Gentoo,NixOS 在内核支持、官方包数量和基于源的编译支持上都有所欠缺,发行版配套工具也不够全面和易用,社区支持相对也弱。

    不过 NixOS 在灵活性和管理思路上要领先很多。对于全栈或者 DevOps 更加友好。

    由于 NixOS 本身并不专注与源代码发布,所以在一致性问题上,需要人工介入比较多。

    8 条回复    2019-03-11 12:37:55 +08:00
    vietor
        1
    vietor  
       2015-07-28 07:29:42 +08:00 via Android
    我们现在,一部分源码编译,一部分官方二进制,自建DNS。
    clongbupt
        2
    clongbupt  
       2015-08-27 00:20:16 +08:00
    基于操作系统发行版如何解决分布式系统一致性中的差异性:如根据系统分工不同,前端服务器,后端服务器,数据库服务器,日志系统,监控系统等系统,我们如何对操作系统的发行版进行考虑?
    zhuang
        3
    zhuang  
    OP
       2015-08-27 11:40:07 +08:00
    @clongbupt

    这个问题太笼统了。笼统地回答的话,有两个方面:

    一是数据和应用(容器)分离,简单的做法就是使用 docker data-only volume 或者其它第三方作为存储后端;

    二是配置和应用(容器)分离,在容器镜像的构建上嵌入某种自动化配置管理,比如基于服务注册和发现的方法和模型。

    帖子里的重点在于 Reproducible ,你的问题侧重于 Stateless ,目前来说两个问题都没有成熟的解决方案。
    fool
        4
    fool  
       2016-11-18 17:16:15 +08:00
    @zhuang

    大神,能不能给一个体现一致性 Reproducible 重要的实操?
    我想拿去考别人
    zhuang
        5
    zhuang  
    OP
       2016-11-18 17:51:52 +08:00 via iPhone   ❤️ 1
    @fool 这个事情实践大于理论,我写的东西主要是理论。如果你要考别人,可以分两个层次,一个是基础层面的,基本的版本控制工作流程,二是经验方面的,大规模部署技术。

    个人层面可以从常见问题开始,比如是否遇到过开发机正常,测试通过然而上线出错的情况,进而如何排查,如何改进降低出错可能等等。

    技术层面我也不是专家,毕竟工作在一线有大规模运维经验的很少。可以侧重问控制侧重点是什么,策略流程中自动化的程度等等。
    fool
        6
    fool  
       2016-11-18 18:46:15 +08:00
    @zhuang

    是这样的,比如
    要求报警 cpu 的使用率的异常而不是阈值,这是体现监控重要的是机械学习
    要求备份一个正在下载没有完成的文件,这是靠断点续传的一种附带的特性功能
    fool
        7
    fool  
       2016-11-18 18:52:16 +08:00
    @zhuang

    诶,好像有点想法了

    我可一搭建两个相同的环境,随便找一个包的 sourcecode ,让其修改后编译并能在另一个环境运行

    说明就这样写 "请修改 sourcecode 并确保符合 reproducible ,成功后拷贝程序至 xx 环境?"

    如果是一个不懂的人那他就会不知道怎么才能符合,如果明白的人那就不会有疑惑因为当前环境(virtual)都是同样的。
    dcoder
        8
    dcoder  
       2019-03-11 12:37:55 +08:00
    @zhuang
    好帖子,Mark 了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3147 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 13:39 · PVG 21:39 · LAX 05:39 · JFK 08:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.