snap學習之打包Nginx實踐

  snap是Ubuntu母公司Canonical於2016年4月發佈Ubuntu16.04時候引入的一種安全的、易於管理的、沙盒化的軟件包格式。
  snap包基於squashFS文件系統,完全獨立與操作系統,它包含了軟件運行所需要的庫和runtime,並且具有沙箱的屬性,不能隨意的訪問外部資源,需要通過interfaces機制配置接口才能實現。
  snapcraft是構建和發佈snap包的包管理系統。開發者可以編寫配置文件snapcraft.yaml來定義snap包,然後通過snapcraft工具生成和發佈snap包。snapcraft.yaml的詳細定義,請參考https://snapcraft.io/docs/snapcraft-overview,由於涉及的定義很多,這裏不一一描述。在打包Nginx的實踐中,我們針對用到的字段做詳細說明。

  下面我們開始在Ubuntu 16.04上實踐打包Nginx。

1.軟件安裝
  Ubuntu 16.04自帶snap和snapcraft,可以用which命令確認一下。如果軟件未安裝,直接安裝一下。

  sudo apt install snap
  sudo apt install snapcraft  

  snapcraft工具也可以直接安裝snap包版本。

  sudo snap install snapcraft --classic

  Ubuntu 16.04自帶的或用apt安裝的snapcraft版本較舊,默認使用snap base是core,snap安裝的snapcraft版本較新,默認使用的snap base是core18。實際實踐中,我使用了Ubutu 16.04自帶的snapcraft,用的snap base是core。
  snap base是snap包執行的基礎環境,在安裝snap包的時候,如果本地沒有snap base,會自動下載。我們可以用snap命令查看本地是否存在。

  pp@pp-ThinkPad-S2-2nd-Gen:~$ snap list
  Name       Version    Rev   Tracking  Publisher   Notes
  core       16-2.42.5  8268  stable    canonical✓  core
  core18     20200113   1650  stable    canonical✓  base

  文件一般在/snap目錄下。

  我們再確認一下snap的後臺服務snapd是否已經啓動。

  pp@pp-ThinkPad-S2-2nd-Gen:~$ ps -A | grep "snapd"
   5072 ?        00:00:36 snapd
  17926 ?        00:00:00 snapd

  如果snapd未啓動,需要用命令啓動。

  service snapd start

2.打包nginx軟件
2.1 註冊登錄
  snapcraft工具完成打包後,可以直接把snap包發佈到snap store上。爲此,我們需要到https://snapcraft.io/account上申請Ubuntu One賬號,並登錄。

  pp@pp-ThinkPad-S2-2nd-Gen:/snap$ snapcraft login
  Enter your Ubuntu One e-mail address and password.
  If you do not have an Ubuntu One account, you can create one at  https://snapcraft.io/account
  Email:

  登錄之後,就可以創建我們發佈到snap store上的包的名字。

  pp@pp-ThinkPad-S2-2nd-Gen:~/snap$ snapcraft register ****
  
  We always want to ensure that users get the software they expect 
  for a particular name.
  
  If needed, we will rename snaps to ensure that a particular name
  reflects the software most widely expected by our community.
  ......

  註冊好之後,我們可以登錄https://snapcraft.io/snaps查看創建好的snap包名字。

