2018-3-11Linux系统管理(10)(11)程序包初步概念及后端管理工具

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018-3-11Linux系统管理(10)(11)程序包初步概念及后端管理工具相关的知识,希望对你有一定的参考价值。

  本章我们来介绍Linux程序包的概念及安装校验卸载等管理操作。

一、概述

  我们不止一遍讲述过操作系统的概念,首先是硬件,计算机它的计算能力都是在硬件设计逻辑上实现的,而这个设计硬件设计逻辑不同厂商所生产的硬件芯片及接口的方式都不一样。那么在向上一层就是将硬件规格给封装起来的操作系统层,它将硬件的差异化和复杂化而由丑陋的接口隐藏起来,向上提供了一个简洁而又统一的接口,我们称之为系统调用(system call),但系统调用仍然很底层,为了加速开发和易于维护,在系统调用的半层接口上又封装了一个更复杂的接口,我们称之为库调用(lib call),因为对于程序开发者来讲,既可以面向半层来写程序,又可以面向操作系统层上的系统调用接口来写程序,最后在向上就是各种各样的应用程序了,而对于主要的对于生产力来说就是在操作系统上跑的应用程序,在众多应用程序当中,还有让用户与主机交互的我们称之为shell程序,所以,各种各样的任务操作都是由应用程序来完成的。

  所以在运维过程中,除了系统管理及库调用之外,最主要就是在操作系统上安装及配置程序包,然后让该程序运行起来,并提供服务,或完成某种具体的相应操作的过程,安装及卸载程序包,是运维最基本也是最根本的任务,因为我们需要实现安装及管理程序包等操作。但是,任何程序的运行,在程序包上会提供至少两种的格式的安装包,一种为源码包,另一种为二进制包,那么我们就得需要回顾一下APIABI

  API层次兼容未必就ABI层次兼容,因为有些操作系统的执行格式并非是相同的,对于类Unix程序来说,它们的执行程序为ELF,对于Windows来说,它们的执行格式为.exe,或msi,因此它们在ABI层次上并不兼容,即使用高级语言编写的程序,在源码层是兼容的,但对二进制层来说相互并不一定兼容。所以说带来的结果是如果在将源码包在Linux上编译好了,在Windows上运行是很难实现的,反过来也亦是如此。
