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