2.2 初始化snapcraft工程
  我們爲nginx工程創建nginx-snap目錄,並初始化,生成了snapcraffile:///C:/Users/zhangjijin.ROGEN/Desktop/教程/snap/snap hooks實現安裝過程中config文件拷貝.mdt.yaml文件。

  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap$ snapcraft init
  Created snap/snapcraft.yaml.
  Go to https://docs.snapcraft.io/the-snapcraft-format/8337 for more 
  information about the snapcraft.yaml format.

  生成的snapcraft.yaml文件內容如下:

  name: my-snap-name # you probably want to 'snapcraft register <name>'
  version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'
  summary: Single-line elevator pitch for your amazing snap # 79 char long summary
  description: |
    This is my-snap's description. You have a paragraph or two to tell the
    most important story about your snap. Keep it under 100 words though,
    we live in tweetspace and your description wants to look good in the snap
    store.

  grade: devel # must be 'stable' to release into candidate/stable channels
  confinement: devmode # use 'strict' once you have the right plugs and slots

  parts:
    my-part:
      # See 'snapcraft plugins'
      plugin: nil

  snapcraft.yaml文件由以下字段組成:
  name —— snap包的名字
  version —— snap包的版本號。可以是源代碼git庫中分支或者標籤,也可以是當前日期或者自定義
  summary —— 不超過80個字符的摘要
  description —— 不超過100個字的snap包描述
  grade —— snap包的質量等級,stable或者devel。如果需要在snap store的stable channel中發佈snap包,需要設置成stable
  confinement —— 標記snap運行時,與系統的隔離度。有3個等級:devmode、strict、classic,通常開發時,設置爲devmode,snap包驗證完成後,改爲classic
  parts —— 描述snap包中代碼如何獲取、依賴關係和如何編譯等
  另外一個重要字段是apps —— 描述snap包暴露出來給外部調用的命令或服務名稱

2.3 打nginx軟件的snap包
  下面我們結合nginx的實際情況對snapcraft.yaml文件進行修改來完成打包。
  從nginx源碼下載地址http://nginx.org/download/上我們看到最新的nginx源碼版本是1.17.7,源碼編譯使用autotools,因此文件修改爲:

  name: nginx
  version: '1.17.7'
  summary: nginx server
  description: |
      nginx is a free, open-source, high-performance HTTP server and reverse proxy, as well as an IMAP/POP3 proxy server.
  
  grade: stable
  confinement: devmode

  apps:
    nginx:
      command: nginx
      plugs: [home]
  
  parts:
  nginx:
      source: http://nginx.org/download/nginx-1.17.7.tar.gz
      source-type: tar
      plugin: autotools
      configflags:
          - --conf-path=/var/snap/nginx/common/conf/nginx.conf
          - --error-log-path=/var/snap/nginx/common/logs/error.log
          - --http-log-path=/var/snap/nginx/common/logs/access.log
          - --pid-path=/var/snap/nginx/common/run/nginx.pid
          - --lock-path=/var/snap/nginx/common/lock/nginx.lock
          - --http-client-body-temp-path=/var/snap/nginx/common/lib/nginx_client_body
          - --http-proxy-temp-path=/var/snap/nginx/common/lib/nginx_proxy
          - --http-fastcgi-temp-path=/var/snap/nginx/common/lib/nginx_fastcgi
          - --http-uwsgi-temp-path=/var/snap/nginx/common/lib/nginx_uwsgi
          - --http-scgi-temp-path=/var/snap/nginx/common/lib/nginx_scgi
          - --with-http_ssl_module

  configflags字段描述了執行configure命令的參數,具體參數不做具體描述了。這裏重點說明一下/var/snap/nginx/common/這個目錄。
  我們以nginx snap包爲例,snap包安裝完成後,它的文件系統被劃分爲只讀和可讀寫的兩種不同權限的區域,一般情況下只讀區域爲/snap/nginx目錄,可讀寫區域就是/var/snap/nginx/common/,因爲用戶需要修改nginx的配置文件,nginx服務也會生成各種日誌,因此我們就需要把編譯參數中的目錄都修改到這個可讀寫目錄來,這個跟apt安裝的nginx服務有較大區別。

  snapcraft.yaml文件修改後之後,我們就開始打snap包,但打包過程中,會遇到以下錯誤:

  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ sudo snapcraft
  ......  
  ./configure: error: the HTTP rewrite module requires the PCRE library.
  ......
  ./configure: error: the HTTP gzip module requires the zlib library.
  ......
  ./configure: error: SSL modules require the OpenSSL library.
  ......

  我們在parts中增加編譯所依賴的包:

  build-packages: [ libpcre3, libpcre3-dev, zlib1g, zlib1g-dev,  openssl, libssl-dev ]

  依賴包的包名,我們可以通過apt命令查找到,例如:

  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ sudo apt-cache search PCRE
  ......
  libpcre3 - Old Perl 5 Compatible Regular Expression Library - runtime files
  libpcre3-dbg - Old Perl 5 Compatible Regular Expression Library - debug symbols
  libpcre3-dev - Old Perl 5 Compatible Regular Expression Library - development files
  libpcre32-3 - Old Perl 5 Compatible Regular Expression Library - 32 bit runtime files
  ......

  打包過程中,遇到問題修改後,重新打包時,需要clean掉重新編譯。

  sudo snapcraft clean
  sudo snapcraft

  添加好依賴包之後,終於打包成功了。

  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ sudo snapcraft
  ......  
  usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
  usr/lib/x86_64-linux-gnu/libssl.so.1.1
  Snapping 'nginx' /                                                                                                             
  Snapped nginx_1.17.7_amd64.snap
  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ ls
  nginx_1.17.7_amd64.snap  parts  prime  snap  snapcraft.yaml  stage