不过,虽然很难,我们可以借助于虚拟化,使得二者的差异性将其磨平,比如现在各种应用程序,几乎都是针对库调用来开发的,在系统调用上开发也是没有问题的,现在有很多Windows程序也模拟Linux库的程序,相反也有Linux模拟Windows库的程序,比如说WinE,在Windows我们可以安装Cywin来进行模拟。

   概述:
       API:Application Program Interface
       ABI:Application Binary Interface
          Unix -like
            ELF
           Windows
            exe, msi
            
           库级别的虚拟化:
            Linux:WinE
            Windows:Cywin

  不过,这些都是一些虚拟化的借助工具而已,由于ABI和库调用是不兼容的或不相同的在二进制层次上,它们并没有办法实现互相调用。

  那么各种编程语言当中,对于高级语言来说,大体分为两类,一种是系统级开发,还有一种是应用级开发,有些程序对于系统要求比较严苛而且是服务级别的程序的话,可能会使用系统级开发来编写该程序,现在的程序可能柔和多种编程语言的风格,对于系统要求较高的,都会使用系统级开发去编写该程序,而使用应用级开发有可能是对用户来说去写一些辅助程序,所以我们来总结一下。

       系统级开发:
          C/C++:httpd, vsftpd, nginx
          go
       应用级开发:
          Java/Python/perl/ruby/php
             java: hadoop, hbase
             Python: OpenStack
             perl: perl
             ruby:(ruby)
             php:(php)

  但无论是哪一种应用程序,像C/C它们依赖于库,这种库是由系统根据某一种标准来提供的,而这里的库调用指的就是C/C的库,在系统中/lib或/lib64等目录,指的就是里面的库程序,而它们通常是共享库,而应用级别,例如Java,要想运行某个Java程序,需要依赖于JVM,也就是Java虚拟机,同时,Python也是一样,要想运行需要依赖于PVM,也就是Python虚拟机,而这种解释器或虚拟机,是由C/C++开发的,因此对于应用级开发来说,运行性能会差一些,但是代码量较小,库接口丰富,所以写代码的周期较短一些,不过需要确保运行的环境存在,则可以运行该程序。

  不过,由于拿到的程序有可能是两种格式,这里指C/C++来说,一种为源代码,另一种为二进制,对于源代码来说,就是由文本格式编写的程序代码,万一只是提供了源代码,我们是需要进行手工编译的,而要想进行编译,需要依赖编译开发环境,而提供开发环境是一件很费力的一件事情,而对于二进制来说是由文本格式的程序代码经过编译器成为该平台运行后的二进制格式,不过对于二进制格式文件来说,有四类文件组成,我们来总结一下:

       C/C++程序格式:
          源代码:文本格式的程序代码;
             编译开发环境:编译器、头文件、开发库;
          二进制格式:文本格式的程序代码 --> 编译器 --> 二进制格式(二进制格式、库文件、配置文件、帮助文件);

  在二进制格式中,配置文件是由文本保存的,这也是Linux重要的哲学思想之一,所以的配置信息保存在文本文件里,这样做的好处是可以使用不同的文本编辑器可以打开该配置文件。

  而对于java/Python等这样的应用级开发语言来说,它们的格式也是一样的,也无非就是源代码或二进制,对于源代码来说也是需要编译的,但不同的是,它们的编译与系统级开发的语言编译有所不同,因为应用级开发语言的编译并不是指的是在CPU上运行的二进制格式,而是能够编译成其在虚拟机上所运行的二进制格式,意味着虚拟机能够转换或翻译成CPU所理解的格式,中间多了一层,所以说性能差也就是这个原因,而无论是C还是java,它们生成的目标程序文件都不止一个,所以我们在编译程序时,有可能会出现错综复杂的依赖关系,这样也导致有可能先编译第一个,不过依赖于第二个,那就先把被依赖的程序先编译,或许第二个也依赖于第三个,除非能读懂源代码,因此各种各样的源代码都会使用一个项目构建工具来实现。

  对于java和python来说,它们也有自己的开发环境,只不过它们的开发环境就是所对应的应用程序的虚拟机,和虚拟机所提供的编译器。也需要开发库,只不过没有头文件而已。

        java/Python程序格式:
          源代码:编译成能够在其虚拟机(jvm/pvm)运行的格式;
             开发环境:编译器、开发库
          二进制
    
        项目构建工具:
          c/c++:make
          java:maven

  所以说为了降低终端用户的使用难度,我们就要使用程序包来协助终端用户的管理工作。

