1. 程式人生 > >2018-3-11Linux系統管理(10)(11)程序包初步概念及後端管理工具

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

Linux 系統管理

本章我們來介紹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)程序包初步概念及後端管理工具