3.安裝驗證
  nginx的snap打好了,我們來安裝驗證nginx snap包。

  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ sudo snap install ./nginx_1.17.7_amd64.snap --dangerous --devmode
  nginx 1.17.7 installed
  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ which nginx
  /snap/bin/nginx

  安裝nginx snap包後,我們可以看到snap包的默認安裝目錄是/snap下。
  我們來驗證一下nginx能否正常工作。

  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ sudo nginx
  nginx: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.27' not found (required by nginx)
  nginx: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.25' not found (required by /snap/nginx/x1/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1)

  執行nginx命令,無法正常運行,缺少libc.so庫,我們再修改snapcraft.yaml文件,通過stage-packages字段在parts中添加運行時的依賴庫。

  stage-packages: [ libc6, libc6-dev ]

  重新執行snapcraft命令打包,並重新安裝nginx snap包。

  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ sudo snap remove nginx
  nginx removed
  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ which nginx
  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ sudo snap install ./nginx_1.17.7_amd64.snap --dangerous --devmode
  nginx 1.17.7 installed
  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ nginx
  nginx: [alert] could not open error log file: open() "/var/snap/nginx/common/logs/error.log" failed (2: No such file or directory)
  2020/01/28 17:39:10 [emerg] 17947#0: open() "/var/snap/nginx/common/conf/nginx.conf" failed (2: No such file or directory)

  出現無法打開log文件和無法找到配置文件的錯誤,這是因爲安裝nginx snap包時,在snapcraft.yaml文件中定義的文件,並沒有被複制到對應的可讀寫區目錄中,還在只讀區的安裝目錄中,我們來看一下。

  pp@pp-ThinkPad-S2-2nd-Gen:/snap/nginx/current/var/snap/nginx/common$ ls
  conf  logs  run
  pp@pp-ThinkPad-S2-2nd-Gen:/snap/nginx/current/var/snap/nginx/common$ cd /var/snap/nginx/common
  pp@pp-ThinkPad-S2-2nd-Gen:/var/snap/nginx/common$ ls
  pp@pp-ThinkPad-S2-2nd-Gen:/var/snap/nginx/common$ 

  我們把只讀區的common目錄中的內容拷貝到可讀寫區的對應目錄中,並手動創建lib目錄,再次執行nginx命令,成功。

  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ sudo nginx
  pp@pp-ThinkPad-S2-2nd-Gen:~/nginx-snap/snap$ ps -A | grep "nginx"
  18109 ?        00:00:00 nginx
  18110 ?        00:00:00 nginx

4.後續工作
  以上我們熟悉了使用snapcraft工具打包snap包的過程,和snap包的初步驗證過程,還有兩部分的工作,我們會在後續的教程中詳細講述,請大家持續關注。
  1) 使用snap hooks在安裝時自動把配置文件從只讀區拷貝到可讀寫區
  2) 搭建lxc容器,在乾淨的ubuntu環境中驗證snap包

  nginx包的snapcraft工程文件請訪問https://github.com/dangelzjj/enjoy_snap.git

5.參考資料:
  https://tutorials.ubuntu.com/tutorial/create-your-first-snap
  https://snapcraft.io/docs/t/pre-built-apps/6739
  https://snapcraft.io/docs/snapcraft-parts-metadata
  https://snapcraft.io/docs/snapcraft-app-and-service-metadata
  https://snapcraft.io/docs/supported-plugins
  https://snapcraft.io/docs/autotools-plugin

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章