二、程序包管理器

  俗话说:送佛送到西,那么在这里的意思就是这个源代码程序,为了尽可能提高终端用户的体验,将源代码编译成可在所需要的目标系统上能运行的二进制格式,不过编译完成之后,其实除了二进制文件及库文件还有帮助文件及配置文件,编译起来也是非常困难,所以在编译好之后,把这四类文件按照特定的方式组织起来,组织成一个或有限几个"包"文件,要成为包文件的话,它必须要实现几个基本操作,比如:安装、卸载、查询升级等操作,甚至对于Linux来说还能实现校验的操作。

  而将源代码转换成目标二进制文件(包含这四类文件),而要想组织成一个或有限几个包文件的话,这就需要包管理器来实现。

  对于Linux来说,我们得需要知道它背后发生了什么,因为它是个自由软件程序,自由的代价是责任,自己需要去实现各种各样的功能,而后还要对其背后的运作过程有所了解,才能够真正实现自由的目的,所以说这个程序包怎么组织实现及如何使用,我们都需要知道其背后如何运作。

  Linux发行版共有三大主流分支,分别是DebianRedHatS.u.S.E,它们使用的程序包管理器,并不一定完全相同,因为自由,各自为站,那么对于三大阵营的程序包管理器我们总结一下。

   程序包管理器:
      源代码 --> 目标二进制格式(二进制程序、库文件、配置文件、帮助文件) --> 组织成为一个或有限几个"包文件";
         安装、升级、卸载、查询、校验;
        
      程序包管理器:
         debian:dpt, dpkg, ".deb"
         redhat:redhat package manager, rpm, ".rpm"; rpm is package manager
         S.u.S.E:rpm, ".rpm"
        
         Gentoo:ports
         ArchLinux:

  那么接下来我们说一下程序包的组成格式,Linux的重要组成思想叫做一个程序只做一件事,并且做好,组个小程序能够完成复杂任务。所以说带来的结果就是,所以说程序包都是简单而又单一的,而单个程序通常非常简单,而带来的结果就是一个程序运行的话,可能要依赖于其它程序,不过我们先说一下程序包的组成格式,我们先说一下源代码的组成包,源码包的通常的命名格式为:name-VERION.tar.gz,而rpm包命名格式为:name-VERSION-release.arch.rpm,而对于VERSION来说,包含什么,以及包名的详细信息,我们总结如下:

       源代码:name-VERION.tar.gz
          VERSION: major.minor.release
                     主    次     发行
          主:代表重大的版本分支;
          次:在这个分支版本进行改变;
          发行:修复某个bug;
    
       rpm包命名格式:
          name-VERSION-release.arch.rpm
              VERSION: major.minor.release
              release.arch: rpm包的发行号;
                  release.os:2.el7.i386.rpm
                  archetecture: i386, X64(amd64), ppc, noarch
                
              redis-3.0.2.tar.gz --> redis-3.0.2-1.centos7.x64.rpm

  每一次版本演进会有chagelog,主要发生了那些改变,详细都会有相关的说明,而这种文档就叫做chagelog。除了i386还有i686,区别就是对于CPU的新旧支持,i386能够支持较老的32位CPU,i686支持较新的32位CPU,对我们来讲并没有太大区别。

  对于rpm包来说,有拆包的习惯,其原因就是有很多种程序功能可能并不需要,将一个包的多种功能给它拆分成多个组成部分,所以使得用户可以按需安装,拆完之后就分为了主包和支包,主包就是与该程序命名相同,而支包就是命名加上该功能(function)即可。

           拆包:主包和支包
              主包:name-VERSION-release.arch.rpm
              支包:name-funcation-VERSION-release.arch.rpm
                  function: devel, utils, libs, ...

  拆成多个包之后,很有可能会存在依赖关系,在Linux中,每个程序都做到短小精悍,所以每个程序包的体积都是很小的,但是这样一来,每个程序包都很简单,于是必须要依赖于其它依赖包的功能所能够为自己运行。所以包与包之间会存在复杂的关系,比如说我们去安装X包,X又依赖于Y和Z,而安装Y时又依赖A、B、C,而C又依赖于Y,那么这是一种循环依赖关系,如果要强制安装的话,其功能无法完全发挥出来。如果有自动解决的前端工具,这种工具借助于包管理器自动解决包和包之间的依赖关系,从而安装那个安装包依赖性都会自动给予解决。

       依赖关系:
          X, Y, Z
        
            X --> Y,Z
                Y --> A, B, C
                C --> Y
                
          前端工具:自动解决依赖关系;
             yum:rpm包管理器的前端工具;
             apt-get(apt-cache):deb包管理器的前端工具;
             zypper:suse的rpm管理器前端工具;
             dnf:Fedora22+系统上rpm包管理器的前端工具;

  前端管理工具能解决后端管理工具的诸多不便之处,这样使得管理操作更为简洁。不过我们需要先学习后端包管理工具的用法,然后再去学前端管理工具所带来的各种功能,最后我们可以使用源代码包来进行编译安装。

2.1 程序包管理器

  我们说一下程序包管理器的本身,其功能和组成部分为:

       程序包管理器:
          功能:将编译好的应用程序的各组成文件打包成一个或几个程序包文件,从而更方便地实现程序包的安装、升级、卸载和查询等管理操作;

  因此,一个程序包的组成格式,大体上有以下几种:

        1、程序包的组成清单(每个程序包都单独实现);
             文件清单;
             安装或卸载时运行的脚本
        
        2、数据库(公共)
             程序包的名称和版本;
             依赖关系;
             功能说明;
             安装生成的各文件的文件路径及验证码信息;
             等等等
            
             /var/lib/rpm

2.2 获取程序包途径

  要想安装或管理程序包的话,得先知道从某些位置去获取安装包,对于开源的程序包,收费的数量很少,所以不存在什么盗版问题,但是可能存在篡改问题,所以要在正规途径获取,那么获取程序包的方式总结如下:

       获取程序包的途径:
          (1) 系统发行版的光盘或官方的文件服务器(或镜像站点);
             http://mirrors.aliyun.com
             http://mirrors.163.com
            
          (2) 项目的官方站点
          (3) 第三方组织
              (a) EPEL
              (B) 搜索引擎
                  http://pkgs.org
                  http://rpmfind.org
                  http://rpm.phone.net
       
          (4) 自己动手,丰衣足食;
        
          建议:检查其合法性
              来源合法性
              程序包的完整性

三、CentOS系统上rpm命令管理程序包

  其实对于安装包的管理来说无非就是:

   安装、升级、卸载、查询和校验、数据库维护

  以上前五种都使用rpm命令来实现管理,该命令格式如下:

   rpm命令:rpm [OPTIONS] [PACKAGE_FILE]

  如果要想查询该安装包的话,只需在后面跟上该安装包的名称而已,而安装时必须要指明PACKAGE_FILE才可以,该命令的选项如下:

     安装:-i, --install
     升级:-U, --update, -F, --frshen
     卸载:-e, --erase
     查询:-q, --query
     校验:-V, --verify
     数据库维护:--builddb, initdb

3.1 安装

  每一种功能都有很多专用的子选项,有许多复杂的使用机制,安装的子命令及选项为:

   安装:
      rpm {-i|--install} [install-options] PACKAGE_FILE
    
         rpm -ivh PACKAGE_FILE
        
         GENERAL OPTIONS
             -v: verbose, 详细信息;
             -vv: 更详细的输出;
            
         [install-options]:
             -h: hash marks输出进度条;每个#表示2%的进度;
             --test:测试安装,检查并报告依赖关系及冲突信息等;
             --nodeps: 忽略依赖关系;不建议;
             --replacepkgs: 重新安装,但不能重置配置文件;

  每一个程序包在安装时会自带运行一些脚本,共分为四类,来做一些准备操作,所以我们需要注意的是:

         注意:
            rpm可以自带脚本;
                四类:--noscripts
                    preinstall:安装过程中开始之前运行的脚本,%pre, --nopre
                    postinstall:安装过程完成之后运行的脚本,%post --nopost
                    preuninstall:卸载过程真正开始执行之前运行的脚本,%perun, --nopreun
                    postuninstall:卸载过程完成之后运行的脚本,%postun, --nopostun
               
         --nosingnature:不检查签名信息,及不检查来源合法性;
         --nodigest:不检查包完整性信息;

3.2 升级

  以上就是安装程序包的内容,接下来我们开始讲述如何升级安装包,一旦某个程序包发现了严重了bug,或者是某个功能有个重大版本演进的时候,我们将会把该程序包升级为较新的版本中。而升级所用到的rpm包的操作与安装是类似的,只不过将安装换成了升级而已。那么升级的子命令为:

   升级:
      rpm {-U|--upgrade} [install-options] PACKAGE_FILE ...
      rpm {-F|--freshen} [install-options] PACKAGE_FILE ...
    
         -U:升级或安装;
         -F:升级;
        
         rpm -Uvh PACKAGE_FILE ...
         rpm -Fvh PACKAGE_FILE ...
        
            --oldpackage:降级;
            --force:强制升级;

  对于升级安装包来说,我们需要注意的是:

       注意:
          (1) 不要对内核升级:Linux支持多内核版本并存,因此,直接安装新版本内核;
          (2) 如果原程序包的配置文件安装后曾被修改过,升级时,新版本的程序提供一个配置文件不会覆盖原有的版本的配置文件,而是把新版本的配置文件重命名为(FILENAME.rpmnew)后提供(保留);

3.3 卸载

  接下来说卸载安装包的操作,卸载就是将该程序从系统中移除,那么卸载的子命令为:

   卸载:
      rpm {-e|--erase} [--allmatches] [--nodeps] [--noscripts] [--test] PACKAGE_FILE ...
    
         --allmatches:卸载所有的匹配制定名称的程序包的各个版本‘
         --nodeps:忽略依赖关系;
         --test:测试卸载,dry run模式;

3.4 查询

  查询安装包对我们来讲是一件非常重要的功能及能力,将来经常能用到,也是非常重要的一个操作手段,而且它的选项也非常之多,那么查询的子命令为:

   查询:
      rpm {-q|--query} [select-options] [query-options]
    
         [select-options]
             PACKAGE_NAME:查询指定程序包是否已经安装,及其版本;
             -a, --all:查询所有已经安装过的包;
             -f FILE:查询指定的文件由那个程序包安装生成;
        
             -p, --package PACKAGE_FILE:用于实现对未安装的程序包执行查询操作;
        
             --whatprovides CAPABILITY:查询指定的CAPABILITY由那个程序包提供;
             --whatrequires CAPABILITY:查询指定的CAPABILITY被那个包所依赖;
            
         [query-options]
             --chagelog:查询rpm包的chagelog;
             -l, --list:程序安装生成的所有文件列表;
             -i, --info:程序包相关的信息,版本号、大小、所属的包组,等;
             -c, --configfiles:查询指定的程序包提供的配置文件;
             -d, --docfiles:查询指定的程序包提供的文档;
             --provides:列出指定的程序包提供的所有的CAPABILITY;
             -R, --requires:查询指定的程序包的依赖关系;
             --scripts:查看程序包自带的脚本片段;
            
         用法:
             -qi PACKAGE, -qf FILE, -qc PACKAGE, -ql PACKAGE, 
             -qd PACKAGE, 
             -qpl PACKAGE_FILE, -qpi PACKAGE_FILE, -qpc PACKAGE_FILE

3.5 校验

  校验是用来查看该程序包是否该篡改,以及检查它的来源合法性,那么校验该子命令的用法为:

   校验:
      rpm {-V|--verify} [select-options] [verify-options]
        
         S file Size differs (文件大小发生改变)
         M Mode differs (include permissions and file type)  (文件权限发生改变)
         5 digest (formerly MD5 sum) differs (MD5发生改变,内容完整性改变)
         D Device major/minor number mismatch    (主/次设备号不匹配)
         L readlink(2) path mismatch (readlink路径不匹配)
         U User ownership differs    (属主发生改变)
         G Group ownership differs   (属组发生改变)
         T mTime differs (时间戳发生改变)
         P caPabilities differ   (capabilites发生改变)

  对于安装包的合法性及完整性,我们是需要验证的,那么安装包的来源及合法性验证如下:

   包来源合法性验证和完整性验证:
      来源合法验证;
      完整性验证;

  对于来源合法性来说,指的就是我们去检查验证由官方签发的数字签名,由非对称加密来实现,生成密钥对儿,称为公钥和私钥,公钥加密后的数据由该私钥解密,反之亦然,使用私钥加密的由该公钥去解密。每一个组织后每个人制作包的时候,就会制作一对儿密钥,然后用自己的私钥进行签名,而公钥是可以公开的,所以只要能解密出来,就可以认为该程序包是原作者的。要想获取程序包的公钥的话,我们可以通过安装盘来获得,名称为RPM-GPG-KEY-CentOS-7,或者在系统上/etc/pki/rpm-gpg/目录下也有该文件,通过它来获取公钥验证程序包的合法与完整性。

    获取并导入信任的包制作者的密钥:
        对于CentOS发行版来说:rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
        RPM-GPG-KEY-CentOS-7
        
    验证:
        (1) 安装此组织签名的程序时,会自动执行验证;
        (2) 手动验证:rpm -k PACKAGE_FILE;

  所有的数字签名都是用自己的私钥去加密对应数据的特征码,这样可以实现两重作用,第一就是来源合法性,第二就是数据完整性可以做到验证。但这两种加密方式并不涉及保密性的概念及功能。

3.6 数据库重建

  数据库重建这个工作未必能够重建起来,建议不要测试在生产环境中,rpm包管理器通过某个数据库来对包进行查询操作的,该路径在/var/lib/rpm目录下,所以安装的所生成的那些文件及目录信息由数据库记录及提供,所以查询操作就是由该数据库来实现的。万一数据库损坏,我们可以进行重建,一般来说有两种来进行数据库的重建操作。

   数据库重建:
      rpm管理器数据库路径:/var/lib/rpm
         查询操作:通过此处的数据库进行;
        
      获取帮助:
         CentOS 6: man rpm
         CentOS 7: man rpmdb
        
      rpm {--initdb|--rebuilddb} [--dbpath DIRECTORY] [--root DIRECTORY]
          --initdb:初始化数据库,当前无任何数据库可实例化创建一个新的数据库;已存在时不执行任何操作’
          --rebuilddb:重新构建,通过读取当前系统上所有已经安装过的程序包进行重新创建;


以上是关于2018-3-11Linux系统管理(10)(11)程序包初步概念及后端管理工具的主要内容,如果未能解决你的问题,请参考以下文章

11,Linux磁盘管理

2019.10.11

2019-10-11

Linux命令——系统管理

FreeBSD_11-系统管理——{Part_10 - bhyve}

UNIX/Linux 系统管理技术手册阅读